Files
atomic-design-poc/docs/project/backlog/WP-66-behandelportal-openzaak-write.md
T
ehoandClaude Sonnet 5 3ff80c124f feat(openzaak): bounded retry + flagged write divergence (WP-60)
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>
2026-07-30 18:11:55 +02:00

2.9 KiB

WP-66 — Wire the decision into OpenZaak

Status: todo Phase: 11 — Behandelportal

Why

WP-65's decision currently only updates local state (LocalZaakSource). For the behandelportal to actually function against a real register, the recorded decision needs to also write a besluit/status transition to ZGW — extending the write capability that already partially exists (CreateStatusRequest, CreateRolRequest in OpenZaakZaakSource.cs) rather than building a new ZGW client from scratch.

Read first

  • backend/src/BigRegister.Api/Zgw/OpenZaakZaakSource.cs (existing write records)
  • ZGW's Besluiten API (referenced in openzaak-integration.md if covered, or the ZGW standard docs) for besluit creation
  • WP-50 (the first ZGW write slice, for the pattern to follow)

Decisions (pre-made, don't relitigate)

  • Extend IZaakSource/OpenZaakZaakSource with a besluit/status-transition write, following the same pattern WP-50 established for create-zaak (a records + mapper addition, not a new abstraction).
  • Gated by Zgw:Enabled like every other ZGW write — the behandelportal keeps working against LocalZaakSource when it's off.
  • Best done after Phase 10's WP-60 (write-divergence resilience) lands, since this is exactly the second write pair that resilience work should already cover — but not strictly blocked on it if Phase 10 is still in progress (call out the residual risk explicitly if shipped first).

Files

Zgw/OpenZaakZaakSource.cs (besluit/status write), Data/IZaakSource.cs (new write method), tests.

Steps

  1. Add the besluit/status-transition write to OpenZaakZaakSource, mirroring WP-50's create-zaak pattern.
  2. Wire WP-65's decision command to call it when Zgw:Enabled=true.
  3. Integration test against the WP-54 harness (extend OpenZaakIntegrationTests).

Acceptance criteria

  • A recorded decision writes a real besluit/status transition to OpenZaak when Zgw:Enabled=true.
  • Behandelportal still works unchanged against LocalZaakSource when Zgw:Enabled=false.
  • OpenZaakIntegrationTests covers the new write.

Verification

cd backend && dotnet test --filter Category=Integration against the (ideally Phase-10-hardened) OpenZaak harness; manual smoke with Zgw:Enabled=true.

Out of scope

Any further behandelportal screens beyond beoordeling.

Risks

WP-60 (write-divergence resilience) has landed: bounded retry lives in ZgwHttpClient, so this write pair inherits it automatically. It does not get the flagging half for free — call RecordZgwDivergence (or the equivalent for whichever endpoint hosts the besluit write) on this path's catch too, the same way Program.cs's submit endpoint does for create-zaak/document writes, or this becomes the "second, currently-unprotected write pair" WP-60's own scope note anticipated.

Depends on: WP-65.