Two backlog trees are complete: `docs/project/backlog/` (75 files, every WP done) and `docs/project/refactor-backlog-setup/` (the arc before it). Move both under `docs/project/archive/` with `git mv`, so history stays intact through `git log --follow`. `SHOWCASE-ROADMAP.md` moves with them, because it points at the now-archived backlog README. Add `docs/project/archive/README.md`. It states that these trees are historical and names the two directories that are still live. Repoint every inbound reference named in RD-30's Files table: CLAUDE.md, the root README, both backend READMEs, `LetterHtml.cs`, `a11y.mdx`, the `document-feature` and `new-ssp` skills, and the readable-codebase PLAN, README, and RD-19 ticket. Fix two upward-relative links inside the moved WP files (WP-68, WP-69) that gained a directory level and would otherwise break. Repoint `.prettierignore`'s two agent-prompt exclusions to their new path, so prettier keeps leaving those files' exact wording alone. Mark RD-30 done and check off its acceptance criteria; flip its README row to done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
81 lines
5.5 KiB
Markdown
81 lines
5.5 KiB
Markdown
# WP-29 — Stamdata beheer editor (low-code, PR-emitting)
|
|
|
|
Status: done (0e77faf)
|
|
Phase: follow-on — ADR-0004 realization (not part of the 2026-07-02 showcase audit)
|
|
|
|
## Why
|
|
|
|
ADR-0004 (stamdata-as-code) named a **future low-code editor that commits a PR** as its
|
|
mitigation for "a non-developer may need dev assistance to edit C#", and floated a
|
|
**data-file format** as the alternative to typed-C# constants when hand-editing ergonomics
|
|
outweigh maximal compile-time safety. This WP realizes both: an admin-only maintenance editor
|
|
that reads the stamdata catalog, edits rows in a grid, and produces the edited JSON data-file
|
|
the admin drops into the repo — the existing CI build + `StamdataValidationTests` stay the
|
|
authority. No production database, no runtime write path (ADR-0004 unchanged).
|
|
|
|
## Read first
|
|
|
|
- ADR-0004 (`docs/reference/architecture/0004-stamdata-as-code.md`) — the model this obeys.
|
|
- ADR-0001 (BFF-lite + decision DTOs) — the endpoints are screen-shaped, admin-gated reads.
|
|
- `src/app/brief/**` (WP-23/26) — the org-template admin editor is the closest prior art
|
|
(root store + machine + capability guard + admin role).
|
|
|
|
## Decisions (pre-made, don't relitigate)
|
|
|
|
- **Read-only endpoints only.** `GET /stamdata` (catalog) and `GET /stamdata/{table}?peildatum=`
|
|
(schema + rows). No POST/PUT/DELETE — the edit lands as a reviewed PR, not a write. The
|
|
`stamdata:edit` capability / `CanEditStamdata` gate the _reads_ (naming is the enforce-twin
|
|
of a future edit capability; deliberate).
|
|
- **Generic, schema-driven.** One endpoint pair + one grid editor serve every table. Columns
|
|
are reflected from the typed record (`StamdataTable.Of<T>`); the FE renders inputs by column
|
|
type (`date`/`number`/`enum`/`text`). A new table is one line in `StamdataCatalog` — no new
|
|
endpoint, UI, or test. (Catalog of one today; this is the shape ADR-0004 prescribed.)
|
|
- **Data-file format for `professions`.** `professions.json` (embedded resource) replaces the
|
|
hardcoded C# dictionary, deserialized into `ProfessionMapping`. This trades compile-time
|
|
_value_ checking (gate #1) for editor ergonomics — the value gate becomes
|
|
`StamdataValidationTests` (gate #2), exactly the trade-off ADR-0004's consequences listed.
|
|
- **Valid-time.** `geldigVan`/`geldigTot` (half-open `[van, tot)`); a table is temporal iff it
|
|
has both columns. `peildatum` previews "which rows applied on date X". `Professions.ByProgram`
|
|
preserves pre-valid-time behaviour by filtering to rows active today.
|
|
- **Apply path = download → PR.** The editor's `download()` serializes the draft to
|
|
`{table}.json`; the admin commits it. `mutation-command` is intentionally not used.
|
|
- Admin-only, resource-independent authz — same shape as org-template management (role IS the
|
|
decision), denials audited (no PII).
|
|
|
|
## Files
|
|
|
|
- Backend: `backend/src/BigRegister.Api/Stamdata/{StamdataCatalog,StamdataTable,StamdataFile,ProfessionMapping}.cs` (new), `Professions.cs` (now loads the data-file), `professions.json` (new), `BigRegister.Api.csproj` (embed `Stamdata\*.json`); `Program.cs` (two GET endpoints + `StamdataAdmin` gate), `Contracts/Dtos.cs` (3 DTOs), `Domain/Authorization/Authz.cs` (`stamdata:edit` + `CanEditStamdata`); tests `StamdataEndpointTests.cs` (new), `StamdataValidationTests.cs` (generic `Every_catalog_table_is_valid`).
|
|
- Frontend: `src/app/beheer/**` (contracts / domain + specs / infrastructure + spec / application / ui + organism story); `app.routes.ts` (guarded lazy route), `shared/domain/capability.ts` + `shared/infrastructure/me.adapter.ts` (`stamdata:edit`), `eslint.config.mjs` (`beheer` boundary rules), `tsconfig.json` (`@beheer/*` alias); regenerated `backend/swagger.json` + `src/app/shared/infrastructure/api-client.ts`.
|
|
|
|
## Acceptance criteria
|
|
|
|
- [x] `GET /stamdata` and `GET /stamdata/{table}` return admin-only (403 + audit otherwise).
|
|
- [x] `professions` served from `professions.json`; `ProfessionMapping` typed; behaviour of
|
|
`Professions.ByProgram` unchanged for all-current rows.
|
|
- [x] Generic build gate: `Every_catalog_table_is_valid` covers every catalog table (keys
|
|
non-blank, no overlapping validity, well-formed windows).
|
|
- [x] `beheer/stamdata` route capability-guarded; page shows denial for non-admin; grid
|
|
renders from reflected schema; edits update dirty/change-count; `download()` yields a
|
|
valid `{table}.json`; `peildatum` before 2000-01-01 → zero rows.
|
|
- [x] Full gate GREEN both sides; `npm run gen:api` leaves no drift; new stamdata story passes axe.
|
|
|
|
## Verification
|
|
|
|
`cd backend && dotnet test && dotnet format --verify-no-changes`; `npm run lint && npm run
|
|
check:tokens && npm test && npm run build && npm run build-storybook && npm run test-storybook:ci`;
|
|
`npm run gen:api && git diff --exit-code -- backend/swagger.json src/app/shared/infrastructure/api-client.ts`.
|
|
Live: `/beheer/stamdata?role=admin` renders + edits + downloads; without `?role=admin` denies.
|
|
|
|
## Out of scope
|
|
|
|
- Runtime persistence of edits (would contradict ADR-0004) — the download-to-PR path is the design.
|
|
- Migrating `PolicyQuestions` / document-categories into the catalog (each is a later one-liner).
|
|
- A write-back "commit a PR on the admin's behalf" integration (the `download()` seam is where it slots in).
|
|
|
|
## Risks
|
|
|
|
- Data-file weakens compile-time value safety for `professions` — mitigated by
|
|
`StamdataValidationTests` running in CI (a bad value fails the build, never prod).
|
|
- Generic reflection assumes the record's first property is the key and camelCase JSON names —
|
|
documented conventions in `StamdataTable`; covered by the endpoint schema test.
|