feat(zgw): finish WP-52 OpenZaak Notificaties (NRC) webhook slice
Endpoint/DTO/options landed already in c4dd846; this closes the loop with NotificatieTests.cs (accept/reject/missing-header, asserting the AuthzAuditStore row), missing appsettings.json keys (also backfills DrcBaseUrl/ InformatieobjecttypeUrls, stale since WP-51), and the webhook + abonnement provisioning docs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -108,6 +108,37 @@ confidentiality level would matter for production but isn't needed to prove the
|
||||
- `OpenZaakZaakSource.cs` — follows `{count,next,previous,results}` pagination, resolves +
|
||||
caches zaaktype labels, attaches `Authorization: Bearer <jwt>`.
|
||||
- `OpenZaakDocumentSource.cs` — DRC upload + zaak-link (WP-51), same auth/JSON pattern.
|
||||
- `NotificatieDto.cs` + the `POST /api/v1/zgw/notificaties` endpoint (`Program.cs`, WP-52) — the
|
||||
**inbound** NRC webhook, not a source/mapper: see the dedicated section below.
|
||||
|
||||
## Notificaties (NRC) webhook — inbound, WP-52
|
||||
|
||||
Unlike ZRC/ZTC/DRC (which the BFF calls outbound as a client), the Notificaties API calls
|
||||
**this BFF** — OpenZaak POSTs a `NotificatieDto`-shaped body to `POST /api/v1/zgw/notificaties`
|
||||
on every event on a subscribed kanaal. Auth is inverted too: no per-call JWT, just a fixed
|
||||
shared secret compared in constant time (`CryptographicOperations.FixedTimeEquals`) against
|
||||
`ZgwOptions.NotificatieAuthorization` — an unconfigured (empty) secret rejects every call,
|
||||
never accepts. Every attempt (accept or reject) is written to the same `AuthzAuditStore` the
|
||||
authz gate uses (`action="zgw:notificatie"`, `resource=hoofdObject` — a URL, not PII, `role="nrc"`)
|
||||
via the store directly, since there's no `Principal` for an NRC caller to run through the
|
||||
`AuditAuthz` helper.
|
||||
|
||||
There is no cache to invalidate today (`/admin/cases` and every other read already goes straight
|
||||
to `IZaakSource` per call), so a valid notification's only visible effect right now is the audit
|
||||
row proving the round-trip works end-to-end. Add real invalidation at the `// ponytail:` marker
|
||||
in `Program.cs` if a cache is ever introduced.
|
||||
|
||||
**Provisioning the `abonnement` is out-of-band, one-time config against a live OpenZaak — not
|
||||
app code.** Register it once (e.g. via OpenZaak's admin UI or a `POST` to its Abonnementen API)
|
||||
pointing at this BFF's public URL:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"callbackUrl": "https://<this-bff>/api/v1/zgw/notificaties",
|
||||
"auth": "<same value as Zgw:NotificatieAuthorization>",
|
||||
"kanalen": [{ "filters": {}, "naam": "zaken" }],
|
||||
}
|
||||
```
|
||||
|
||||
## The five ZGW APIs (context for later slices)
|
||||
|
||||
@@ -162,7 +193,11 @@ default.
|
||||
"InformatieobjecttypeUrls": {
|
||||
"identiteit": "https://open-zaak.example/catalogi/api/v1/informatieobjecttypen/<uuid>",
|
||||
"diploma": "https://open-zaak.example/catalogi/api/v1/informatieobjecttypen/<uuid>"
|
||||
}
|
||||
},
|
||||
// WP-52 (Notificaties): NRC base URL (documentation/provisioning only, no outbound call) +
|
||||
// the shared secret NRC must send back on every webhook POST.
|
||||
"NrcBaseUrl": "https://open-zaak.example/notificaties/api/v1",
|
||||
"NotificatieAuthorization": "<same value registered in the abonnement's `auth` field>"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -198,10 +233,11 @@ Principles this demonstrates:
|
||||
comment in `ZgwZaakMapper` show where the ACL is deliberately thin — an ACL need not be
|
||||
complete on day one, but its shortcuts should be visible.
|
||||
|
||||
Caveat: `IZaakSource` covers the cases **read + create** path (WP-49/50) and `IDocumentSource`
|
||||
covers **upload + zaak-link** (WP-51). Other BFF endpoints still read `SeedData`/static stores
|
||||
directly — ACL-ready (the DTO seam exists) but not yet swappable. That is the WP-52 roadmap
|
||||
(notificaties), plus the two cross-cutting WPs the arc needs for production: **WP-53** (a real
|
||||
Caveat: `IZaakSource` covers the cases **read + create** path (WP-49/50), `IDocumentSource`
|
||||
covers **upload + zaak-link** (WP-51), and the inbound `POST /zgw/notificaties` webhook
|
||||
(WP-52) closes the read/write/document/notify arc. Other BFF endpoints still read
|
||||
`SeedData`/static stores directly — ACL-ready (the DTO seam exists) but not yet swappable.
|
||||
What's left in this arc is the two cross-cutting WPs production needs: **WP-53** (a real
|
||||
per-request identity seam + citizen-scoping — today the owner/BSN is stubbed) and **WP-54** (a
|
||||
docker OpenZaak harness + opt-in integration test — today everything is fixture/mock-tested
|
||||
against no live instance).
|
||||
|
||||
Reference in New Issue
Block a user