Local aanvraag/document writes and their paired ZGW writes aren't transactional; a ZGW failure after the local write succeeds used to diverge silently. ZgwHttpClient now retries transport-shaped failures (not 500, which can follow a partial commit on the non-idempotent statussen/rollen POSTs), and a ZGW failure that survives retry sets Aanvraag.ZgwError plus a zgw:divergence audit row instead of failing or diverging quietly. No outbox/reconcile job: three request-triggered write paths don't justify a persisted queue that would also need to carry citizen PII for the JWT audit claims. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.9 KiB
WP-59 — Per-document-type confidentialiteit config
Status: done Phase: 10 — OpenZaak production hardening
Why
OpenZaakDocumentSource hardcodes vertrouwelijkheidaanduiding to "openbaar" for every
uploaded document, regardless of document type. Real BIG-register documents (diploma's, ID
scans) plausibly need different confidentiality levels. This repo already has a house
pattern for exactly this kind of business-tunable value — stamdata-as-code (ADR-0004) — so
this slice is "apply the existing pattern," not invent a new one.
Read first
- ADR-0004 — Stamdata as code
backend/src/BigRegister.Api/Stamdata/(an existing table for the shape to imitate)backend/src/BigRegister.Api/Zgw/OpenZaakDocumentSource.cs
Decisions (pre-made, don't relitigate)
- Confidentiality level is keyed by document type (whatever type already distinguishes
uploads, e.g. diploma vs. id-bewijs) via a new Stamdata table, using the existing
StamdataTable.Of<T>mechanism — not a new ad hoc config format. - Default/fallback value stays
"openbaar"if a document type isn't in the table, to avoid a silent upload failure.
Files
Stamdata/(new table + validation)Zgw/OpenZaakDocumentSource.csStamdataCatalog.cs(register the new table)
Steps
- Add a
DocumentConfidentialiteitstamdata table (document type → vertrouwelijkheidaanduiding), validated at build like every other stamdata table (StamdataValidationTests). - Register it in
StamdataCatalogso it's editable via the existing/beheer/stamdatagrid. OpenZaakDocumentSourcelooks up the level by document type instead of hardcoding"openbaar".
Acceptance criteria
- Confidentiality level for a real upload varies by document type per the new
stamdata table (
identiteit→vertrouwelijk; everything else →openbaar). StamdataValidationTestscover the new table (a bad edit fails CI, per ADR-0004)./beheer/stamdatacan edit the new table without a code change (existing generic editor — theStamdataCatalogregistration is the only wiring needed).
What actually happened
Implemented mostly as planned — one gap found and closed: the diff as first written
registered DocumentConfidentialiteit in StamdataCatalog and wired the lookup into
OpenZaakDocumentSource, plus a positive test (identiteit → vertrouwelijk) and a
fallback test (an unmapped category, org-logo, → openbaar), but had no
StamdataValidationTests reference-integrity entry for the new table — the second
acceptance box was unchecked. Added one: a StamdataRef resolving every
documentconfidentialiteit.json categoryId against the real set of document category
ids (DocumentRules.AllCategoriesFor across registratie/herregistratie/org-template),
so a typo'd or stale categoryId now fails the build instead of silently never matching
(OpenZaakDocumentSource.ConfidentialiteitFor's dictionary lookup would otherwise just
fall back to "openbaar" forever with no signal). org-logo deliberately stays absent
from the confidentialiteit table (falls back to "openbaar") and correctly still
resolves as a known category — the reference check validates "is this a real category",
not "must every category be configured."
Verification
cd backend && dotnet test (161/161 green, incl. the 2 new OpenZaakDocumentSourceTests plus
the new StamdataValidationTests reference entry); dotnet format --verify-no-changes clean.
Manual: /beheer/stamdata shows and edits the new table; an upload for a mapped document type
carries the mapped confidentiality level (test asserted).
Out of scope
Any UI-facing confidentiality display/change on the citizen side (FE keeps rendering decisions, not recomputing them, per ADR-0001).
Risks
None significant — this is a config/data-shape change reusing an established mechanism.