Commit Graph

118 Commits

Author SHA1 Message Date
Tyler 1bd2334e40 feat(backend): add PRAGMA user_version migration runner + 0001_initial 2026-06-19 21:19:43 -06:00
Tyler 854078a726 feat(backend): add cyclone.db with engine, SessionLocal, Base, init_db 2026-06-19 21:03:21 -06:00
Tyler 4abc03a003 build(backend): add sqlalchemy>=2.0,<3 dependency 2026-06-19 20:58:57 -06:00
Tyler 53010b89dd docs: add DB + reconciliation implementation plan (30 tasks, 7 phases)
Implements the spec at docs/superpowers/specs/2026-06-19-cyclone-db-reconciliation-design.md.

Phase 1 — Backend foundation (T1-T3): SQLAlchemy dep, db.py skeleton,
PRAGMA user_version migration runner, 0001_initial.sql with 6 tables.
Phase 2 — ORM models (T4-T6): Batch, Claim, Remittance, CasAdjustment,
Match, ActivityEvent + ClaimState enum.
Phase 3 — Reconciliation pure functions (T7-T8): match() with date
window + multi-claim fallback, apply_payment/apply_reversal,
split_unmatched.
Phase 4 — Store facade refactor (T9-T12): CycloneStore replaces
InMemoryStore with same public API + list_unmatched / manual_match /
manual_unmatch; reconcile.run orchestrator wired into store.add().
Phase 5 — API additions (T13-T17): db.init() in startup,
GET /api/reconciliation/unmatched, POST /match, POST /unmatch,
parse-835 response includes reconciliation summary; TODO marker
removal verification.
Phase 6 — Frontend (T18-T26): ClaimState types, api.listUnmatched/
matchRemit/unmatchClaim, useReconciliation hook, ClaimStateBadge
primitive (7 states, same palette), Reconciliation page, sidebar
nav entry, vitest worktree exclude.
Phase 7 — Docs + smoke (T27-T30): README persistence section + DB
URL docs, tick off sub-project 1 plan boxes, full end-to-end smoke
procedure, merge to main.

Total: 30 tasks across 7 phases. TDD discipline per task with
~32 new backend tests + ~4 new frontend tests. Target after
completion: 210 backend + 7 frontend tests passing.
2026-06-19 20:51:31 -06:00
Tyler cf9af8e1d9 docs: add DB + reconciliation design spec (sub-project 2 of 4)
Replaces the in-memory store with SQLite via SQLAlchemy 2.0; adds
automatic 837P ↔ 835 reconciliation on every 835 parse; ships a
manual /reconciliation page; extends the claim lifecycle to a
7-state model with reversal handling.

Key decisions (locked from brainstorming):
- SQLite at ~/.local/share/cyclone/cyclone.db, overridable via
  CYCLONE_DB_URL (Postgres escape hatch)
- SQLAlchemy 2.0 sync ORM; PRAGMA user_version migration runner
- Strict auto-match on patient_control_number (CLM01 == CLP01)
  within +/-7 days of service_date
- 7-state claim model with reversal that sets Claim.state=REVERSED
  and preserves prior state on Match.prior_claim_state
- Reconciliation triggered inside store.add() after ERA persist;
  fail-soft (logged + activity event, never blocks parse)
- 3 new API endpoints; new /reconciliation page; same palette
  and aesthetic voice as sub-project 1

