docs(sp42): README.md — refresh auth/bind claim, project layout, streaming endpoints, sub-project count

This commit is contained in:
Nora
2026-07-08 23:03:45 -06:00
parent b3aec27e52
commit b0956d039c
+62 -44
View File
@@ -2,12 +2,17 @@
A self-hosted EDI claims management suite for a single billing office. A self-hosted EDI claims management suite for a single billing office.
Parses 837P professional claims and 835 ERA remittances (X12 005010X222A1 Parses 837P professional claims and 835 ERA remittances (X12 005010X222A1
and 005010X221A1), with a local-only FastAPI backend and a React UI for and 005010X221A1), with a FastAPI backend and a React UI for browsing,
browsing, filtering, and inspecting the parsed data. filtering, and inspecting the parsed data.
Local-only on purpose: binds to `127.0.0.1`, no auth, no internet exposure. LAN-only by design: always binds to `0.0.0.0:8000` and requires login
Built for one operator, one machine, one trading partner (Colorado (bcrypt + HttpOnly session cookie; first admin bootstrapped from
Medicaid, currently). `CYCLONE_ADMIN_USERNAME` + `CYCLONE_ADMIN_PASSWORD`). Reachability is
controlled by the host firewall / compose port publishing, not by the
bind address. Built for one operator, one machine, one trading partner
(Colorado Medicaid, currently). Do not expose the published ports to
the public internet. See [SP23](docs/superpowers/specs/2026-06-22-cyclone-ubuntu-docker-deployment-design.md)
for the LAN-bind / Docker / RBAC product fork that shipped 2026-06-23.
## Install ## Install
@@ -184,13 +189,15 @@ happening — clients flip to `stalled` after 30s of total silence
### Endpoints ### Endpoints
| Method | Path | Subscribes to | Default sort | | Method | Path | Subscribes to | Default sort |
| ------ | -------------------------- | ------------------- | ------------------- | | ------ | -------------------------- | -------------------- | ------------------- |
| GET | `/api/claims/stream` | `claim_written` | `-submission_date` | | GET | `/api/claims/stream` | `claim_written` | `-submission_date` |
| GET | `/api/remittances/stream` | `remittance_written`| `-received_date` | | GET | `/api/remittances/stream` | `remittance_written` | `-received_date` |
| GET | `/api/activity/stream` | `activity_recorded` | `-timestamp` (limit 50) | | GET | `/api/activity/stream` | `activity_recorded` | `-timestamp` (limit 50) |
| GET | `/api/acks/stream` | `ack_received` | `-received_date` |
| GET | `/api/ta1-acks/stream` | `ta1_ack_received` | `-received_date` |
All three accept the same query params as their non-streaming All five accept the same query params as their non-streaming
counterparts (`status`, `payer`, `date_from`, …) so a frontend can counterparts (`status`, `payer`, `date_from`, …) so a frontend can
swap a one-shot fetch for a tail with no URL surgery. Responses swap a one-shot fetch for a tail with no URL surgery. Responses
are `Content-Type: application/x-ndjson`. are `Content-Type: application/x-ndjson`.
@@ -743,12 +750,11 @@ backup API).
. .
├── backend/ ├── backend/
│ ├── src/cyclone/ │ ├── src/cyclone/
│ │ ├── api.py # FastAPI app, GET + parse routes, /api/{resource}/stream │ │ ├── api.py # FastAPI app shell (~377 LOC post-SP36; routes live in api_routers/)
│ │ ├── api_helpers.py # NDJSON / content-negotiation / live-tail helpers │ │ ├── api_helpers.py # NDJSON / content-negotiation / live-tail helpers
│ │ ├── pubsub.py # in-process EventBus (drop-oldest, per-kind fan-out) │ │ ├── pubsub.py # in-process EventBus (drop-oldest, per-kind fan-out)
│ │ ├── store.py # CycloneStore, mappers, publish-on-write
│ │ ├── db.py # SQLAlchemy engine, session factory, ORM models │ │ ├── db.py # SQLAlchemy engine, session factory, ORM models
│ │ ├── db_migrate.py # PRAGMA user_version migration runner │ │ ├── db_migrate.py # PRAGMA user_version migration runner (23 migrations)
│ │ ├── db_crypto.py # optional SQLCipher encryption at rest (SP12) │ │ ├── db_crypto.py # optional SQLCipher encryption at rest (SP12)
│ │ ├── audit_log.py # tamper-evident hash-chained audit_log (SP11) │ │ ├── audit_log.py # tamper-evident hash-chained audit_log (SP11)
│ │ ├── inbox_lanes.py # rejected / payer_rejected / candidates / unmatched / done_today │ │ ├── inbox_lanes.py # rejected / payer_rejected / candidates / unmatched / done_today
@@ -756,37 +762,45 @@ backup API).
│ │ ├── inbox_state_277ca.py # 277CA STC A4/A6/A7 → payer_rejected stamp (SP10) │ │ ├── inbox_state_277ca.py # 277CA STC A4/A6/A7 → payer_rejected stamp (SP10)
│ │ ├── providers.py # multi-NPI provider lookups (SP9) │ │ ├── providers.py # multi-NPI provider lookups (SP9)
│ │ ├── payers.py # payer / payer_config lookups (SP9) │ │ ├── payers.py # payer / payer_config lookups (SP9)
│ │ ├── secrets.py # macOS Keychain-backed secret fetcher │ │ ├── secrets.py # macOS Keychain-backed secret fetcher (4-tier: _FILE > env > Keychain > None)
│ │ ├── reconcile.py # pure-function 835→claim match + line-level match │ │ ├── reconcile.py # pure-function 835→claim match + line-level match (SP31 pcn-exact)
│ │ ├── __main__.py # `python -m cyclone serve` │ │ ├── scheduler.py # inbound MFT polling scheduler (SP16, SP27 per-op timeout)
│ │ ├── cli.py # click CLI │ │ ├── edifabric.py # Edifabric /v2/x12/{read,validate} HTTP client (SP40)
│ │ ── parsers/ # X12 tokenizer, models, validator, writers, 277CA, 999, TA1, 270, 271 │ │ ── backup.py / backup_service.py / backup_scheduler.py # SP17 encrypted backups
└── tests/ │ ├── __main__.py # `python -m cyclone serve` (auth bootstrap then dispatch)
├── fixtures/ # co_medicaid_*.txt, minimal_*.txt ├── cli.py # click CLI (15+ subcommands; see cyclone-cli skill)
├── test_api.py # parse-837/835 round-trip ├── api_routers/ # SP36 — 22 FastAPI routers + _shared.py helpers
├── test_api_gets.py # 6 GET endpoints ├── auth/ # SP24 — bcrypt + sessions + matrix_gate + admin users + rate_limit
├── test_store.py # store + mappers + iterators ├── clearhouse/ # SftpClient + InboundFile + SftpStat
├── test_api_streaming.py ├── edi/ # filename regex/builder helpers
├── test_api_stream_live.py # 3 live-tail endpoints + disconnect cleanup ├── handlers/ # SP27 — per-file-type inbound parse handlers
├── test_pubsub.py # EventBus + subscribe/unsubscribe ├── parsers/ # X12 tokenizer, models, validator, writers, 277CA, 999, TA1, 270, 271
├── test_api_parse_persists.py ├── rebill/ # SP41 — in-window rebill pipeline (13 modules)
├── test_db.py / test_db_crypto.py / test_db_migrate.py ├── reissue/ # SP24 — offline 837P reissue workflow
├── test_audit_log.py ├── store/ # SP21 — split CycloneStore facade (16 modules)
── test_inbox_lanes.py / test_inbox_state.py ── submission/ # SP37 — canonical submit_file helper + recover + bulk_ingest
── test_apply_277ca_rejections.py ── tests/ # 178 pytest files (post-SP41)
│ ├── test_sftp_stub.py / test_sftp_paramiko.py │ ├── fixtures/ # 22 entries (837P / 835 / 999 / TA1 / 277CA samples + visits CSV)
── test_providers_seed.py / test_payer_config_loading.py ── test_api_*.py # FastAPI integration via TestClient
├── src/ # React + Vite + TypeScript UI │ ├── test_*.py # pure-unit
│ └── ...
├── src/ # React + Vite + TypeScript UI (12 pages, 84 test files)
│ ├── components/ │ ├── components/
│ │ ├── ui/ # Skeleton, EmptyState, ErrorState, FilterChips, Pagination, … │ │ ├── ui/ # Skeleton, EmptyState, ErrorState, FilterChips, Pagination, …
│ │ ├── ClaimDrawer/ # 12 sibling tests
│ │ ├── RemitDrawer/ # 8 sibling tests
│ │ ├── ProviderDrawer/ # right-anchored side panel
│ │ ├── AckDrawer/ # right-anchored side panel (SP28 ack-claim auto-link)
│ │ ├── inbox/ # 5-lane triage surface (SP14)
│ │ ├── drill/ # DrillStackProvider + DrillableCell + PeekModal
│ │ └── TailStatusPill.tsx # live-tail status badge + reconnect button │ │ └── TailStatusPill.tsx # live-tail status badge + reconnect button
│ ├── pages/ # Claims, Remittances, Providers, Acks, Activity, Upload, Inbox, … │ ├── pages/ # Dashboard, Claims, Remittances, Providers, ActivityLog,
│ │ # Upload, Reconciliation, Inbox, Acks, Batches, BatchDiff, Login
│ ├── hooks/ # useBatches, useClaims, useRemittances, useProviders, useActivity, useParse │ ├── hooks/ # useBatches, useClaims, useRemittances, useProviders, useActivity, useParse
│ │ # + useTailStream, useMergedTail (live tail) │ │ # + useTailStream, useMergedTail (live tail triplet)
│ ├── lib/ # api.ts, format.ts, utils.ts │ ├── auth/ # AuthProvider, RoleGate, api client (SP24)
# + tail-stream.ts (NDJSON parser) ├── lib/ # api.ts, format.ts, utils.ts, tail-stream.ts (NDJSON parser), inbox-api.ts
│ ├── store/ # zustand sample-data + parsed-batches store │ ├── store/ # zustand useAppStore (sample data) + useTailStore (FIFO-capped live tail slices)
│ │ # + tail-store.ts (FIFO-capped live tail slices)
│ └── types/ # shared TS types │ └── types/ # shared TS types
├── config/ ├── config/
│ └── payers.yaml # YAML-driven payer + clearhouse config (SP9) │ └── payers.yaml # YAML-driven payer + clearhouse config (SP9)
@@ -807,11 +821,15 @@ backup API).
> 3. The per-SP spec under [`docs/superpowers/specs/`](docs/superpowers/specs/) for whatever you're touching. > 3. The per-SP spec under [`docs/superpowers/specs/`](docs/superpowers/specs/) for whatever you're touching.
> 4. The per-SP plan under [`docs/superpowers/plans/`](docs/superpowers/plans/) if you're implementing. > 4. The per-SP plan under [`docs/superpowers/plans/`](docs/superpowers/plans/) if you're implementing.
Sub-projects 2 through 19 are **shipped**. See the [completeness Sub-projects 2 through 41 are **shipped** (last merged: SP41 in-window
rebill pipeline, `merge: SP41 inwindow-rebill-pipeline into main` at
`309e6c0`). See the [completeness
review](docs/reviews/2026-06-20-cyclone-completeness-review.md) for review](docs/reviews/2026-06-20-cyclone-completeness-review.md) for
the honest gap analysis against the industry definition of a HIPAA the honest gap analysis against the industry definition of a HIPAA
clearinghouse — the short version is that the local-only, clearinghouse — the short version is that the LAN-only,
single-operator, single-payer design contract is honored, and the single-operator, single-payer design contract is honored (auth per
SP23, encryption at rest via SQLCipher per SP12, RBAC per SP23, audit
log per SP11), and the
items that would be needed to expand that contract (AS2/AS4, SNIP 17, items that would be needed to expand that contract (AS2/AS4, SNIP 17,
HITRUST, 276/277 status, 278 referrals, COB) are intentionally out of HITRUST, 276/277 status, 278 referrals, COB) are intentionally out of
scope. scope.