Documents the SP16 scheduler control surface (5 endpoints under
/api/admin/scheduler/*) and brings the Project layout tree in sync
with the latest api_routers/ split state:
- new 'Inbound MFT Scheduler (SP16)' section between SFTP Wire-Up
and Batches/Reconciliation/Activity, covering start/stop/status/
tick/processed-files with a forward-compat note that
cyclone.scheduler + cyclone.db.ProcessedInboundFile are in flight
- api_routers/ tree now lists all 14 routers, including the four
parse_* routers (parse_835/837/999/ta1) and admin.py carrying the
scheduler endpoints
- api.py comment updated to 'app + middleware; mounts api_routers/
sub-apps' (no inline route bodies remain)
Another router extraction landed: api_routers/remittances.py now owns
the three /api/remittances[...] routes (list, stream, detail). Pure
code-organization move from api.py — no new endpoints, no new
functionality.
Update the Project layout block to list remittances.py alongside the
other 9 routers with the routes it owns.
Another router extraction landed: api_routers/claims.py now owns the
five /api/claims[...] routes (list, stream, detail, serialize-837,
line-reconciliation). Pure code-organization move from api.py — no
new endpoints, no new functionality.
Update the Project layout block to list claims.py alongside the other
8 routers with the routes it owns.
Four additional routers landed since the last doc pass:
- activity.py (GET /api/activity, /api/activity/stream)
- batches.py (GET /api/batches, /api/batches/{id}, /api/batch-diff)
- providers.py (GET /api/providers)
- clearhouse.py (GET /api/clearhouse, POST /api/clearhouse/submit)
- config.py (/api/config/providers[/...], /api/config/payers[/...],
POST /api/admin/reload-config)
Update the Project layout block to list all 8 routers with the routes
they own. No new functionality is introduced — the refactor is purely
a code-organization move from api.py into the api_routers/ subpackage.
No code changes; no tests touched.
The README's SP-specific endpoint reference blocks (SP3-SP15 in the
Roadmap) cover the per-SP additions, but the pre-existing core operator
surface was never documented as a single block. This pass adds the
missing endpoints:
- GET /api/batches, GET /api/batches/{batch_id} — batch list + detail.
- GET /api/batch-diff?a=<id>&b=<id> — side-by-side diff between two
batches (added/removed/changed claims + envelope metadata).
- GET /api/reconciliation/unmatched — every claim with no paired
remit and every remit with no paired claim; powers the
reconciliation review UI.
- POST /api/reconciliation/match — manual pair (claim_id, remit_id);
400/404/409 contract.
- POST /api/reconciliation/unmatch — remove a match and reset the
claim to 'submitted'.
- GET /api/providers — distinct providers from the parsed claim
stream. Distinct from /api/config/providers/{npi} (the SP9 config
table endpoint).
- GET /api/activity — recent activity events. Powers the Activity
page; the streaming counterpart /api/activity/stream is already
documented under 'Live updates'.
These 7 routes are referenced by the UI (BatchesList, BatchDetail,
BatchDiffView, Reconciliation page, Providers page, Activity page) but
were missing from the README's route inventory. The new section sits
between 'SFTP Wire-Up' and 'Persistence', with a one-paragraph pointer
to the per-SP endpoint reference blocks for SP-specific routes.
No code changes. No tests touched.
The README's most recent merge was SP13. Since then two more sub-projects
landed in main:
- SP14 (5c9365e + 8a65baa) — 5-lane Inbox UI with the Payer-Rejected
lane rendered alongside Rejected/Candidates/Unmatched/Done today,
and a bulk Acknowledge action that drops claims from the working
surface without erasing the original 277CA rejection event. New
endpoint POST /api/inbox/payer-rejected/acknowledge (idempotent,
audit-logged). Migration 0010.
- SP15 (47902fd + ab00909) — SQLCipher key rotation in place via
PRAGMA rekey. New endpoint POST /api/admin/db/rotate-key, serialized
through a module-level threading.Lock. Switches the SQLAlchemy
engine to NullPool when SQLCipher is enabled (QueuePool breaks
SQLCipher thread affinity under FastAPI's per-request threadpool).
Writes a db.key_rotated audit event with old + new key
fingerprints and post-rotation table_count.
What this PR does:
- Inbox section + Inbox endpoint table: document the Payer-Rejected
acknowledge action.
- Encryption at Rest: add a 'Key rotation' sub-section that explains
the rotate-key handler, the NullPool choice, the threading.Lock,
and the error code mapping (409/400/503).
- Tamper-Evident Audit Log: note that key rotations + Payer-Rejected
acknowledgements are part of the audit-logged event set.
- Project layout: add api_routers/ (health.py, acks.py, ta1_acks.py)
as the FastAPI APIRouter subpackage extracted from api.py.
- Roadmap: bump 'shipped 2-13' to 'shipped 2-15'; add SP14 and SP15
entries to the shipped list; add SP14 + SP15 endpoint reference
sections at the end.
Verification:
- pytest --collect-only collects 759 tests (up from 733 at the
previous doc pass).
- git diff --check clean.
- No code changes; no tests touched.
- Mark SP8 as shipped (Sub-projects 2 through 8)
- Drop the 'Next up: outbound 837P serializer' trailer
- New 'Outbound 837 Serializer' section above 'Per-Line Adjustment
Audit': design rationale (Approach A full rebuild vs spec §3.1
hybrid), two-surface UX (single-claim drawer download + multi-claim
inbox ZIP bundle), pointers to the serializer module, the two API
endpoints, the frontend helpers, and the UI entry points.
- New 'SP8 endpoints' subsection in the endpoint inventory.
- Mark SP4 as fully shipped (batch diff, search, CSV, a11y all landed)
- Add SP6 (Inbox) and SP7 (Per-line reconciliation) sections
- Add SP6 + SP7 endpoint inventories
- Note next up: outbound 837P serializer
The workflow-automation plan was authored but never committed; the
features it specified have shipped, so commit it for the historical
record alongside this README refresh.
The previous static key={c.id} let React reuse the same <TableRow>
element across refetches, so animate-row-flash only played on
initial mount and on the first render of a brand-new claim_id.
Updated rows whose claim_id was unchanged never re-flashed.
Re-keying on `${c.id}-${dataUpdatedAt}` re-mounts the row on
every refetch (initial load, filter change, parse invalidation),
so the 1.2s accent-tint flash replays each time.
Also: README's 'Frontend unit tests (when added)' is stale — npm
test now exists and runs 3 passing tests.
hooks: add dataUpdatedAt: 0 to the !isConfigured fallback return
so the pages type-check.