# Signal Support Manual Curated operations knowledge for the Signal CGM documentation readiness platform. Support bot reads this + support-api-ref.json + Barrier Log for troubleshooting. See signal/docs/support-api-ref.json for auto-generated API routes and error codes. --- ## CSV Import Signal ingests order data from any DME order management CSV export. ### Required Columns Column names are matched case-insensitively. At minimum, the CSV must contain identifying and status fields. Signal evaluates each row against documentation requirements and produces a status per patient. | Column | Required | Purpose | |--------|----------|---------| | patient_name | Yes | Patient identifier | | cgm_type | Yes | Device type for LCD rule matching | | sw0_status | No | Signed written order status | | qualifying_visit_date | No | Last qualifying visit date | | pa_status | No | Prior authorization status | | next_shipment_date | No | Expected resupply date | | payer | No | Payer name for routing checks | If a column is absent, Signal treats the requirement as "not evaluated" — not a gap. This prevents false negatives when a supplier's export format omits fields they don't track. ### Validation Rules - Rows with empty patient_name are skipped - Unknown cgm_type values log a warning and skip LCD matching - Date columns must be ISO 8601 (YYYY-MM-DD) or a parseable US format - Files over 10MB are rejected (supplier sends manageable subsets) ### Error Messages (common) | Error | Cause | Fix | |-------|-------|-----| | "Missing required columns" | CSV missing patient_name or cgm_type | Check export template | | "Upload failed — auth error" | API key missing or expired | Generate new key in Railway env | | "Upload failed — CORS error" | Frontend domain not in allow list | Add domain to ALLOWED_ORIGINS_REGEX | | "Upload failed — server error" | Backend crashed or timed out | Check Railway logs | | "No parsable rows found" | All rows failed validation | Check column names in export | --- ## API Reference See `signal/docs/support-api-ref.json` for full auto-generated route listing. ### Authentication - All endpoints require `X-API-Key` header matching the value in Railway env vars - Clerk-authenticated endpoints use Bearer JWT tokens - Dev keys are for sandbox only; rotate before any external user accesses the app ### Key Endpoints | Endpoint | Method | Purpose | |----------|--------|---------| | /api/health | GET | Health check — returns {"status": "ok"} | | /api/upload-csv | POST | Upload and process CSV file | | /api/patients | GET | List all patients with status summary | | /api/patients/{id} | GET | Single patient detail and cascade | | /api/confirm-visit | POST | Record qualifying visit confirmation | | /api/update-doc-status | POST | Update document status for a requirement | | /api/export | GET | Download Signal Report as CSV | ### Common Response Codes | Code | Meaning | Likely Cause | |------|---------|--------------| | 200 | Success | — | | 400 | Bad request | Missing or malformed parameters | | 401 | Unauthorized | Missing or invalid API key | | 403 | Forbidden | Valid key, insufficient scope | | 404 | Not found | Patient ID doesn't exist | | 500 | Server error | Backend exception (check logs) | | 503 | Service unavailable | Database connection issue or deployment cycling | --- ## Status Labels Signal uses 4 UI tabs. The backend computes 8 internal flags that map to these. ### Internal Flags (backend) | Flag | Meaning | Trigger | |------|---------|---------| | SUPPLY_LAPSED | Patient is past resuppy date | next_shipment_date passed | | VISIT_REQUIRED | 6-month qualifying visit expired | qualifying_visit_date > 6 months ago | | RENEWAL_CRITICAL | Prescription renewal due within 15 days | Calculated from renewal date | | RENEWAL_ELEVATED | Renewal due within 30 days | | | RENEWAL_SOON | Renewal due within 60 days | | | RESUPPLY_READY | All requirements met, ready to ship | SWO on file + PA approved + visit current + no cascade gaps | | ACTIVE | Patient is stable, no flags | Nothing due, no gaps | | TRANSFER_PENDING | Incoming from another supplier | Set manually in CSV or UI | ### UI Tabs (frontend, mapped from internal flags) | Tab | Internal Flags Included | |-----|------------------------| | At Risk | SUPPLY_LAPSED | | Action Needed | VISIT_REQUIRED, RENEWAL_CRITICAL, RENEWAL_ELEVATED | | Clear to Ship | RESUPPLY_READY (with no cascade items) | | On Track | ACTIVE, RENEWAL_SOON, TRANSFER_PENDING, NO_RECENT_SHIPMENT | --- ## Documentation Requirements (Cascade) Each patient has a cascade — a list of documentation actions needed to reach Clear to Ship. Cascade items are only shown when their source column was supplied in the CSV. ### Possible Cascade Items | Item | Cause | Cleared By | |------|-------|------------| | Signed Written Order (SWO) | sw0_status is not "On File" | Update sw0_status or use "Confirm Visit" | | Qualifying Visit | qualifying_visit_date missing or > 6 months | Schedule and confirm visit | | Prior Authorization | pa_status is not "Approved" | Submit PA and update status in CSV | | Prescription Renewal | renewal_date approaching or passed | Obtain new prescription | --- ## Common Failures & Resolutions Issues from the Barrier Log that appear most often. Full history at `STTIL-Vault/Projects/Barrier-Log.md`. ### Uploads Fail Silently **Symptoms:** CSV uploads return success but worklist stays empty or shows wrong statuses. No error message shown to user. **Root cause:** `api.js` had `catch { return null }` blocks swallowing all errors. Fixed by re-throwing real errors and adding toast notifications. **Status:** Fixed and deployed. If it recurs, check that: 1. The frontend is deployed from the fix branch (vercel --prod) 2. The backend is deployed from the matching fix (railway up --detach) 3. ALLOWED_ORIGINS_REGEX includes the domain ### Clear to Ship Never Goes Green **Symptoms:** All patients show amber status, even resupply-ready ones. Green count is permanently 0. **Root cause:** The backend scored missing CSV columns as doc gaps. An absent "sw0_status" column meant every patient had a "missing SWO" cascade item. Green = "no cascade items" so green was unreachable. **Fix:** Added "supplied" sentinel flags. An absent column is "not evaluated," not a gap. Green means "no known blocker from the data provided." **Status:** Fixed and deployed. Verify by uploading a CSV with resupply-ready patients — they should show green. ### CORS Errors on Vercel Deploy **Symptoms:** Upload fails with browser CORS error on preview URLs. **Root cause:** ALLOWED_ORIGINS was a fixed list. Vercel preview URLs (project-xxxx.vercel.app) weren't included. **Fix:** Changed to ALLOWED_ORIGINS_REGEX to accept *.vercel.app patterns. ### Status Count Mismatch (Stat Card vs Row Count) **Symptoms:** The stat card shows a different green count than filtering by "Clear to Ship" tab. **Root cause:** Stat card counted RESUPPLY_READY. Tab counted RESUPPLY_READY AND cascade empty. Cascade was never empty (see above). **Fix:** Both now use the same logic: RESUPPLY_READY with no cascade gaps. --- ## Known Issues (Active) | Issue | Status | Workaround | |-------|--------|------------| | Clerk production migration deferred | Blocking real supplier login | Use sandbox keys for dev; manual Google OAuth setup needed | | Gaboro demo API key in Railway env | Security risk before external access | Rotate before Robert Robinson pilot | | granola-ingest portable path | Needs path update | Script works from full path; symlink/alias pending | --- ## Cross-References - **State machine code:** python-backend/core/doc_state_machine.py - **Cascade builder:** python-backend/core/doc_state_machine.py (_build_cascade) - **Frontend status mapping:** signal-ui/src/components/WorklistTable.jsx - **Upload handler:** signal-ui/src/lib/api.js - **API auth:** python-backend/api/main.py (X-API-Key middleware) - **Barrier Log (all resolved issues):** STTIL-Vault/Projects/Barrier-Log.md - **TriLane research library:** Signal workspace (research docs, payer matrix, synthesis)