Persist the security-relevant events (authz denials + BIG-nummer reveal/step-up) into a data-minimised EF table (AuthzAuditEntry: At/Action/Resource/Decision/Role/CorrelationId — never a name/BSN/value), extending the DocumentStore AuditEntry pattern (migration AuthzAudit). AuditAuthz now persists via AuthzAuditStore.Record alongside its log line. GET /admin/audit (admin-gated by the existing CasesAdmin) returns the trail newest-first. +3 backend tests incl. a schema-carries-no-PII reflection test. Typed client regenerated (audit() + AuthzAuditDto); no FE consumer yet (a future audit view must add the ROLE_AWARE prefix). Finishes WP-42's audit half. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
142 lines
12 KiB
Markdown
142 lines
12 KiB
Markdown
# Backlog — showcase hardening
|
||
|
||
Ordered work packages that take this POC from "good" to **reference showcase**: CIBG
|
||
design-system fidelity, DDD/FP consistency, Storybook as curriculum, and WCAG compliance
|
||
with automated gates. Source: the architecture/CIBG/a11y audit of 2026-07-02 (plan:
|
||
"Showcase hardening").
|
||
|
||
This backlog **supersedes `docs/project/SHOWCASE-ROADMAP.md`**.
|
||
|
||
## Session protocol
|
||
|
||
- **Switch to Opus first** (`/model opus`) before tackling any WP.
|
||
- **One WP per session.** Read `CLAUDE.md`, this README, the WP file, and the WP's
|
||
"Read first" list — then execute. Do not start the next WP in the same session.
|
||
- The **Decisions** block in each WP is pre-made — don't relitigate it.
|
||
- A WP ends **GREEN** (below) with its acceptance criteria checked off and its Status
|
||
updated to `done` (+ commit hash).
|
||
- No WP leaves a lint rule/check disabled without an inline justification comment **and**
|
||
a cross-reference to the WP that will remove it.
|
||
|
||
## GREEN (global definition of done)
|
||
|
||
```bash
|
||
npm run lint && npm run check:tokens && npm test && npm run build && npm run build-storybook
|
||
```
|
||
|
||
From WP-01 onward, additionally:
|
||
|
||
```bash
|
||
npm run test-storybook:ci
|
||
```
|
||
|
||
Phases 0–5 were frontend-only; **phase 6 (Brief v2) touches `backend/`** — for those
|
||
WPs `cd backend && dotnet test` is part of GREEN, and any wire change ends with
|
||
`npm run gen:api` leaving no drift.
|
||
|
||
From WP-19 onward, `npm run e2e` is part of CI (its own job) but NOT part of the local
|
||
GREEN one-liner above — it needs the real backend + `npm start` already running (see
|
||
WP-19's own file), so it's a separate manual/CI step, not chained into the others.
|
||
|
||
## Order
|
||
|
||
Gates land before the work they cover; each lint rule lands in the same WP as the fixes
|
||
for its existing violations, so every WP ends green.
|
||
|
||
| WP | Title | Phase | Status |
|
||
| ---------------------------------------------- | --------------------------------------------------------------------------------- | --------------------------- | ------- |
|
||
| [WP-01](WP-01-axe-ci-gate.md) | Axe-on-every-story CI gate | 0 · gates | done |
|
||
| [WP-02](WP-02-check-tokens.md) | Harden `check:tokens` + fix what it catches | 0 · gates | done |
|
||
| [WP-03](WP-03-contracts-purity.md) | Boundaries I: contracts purity + ApiClient confinement | 0 · gates | done |
|
||
| [WP-04](WP-04-ui-not-infrastructure.md) | Boundaries II: `ui ↛ infrastructure` + showcase sanction | 0 · gates | done |
|
||
| [WP-05](WP-05-parse-boundaries.md) | Parse-don't-validate closure + MDX | 1 · FP/DDD | done |
|
||
| [WP-06](WP-06-typed-async.md) | Generic async template contexts — kill `$any()` | 1 · FP/DDD | done |
|
||
| [WP-07](WP-07-brief-idioms.md) | Brief on the shared idioms + RemoteData MDX | 1 · FP/DDD | done |
|
||
| [WP-08](WP-08-store-idiom.md) | One store idiom + machine naming + TEA MDX | 1 · FP/DDD | done |
|
||
| [WP-09](WP-09-pure-logic.md) | Pure-logic closure: dates + missing command specs | 1 · FP/DDD | done |
|
||
| [WP-10](WP-10-button-fidelity.md) | CIBG button fidelity | 2 · CIBG | done |
|
||
| [WP-11](WP-11-markup-fidelity.md) | CIBG markup fidelity: application-link + absent-class triage | 2 · CIBG | done |
|
||
| [WP-12](WP-12-datablock.md) | CIBG Datablock for application data | 2 · CIBG | done |
|
||
| [WP-13](WP-13-cibg-gap-register.md) | CIBG-gap register + hygiene + MDX | 2 · CIBG | done |
|
||
| [WP-14](WP-14-storybook-taxonomy.md) | Storybook taxonomy reorg + Layers MDX | 3 · Storybook | done |
|
||
| [WP-15](WP-15-missing-stories.md) | Missing stories: shell + brief components | 3 · Storybook | done |
|
||
| [WP-16](WP-16-component-a11y.md) | Component a11y: description wiring + alert role | 4 · a11y | done |
|
||
| [WP-17](WP-17-app-a11y.md) | App-level a11y: route focus, template lint, WCAG checklist | 4 · a11y | done |
|
||
| [WP-18](WP-18-abac-capability-spine.md) | ABAC capability spine (Principal + capabilities, phase P1) | 5 · productie-volwassenheid | done |
|
||
| [WP-19](WP-19-e2e-smoke.md) | Playwright e2e smoke | 5 · productie-volwassenheid | done |
|
||
| [WP-20](WP-20-second-locale.md) | Second locale proof | 5 · productie-volwassenheid | done |
|
||
| [WP-21](WP-21-resilience-seams.md) | Resilience seams (correlation-id, idempotency, retry) | 5 · productie-volwassenheid | done |
|
||
| [WP-22](WP-22-durable-persistence.md) | Durable persistence (optional tier) | 5 · productie-volwassenheid | done |
|
||
| [WP-23](WP-23-org-template-backend.md) | Org-template backend + admin role | 6 · Brief v2 | done |
|
||
| [WP-24](WP-24-letter-canvas.md) | Letter canvas (edit on the letter) | 6 · Brief v2 | done |
|
||
| [WP-25](WP-25-letter-preview-html.md) | Server-rendered letter preview (HTML; PDF deferred) | 6 · Brief v2 | done |
|
||
| [WP-26](WP-26-org-template-editor.md) | Admin org-template editor | 6 · Brief v2 | done |
|
||
| [WP-27](WP-27-brief-ux-layer.md) | Brief UX layer (undo/redo, standaardbrief, diff) | 6 · Brief v2 | done |
|
||
| [WP-28](WP-28-brief-v2-demo-polish.md) | Brief v2 demo polish (scenarios, e2e, docs) | 6 · Brief v2 | todo |
|
||
| [WP-29](WP-29-stamdata-beheer-editor.md) | Stamdata beheer editor (low-code, PR-emitting) | follow-on · ADR-0004 | done |
|
||
| [WP-30](WP-30-ci-perf-followups.md) | CI performance follow-ups (node_modules cache, runner image, path filters) | follow-on · CI/infra | todo |
|
||
| [WP-31](WP-31-shared-store-helpers.md) | Shared store helpers (ActionState/SaveState, history, debounced-save, RemoteData) | 7 · refinements | done |
|
||
| [WP-32](WP-32-stamdata-undo.md) | Undo/redo in the stamdata editor | 7 · refinements | done |
|
||
| [WP-33](WP-33-dev-switchers.md) | In-app dev switchers (scenario + role) | 7 · refinements | done |
|
||
| [WP-34](WP-34-adres-phone-brp-readonly.md) | Adres: phone field + BRP address read-only | 7 · refinements | done |
|
||
| [WP-35](WP-35-one-concept-per-type.md) | One Concept per case type (server-enforced) | 7 · refinements | done |
|
||
| [WP-36](WP-36-admin-cases.md) | Admin cases page + admin delete | 7 · refinements | done |
|
||
| [WP-37](WP-37-dev-switcher-reset.md) | Dev-switcher reset fix (scenario/role URL param) | 8 · platform/DX/showcase | done |
|
||
| [WP-38](WP-38-dependency-graph-boundaries.md) | Dependency graph + declarative boundaries (visualize + enforce) | 8 · platform/DX/showcase | done |
|
||
| [WP-39](WP-39-showcase-snippets-animations.md) | Showcase: linked code snippets + teaching animations | 8 · platform/DX/showcase | done |
|
||
| [WP-40](WP-40-pii-kernel.md) | PII kernel: branded `Bsn` VO (elfproef) + masked-value atom | 8 · platform/DX/showcase | done |
|
||
| [WP-41](WP-41-persisted-authz-audit.md) | Persisted, queryable authz/PII-reveal audit (no PII) | 8 · platform/DX/showcase | done |
|
||
| [WP-42](WP-42-privacy-security-showcase.md) | Privacy & security showcase page (mask + no-PII log) | 8 · platform/DX/showcase | partial |
|
||
| [WP-43](WP-43-scaffold-generators.md) | Runnable generators: value-object / form-machine / bff-endpoint / ui-component | 8 · platform/DX/showcase | todo |
|
||
| [WP-44](WP-44-context-generator.md) | Runnable generator: `gen:context` | 8 · platform/DX/showcase | todo |
|
||
| [WP-45](WP-45-create-ssp-generator.md) | `create-ssp` bootstrap generator (mechanise new-ssp) | 8 · platform/DX/showcase | todo |
|
||
| [WP-46](WP-46-vitest-coverage.md) | Vitest coverage (report + report-only thresholds) | 8 · platform/DX/showcase | done |
|
||
|
||
Sequencing dependencies (stated in the WPs too): 01 before 10–15 (axe covers story churn);
|
||
03/04 before 05–09 (boundaries stop new violations during refactors); 06 before 07 (typed
|
||
`<app-async>` before brief adopts it); 13 defines the gap-marker format that 11/12 reference
|
||
— if 11/12 run first, they define it and 13 adopts it. 18–22 (phase 5, "productie-volwassenheid")
|
||
are independent of each other and of phases 1–4 — pick any order; **18 is the recommended
|
||
first pick** (it's the headline gap: no authorization spine exists yet, and it closes the
|
||
FE-computed-authz anti-pattern in `brief.store.ts`). 22 is explicitly lower priority — the
|
||
current in-memory persistence is a documented, defensible POC choice, not a bug.
|
||
Phase 6 (Brief v2, the "Brief opstellen v2" PRD) is strictly ordered
|
||
23 → 24 → 25 → 26 → 27 → 28: 24 needs 23's `orgTemplate` on the wire, 25 needs 24's
|
||
`letter.css` contract, 26 needs 23's endpoints + 24's canvas, 27/28 polish on top.
|
||
Phase 7 (refinements, WP-31..36): only 31 → 32 is ordered (32 reuses the `createHistory`
|
||
helper 31 extracts); 33–36 are independent — pick any order.
|
||
Phase 8 (platform/DX/showcase, WP-37..46): goal is BOTH a teaching showcase AND a production
|
||
starter template. Priority: WP-37 (P0 quick fix) → WP-46 + WP-38 + WP-39 (P1, parallel) →
|
||
WP-40 (P2) → WP-43 (P3) → WP-41 → WP-42 → WP-44 → WP-45 (P4). Ordering constraints:
|
||
41 needs 40's PII kernel; 42 needs 40+41; 44 (`gen:context`) needs 38 (declarative boundaries
|
||
make the generator simple) + 43; 45 (`create-ssp`) needs 43+44. 37/38/39/40/43/46 are otherwise
|
||
independent. Two open tool forks, decided as step 1 of their WP: 38 dependency-cruiser vs Sheriff;
|
||
43 plop vs Angular schematics.
|
||
|
||
## WP template
|
||
|
||
```markdown
|
||
# WP-NN — Title
|
||
|
||
Status: todo | in-progress | done (<commit>)
|
||
Phase: N — name
|
||
|
||
## Why
|
||
|
||
## Read first
|
||
|
||
## Decisions (pre-made, don't relitigate)
|
||
|
||
## Files
|
||
|
||
## Steps
|
||
|
||
## Acceptance criteria
|
||
|
||
## Verification
|
||
|
||
## Out of scope
|
||
|
||
## Risks
|
||
```
|