## What & why The host-browser stack (`make local`) had drifted behind three slices, so a fresh bring-up couldn't complete the flow: registrations stuck at `OpenZaakAanmaken`, the behandel werkbak stayed empty, and the openbaar register showed nothing. The `verify-*` scripts do this setup for CI at test time; `make local` had no equivalent. This makes the local stack **self-seed at bring-up** so it just works in a browser: - **DMN** — `flowable-init` now also deploys `diploma-eligibility.dmn` (was BPMN-only), so completing `WachtOpDocumenten` routes through the DMN to `Beoordelen` instead of 404ing. - **Zaaktype + ACL** — a `local-seed` one-shot publishes the BIG zaaktype (whose UUID is server-assigned, hence not static in the compose file) and writes the real URLs to `seed-env:/acl.env`; the ACL sources it on startup via an entrypoint override. - **NRC abonnement** — an `nrc-subscribe` one-shot registers the `zaken` subscription at the event-subscriber callback, so notifications reach the projection/openbaar register. Both one-shots reach OpenZaak/NRC by **container IP** (a single-label host fails their Django URLValidator), mirroring the CI verify scripts. Design + trade-offs in **ADR-0020**. Closes #110 ## Definition of Done - [x] Linked Gitea issue (#110). - [x] Failing test committed before the implementation — `test(infra): …` adds `infra/run-local-flow-check.sh` / `make verify-local`; the three gaps' failures were observed live on a fresh `make local` (red), and the fix turns it green. - [x] Implementation makes the test pass; docs commit follows. - [x] Conventional Commits referencing the issue (`refs #110`). - [ ] CI green — running on the restored runner. Infra-only change; the CI `verify-stack` job uses `docker-compose.yml` (untouched). Also validated locally: `make verify-local` passes against a fresh `make local` (see below). - [x] `docker compose up` from a fresh clone reaches green health checks — verified: `make local` healthy in ~2m20s, then `make verify-local` green. - [x] Docs updated — ADR-0020 + demo-script note. - [x] ADR added in `docs/architecture/` — ADR-0020. - [x] Demo note in `docs/demo-script.md`. ## Notes for reviewers - **Infra-only** — no service code changes; the ACL image and the CI stack (`docker-compose.yml`) are untouched. - **Verified end-to-end on a fresh stack** (`make local-down && make local && make verify-local`): ``` >> 2. zaak opened (zaaktype seeded + wired) >> 3. documents accepted 204 (DMN deployed) >> 4. in the werkbak (DMN routing → Beoordelen) >> 5. visible in the openbaar register (NRC abonnement) OK — a fresh local stack completed the flow with no manual seeding ``` - **Follow-up:** the cleaner design — ACL resolving its zaaktype by `identificatie` instead of a pinned server-assigned URL — is split out as **S-27 (#113)**; landing it would remove the `acl.env` injection here. ADR-0020 records this. - The `seed-env` volume carries the generated `acl.env` from `local-seed` to the ACL; a `down --volumes` (as `make local-down` does) resets it cleanly. Reviewed-on: #114
This commit was merged in pull request #114.
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
# LOCAL development stack — runs with a plain `docker compose up`, no make / no
|
||||
# seed step / no bash. Use this on a local engine (Docker Desktop on Windows or
|
||||
# external seed step / no bash. Use this on a local engine (Docker Desktop on Windows or
|
||||
# macOS, or rootless Podman on Linux).
|
||||
#
|
||||
# Self-seeding (S-B04, #110, ADR-0020): unlike the CI stack — where the verify-* scripts seed the
|
||||
# zaaktype and register the NRC abonnement at test time — this stack does that itself, via one-shot
|
||||
# init containers (local-seed, nrc-subscribe) + a DMN deploy in flowable-init, so a fresh bring-up
|
||||
# completes the whole flow with no manual steps. `make verify-local` asserts it.
|
||||
#
|
||||
# docker compose -f infra/docker-compose.local.yml up -d --build # podman
|
||||
# docker compose -f infra/docker-compose.local.yml up -d --build --wait # Docker Desktop
|
||||
# docker compose -f infra/docker-compose.local.yml down --volumes
|
||||
@@ -257,28 +262,65 @@ services:
|
||||
restart: "no"
|
||||
volumes:
|
||||
- ../workflows/registratie.bpmn:/work/registratie.bpmn:ro,z
|
||||
- ../workflows/diploma-eligibility.dmn:/work/diploma-eligibility.dmn:ro,z
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
base=http://flowable-rest:8080/flowable-rest/service/repository/deployments
|
||||
until curl -sf -u rest-admin:test "$$base" >/dev/null 2>&1; do echo "waiting for flowable-rest..."; sleep 3; done
|
||||
if curl -s -u rest-admin:test "$$base?name=registratie" | grep -q '"name":"registratie"'; then
|
||||
echo "registratie already deployed; skip"
|
||||
svc=http://flowable-rest:8080/flowable-rest/service/repository/deployments
|
||||
dmn=http://flowable-rest:8080/flowable-rest/dmn-api/dmn-repository/deployments
|
||||
until curl -sf -u rest-admin:test "$$svc" >/dev/null 2>&1; do echo "waiting for flowable-rest..."; sleep 3; done
|
||||
# Deploy the DMN to the DMN engine and the BPMN to the process engine as SEPARATE deployments:
|
||||
# flowable-rest does NOT cascade a .dmn bundled in a process .bar into the DMN engine, so the DMN
|
||||
# must go via dmn-api. The registratie process's DMN service task then resolves the decision across
|
||||
# deployments by key (S-13, ADR-0016). Without this the WachtOpDocumenten completion 404s on the
|
||||
# missing decision and the case never reaches Beoordelen (S-B04). Both steps are idempotent.
|
||||
if curl -s -u rest-admin:test "$$dmn" | grep -q '"name":"diploma-eligibility.dmn"'; then
|
||||
echo "diploma-eligibility DMN already deployed; skip"
|
||||
else
|
||||
curl -sf -u rest-admin:test -F 'file=@/work/registratie.bpmn;filename=registratie.bpmn' "$$base" >/dev/null && echo "deployed registratie"
|
||||
curl -sf -u rest-admin:test -F 'file=@/work/diploma-eligibility.dmn;filename=diploma-eligibility.dmn' "$$dmn" >/dev/null && echo "deployed diploma-eligibility DMN"
|
||||
fi
|
||||
if curl -s -u rest-admin:test "$$svc?name=registratie" | grep -q '"name":"registratie"'; then
|
||||
echo "registratie BPMN already deployed; skip"
|
||||
else
|
||||
curl -sf -u rest-admin:test -F 'file=@/work/registratie.bpmn;filename=registratie.bpmn' "$$svc" >/dev/null && echo "deployed registratie BPMN"
|
||||
fi
|
||||
depends_on:
|
||||
flowable-rest:
|
||||
condition: service_started
|
||||
networks: [cg]
|
||||
|
||||
# ── Local bootstrap: seed the zaaktype + wire the ACL (S-B04, #110, ADR-0020) ─────────────────
|
||||
# The zaaktype UUID is assigned by OpenZaak at creation, so it can't be a static value in this
|
||||
# file. This one-shot seeds + publishes the BIG zaaktype (and the Diploma informatieobjecttype)
|
||||
# and writes their server-assigned URLs into a shared volume as acl.env, which the ACL sources on
|
||||
# startup (below). It is the local-stack equivalent of what infra/run-domain-check.sh does for CI.
|
||||
# Reaches OpenZaak by its container IP because a single-label host fails OpenZaak's URLValidator.
|
||||
local-seed:
|
||||
image: docker.io/library/python:3-slim
|
||||
restart: "no"
|
||||
volumes:
|
||||
- ./openzaak/seed_catalogus.py:/work/seed_catalogus.py:ro,z
|
||||
- ./local/seed-zaaktype.sh:/work/seed-zaaktype.sh:ro,z
|
||||
- seed-env:/out
|
||||
command: ["sh", "/work/seed-zaaktype.sh"]
|
||||
depends_on:
|
||||
openzaak:
|
||||
condition: service_healthy
|
||||
networks: [cg]
|
||||
|
||||
# ── ACL ──────────────────────────────────────────────────────────────────
|
||||
acl:
|
||||
build:
|
||||
context: ../services/acl
|
||||
dockerfile: Dockerfile
|
||||
image: register-referentie/acl:dev
|
||||
# The base/zaaktype/informatieobjecttype below are PLACEHOLDERS. The real, server-assigned
|
||||
# values are written by the local-seed one-shot into seed-env:/seed/acl.env, which the entrypoint
|
||||
# sources (set -a) so they override these before the app starts (S-B04, #110, ADR-0020). Sourcing
|
||||
# a runtime-generated env file is why we override the entrypoint here rather than use `env_file:`
|
||||
# (which compose reads at parse time, before the seed has run).
|
||||
entrypoint: ["/bin/sh", "-c", "set -a; . /seed/acl.env; set +a; exec dotnet Acl.Api.dll"]
|
||||
environment:
|
||||
Acl__OpenZaak__BaseUrl: http://openzaak:8000/
|
||||
Acl__OpenZaak__ClientId: big-reference-seed
|
||||
@@ -286,9 +328,12 @@ services:
|
||||
Acl__Defaults__Bronorganisatie: "517439943"
|
||||
Acl__Defaults__VerantwoordelijkeOrganisatie: "517439943"
|
||||
Acl__Defaults__Vertrouwelijkheidaanduiding: openbaar
|
||||
Acl__Defaults__ZaaktypeUrl: ${ACL_ZAAKTYPE_URL:-http://openzaak:8000/catalogi/api/v1/zaaktypen/00000000-0000-0000-0000-000000000000}
|
||||
Acl__Defaults__ZaaktypeUrl: http://openzaak:8000/catalogi/api/v1/zaaktypen/00000000-0000-0000-0000-000000000000
|
||||
Acl__Defaults__InformatieobjecttypeUrl: http://openzaak:8000/catalogi/api/v1/informatieobjecttypen/00000000-0000-0000-0000-000000000000
|
||||
ports:
|
||||
- "8100:8080"
|
||||
volumes:
|
||||
- seed-env:/seed:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
|
||||
interval: 5s
|
||||
@@ -298,6 +343,8 @@ services:
|
||||
depends_on:
|
||||
openzaak:
|
||||
condition: service_healthy
|
||||
local-seed:
|
||||
condition: service_completed_successfully
|
||||
networks: [cg]
|
||||
|
||||
# ── BFF ──────────────────────────────────────────────────────────────────
|
||||
@@ -400,6 +447,31 @@ services:
|
||||
condition: service_healthy
|
||||
networks: [cg]
|
||||
|
||||
# ── Local bootstrap: register the NRC abonnement (S-B04, #110, ADR-0020) ──────────────────────
|
||||
# Without a subscription, OpenZaak's notifications reach NRC and are delivered nowhere, so the
|
||||
# projection (and the openbaar register) stay empty. This one-shot registers an abonnement on the
|
||||
# `zaken` kanaal pointing at the event-subscriber's /notifications callback — the CI equivalent is
|
||||
# infra/verify-notification-driver.py. The callback uses the event-subscriber's container IP (a
|
||||
# single-label host fails NRC's URLValidator). It is a leaf (nothing depends on it), so it can wait
|
||||
# for the event-subscriber without creating a cycle with the ACL bootstrap.
|
||||
nrc-subscribe:
|
||||
image: docker.io/library/python:3-slim
|
||||
restart: "no"
|
||||
volumes:
|
||||
- ./local/register-abonnement.py:/work/register-abonnement.py:ro,z
|
||||
environment:
|
||||
NRC_BASE: http://nrc-web:8000
|
||||
SINK_HOST: event-subscriber
|
||||
SINK_PORT: "8080"
|
||||
SINK_AUTH: ${NOTIFICATION_WEBHOOK_TOKEN:-Bearer big-reference-notifications}
|
||||
command: ["python", "/work/register-abonnement.py"]
|
||||
depends_on:
|
||||
nrc-web:
|
||||
condition: service_healthy
|
||||
event-subscriber:
|
||||
condition: service_started
|
||||
networks: [cg]
|
||||
|
||||
projection-api:
|
||||
build:
|
||||
context: ..
|
||||
@@ -492,6 +564,8 @@ volumes:
|
||||
nrc-db:
|
||||
flowable-db:
|
||||
projection-db:
|
||||
# Carries the seed-generated acl.env (server-assigned zaaktype URLs) from local-seed to the ACL.
|
||||
seed-env:
|
||||
|
||||
networks:
|
||||
cg:
|
||||
|
||||
Reference in New Issue
Block a user