update CLAUDE.md and coverage calculator; add n8n content radar workflow, vercel SPA rewrite, and ui workspace config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d4e5187350
commit
07120ec062
5 changed files with 112 additions and 42 deletions
112
CLAUDE.md
112
CLAUDE.md
|
|
@ -1,11 +1,11 @@
|
||||||
# STTIL Solutions — Signal | Level 1 Active Context
|
# STTIL Solutions — Signal | Active Build Context
|
||||||
|
|
||||||
## What This Tool Does
|
## What This Tool Does
|
||||||
Signal is a B2B CGM documentation readiness tracker for DMEPOS suppliers.
|
Signal is a B2B DMEPOS documentation readiness tracker for CGM suppliers.
|
||||||
It ingests order data from any DME order management CSV export (e.g., Brightree),
|
It ingests order data from any DME order management CSV export (e.g., Brightree),
|
||||||
evaluates each patient against documentation requirements (6-month qualifying
|
evaluates each patient against documentation requirements (6-month qualifying
|
||||||
visit, PECOS enrollment, SWO, resupply eligibility), and produces a Signal Report
|
visit, PECOS enrollment, SWO, resupply eligibility), and produces an actionable
|
||||||
so supplier staff can prioritize outreach and capture revenue before it leaks.
|
worklist for supplier staff to prioritize outreach and capture revenue before it leaks.
|
||||||
NOTE: Signal identifies gaps. It does not conduct outreach. Never write copy
|
NOTE: Signal identifies gaps. It does not conduct outreach. Never write copy
|
||||||
implying Signal contacts prescribers or patients directly.
|
implying Signal contacts prescribers or patients directly.
|
||||||
|
|
||||||
|
|
@ -24,53 +24,85 @@ and stays predictable.
|
||||||
quantity, payer — NOTHING else
|
quantity, payer — NOTHING else
|
||||||
- All logs use hashed patient_id, never raw
|
- All logs use hashed patient_id, never raw
|
||||||
|
|
||||||
## Level 1 Stack (Active)
|
## Current Stack (Updated 2026-05-29)
|
||||||
- Hosting: Hostinger VPS (self-hosted, data never leaves VPS)
|
- Backend: Railway (Python/FastAPI) — live at https://signal-api-production-91c2.up.railway.app
|
||||||
- Language: Python (FastAPI or Flask)
|
- Database: Supabase (PostgreSQL + RLS policies + Third Party Auth with Clerk)
|
||||||
- Database: PostgreSQL (encrypted at rest, audit logs)
|
- Auth: Clerk — app name: eternal-goblin-1, domain: eternal-goblin-1.clerk.accounts.dev
|
||||||
- Orchestration: n8n self-hosted (24-hr batch trigger)
|
- Frontend: Vite/React (signal-ui) — local dev only at localhost:5173, NOT YET deployed publicly
|
||||||
- Notifications: Self-hosted Mailcow — encrypted email to DME staff only
|
- Orgs in Clerk: STTIL Solutions (default), Gaboro DME (org_3EPAEcAw06V2yGMSkxE3UjqIA3c)
|
||||||
- Frontend: Simple dashboard (Vercel or self-hosted)
|
|
||||||
- Auth: Session tokens in PostgreSQL (no Convex needed for MVP)
|
## Run Commands
|
||||||
|
- Frontend (local): `cd signal-ui && pnpm dev` → localhost:5173
|
||||||
|
- Backend deploy (code change): `railway up --detach` from project root — forces fresh build
|
||||||
|
- Backend redeploy (no code change): `railway redeploy` — reuses existing image
|
||||||
|
|
||||||
## Active Files
|
## Active Files
|
||||||
- python-backend/core/coverage_calculator.py
|
- signal-ui/src/App.jsx — Clerk auth gate, OrganizationSwitcher
|
||||||
|
- signal-ui/src/components/WorklistTable.jsx — main worklist display
|
||||||
|
- signal-ui/src/components/CSVImport.jsx — CSV upload
|
||||||
|
- signal-ui/src/components/CSVExport.jsx — CSV export
|
||||||
|
- python-backend/core/coverage_calculator.py — gap detection logic (see Known Bugs)
|
||||||
- python-backend/core/audit_logger.py
|
- python-backend/core/audit_logger.py
|
||||||
|
- python-backend/core/persistence.py
|
||||||
|
- python-backend/core/supabase_client.py
|
||||||
|
- python-backend/api/main.py
|
||||||
|
- python-backend/api/normalizer.py
|
||||||
- python-backend/config/payer_rules.json
|
- python-backend/config/payer_rules.json
|
||||||
- research/dmepos-research-v3.md (market context)
|
|
||||||
- docs/hipaa-deployment-analysis-v1.md (compliance)
|
|
||||||
- docs/sttil-brand-system-v1.md (brand)
|
|
||||||
|
|
||||||
## Current BAA Obligations (Level 1 Only)
|
## Known Bugs — Fix Before Pilot
|
||||||
- Hostinger VPS: Request BAA (PHI host)
|
1. ~~**Payer matching**~~ — FIXED 2026-05-29. `_normalize_payer()` added to `coverage_calculator.py`. Handles: "Medicare Part B" → medicare, "Tricare for Life" / "TFL" → medicare, "Medicaid - GA" → medicaid, commercial insurer names → commercial.
|
||||||
- Anthropic API: Request BAA if AI layer touches PHI
|
2. **Visit date**: coverage_calculator.py uses shipment_date as proxy for qualifying visit, not an actual visit date. Fix: use stored confirmed visit date when available; fall back to shipment_date - 30 days labeled as estimated.
|
||||||
- Everything else: self-hosted = you are the operator
|
|
||||||
|
|
||||||
## Workload Impact Model (Build This)
|
## Features Not Yet Built — Pilot Priority
|
||||||
Two-curve graph showing supplier staff time over months:
|
- **Confirm Visit workflow**: staff button on each worklist row to record a confirmed visit date. Signal stores it against patient_id in Supabase. This is Signal's core persistent value — without it, visit dates never improve beyond estimates.
|
||||||
- Curve A: Appeals/denials workload (reactive) — starts HIGH, trends DOWN
|
- **Frontend public URL**: DEPLOYED 2026-05-29 — https://signal-ui-xi.vercel.app
|
||||||
- Curve B: Proactive outreach via Signal — starts MANAGEABLE, stays FLAT
|
- **25 CSV variant test suite**: whitepaper requirement. Generate and test 25 mock CSVs with different column orders, headers, date formats, and payer name variants.
|
||||||
- X-axis: Months 1–12 post-onboarding
|
- **Mapping review interface**: confidence score display, user override dropdown per column (per whitepaper spec).
|
||||||
- Crossover point = ROI moment to show on discovery calls
|
|
||||||
|
|
||||||
## What Is Tabled (Do Not Build Yet)
|
## Pilot Readiness — Authoritative Gauge
|
||||||
|
**Progress is measured against the whitepaper checklist only. Do not estimate % from feel.**
|
||||||
|
|
||||||
| Item | Phase | Reason deferred |
|
Whitepaper: `/Users/sttil-solutions/Documents/Obsidian_Vault/STTIL-Vault/Projects/2026-05-18-pilot-readiness-whitepaper.md`
|
||||||
|------|-------|----------------|
|
|
||||||
| AWS infrastructure (any service) | Post-pilot | Jakub (coach, 2026-05-28): mock data is sufficient for demos and pilots. AWS takes 2 hours to set up — do it right before signing live PHI contracts. Do not start during MVP or pilot phase. |
|
### Checklist Status (as of 2026-05-29) — 40-45% pilot-ready
|
||||||
| Dexcom OAuth API integration | Phase 2 | Requires vendor agreement + PHI scope expansion |
|
|
||||||
| Billing system API integration (Brightree, Bonafide, Fastrack, etc.) | Phase 2 | Build after pilot reveals which systems suppliers use; vendor agreements required; PHI scope expands significantly |
|
| Checklist Item | Status |
|
||||||
| CMS and contact management integration (Salesforce, etc.) | Phase 2 | Pilot feedback will reveal if suppliers have CMS and what they use; do not assume |
|
|---|---|
|
||||||
| Prescriber fax automation | Phase 2 | Workflow complexity; Level 1 manual outreach sufficient |
|
| App hosted behind stable URL | PASS — https://signal-ui-xi.vercel.app (deployed 2026-05-29) |
|
||||||
| Patient-facing SMS (Twilio, not SignalWire) | Phase 3 | PHI transmission to third-party; requires BAA + consent layer |
|
| Demo login / controlled access working | PASS |
|
||||||
| Consortium strategy (Level 2/3) | 18–24 months | Depends on 15+ paying Level 1 suppliers first |
|
| Synthetic sample data loads end to end | NOT VERIFIED as Gaboro org |
|
||||||
| Convex | Phase 2+ | Not needed until real-time sync requirements emerge |
|
| 25 CSV variants pass ingestion tests | NOT DONE |
|
||||||
|
| Import flow: mapping, validation, warnings | PARTIAL — CSVImport exists, full mapping review unconfirmed |
|
||||||
|
| Report generation calculates from backend | PASS |
|
||||||
|
| Each status has reason + recommended action | PARTIAL — payer bug fixed; visit date still uses shipment proxy |
|
||||||
|
| Export CSV works and opens cleanly | NOT VERIFIED end to end |
|
||||||
|
| Placeholder content removed | NOT VERIFIED |
|
||||||
|
| Browser smoke test passes | NOT RUN |
|
||||||
|
| Data handling rules documented | PASS |
|
||||||
|
| Real PHI blocked | PASS |
|
||||||
|
| Pilot success metrics written down | PASS |
|
||||||
|
|
||||||
|
Update this table every build session. Re-count PASS items before quoting a % to anyone.
|
||||||
|
|
||||||
|
## What Is Tabled — Do Not Build Yet
|
||||||
|
|
||||||
|
| Item | Phase | Reason |
|
||||||
|
|---|---|---|
|
||||||
|
| AWS infrastructure | Post-pilot | Railway is sufficient until live PHI contracts signed |
|
||||||
|
| Dexcom OAuth API | Phase 2 | Requires vendor agreement + PHI scope expansion |
|
||||||
|
| Billing system API (Brightree, etc.) | Phase 2 | Build after pilot reveals which systems suppliers use |
|
||||||
|
| CMS / Salesforce integration | Phase 2 | Pilot feedback needed first |
|
||||||
|
| Prescriber fax automation | Phase 2 | Manual outreach sufficient for pilot |
|
||||||
|
| Patient-facing SMS | Phase 3 | PHI transmission requires BAA + consent layer |
|
||||||
|
| Doc upload + AI validation | Phase 2 | Explicitly deferred |
|
||||||
|
| Consortium strategy | 18-24 months | Need 15+ paying Level 1 suppliers first |
|
||||||
|
|
||||||
## Instructions for Claude Code Sessions
|
## Instructions for Claude Code Sessions
|
||||||
- Work only on Level 1 scope
|
- Work only on pilot-scope items from the checklist above
|
||||||
- Never suggest adding PHI fields beyond patient_id
|
- Never suggest adding PHI fields beyond patient_id
|
||||||
- Flag any vendor integration that would require a new BAA
|
- Flag any vendor integration that would require a new BAA
|
||||||
- When building calculations, reference payer_rules.json for wear days
|
- When building calculations, reference payer_rules.json for wear days
|
||||||
- When building audit logs, always hash patient_id before storing
|
- When building audit logs, always hash patient_id before storing
|
||||||
- If asked about Phase 2/3, acknowledge and defer — do not spec or build
|
- Use "resupply" not "refill" — CGM supply allowances are exempt from Medicare refill rules
|
||||||
- Use "resupply" not "refill". CGM supply allowances are exempt from Medicare refill rules
|
- Always calculate progress against the whitepaper checklist table above — not subjective feel
|
||||||
|
- Before quoting any % complete to Kisa, count the PASS items in the checklist
|
||||||
|
|
|
||||||
1
n8n-workflows/content-radar.json
Normal file
1
n8n-workflows/content-radar.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -97,9 +97,43 @@ def _get_wear_days(rules: dict, device_type: str, component: str) -> int:
|
||||||
return wear_days
|
return wear_days
|
||||||
|
|
||||||
|
|
||||||
|
_COMMERCIAL_KEYWORDS = {
|
||||||
|
"aetna", "united", "unitedhealthcare", "cigna", "humana",
|
||||||
|
"bcbs", "blue cross", "blue shield", "anthem", "molina",
|
||||||
|
"centene", "wellcare", "oscar", "ambetter", "carefirst",
|
||||||
|
"highmark", "geisinger", "kaiser", "commercial",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_payer(payer: str) -> str:
|
||||||
|
"""
|
||||||
|
Map raw DME CSV payer strings to canonical payer_rules.json keys.
|
||||||
|
|
||||||
|
"Medicare Part B" → "medicare"
|
||||||
|
"Medicaid - GA" → "medicaid"
|
||||||
|
"Aetna PPO" → "commercial"
|
||||||
|
|
||||||
|
Preserves original value in CoverageResult.payer for display.
|
||||||
|
"""
|
||||||
|
s = payer.strip().lower()
|
||||||
|
if "medicare" in s:
|
||||||
|
return "medicare"
|
||||||
|
if "tricare for life" in s or s == "tfl":
|
||||||
|
return "medicare"
|
||||||
|
if "medicaid" in s:
|
||||||
|
return "medicaid"
|
||||||
|
if "tricare" in s:
|
||||||
|
return "commercial"
|
||||||
|
for keyword in _COMMERCIAL_KEYWORDS:
|
||||||
|
if keyword in s:
|
||||||
|
return "commercial"
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
def _get_payer_config(rules: dict, payer: str) -> dict:
|
def _get_payer_config(rules: dict, payer: str) -> dict:
|
||||||
payer_rules = rules.get("payer_rules", {})
|
payer_rules = rules.get("payer_rules", {})
|
||||||
return payer_rules.get(payer.lower(), payer_rules.get("default", {}))
|
normalized = _normalize_payer(payer)
|
||||||
|
return payer_rules.get(normalized, payer_rules.get("default", {}))
|
||||||
|
|
||||||
|
|
||||||
def _compute_priority(flag: CoverageFlag, days_until_end: int) -> int:
|
def _compute_priority(flag: CoverageFlag, days_until_end: int) -> int:
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
allowBuilds:
|
allowBuilds:
|
||||||
'@clerk/shared': set this to true or false
|
'@clerk/shared': true
|
||||||
|
|
|
||||||
3
signal-ui/vercel.json
Normal file
3
signal-ui/vercel.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue