Two-tier service model the marketplace is priced and searched on. Admin catalog skeleton (categories + EAV option groups/values, addable as data not migrations; NULL category = cross-category) and the nurse pricing layer (nurse_service_variants — the atomic bookable unit: category + one value per required dimension at the nurse's own IRR price and price unit). - New `catalog` schema via one additive migration; Price BIGINT (no floats), on the wire as a string of digits; total = price + unit + session_count. - Duplicate-listing guard: deterministic option_set_hash + filtered UNIQUE(nurse_id, service_category_id, option_set_hash) WHERE deleted_at IS NULL + friendly 409 pre-check. One value per dimension; required groups (incl. cross-category) enforced; deactivate, never delete. - Public catalog browse cached behind a CatalogCache generation token, invalidated on any admin write. IVariantSnapshotSerializer shipped for b8. - Contract (catalog.md) + handoff + report published; swagger refreshed. 122 tests green; zero new build warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
OpenAPI snapshots
The server already generates OpenAPI via NSwag (Swagger UI at /swagger, documents v1, v1.1).
This folder holds the published swagger.json snapshot(s) so the frontend can generate/verify types
without running the backend.
Backend: publish on every API-shipping phase
After adding/changing endpoints and confirming the build, export the OpenAPI document and commit it here
as swagger.v1.json (overwrite — git history is the version trail). Typical options:
- Run the API and save
GET /swagger/v1/swagger.jsontodev/contracts/openapi/swagger.v1.json, or - Use the NSwag CLI / build target the server already wires to emit the document.
Record in your handoff that the snapshot was refreshed. Keep it in sync with ../domains/*.md — the
markdown is the human contract, this JSON is the machine contract; they must agree.
Frontend: consume
Generate types from swagger.v1.json (e.g. an openapi-typescript-style step) or hand-write
src/services/{domain}/types.ts to match it. Either way, the wire shapes come from here — not from
guessing. Casing/format questions are resolved by this file.
Until the first API-shipping backend phase runs, this folder is empty by design.