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.