Spec is approved-section-by-section and self-reviewed.
2026-06-19 20:42:44 -06:00
Tyler 87cd51e1fc fix(frontend): replay row-flash on every refetch via dataUpdatedAt key
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.
2026-06-19 20:00:05 -06:00
Tyler fbd03cd321 docs: rewrite root README for sub-project 1 2026-06-19 19:49:48 -06:00
Tyler 307a8d3b69 docs: add co-medicaid reference note 2026-06-19 19:49:34 -06:00
Tyler 8c12e3c81a docs: add x12 naming reference note 2026-06-19 19:49:26 -06:00
Tyler 5927636b7b docs: add 835 reference note 2026-06-19 19:49:15 -06:00
Tyler 9fe41b7269 docs: add 837p reference note 2026-06-19 19:49:02 -06:00
Tyler 5c26d296be feat(frontend): refactor Upload page to use useParse hook 2026-06-19 19:46:12 -06:00
Tyler 7333f0f50e feat(frontend): refactor ActivityLog page to useActivity + primitives 2026-06-19 19:45:12 -06:00
Tyler 22b9eb59d2 feat(frontend): refactor Providers page to useProviders + primitives 2026-06-19 19:44:54 -06:00
Tyler deca199951 feat(frontend): refactor Remittances page to useRemittances + primitives 2026-06-19 19:44:28 -06:00
Tyler 70e7745912 feat(frontend): refactor Claims page to useClaims + primitives 2026-06-19 19:44:00 -06:00
Tyler d7bd061ee0 feat(frontend): add 6 query/mutation hooks (batches, claims, remits, providers, activity, parse) 2026-06-19 19:41:42 -06:00
Tyler 3ddf962da2 feat(frontend): add 6 GET methods (batches, batch, claims, remits, providers, activity) + tests 2026-06-19 19:41:07 -06:00
Tyler 585548e046 feat(frontend): add 1px refetch indicator to Layout 2026-06-19 19:39:33 -06:00
Tyler 6af787614e feat(frontend): add Pagination primitive 2026-06-19 19:37:01 -06:00
Tyler daccb2d223 feat(frontend): add FilterChips primitive 2026-06-19 19:36:41 -06:00
Tyler 511230ec04 feat(frontend): add ErrorState primitive 2026-06-19 19:36:22 -06:00
Tyler fb6730813f feat(frontend): add EmptyState primitive 2026-06-19 19:35:59 -06:00
Tyler f094b250b5 feat(frontend): add Skeleton primitive with scanline-shimmer 2026-06-19 19:35:43 -06:00
Tyler a355922b4c feat(frontend): add shimmer, scan, row-flash keyframes 2026-06-19 19:35:28 -06:00
Tyler ebd5566d7a feat(frontend): wrap App in QueryClientProvider 2026-06-19 19:35:11 -06:00
Tyler a92ec14a37 feat(frontend): add @tanstack/react-query ^5.59.0 2026-06-19 19:34:55 -06:00
Tyler 300522aac1 fix(backend): default GET list endpoints to JSON per spec 6.2
Spec 6.2 says: 'Default JSON response wraps the same data in a
{items, total, returned, has_more} envelope so the frontend can
paginate uniformly.' Previously the GET list endpoints defaulted
to NDJSON (consistent with the parse endpoints), which forced
every curl call to set Accept: application/json.

Now NDJSON is strictly opt-in via Accept: application/x-ndjson;
JSON is the default. Parse endpoints keep their existing NDJSON
default (browser uploads).

T8 test 'test_claims_default_accept_returns_ndjson' updated to
assert the new default.
2026-06-19 19:32:45 -06:00
Tyler 07ceeaf4cd feat(backend): bind serve to 127.0.0.1:8000, honor CYCLONE_PORT/CYCLONE_RELOAD 2026-06-19 19:30:55 -06:00
Tyler 74a673a360 feat(backend): add NDJSON streaming on list endpoints 2026-06-19 19:28:17 -06:00
Tyler cbffdbd2af feat(backend): add GET /api/{remittances,providers,activity} 2026-06-19 19:26:58 -06:00
Tyler cab8ff6656 feat(backend): add GET /api/claims with filter/sort/pagination 2026-06-19 19:26:17 -06:00
Tyler 39379d2d5e feat(backend): add GET /api/batches and GET /api/batches/{id} 2026-06-19 19:25:54 -06:00
Tyler 86e69d5b95 feat(backend): wire parse-837/parse-835 to persist to InMemoryStore 2026-06-19 19:25:23 -06:00
Tyler ca645db518 refactor(store): code quality fixes per review
- iter_claims/iter_remittances now return list[dict] (snapshot under
  the lock, return outside) so slow consumers no longer hold the
  write lock during iteration
- iter_claims gains payer (case-insensitive substring) and
  date_from/date_to filters via the new _date_in_bounds helper
- iter_remittances wires date_from/date_to and payer
- BatchRecord split into BatchRecord837 / BatchRecord835 with
  __new__ dispatch so isinstance narrows result correctly,
  eliminating the four 'type: ignore[assignment]' band-aids
