Three how-it-works/how-to-extend reference docs (docs/reference/), each with a coupling section, indexed in docs/README.md. New document-feature skill so docs ship in the same diff as the code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.0 KiB
Stamdata (config-as-code reference data) — how it's built & extended
Business-tunable reference data — the tables the business controls (profession↔diploma map, policy-question text, thresholds) — is typed, checked-in config changed via git → PR → build, not a runtime-editable database. For the why, see ADR-0004 — Stamdata as code; this page is how the code is laid out and how to add a table without coupling. Built in WP-29, hardened in WP-48.
The one rule that shapes everything: no runtime write path
The catalog is the source of truth and lives in code. The admin editor downloads an
edited {table}.json for a human to commit — it never PUTs. The authority that a change is
valid is the CI gate, not the server. This is what keeps a bad edit out of prod instead
of out of the database.
Layered pipeline
Backend (backend/src/BigRegister.Api/Stamdata/):
StamdataCatalog.cs— the registry. Adding a table is one line:StamdataTable.Of<ProfessionMapping>("professions", …).StamdataTable.cs— generic table model: columns are reflected from the typed record (first property = key; temporal iff it hasgeldigVan+geldigTot). HoldsValidate()(referential integrity) andRowsOn(date).StamdataFile.cs— reads the JSON as an embedded resource (identical read from API and test assembly). No write method exists.- Endpoints in
Program.cs:GET /stamdataandGET /stamdata/{table}?peildatum=— reads only, both behind theStamdataAdmingate.
Frontend (src/app/beheer/, the beheer context):
domain/stamdata.ts(pure model +activeOn/rowErrors/toJson),domain/stamdata-editor.machine.ts(Elm-style union — no save Msg by design).contracts/stamdata.dto.ts→infrastructure/stamdata.adapter.ts(list()/load()with aparseStamdataTabletrust boundary; no write method).application/stamdata.store.ts— root singleton; derivesdirty/counts/errors;download()serializes the edited table to a blob to commit.ui/stamdata.page.ts(thin container) +ui/stamdata-table-editor/(the generic grid).
How to add a table (zero UI code)
- Add a typed record + its
professions.json-style embedded JSON inStamdata/. - Register it with one line in
StamdataCatalog.cs. - If it references another table, add a
StamdataRefto the CI gate (below).
That's it — the editor grid renders from the reflected column schema, so no per-table component. This is the payoff of the schema-driven design.
The CI gate is the authority
backend/tests/BigRegister.Tests/StamdataValidationTests.cs. Every_catalog_table_is_valid
covers every registered table generically; the StamdataRef list catches dangling
references (today: Diploma.Opleiding → professions.program). A bad edit, an orphaning
delete, or a premature expire fails the PR build — never prod.
Coupling
Low, and deliberately so. The page is a thin container binding store signals to the grid
organism and mapping the organism's outputs back to store commands
((cellEdited)="store.editCell(…)"); the organism owns no state (pure input/output).
Because the editor is schema-driven, a new table adds no UI coupling. The only
editor-side niceties (WP-48) are fast-feedback nudges — onExpire() reuses the CellEdited
output to set geldigTot; the CI gate stays authoritative.
See also
- ADR-0004 — Stamdata as code — the decision + the org-template exception.
- WP-29 (editor), WP-48 (deletion protection).
backend/src/BigRegister.Api/Stamdata/StamdataCatalog.cs— register a table here.backend/tests/BigRegister.Tests/StamdataValidationTests.cs— the authoritative gate.src/app/beheer/ui/stamdata-table-editor/— the generic, schema-driven grid.- Roles & access — the
stamdata:editcapability + admin gating.