feat: complete published registry contracts and gated SRO ingestion
All checks were successful
Mostovik Backend CI/CD / Tests and lint (push) Successful in 3m55s
Mostovik Backend CI/CD / Build linux/amd64 release images (push) Successful in 3m43s
Mostovik Backend CI/CD / Deploy and verify internal main (push) Has been skipped
Mostovik Backend CI/CD / Deploy customer main (push) Has been skipped
Mostovik Backend CI/CD / Deploy dev (push) Successful in 1m45s

This commit is contained in:
Aleksandr Meshchryakov
2026-09-14 17:01:02 +02:00
parent 49cbfd265c
commit 18971d33ec
76 changed files with 33156 additions and 311 deletions

67
tools/openapi/README.md Normal file
View File

@@ -0,0 +1,67 @@
# Canonical OpenAPI
`GET /openapi.json` serves the OpenAPI 3 document bundled with the backend release.
The Swagger UI and its Swagger 2 export remain available at `/`.
The source is the actual DRF serializers and view annotations. `build.mjs` converts
Swagger 2 to OpenAPI 3, adds the source-record discriminated variants and the named
ordering enum with comma-separated ordering, then validates the resulting document.
Do not edit `src/core/openapi.json` or generated TypeScript by hand.
From the backend root (Python dependencies installed with uv):
```sh
PYTHONPATH=src uv run python src/manage.py generate_swagger tools/openapi/swagger.json --overwrite --format=json --settings=settings.test
cd tools/openapi
bun install --frozen-lockfile --ignore-scripts
bun build.mjs
bun run apigen
bun run type-check
```
The runtime gate also validates rendered responses from the real DRF list/detail
views against Orval's generated Zod schemas, including every documented HTTP
status. Generate its synthetic fixtures in the isolated test database, then run:
```sh
# From the backend root. The parent directory of this explicit path must exist.
OPENAPI_RUNTIME_FIXTURES=/tmp/mostovik-openapi-runtime.json PYTHONPATH=src uv run pytest tests/apps/organizations/test_openapi_runtime_fixtures.py -q
cd tools/openapi
bun run apigen
bun run contract-check /tmp/mostovik-openapi-runtime.json
```
Zod is pinned to 4.3.6. The gate covers a full Budget payload with unknown raw
fields, all five SME size units, nullable SRO admission dates, mixed/filtered lists,
empty arrays and zero counts, and 400/404 errors. Parsed responses must equal the
original JSON so that an apparently successful parser cannot silently discard
raw keys. Ordinary pytest runs write no fixture file; writing is enabled only by
`OPENAPI_RUNTIME_FIXTURES`. No live upstream requests or business databases are
used. The generated validators are disposable build output, never handwritten.
Bun is pinned to 1.3.9 in CI; the tool dependencies are locked in `bun.lock`.
CI regenerates the source Swagger document, runs `bun build.mjs --check`, generates
a client and compiles a strict TypeScript fixture. It fails if the bundled contract
is stale, invalid, loses discrimination, or removes the named ordering enum.
For the frontend, copy the bundled document to its `openapi.json`, then run its own
`bun run apigen` and `bun run type-check`. Keep source-group checks before reading
source-specific payloads. Multipart upload operations now have one accurately
documented content type, so Orval generates `...Mutation` rather than the former
multi-content-type `...MutationWithFormData` name. The generated function still
constructs FormData and sends multipart data.
Before accepting an upgraded live dataset:
```sh
python src/manage.py migrate --noinput
python src/manage.py normalize_published_registry_payloads
python src/manage.py normalize_published_registry_payloads --apply
python src/manage.py build_source_record_exports
```
The first normalization command is a dry run. Applying it preserves record UIDs,
publication timestamps and artifact IDs, but atomically increments the affected
artifact content revisions. New export tickets return 503 until a matching export
generation is built; already issued tickets keep their pinned generation.
SRO access remains gated as described in `docs/sro-membership-source.md`.