feat(api): typed OpenAPI client consumed by the SPA (Phase 0 finish)#23
Merged
Conversation
Finish Phase 0's typed-client gate: wire the SPA to consume a typed client generated from the live OpenAPI schema, and drift-gate it in CI so it can't go stale. - frontend/lib/apiSchema.ts: typed entrypoint re-exporting the order schemas + the StatusCa7Enum from the generated client (frontend/lib/api-types.ts). - frontend/lib/orders.ts: ORDER_STATUSES is now `... as const satisfies readonly OrderStatus[]`, type-coupling the Orders screen to the API enum (a renamed/removed status breaks the typecheck). - frontend/lib/records.ts: Column.options widened to `readonly string[]` to accept the const-asserted list. - frontend/.gitignore: stop ignoring lib/api-types.ts now that it has a consumer (committed so the SPA builds without a Django runtime; the Docker frontend build has no Django to regenerate it). - tools/modernization/gen_api_client.sh: regenerate schema -> client -> strict typecheck, pinning openapi-typescript to the frontend's version so CI regeneration is byte-identical to a local run. - .github/workflows/ubuntu24.yml: after regenerating, `git diff --exit-code` drift-gates the committed schema + client; runs on PRs into modernization (base_ref) and uploads the regenerated client even on a gate failure. The streaming OUTPUT endpoints (pivot/pegging) are plain Django views (no DRF serializer) so they're absent from the schema by design and keep hand-written shapes. Two contract nuances the typed client surfaced (MO schema has no `item` field; bulk-CRUD operationId collisions) are noted in the plan as non-blocking. Frontend `tsc --noEmit` clean; 73 vitest tests pass.
…, CI-verified)
Generated artifacts, regenerated + drift-checked by ubuntu24.yml:
- generated/openapi.yaml (drf-spectacular, with a migrated DB so the
model-choices enum is complete)
- frontend/lib/api-types.ts (openapi-typescript 7.0.0)
Reviewers can skip these; they're machine-generated and gate-verified.
d4629cf to
407d4fb
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Finishes Phase 0's typed-client gate: the OpenAPI schema + a typed TypeScript client are committed, the SPA consumes the client, and CI drift-gates it against the live API.
Most of the plumbing already existed (drf-spectacular configured,
/api/schema/+ swagger/redoc routes,gen_api_client.sh, a CI step). What was missing — and is delivered here — is the committed client + actual consumption + a drift gate.Committed artifacts (source of truth)
generated/openapi.yaml— OpenAPI 3 schema fromfrepplectl spectacular --validate(covers the DRF input/master-data CRUD).frontend/lib/api-types.ts— typed client (openapi-typescript, pinned 7.0.0). Now committed (it was gitignored before it had a consumer) so the SPA builds anywhere without a Django runtime.SPA consumption
frontend/lib/apiSchema.ts— typed entrypoint re-exporting the order schemas +StatusCa7Enum.orders.ts—ORDER_STATUSES … as const satisfies readonly OrderStatus[]type-couples the Orders screen to the API enum: a renamed/removed status in Django now breaks the frontend typecheck. (records.tsColumn.optionswidened toreadonly.)tsc --noEmitclean + 73 vitest tests pass.Drift gate
tools/modernization/gen_api_client.shregenerates schema → client → strict typecheck, pinningopenapi-typescriptto the frontend's version so CI regeneration is byte-identical.ubuntu24.ymlruns it thengit diff --exit-code— the committed schema/client can't drift from the live API.Scope notes
ManufacturingOrderschema has noitemfield; bulk-CRUD operationId collisions) — noted in the plan as non-blocking cleanups.Large diff is the two generated files (~25k lines) — review the hand-written
apiSchema.ts/orders.ts/ script / workflow. No UI change → no screenshots. Per convention, not auto-merging.Self-review pass
apiSchema.tsto the consumed surface (removed speculativeOrderPatch/EditableOrderField).gen_api_client.shreads theopenapi-typescriptversion from eitherdependenciesordevDependencies(robustness).ManufacturingOrderserializer genuinely omitsitem(the MO grid's item is view/annotation-derived) — kept as a documented non-blocking finding.