From f3e9db7147b5c1c24da553e51d44bc36679fe528 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Mon, 29 Jun 2026 14:29:12 +0200 Subject: [PATCH] =?UTF-8?q?feat(infra):=20wire=20OpenZaak=20=E2=86=92=20Op?= =?UTF-8?q?en=20Notificaties=20notifications=20(refs=20#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the S-01-c wiring so a zaak created in OpenZaak is published to NRC: - OpenZaak: a zgw_consumers 'nrc' service + notifications_config (setup_configuration), publishing as big-reference-seed. NOTIFICATIONS_DISABLED stays true for OpenZaak-only bring-ups (OZ_NOTIFICATIONS_DISABLED) so the ACL integration test doesn't 500; the full/local stacks and stack-up set it false. - NRC: the JWT credential, an 'ac' service + autorisaties_api delegation to OpenZaak's Autorisaties API, and the 'zaken' kanaal. nrc-init now runs setup_configuration; its data.yaml is delivered via the rr-nrc-config volume (seed-config.sh nrc), mirroring oz. - nrc-beat added to every stack: NRC accepts a notification then drains it via a scheduled execute_notifications task — without beat, nothing is delivered. Interval 5s. Applied across the standalone, full, and local-bind-mount composes. Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 24 ++++++---- infra/docker-compose.local.yml | 24 ++++++++-- infra/docker-compose.yml | 36 ++++++++++++--- infra/opennotificaties/docker-compose.yml | 34 ++++++++++++-- .../setup_configuration/data.yaml | 46 +++++++++++++++++-- infra/openzaak/docker-compose.yml | 9 ++-- infra/openzaak/setup_configuration/data.yaml | 19 ++++++++ infra/seed-config.sh | 3 +- 8 files changed, 164 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index 8fde334..f91db3c 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ WAIT_SVCS := openzaak nrc-web acl bff # volumes are `external`, so compose won't remove them — CFG_VOLS lists them for # explicit teardown. See docs/runbooks/gitea-actions-gotchas.md. SEED := bash infra/seed-config.sh -CFG_VOLS := rr-oz-config rr-kc-realms rr-fl-bpmn +CFG_VOLS := rr-oz-config rr-nrc-config rr-kc-realms rr-fl-bpmn # Local-only stack: same services but config is bind-mounted (no seed step), so a # plain `docker compose -f infra/docker-compose.local.yml up` works on any local # engine. This is the no-make / Windows-friendly path. See that file's header. @@ -43,7 +43,7 @@ export DOCKER_HOST := unix://$(PODMAN_SOCK) endif endif -.PHONY: ci lint build unit mutation integration smoke up down local local-down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help +.PHONY: ci lint build unit mutation integration verify-notifications smoke up down local local-down changelog openzaak-up openzaak-smoke openzaak-seed openzaak-down stack-up stack-smoke stack-down keycloak-up keycloak-smoke keycloak-down flowable-up flowable-smoke flowable-down help ## ci: run the full pipeline — lint, build, unit, mutation, smoke (mirrors Gitea Actions) ci: lint build unit mutation smoke @@ -77,14 +77,14 @@ mutation: # podman-compose, and needing no `--wait` flag or host port access. The one-shots # (oz-init, flowable-init) aren't polled; they just need to have run. smoke: - $(SEED) oz kc fl + $(SEED) oz nrc kc fl docker compose -f $(COMPOSE) up -d --build bash -c 'WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS); rc=$$?; docker compose -f $(COMPOSE) down --volumes; docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; exit $$rc' ## up: seed config volumes and start the full stack (use instead of bare ## `docker compose up`, which can't self-seed the external config volumes) up: - $(SEED) oz kc fl + $(SEED) oz nrc kc fl docker compose -f $(COMPOSE) up -d --build ## down: stop and remove the local stack (incl. the external config volumes) @@ -147,10 +147,18 @@ openzaak-down: docker compose -f $(OZ_COMPOSE) down --volumes -docker volume rm -f rr-oz-config -## stack-up: start OpenZaak + Open Notificaties together (shared network) +## verify-notifications: end-to-end check that a zaak created in OpenZaak is +## published to NRC and delivered to a subscriber (S-01-c). Brings the stack up, +## seeds, drives a zaak + sink abonnement inside the network, asserts delivery, +## tears down. Runner-safe (no host-port access). See infra/verify-notifications.sh. +verify-notifications: + bash infra/verify-notifications.sh + +## stack-up: start OpenZaak + Open Notificaties together (shared network), with +## OpenZaak publishing notifications to NRC (S-01-c). stack-up: - $(SEED) oz - docker compose $(STACK_FILES) up -d + $(SEED) oz nrc + OZ_NOTIFICATIONS_DISABLED=false docker compose $(STACK_FILES) up -d ## stack-smoke: start both, assert OpenZaak (403/302/200) and NRC (302) are reachable stack-smoke: stack-up @@ -169,7 +177,7 @@ stack-smoke: stack-up ## stack-down: stop and remove both stacks (wipes data) stack-down: docker compose $(STACK_FILES) down --volumes - -docker volume rm -f rr-oz-config + -docker volume rm -f rr-oz-config rr-nrc-config ## keycloak-up: start Keycloak with the four imported realms keycloak-up: diff --git a/infra/docker-compose.local.yml b/infra/docker-compose.local.yml index 691ec77..f2c59dc 100644 --- a/infra/docker-compose.local.yml +++ b/infra/docker-compose.local.yml @@ -59,7 +59,8 @@ services: CELERY_BROKER_URL: redis://oz-redis:6379/1 CELERY_RESULT_BACKEND: redis://oz-redis:6379/1 DISABLE_2FA: "true" - NOTIFICATIONS_DISABLED: "true" + # Publish notifications to NRC (always present in this twin). See ADR-0007. + NOTIFICATIONS_DISABLED: "false" OPENZAAK_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENZAAK_SUPERUSER_EMAIL: admin@localhost @@ -122,7 +123,9 @@ services: networks: [cg] nrc-init: - # Migrations only (see the canonical compose / ADR-0002); no config needed. + # Migrations + setup_configuration (S-01-c): the JWT credential, Autorisaties-API + # delegation, and the `zaken` kanaal that let OpenZaak publish. Config is + # bind-mounted here (this twin is the local/no-make path). See ADR-0007. image: docker.io/openzaak/open-notificaties:${OPENNOTIFICATIES_TAG:-1.16.1} environment: &nrc-env DJANGO_SETTINGS_MODULE: nrc.conf.docker @@ -141,7 +144,11 @@ services: OPENNOTIFICATIES_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENNOTIFICATIES_SUPERUSER_EMAIL: admin@localhost - command: ["sh", "-c", "/wait_for_db.sh && OTEL_SDK_DISABLED=True python src/manage.py migrate"] + RUN_SETUP_CONFIG: "true" + NOTIFICATION_SEC_INTERVAL: "5" + command: /setup_configuration.sh + volumes: + - ./opennotificaties/setup_configuration:/app/setup_configuration:ro,z depends_on: nrc-db: condition: service_healthy @@ -176,6 +183,17 @@ services: condition: service_completed_successfully networks: [cg] + # Celery beat drains scheduled notifications to subscribers — required for + # delivery, not optional. See ADR-0007. + nrc-beat: + image: docker.io/openzaak/open-notificaties:${OPENNOTIFICATIES_TAG:-1.16.1} + environment: *nrc-env + command: /celery_beat.sh + depends_on: + nrc-init: + condition: service_completed_successfully + networks: [cg] + # ── Keycloak (S-02) ────────────────────────────────────────────────────── keycloak: image: quay.io/keycloak/keycloak:26.1 diff --git a/infra/docker-compose.yml b/infra/docker-compose.yml index b138c6a..bc53e28 100644 --- a/infra/docker-compose.yml +++ b/infra/docker-compose.yml @@ -62,7 +62,10 @@ services: CELERY_BROKER_URL: redis://oz-redis:6379/1 CELERY_RESULT_BACKEND: redis://oz-redis:6379/1 DISABLE_2FA: "true" - NOTIFICATIONS_DISABLED: "true" + # Publish notifications to NRC (always present in this full stack). The NRC + # service + notifications_config are provisioned by setup_configuration + # (infra/openzaak/setup_configuration/data.yaml). See ADR-0007 / S-01-c. + NOTIFICATIONS_DISABLED: "false" OPENZAAK_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENZAAK_SUPERUSER_EMAIL: admin@localhost @@ -146,11 +149,17 @@ services: OPENNOTIFICATIES_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENNOTIFICATIES_SUPERUSER_EMAIL: admin@localhost - # Migrations only for now. No setup_configuration steps are enabled yet (the - # OZ<->NRC notification wiring lands in S-06), and NRC's `setup_configuration` - # aborts with "No steps enabled" on the empty data.yaml — so we run `migrate` - # directly instead of /setup_configuration.sh. See data.yaml and ADR-0002. - command: ["sh", "-c", "/wait_for_db.sh && OTEL_SDK_DISABLED=True python src/manage.py migrate"] + RUN_SETUP_CONFIG: "true" + # nrc-beat fires `execute_notifications` this often to drain scheduled + # notifications to subscribers (upstream default 20s). See ADR-0007. + NOTIFICATION_SEC_INTERVAL: "5" + # Runs migrations + setup_configuration (S-01-c): the JWT credential, the + # Autorisaties-API delegation, and the `zaken` kanaal that let OpenZaak publish. + # data.yaml is streamed into rr-nrc-config by infra/seed-config.sh (bind mounts + # don't reach sibling containers on the CI runner). See data.yaml + ADR-0007. + command: /setup_configuration.sh + volumes: + - nrc-config:/app/setup_configuration:ro depends_on: nrc-db: condition: service_healthy @@ -185,6 +194,18 @@ services: condition: service_completed_successfully networks: [cg] + # Celery beat drains the ScheduledNotification rows the API creates on publish + # and hands them to the worker. Without it, notifications are accepted but never + # delivered to subscribers — required, not optional. See ADR-0007. + nrc-beat: + image: docker.io/openzaak/open-notificaties:${OPENNOTIFICATIES_TAG:-1.16.1} + environment: *nrc-env + command: /celery_beat.sh + depends_on: + nrc-init: + condition: service_completed_successfully + networks: [cg] + # ── Keycloak (S-02) ────────────────────────────────────────────────────── keycloak: image: quay.io/keycloak/keycloak:26.1 @@ -309,6 +330,9 @@ volumes: oz-config: external: true name: rr-oz-config + nrc-config: + external: true + name: rr-nrc-config kc-realms: external: true name: rr-kc-realms diff --git a/infra/opennotificaties/docker-compose.yml b/infra/opennotificaties/docker-compose.yml index d333413..1275a26 100644 --- a/infra/opennotificaties/docker-compose.yml +++ b/infra/opennotificaties/docker-compose.yml @@ -52,11 +52,18 @@ services: OPENNOTIFICATIES_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENNOTIFICATIES_SUPERUSER_EMAIL: admin@localhost - # Migrations only for now. No setup_configuration steps are enabled yet (the - # OZ<->NRC notification wiring lands in S-06), and NRC's `setup_configuration` - # aborts with "No steps enabled" on the empty data.yaml — so we run `migrate` - # directly instead of /setup_configuration.sh. See data.yaml and ADR-0002. - command: ["sh", "-c", "/wait_for_db.sh && OTEL_SDK_DISABLED=True python src/manage.py migrate"] + RUN_SETUP_CONFIG: "true" + # Delivery cadence: nrc-beat fires `execute_notifications` this often to drain + # scheduled notifications to subscribers. Upstream default is 20s; 5s keeps the + # walking-skeleton + the verify smoke responsive. + NOTIFICATION_SEC_INTERVAL: "5" + # Runs migrations + setup_configuration (S-01-c): the JWT credential, the + # Autorisaties-API delegation, and the `zaken` kanaal that let OpenZaak publish + # notifications. data.yaml is streamed into this external volume by + # infra/seed-config.sh (same pattern as oz-init). See data.yaml + ADR-0006. + command: /setup_configuration.sh + volumes: + - nrc-config:/app/setup_configuration:ro depends_on: nrc-db: condition: service_healthy @@ -89,8 +96,25 @@ services: condition: service_completed_successfully networks: [cg] + # Celery beat: periodically fires `execute_notifications`, which drains the + # ScheduledNotification rows the API creates on publish and hands them to the + # worker for delivery. Without beat, notifications are accepted but never + # delivered to subscribers — so it is required, not optional. See ADR-0007. + nrc-beat: + image: docker.io/openzaak/open-notificaties:${OPENNOTIFICATIES_TAG:-1.16.1} + environment: *nrc-env + command: /celery_beat.sh + depends_on: + nrc-init: + condition: service_completed_successfully + networks: [cg] + volumes: nrc-db: + # populated out-of-band by infra/seed-config.sh (docker cp) — see that script. + nrc-config: + external: true + name: rr-nrc-config networks: cg: diff --git a/infra/opennotificaties/setup_configuration/data.yaml b/infra/opennotificaties/setup_configuration/data.yaml index 9aab817..18abd80 100644 --- a/infra/opennotificaties/setup_configuration/data.yaml +++ b/infra/opennotificaties/setup_configuration/data.yaml @@ -1,5 +1,41 @@ -# Open Notificaties setup_configuration. -# Stage 1 (this commit): intentionally minimal — the init container runs -# migrations; no steps enabled yet. The OpenZaak<->NRC notification wiring -# (Services, Authorization, JWT, Kanalen) is added next. See ADR-0002 / S-01-c. -{} +# Open Notificaties (NRC) setup_configuration (S-01-c, #56). +# Wires NRC so OpenZaak can publish notifications: +# - the JWT credential OpenZaak authenticates with, +# - delegation of authorization checks to OpenZaak's Autorisaties API (AC), +# - the `zaken` kanaal OpenZaak publishes zaak events on. +# Dev-only credentials — not for production. Steps from nrc.setup_configuration. + +# 1. JWT credential NRC uses to verify the token OpenZaak presents. +vng_api_common_credentials_config_enable: true +vng_api_common_credentials: + items: + - identifier: big-reference-seed + secret: insecure-dev-secret-change-me + +# 2. The Autorisaties API (OpenZaak's AC) NRC consults to authorize publishers. +zgw_consumers_config_enable: true +zgw_consumers: + services: + - identifier: openzaak-ac + label: OpenZaak Autorisaties API + api_type: ac + api_root: http://openzaak:8000/autorisaties/api/v1/ + auth_type: zgw + client_id: big-reference-seed + secret: insecure-dev-secret-change-me + +# 3. Delegate authorization to that AC. +autorisaties_api_config_enable: true +autorisaties_api: + authorizations_api_service_identifier: openzaak-ac + +# 4. The kanaal OpenZaak publishes zaak events on. +notifications_kanalen_config_enable: true +notifications_kanalen_config: + items: + - naam: zaken + documentatie_link: https://github.com/VNG-Realisatie/gemma-zaken + filters: + - bronorganisatie + - zaaktype + - vertrouwelijkheidaanduiding diff --git a/infra/openzaak/docker-compose.yml b/infra/openzaak/docker-compose.yml index 9f9e50a..cabc271 100644 --- a/infra/openzaak/docker-compose.yml +++ b/infra/openzaak/docker-compose.yml @@ -47,9 +47,12 @@ services: CELERY_BROKER_URL: redis://oz-redis:6379/1 CELERY_RESULT_BACKEND: redis://oz-redis:6379/1 DISABLE_2FA: "true" - # Notifications go to Open Notificaties (NRC), which arrives in S-01-c. - # Until then, disable outbound notifications so writes don't 500. - NOTIFICATIONS_DISABLED: "true" + # Notifications are OFF by default so OpenZaak-only bring-ups (openzaak-up, + # the ACL integration test) don't 500 trying to reach an absent NRC. When + # OpenZaak runs together with the NRC stack, set OZ_NOTIFICATIONS_DISABLED=false + # (make stack-up does) to publish; the NRC service + notifications_config that + # name it are provisioned by setup_configuration (data.yaml, S-01-c). + NOTIFICATIONS_DISABLED: "${OZ_NOTIFICATIONS_DISABLED:-true}" OPENZAAK_SUPERUSER_USERNAME: admin DJANGO_SUPERUSER_PASSWORD: admin OPENZAAK_SUPERUSER_EMAIL: admin@localhost diff --git a/infra/openzaak/setup_configuration/data.yaml b/infra/openzaak/setup_configuration/data.yaml index 6040ea9..b5d6873 100644 --- a/infra/openzaak/setup_configuration/data.yaml +++ b/infra/openzaak/setup_configuration/data.yaml @@ -20,3 +20,22 @@ vng_api_common_applicaties: - big-reference-seed label: BIG reference seed client heeft_alle_autorisaties: true + +# ── OpenZaak → Open Notificaties (NRC) publishing (S-01-c, #56) ───────────── +# The NRC service OpenZaak posts notifications to, authenticating with the same +# big-reference-seed client (NRC verifies the JWT and authorizes it via the AC). +zgw_consumers_config_enable: true +zgw_consumers: + services: + - identifier: nrc + label: Open Notificaties + api_type: nrc + api_root: http://nrc-web:8000/api/v1/ + auth_type: zgw + client_id: big-reference-seed + secret: insecure-dev-secret-change-me + +# Point OpenZaak's notifications at that service. Requires NOTIFICATIONS_DISABLED=false. +notifications_config_enable: true +notifications_config: + notifications_api_service_identifier: nrc diff --git a/infra/seed-config.sh b/infra/seed-config.sh index 64d2993..4a2ae2d 100755 --- a/infra/seed-config.sh +++ b/infra/seed-config.sh @@ -33,11 +33,12 @@ populate() { # volume source(file or dir/.) echo " seeded $vol" } -[ "$#" -gt 0 ] || { echo "usage: seed-config.sh ..." >&2; exit 2; } +[ "$#" -gt 0 ] || { echo "usage: seed-config.sh ..." >&2; exit 2; } for key in "$@"; do case "$key" in oz) populate rr-oz-config "$here/openzaak/setup_configuration/." ;; + nrc) populate rr-nrc-config "$here/opennotificaties/setup_configuration/." ;; kc) populate rr-kc-realms "$here/keycloak/realms/." ;; fl) populate rr-fl-bpmn "$here/../workflows/registratie.bpmn" ;; *) echo "unknown seed key: $key" >&2; exit 2 ;;