diff --git a/.superpowers/skills/cyclone-api-router/SKILL.md b/.superpowers/skills/cyclone-api-router/SKILL.md index 4f3aa97..47f8cb5 100644 --- a/.superpowers/skills/cyclone-api-router/SKILL.md +++ b/.superpowers/skills/cyclone-api-router/SKILL.md @@ -5,23 +5,27 @@ description: "Cyclone FastAPI router conventions (api_routers/, api_helpers.py, # cyclone-api-router -Cyclone splits its FastAPI surface two ways: small resource-group -routers live in `backend/src/cyclone/api_routers/.py` and are -mounted bare into `api.py`; the high-traffic streaming and parse -endpoints still live as top-level decorators in `api.py` itself. This -skill codifies the conventions so additions stay consistent with the -four routers already shipped (`acks`, `admin`, `health`, `ta1_acks`). +Cyclone splits its FastAPI surface two ways: resource-group routers +live in `backend/src/cyclone/api_routers/.py` and are mounted +bare into `api.py`; the parse endpoints (`/api/parse-837`, +`/api/parse-835`, plus the SP40 `/api/admin/validate-837` etc.) stay +as top-level decorators in `api.py` because they span multiple store +modules. This skill codifies the conventions so additions stay +consistent with the routers already shipped. -As of this writing: **4 router modules** under -`backend/src/cyclone/api_routers/`, **one shared helpers module** at -`backend/src/cyclone/api_helpers.py` (248 lines, NDJSON primitives + -content negotiation + `tail_events`), and ~30 routes still inlined -in `backend/src/cyclone/api.py`. The next refactor target is the -parse endpoints. +As of this writing: **22 router modules** under +`backend/src/cyclone/api_routers/` (`acks`, `activity`, `admin`, +`batches`, `claim_acks`, `claims`, `clearhouse`, `config`, +`dashboard`, `eligibility`, `health`, `inbox`, `parse`, `payers`, +`providers`, `rebill`, `reconciliation`, `remittances`, `submission`, +`ta1_acks`, plus a `_shared.py` for cross-router helpers), **one +shared helpers module** at `backend/src/cyclone/api_helpers.py` +(NDJSON primitives + content negotiation + `tail_events`), and +`api.py` itself is now 378 LOC (down from ~3,145 pre-SP36). -## Auth gate (SP24) +## Auth gate (SP23) -Every router declared in `backend/src/cyclone/api_routers/` **must** carry `dependencies=[Depends(matrix_gate)]` at the `APIRouter(...)` declaration — not on each individual endpoint. The gate lives at `backend/src/cyclone/auth/deps.py:107` and the role matrix is at `backend/src/cyclone/auth/permissions.py`. The roles are `admin / user / viewer`; `matrix_gate` returns 401 when there's no session and 403 when the role is below the endpoint's required role. When `AUTH_DISABLED` is True (conftest autouse fixture flips it; `CYCLONE_AUTH_DISABLED=1` in prod-by-mistake), the gate short-circuits to a synthetic admin — see the SP24 spec for the threat-model implications. New routers get the gate by default; the auth-aware convention is `router = APIRouter(dependencies=[Depends(matrix_gate)])`. +Every router declared in `backend/src/cyclone/api_routers/` **must** carry `dependencies=[Depends(matrix_gate)]` at the `APIRouter(...)` declaration — not on each individual endpoint. The gate lives at `backend/src/cyclone/auth/deps.py:107` and the role matrix is at `backend/src/cyclone/auth/permissions.py`. The roles are `admin / user / viewer`; `matrix_gate` returns 401 when there's no session and 403 when the role is below the endpoint's required role. When `AUTH_DISABLED` is True (conftest autouse fixture flips it; `CYCLONE_AUTH_DISABLED=1` in prod-by-mistake), the gate short-circuits to a synthetic admin — see the SP23 spec for the threat-model implications. New routers get the gate by default; the auth-aware convention is `router = APIRouter(dependencies=[Depends(matrix_gate)])`. ## When to use @@ -45,11 +49,13 @@ Every router declared in `backend/src/cyclone/api_routers/` **must** carry `depe 1. **No new top-level routes in `api.py` for resource groups.** Any endpoint grouped under a resource (`/api/` and its `/{id}` detail) lives in `backend/src/cyclone/api_routers/.py` - as an `APIRouter`. The streaming list endpoints (`/api/claims/stream`, - `/api/remittances/stream`, `/api/activity/stream`) and the parse - endpoints (`/api/parse-*`) currently stay in `api.py` because they - span multiple store modules — don't move them unless you're also - restructuring the store split. + as an `APIRouter`. The streaming list endpoints + (`/api/claims/stream`, `/api/remittances/stream`, + `/api/activity/stream`, `/api/acks/stream`, `/api/ta1-acks/stream`) + were split into their per-resource routers as part of SP36; only + the cross-resource parse endpoints (`/api/parse-*` and the SP40 + `validate-837`) stay in `api.py` because they span multiple store + modules. 2. **Reuse `api_helpers.py`.** NDJSON primitives (`ndjson_line`, `ndjson_stream_list`, `ndjson_stream_837`, `ndjson_stream_835`), content negotiation (`client_wants_json`, `wants_ndjson`), the @@ -80,8 +86,9 @@ Every router declared in `backend/src/cyclone/api_routers/` **must** carry `depe `StreamingResponse(media_type="application/x-ndjson")` and feed it either `ndjson_stream_list(items, total, returned, has_more)` (for list pages) or `tail_events(request, bus, kinds)` (for live-tail - pages). See `acks.py:62-66` for the list-stream skeleton and - `api.py:1357-1401` for the full live-tail pattern (snapshot → + pages). See `api_routers/acks.py:62-66` for the list-stream + skeleton and `api_routers/claims.py` (the `/api/claims/stream` + handler) for the full live-tail pattern (snapshot → `snapshot_end` → subscription → heartbeats). See `cyclone-tail` for the wire format. 6. **Tests.** Every new endpoint gets a `test_api__.py` @@ -170,12 +177,17 @@ just after middleware registration and just before the first # Resource-group routers. Each module owns its own APIRouter and is # registered below. New resources go in `cyclone.api_routers.` # and are wired in here. -from cyclone.api_routers import acks, admin, health, ta1_acks # noqa: E402 +from cyclone.api_routers import ( # noqa: E402 + acks, activity, admin, batches, claim_acks, claims, clearhouse, + config, dashboard, eligibility, health, inbox, parse, payers, + providers, rebill, reconciliation, remittances, submission, ta1_acks, +) app.include_router(health.router) app.include_router(acks.router) -app.include_router(ta1_acks.router) +app.include_router(activity.router) app.include_router(admin.router) +# ... 18 more include_router calls in api.py ... ``` ## Anti-patterns diff --git a/.superpowers/skills/cyclone-edi/SKILL.md b/.superpowers/skills/cyclone-edi/SKILL.md index fd0097a..4eb83d5 100644 --- a/.superpowers/skills/cyclone-edi/SKILL.md +++ b/.superpowers/skills/cyclone-edi/SKILL.md @@ -7,7 +7,7 @@ description: "Cyclone EDI parser/validator conventions (837P/835/999/270/271/277 Cyclone parses seven X12 EDI transaction types (837P, 835, 999, 270, 271, 277CA, TA1) into typed Pydantic models, then runs per-claim / per-batch validator rules that surface as R-coded `ValidationIssue` records. This skill codifies the conventions so new parsers and rules stay consistent with the seven that already exist. -As of this writing: **7 parser modules** under `backend/src/cyclone/parsers/parse_.py`, **~25 per-claim rules** numbered `R010`–`R100` and `R200`–`R210` in `validator.py`, plus a parallel set of **835-specific rules** prefixed `R835_*` in `validator_835.py`. The next increment is **SP22**. +As of this writing: **7 parser modules** under `backend/src/cyclone/parsers/parse_.py` (837P, 835, 999, TA1, 270, 271, 277CA), **~25 per-claim rules** numbered `R010`–`R100` and `R200`–`R210` in `validator.py`, plus a parallel set of **835-specific rules** prefixed `R835_*` in `validator_835.py`. The most recently shipped increment touching this surface is **SP41** (in-window rebill pipeline); the next free increment after this SP42 doc-pass is **SP43**. ## When to use diff --git a/.superpowers/skills/cyclone-frontend-page/SKILL.md b/.superpowers/skills/cyclone-frontend-page/SKILL.md index 3e0d785..fb72fb3 100644 --- a/.superpowers/skills/cyclone-frontend-page/SKILL.md +++ b/.superpowers/skills/cyclone-frontend-page/SKILL.md @@ -5,9 +5,9 @@ description: "Cyclone React page conventions (TanStack Query, use hook, drawe # cyclone-frontend-page -Cyclone pages live at `src/pages/.tsx`: a `use` hook in `src/hooks/use.ts` does the fetching (and optionally the live-tail subscription), `` + `` + `` (`src/components/`) provide the app shell, and any right-side detail (claim, remittance) lives in `src/components//` whose open/close state is mirrored to the URL via `useDrawerUrlState`. This skill codifies the conventions so additions stay consistent with the eleven pages already shipped. +Cyclone pages live at `src/pages/.tsx`: a `use` hook in `src/hooks/use.ts` does the fetching (and optionally the live-tail subscription), `` + `` + `` (`src/components/`) provide the app shell, and any right-side detail (claim, remittance) lives in `src/components//` whose open/close state is mirrored to the URL via `useDrawerUrlState`. This skill codifies the conventions so additions stay consistent with the twelve pages already shipped (Login added in SP23). -As of this writing: **11 pages** under `src/pages/` (9 of 11 with a `*.test.tsx` sibling — Dashboard, Upload, and BatchDiff are not yet covered; be the first when you refactor them), **~30 hooks** under `src/hooks/`, and **2 drawer modules** at `src/components/{ClaimDrawer,RemitDrawer}/`. The next increment is **SP22**. +As of this writing: `**12 pages** under `src/pages/` (10 of 12 with a `*.test.tsx` sibling — Dashboard and BatchDiff are not yet covered; be the first when you refactor them; the Login page does not need a sibling), **~30 hooks** under `src/hooks/`, and **4 drawer modules** at `src/components/{ClaimDrawer,RemitDrawer,ProviderDrawer,AckDrawer}/`. The most recently shipped increment is **SP41** (in-window rebill pipeline); the next free increment after this SP42 doc-pass is **SP43**. ## When to use