- BatchRecord now rejects naive parsed_at via model_validator
- to_ui_remittance's adjustmentAmount=0.0 is documented as a
  TODO for sub-project 2 reconciliation

151 passed, 1 skipped (no regressions; +6 tests for new filters)
2026-06-19 19:22:44 -06:00
Tyler d0411b8186 fix(store): spec compliance fixes per review 2026-06-19 19:13:52 -06:00
Tyler 0fa80e29d5 feat(backend): add store iterators (claims, remits, providers, activity) 2026-06-19 19:06:10 -06:00
Tyler 2a78d129ca feat(backend): add store mappers (claim, remittance, provider, activity) 2026-06-19 19:05:42 -06:00
Tyler 112c08fe14 feat(backend): add cyclone.store with BatchRecord and InMemoryStore 2026-06-19 19:04:53 -06:00
Tyler da4d02e6e8 chore: ignore .worktrees for subagent-driven development 2026-06-19 18:44:45 -06:00
Tyler d7ef35dd9a docs: add production-readiness implementation plan (33 tasks, 4 phases)
Phases:
1. Backend (T1-T10): cyclone.store module, 6 GET routes, NDJSON streaming,
   parse persistence, uvicorn 127.0.0.1 bind, full test suite run
2. Frontend (T11-T27): react-query wiring, 5 new UI primitives (Skeleton,
   EmptyState, ErrorState, FilterChips, Pagination), Layout-level refetch
   indicator, 5 page refactors (Claims, Remittances, Providers, ActivityLog,
   Upload), 6 hooks, 3 keyframes, api.test.ts
3. Docs (T28-T32): 4 reference notes (837p, 835, x12naming, co-medicaid),
   root README rewrite
4. Smoke (T33): end-to-end manual test with full acceptance checklist

Self-review included at end of plan (spec coverage table + placeholder
scan + type consistency check).

For agentic workers: superpowers:subagent-driven-development (recommended)
or superpowers:executing-plans.
2026-06-19 18:43:17 -06:00
Tyler 078de28cc4 docs: add live-data UX section + aesthetic acceptance checks
- Replace 7.6 (skeleton) with hairline + scanline-shimmer design that
  matches the existing precision-instrument voice (Cabinet Grotesk + Geist
  Mono, true-black + electric-blue, hairline chrome, radial light + grain)
- Add 7.7 Live-data UX patterns: skeleton variants, EmptyState primitive,
  ErrorState primitive, Layout-level refetch indicator, Active filter chips,
  newly-streamed row highlight, status color alignment, pagination footer
- Add 13.1 visual / aesthetic acceptance checks
- Voice decision: stay the course — additive only, no new accent / typeface /
  layout primitive / light theme
2026-06-19 18:36:39 -06:00
Tyler 9e34f22cb3 docs: add production-readiness design spec (local-only, sub-project 1 of 4) 2026-06-19 18:31:40 -06:00
Tyler d34a68ef91 Merge feat/frontend-integration: wire Vite frontend to FastAPI parser with NDJSON streaming 2026-06-19 17:33:38 -06:00
Tyler 3d3bdfb07c feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page 2026-06-19 17:31:59 -06:00
Tyler 999889ecb3 Merge feat/835-era-parser: 835 ERA parser with BPR/CLP/SVC balancing, CO Medicaid config, CLI, and FastAPI route 2026-06-19 17:07:57 -06:00
Tyler 12ac72f915 fix(backend): make 835 summary counts consistent with total_claims 2026-06-19 17:07:54 -06:00
Tyler 8ea951f436 feat(backend): 835 ERA parser with BPR/CLP/SVC balancing, CO Medicaid config, CLI, and FastAPI route 2026-06-19 17:01:57 -06:00
Tyler 3dff38045a Merge feat/api-endpoint: FastAPI surface with NDJSON streaming and CORS for Vite 2026-06-19 16:41:21 -06:00
Tyler 1a7a4d3ce4 Merge feat/clm05-co-validation: CLM05-1 POS + CLM05-2 qualifier validation 2026-06-19 16:41:18 -06:00