feat(fp): WP-23 — org-template backend + admin role

Second template axis (org identity: letterhead, footer, signature,
margins) server-side: OrgTemplateStore with JSON version history,
publish/rollback, sent-brief version pinning, admin role + capability,
5 admin endpoints, org-logo upload category. FE seam widened only
(Role/Capability unions, interceptor); WP-24/26 consume it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 11:17:05 +02:00
parent 44eb2d2186
commit 5a610c10f0
31 changed files with 5017 additions and 1834 deletions

View File

@@ -30,8 +30,9 @@ From WP-01 onward, additionally:
npm run test-storybook:ci
```
Backend stays untouched throughout (frontend-only backlog); `cd backend && dotnet test`
only needs re-running if a WP unexpectedly touches `backend/`.
Phases 05 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
@@ -63,9 +64,15 @@ for its existing violations, so every WP ends green.
| [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 | todo |
| [WP-21](WP-21-resilience-seams.md) | Resilience seams (correlation-id, idempotency, retry) | 5 · productie-volwassenheid | todo |
| [WP-22](WP-22-durable-persistence.md) | Durable persistence (optional tier) | 5 · productie-volwassenheid | todo |
| [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 | in-progress |
| [WP-24](WP-24-letter-canvas.md) | Letter canvas (edit on the letter) | 6 · Brief v2 | todo |
| [WP-25](WP-25-letter-preview-html.md) | Server-rendered letter preview (HTML; PDF deferred) | 6 · Brief v2 | todo |
| [WP-26](WP-26-org-template-editor.md) | Admin org-template editor | 6 · Brief v2 | todo |
| [WP-27](WP-27-brief-ux-layer.md) | Brief UX layer (undo/redo, standaardbrief, diff) | 6 · Brief v2 | todo |
| [WP-28](WP-28-brief-v2-demo-polish.md) | Brief v2 demo polish (scenarios, e2e, docs) | 6 · Brief v2 | todo |
Sequencing dependencies (stated in the WPs too): 01 before 1015 (axe covers story churn);
03/04 before 0509 (boundaries stop new violations during refactors); 06 before 07 (typed
@@ -75,6 +82,9 @@ are independent of each other and of phases 14 — pick any order; **18 is th
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.
## WP template