Files
atomic-design-poc/docs/project/archive/backlog/WP-41-persisted-authz-audit.md
T
ehoandClaude Opus 5 12f17d9d73 docs: archive the finished backlogs (RD-30)
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>
2026-09-08 23:00:38 +02:00

2.4 KiB

WP-41 — Persisted, queryable authz/PII-reveal audit

Status: done Phase: 8 — platform/DX/showcase Priority: P2 Depends on: WP-40

Outcome

New data-minimised EF table AuthzAuditEntry (Data/AuthzAuditStore.cs, DbSet + key config in AppDbContext, migration AuthzAudit): At, Action, Resource, Decision, Role, CorrelationIdnever a name/BSN/value. AuditAuthz now persists (via AuthzAuditStore.Record) alongside its log line, so every authz denial + BIG-nummer reveal/step-up attempt is captured. GET /admin/audit (admin-gated by the existing CasesAdmin/cases:manage — a dedicated audit:read cap is a later refinement) returns the trail newest-first (client-side sort — SQLite can't ORDER BY DateTimeOffset). +3 backend tests (deny recorded, reveal recorded, schema-carries-no-PII reflection test). Typed client regenerated (audit() + AuthzAuditDto). No FE consumer yet — a future audit view (WP-42 finish) must add /api/v1/admin/audit to the role.interceptor ROLE_AWARE list or it silently 403s.

Why

The security-relevant events (authz denials via AuditAuthz, BIG-nummer reveal, step-up) are log-only — never persisted, so there's no queryable trail. The one persisted AuditEntry table covers document lifecycle only. PRD-0002 §8 calls for a persisted authorization audit. A register (BIO) wants this queryable, and strictly data-minimised.

Decisions

  • Persist authz/reveal/step-up events into a data-minimised EF table extending the existing AuditEntry/AppDbContext pattern: role, action, resource-ref, decision, correlation-id, timestamp — never the value or any PII.
  • Wire AuditAuthz + the reveal endpoint to persist (in addition to the log line).
  • Optional thin admin read view — reuse cases:manage or add an audit:read capability.

Files

  • backend/.../Data/ — new audit entity + AppDbContext DbSet + EF migration.
  • backend/.../Program.csAuditAuthz + reveal endpoint persist.
  • Backend tests: events are persisted; no PII columns; correlation-id captured.
  • (Optional) FE audit read page + adapter/store, gated by the capability.

Acceptance criteria

  • Denials, reveals, and step-up attempts land as rows with no PII/value fields.
  • A test asserts the schema carries no name/bsn/value column.
  • dotnet test (132) + npm run ci green; api-client drift clean after commit.