Files
svg-frontend/doc
greebo 796f0f4af1 feat(frontend): add editor integration shell and draft read-model views
- add editor integration shell
- add editor context read flow
- add draft flow entry handling
- add summary, structure, validation and compare-preview views
- render backend read models for draft and published states
- verify sample-contract entities: 3 seats, 1 group, 1 sector
2026-03-20 18:51:21 +03:00
..

svg-service backend

Backend for SVG scheme upload, draft editing, pricing, diagnostics, publish preview, and publish lifecycle.

Stack

  • Python 3.11
  • FastAPI
  • SQLAlchemy async
  • PostgreSQL 16
  • Docker Compose

Runtime

Default backend port: 9020

Health check:

  • GET /healthz

Main API prefix:

  • /api/v1

Auth header:

  • X-API-Key

Default local admin key:

  • admin-local-dev-key

Core lifecycle

  1. Upload SVG
  2. Normalize and persist structure
  3. Enter editor flow through context + ensure draft
  4. Edit sectors / groups / seats in current draft
  5. Configure pricing and inspect diagnostics
  6. Build pricing snapshot
  7. Inspect publish readiness and publish preview
  8. Publish current draft
  9. If editing is needed after publish, create or ensure a new draft again

Main concepts

Scheme

Top-level business entity.

Scheme version

Concrete version of the scheme. A version can be draft or published.

Current version

The version referenced by the scheme registry as active current.

Draft

Editable current version. All editor mutations and draft pricing operations must target a current draft version only.

Published version

Non-editable current version. If current version is published, editor flow must first create or ensure a new draft.

Upload artifacts

Stored technical artifacts, including:

  • original svg
  • sanitized svg
  • normalized json
  • display svg
  • publish preview json

Editor entry flow

1. Inspect editor state

GET /api/v1/schemes/{scheme_id}/editor/context

Response tells whether:

  • current version is draft
  • editor is available
  • a new draft should be created
  • recommended action is use_current_draft or create_draft

2. Ensure editable draft

POST /api/v1/schemes/{scheme_id}/draft/ensure

Behavior:

  • if current version is already draft: returns it with created=false
  • if current version is published: clones current version into a new current draft and returns it with created=true

Returned scheme_version_id should be reused as:

  • expected_scheme_version_id

for draft reads and mutations.

Optimistic concurrency

Mutable draft flows support optimistic concurrency through query params:

  • expected_current_scheme_version_id
  • expected_scheme_version_id

Typical typed conflicts:

  • stale_current_version
  • stale_draft_version
  • draft_not_editable
  • publish_not_ready

Main operator routes

System

  • GET /healthz
  • GET /api/v1/ping
  • GET /api/v1/db/ping
  • GET /api/v1/manifest

Uploads

  • POST /api/v1/schemes/upload
  • GET /api/v1/uploads
  • GET /api/v1/uploads/{upload_id}
  • GET /api/v1/uploads/{upload_id}/normalized

Scheme registry

  • GET /api/v1/schemes
  • GET /api/v1/schemes/{scheme_id}
  • GET /api/v1/schemes/{scheme_id}/current
  • GET /api/v1/schemes/{scheme_id}/versions
  • POST /api/v1/schemes/{scheme_id}/versions
  • GET /api/v1/schemes/{scheme_id}/publish/validation
  • GET /api/v1/schemes/{scheme_id}/draft/publish-readiness
  • POST /api/v1/schemes/{scheme_id}/publish
  • POST /api/v1/schemes/{scheme_id}/unpublish
  • POST /api/v1/schemes/{scheme_id}/rollback

Editor / draft

  • GET /api/v1/schemes/{scheme_id}/editor/context
  • POST /api/v1/schemes/{scheme_id}/draft/ensure
  • GET /api/v1/schemes/{scheme_id}/draft/summary
  • GET /api/v1/schemes/{scheme_id}/draft/structure
  • GET /api/v1/schemes/{scheme_id}/draft/validation
  • GET /api/v1/schemes/{scheme_id}/draft/compare-preview
  • GET /api/v1/schemes/{scheme_id}/draft/seats/records/{seat_record_id}
  • GET /api/v1/schemes/{scheme_id}/draft/sectors/records/{sector_record_id}
  • GET /api/v1/schemes/{scheme_id}/draft/groups/records/{group_record_id}
  • POST /api/v1/schemes/{scheme_id}/draft/sectors
  • POST /api/v1/schemes/{scheme_id}/draft/groups
  • DELETE /api/v1/schemes/{scheme_id}/draft/sectors/records/{sector_record_id}
  • DELETE /api/v1/schemes/{scheme_id}/draft/groups/records/{group_record_id}
  • PATCH /api/v1/schemes/{scheme_id}/draft/seats/records/{seat_record_id}
  • POST /api/v1/schemes/{scheme_id}/draft/seats/bulk
  • PATCH /api/v1/schemes/{scheme_id}/draft/sectors/records/{sector_record_id}
  • PATCH /api/v1/schemes/{scheme_id}/draft/groups/records/{group_record_id}
  • POST /api/v1/schemes/{scheme_id}/draft/repair-references

Pricing

  • GET /api/v1/schemes/{scheme_id}/pricing
  • POST /api/v1/schemes/{scheme_id}/pricing/categories
  • PUT /api/v1/schemes/{scheme_id}/pricing/categories/{pricing_category_id}
  • DELETE /api/v1/schemes/{scheme_id}/pricing/categories/{pricing_category_id}
  • POST /api/v1/schemes/{scheme_id}/pricing/rules
  • PUT /api/v1/schemes/{scheme_id}/pricing/rules/{price_rule_id}
  • DELETE /api/v1/schemes/{scheme_id}/pricing/rules/{price_rule_id}

Pricing diagnostics

  • GET /api/v1/schemes/{scheme_id}/pricing/coverage
  • GET /api/v1/schemes/{scheme_id}/pricing/unpriced-seats
  • GET /api/v1/schemes/{scheme_id}/pricing/explain/{seat_id}
  • GET /api/v1/schemes/{scheme_id}/pricing/rules/diagnostics

Publish preview

  • POST /api/v1/schemes/{scheme_id}/draft/pricing/snapshot
  • GET /api/v1/schemes/{scheme_id}/draft/publish-preview
  • POST /api/v1/schemes/{scheme_id}/draft/remap/preview
  • POST /api/v1/schemes/{scheme_id}/draft/remap/apply

Structure read model

  • GET /api/v1/schemes/{scheme_id}/current/sectors
  • GET /api/v1/schemes/{scheme_id}/current/groups
  • GET /api/v1/schemes/{scheme_id}/current/seats
  • GET /api/v1/schemes/{scheme_id}/current/seats/{seat_id}/price
  • GET /api/v1/schemes/{scheme_id}/current/svg
  • GET /api/v1/schemes/{scheme_id}/current/svg/display
  • GET /api/v1/schemes/{scheme_id}/current/svg/display/meta

Test mode

  • GET /api/v1/schemes/{scheme_id}/test/seats/{seat_id}

Audit

  • GET /api/v1/schemes/{scheme_id}/audit

Admin / ops

  • GET /api/v1/admin/schemes/{scheme_id}/current/artifacts
  • GET /api/v1/admin/schemes/{scheme_id}/current/validation
  • POST /api/v1/admin/schemes/{scheme_id}/current/display/regenerate
  • POST /api/v1/admin/display/backfill
  • GET /api/v1/admin/artifacts/publish-preview/audit
  • POST /api/v1/admin/artifacts/publish-preview/cleanup
  • GET /api/v1/admin/schemes/{scheme_id}/pricing/categories/cleanup-preview
  • POST /api/v1/admin/schemes/{scheme_id}/pricing/categories/cleanup

Cleanup of test pricing data

Cleanup endpoints are intended for removing diagnostic / test categories accidentally accumulated in a shared scheme.

Preview candidates: GET /api/v1/admin/schemes/{scheme_id}/pricing/categories/cleanup-preview

Execute cleanup: POST /api/v1/admin/schemes/{scheme_id}/pricing/categories/cleanup

Safety notes:

  • use dry_run=true first
  • keep delete_only_without_rules=true unless you intentionally want a harder cleanup
  • prefer matching by prefixes instead of raw ids for repetitive test artifacts

Helper script:

  • backend/scripts/cleanup_test_pricing_data.sh

Example: SCHEME_ID=... DRY_RUN=true ./backend/scripts/cleanup_test_pricing_data.sh

Typical local flow

1. Read current version

GET /api/v1/schemes/{scheme_id}/current

2. Ensure draft

POST /api/v1/schemes/{scheme_id}/draft/ensure

Store returned:

  • scheme_version_id

3. Read draft state

  • GET /draft/summary?expected_scheme_version_id=...
  • GET /draft/structure?expected_scheme_version_id=...
  • GET /draft/validation?expected_scheme_version_id=...
  • GET /draft/compare-preview?expected_scheme_version_id=...

4. Perform editor mutations

Pass:

  • expected_scheme_version_id={draft_scheme_version_id}

on every mutation route.

5. Inspect pricing quality

  • GET /pricing/coverage
  • GET /pricing/unpriced-seats
  • GET /pricing/explain/{seat_id}
  • GET /pricing/rules/diagnostics

6. Build snapshot and inspect readiness

  • POST /draft/pricing/snapshot
  • GET /draft/publish-readiness
  • GET /draft/publish-preview?refresh=true

7. Publish

  • POST /publish?expected_scheme_version_id=...

Regression

Main operator regressions:

  • backend/scripts/smoke_regression.sh
  • backend/scripts/editor_mutation_regression.sh

Run: API_URL=http://127.0.0.1:9020 API_KEY=admin-local-dev-key SCHEME_ID=... ./backend/scripts/smoke_regression.sh

API_URL=http://127.0.0.1:9020 API_KEY=admin-local-dev-key SCHEME_ID=... ./backend/scripts/editor_mutation_regression.sh