feat(domain): BIG Domain Service skeleton with the Registration aggregate (closes #6) #61
@@ -94,10 +94,12 @@ jobs:
|
|||||||
run: make verify-nrc
|
run: make verify-nrc
|
||||||
- name: OpenZaak → NRC → Event Subscriber → projection-api
|
- name: OpenZaak → NRC → Event Subscriber → projection-api
|
||||||
run: make verify-projection
|
run: make verify-projection
|
||||||
|
- name: Domain → Flowable → ACL → OpenZaak
|
||||||
|
run: make verify-domain
|
||||||
# Log dump must precede teardown (which removes the containers).
|
# Log dump must precede teardown (which removes the containers).
|
||||||
- name: Dump container logs on failure
|
- name: Dump container logs on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat flowable-init keycloak acl bff projection-db event-subscriber projection-api 2>&1 || true
|
run: docker compose -f infra/docker-compose.yml logs --no-color --tail=100 oz-init openzaak nrc-init nrc-web nrc-celery nrc-beat flowable-db flowable-rest flowable-init keycloak acl bff domain projection-db event-subscriber projection-api 2>&1 || true
|
||||||
- name: Tear down
|
- name: Tear down
|
||||||
if: always()
|
if: always()
|
||||||
run: make down
|
run: make down
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -10,7 +10,7 @@ COMPOSE := infra/docker-compose.yml
|
|||||||
# Long-running services with a healthcheck — the smoke polls these for readiness
|
# Long-running services with a healthcheck — the smoke polls these for readiness
|
||||||
# (infra/wait-healthy.sh). One-shot init jobs (oz-init, nrc-init, flowable-init)
|
# (infra/wait-healthy.sh). One-shot init jobs (oz-init, nrc-init, flowable-init)
|
||||||
# are not polled; they only need to have run. See docs/runbooks/gitea-actions-gotchas.md.
|
# are not polled; they only need to have run. See docs/runbooks/gitea-actions-gotchas.md.
|
||||||
WAIT_SVCS := openzaak nrc-web acl bff event-subscriber projection-api
|
WAIT_SVCS := openzaak nrc-web acl bff domain event-subscriber projection-api
|
||||||
# Config files (OpenZaak data.yaml, Keycloak realms, Flowable BPMN) are streamed
|
# Config files (OpenZaak data.yaml, Keycloak realms, Flowable BPMN) are streamed
|
||||||
# into external named volumes via `docker cp` (infra/seed-config.sh) instead of
|
# into external named volumes via `docker cp` (infra/seed-config.sh) instead of
|
||||||
# bind-mounted, because bind mounts don't reach sibling containers on the
|
# bind-mounted, because bind mounts don't reach sibling containers on the
|
||||||
@@ -138,6 +138,11 @@ verify-nrc:
|
|||||||
verify-projection:
|
verify-projection:
|
||||||
bash infra/run-projection-check.sh
|
bash infra/run-projection-check.sh
|
||||||
|
|
||||||
|
## verify-domain: domain → Flowable → ACL → OpenZaak end-to-end (S-05), against the
|
||||||
|
## already-running stack. Recreates the acl service to inject the seeded zaaktype URL.
|
||||||
|
verify-domain:
|
||||||
|
bash infra/run-domain-check.sh
|
||||||
|
|
||||||
## verify: local mirror of the CI verify-stack job — full stack up once, all checks,
|
## verify: local mirror of the CI verify-stack job — full stack up once, all checks,
|
||||||
## tear down (always). For fast single-concern local iteration use `integration`
|
## tear down (always). For fast single-concern local iteration use `integration`
|
||||||
## (oz-only) or `verify-notifications` (oz+nrc) instead.
|
## (oz-only) or `verify-notifications` (oz+nrc) instead.
|
||||||
@@ -148,7 +153,8 @@ verify:
|
|||||||
WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS) \
|
WAIT_TIMEOUT=420 bash infra/wait-healthy.sh $(WAIT_SVCS) \
|
||||||
&& bash infra/run-acl-integration.sh \
|
&& bash infra/run-acl-integration.sh \
|
||||||
&& bash infra/run-notification-check.sh \
|
&& bash infra/run-notification-check.sh \
|
||||||
&& bash infra/run-projection-check.sh || rc=$$?; \
|
&& bash infra/run-projection-check.sh \
|
||||||
|
&& bash infra/run-domain-check.sh || rc=$$?; \
|
||||||
docker compose -f $(COMPOSE) down --volumes >/dev/null 2>&1; \
|
docker compose -f $(COMPOSE) down --volumes >/dev/null 2>&1; \
|
||||||
docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; \
|
docker volume rm -f $(CFG_VOLS) >/dev/null 2>&1; \
|
||||||
exit $$rc'
|
exit $$rc'
|
||||||
|
|||||||
@@ -285,7 +285,9 @@ services:
|
|||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: register-referentie/acl:dev
|
image: register-referentie/acl:dev
|
||||||
environment:
|
environment:
|
||||||
Acl__OpenZaak__BaseUrl: http://openzaak:8000/
|
# Overridable so verify-domain can point the ACL at the same OpenZaak host that
|
||||||
|
# owns the seeded zaaktype URL (host-consistent zaak creation, ADR-0009).
|
||||||
|
Acl__OpenZaak__BaseUrl: ${ACL_OPENZAAK_BASEURL:-http://openzaak:8000/}
|
||||||
Acl__OpenZaak__ClientId: big-reference-seed
|
Acl__OpenZaak__ClientId: big-reference-seed
|
||||||
Acl__OpenZaak__Secret: insecure-dev-secret-change-me
|
Acl__OpenZaak__Secret: insecure-dev-secret-change-me
|
||||||
Acl__Defaults__Bronorganisatie: "517439943"
|
Acl__Defaults__Bronorganisatie: "517439943"
|
||||||
@@ -306,6 +308,36 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
networks: [cg]
|
networks: [cg]
|
||||||
|
|
||||||
|
# ── BIG Domain Service (S-05) ──────────────────────────────────────────────
|
||||||
|
# Orchestrates a registration: POST /registrations creates the aggregate and
|
||||||
|
# starts the registratie Flowable process; a hosted worker acquires the
|
||||||
|
# OpenZaakAanmaken job, opens a zaak via the ACL and completes it (ADR-0009).
|
||||||
|
# Talks only to Flowable (Workflow Client, §8.2) and the ACL (§8.1).
|
||||||
|
domain:
|
||||||
|
build:
|
||||||
|
context: ../services/domain
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: register-referentie/domain:dev
|
||||||
|
environment:
|
||||||
|
Flowable__BaseUrl: http://flowable-rest:8080/flowable-rest/
|
||||||
|
Flowable__Username: rest-admin
|
||||||
|
Flowable__Password: test
|
||||||
|
Acl__BaseUrl: http://acl:8080/
|
||||||
|
ports:
|
||||||
|
- "8130:8080"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
depends_on:
|
||||||
|
acl:
|
||||||
|
condition: service_healthy
|
||||||
|
flowable-init:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
networks: [cg]
|
||||||
|
|
||||||
# ── BFF ──────────────────────────────────────────────────────────────────
|
# ── BFF ──────────────────────────────────────────────────────────────────
|
||||||
bff:
|
bff:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -210,6 +210,10 @@ def main():
|
|||||||
print(f"zaaktypen in BIG: {names}")
|
print(f"zaaktypen in BIG: {names}")
|
||||||
assert "BIG-REGISTRATIE" in names, "BIG-REGISTRATIE not listed"
|
assert "BIG-REGISTRATIE" in names, "BIG-REGISTRATIE not listed"
|
||||||
state = "published" if PUBLISH else "concept"
|
state = "published" if PUBLISH else "concept"
|
||||||
|
# Machine-readable line so callers (e.g. infra/run-domain-check.sh) can capture the
|
||||||
|
# zaaktype URL to configure the ACL's default-fill (ADR-0003/0009).
|
||||||
|
zt_url = next(z["url"] for z in zaaktypen if z.get("identificatie") == "BIG-REGISTRATIE")
|
||||||
|
print(f"ZAAKTYPE_URL {zt_url}")
|
||||||
print(f"OK — BIG catalogus seeded (BIG-REGISTRATIE {state} + bsn eigenschap)")
|
print(f"OK — BIG catalogus seeded (BIG-REGISTRATIE {state} + bsn eigenschap)")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
68
infra/run-domain-check.sh
Executable file
68
infra/run-domain-check.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Verify the BIG Domain Service end-to-end (S-05) against an ALREADY-RUNNING full stack:
|
||||||
|
# domain → Flowable (start the registratie process + external-task worker) → ACL → OpenZaak.
|
||||||
|
# Submits a registration to the domain and asserts the worker opens a zaak in OpenZaak and
|
||||||
|
# records its URL on the aggregate (ADR-0009).
|
||||||
|
#
|
||||||
|
# The seeded zaaktype URL is server-assigned, so it isn't knowable at initial bring-up. This
|
||||||
|
# script therefore seeds a published BIG zaaktype and recreates the `acl` service configured to
|
||||||
|
# default-fill it — pointing the ACL at the SAME OpenZaak host that owns the URL, so zaak creation
|
||||||
|
# is host-consistent (exactly the configuration the ACL integration test proves, ADR-0006). That
|
||||||
|
# one recreate aside, the caller owns stack bring-up + teardown.
|
||||||
|
#
|
||||||
|
# All in-network, reaching services by container IP (a single-label host isn't URL-valid; the
|
||||||
|
# runner can't reach published ports — gitea-actions-gotchas.md §5/§6). Plain docker primitives.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
root="$(cd "$here/.." && pwd)"
|
||||||
|
compose="$root/infra/docker-compose.yml"
|
||||||
|
|
||||||
|
ip() { docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$1"; }
|
||||||
|
|
||||||
|
oz="$(docker ps -q --filter 'name=[-_]openzaak[-_]' | head -1)"
|
||||||
|
dom="$(docker ps -q --filter 'name=domain' | head -1)"
|
||||||
|
[ -n "$oz" ] || { echo "ERROR: no running OpenZaak container — bring the stack up first" >&2; exit 1; }
|
||||||
|
[ -n "$dom" ] || { echo "ERROR: no running domain container — bring the stack up first" >&2; exit 1; }
|
||||||
|
net="$(docker inspect -f '{{range $k,$_ := .NetworkSettings.Networks}}{{$k}}{{"\n"}}{{end}}' "$oz" | head -1)"
|
||||||
|
oz_ip="$(ip "$oz")"; dom_ip="$(ip "$dom")"
|
||||||
|
oz_base="http://$oz_ip:8000"
|
||||||
|
echo ">> openzaak=$oz_ip domain=$dom_ip network=$net"
|
||||||
|
|
||||||
|
echo ">> seeding a published BIG zaaktype (idempotent) and capturing its URL"
|
||||||
|
sid="$(docker create --network "$net" -e "OZ_BASE=$oz_base" -e OZ_PUBLISH=1 python:3-slim python /seed.py)"
|
||||||
|
docker cp "$here/openzaak/seed_catalogus.py" "$sid:/seed.py" >/dev/null
|
||||||
|
zt_url="$(docker start -a "$sid" | sed -n 's/^ZAAKTYPE_URL //p' | head -1)"
|
||||||
|
docker rm -f "$sid" >/dev/null
|
||||||
|
[ -n "$zt_url" ] || { echo "ERROR: seed did not report a ZAAKTYPE_URL" >&2; exit 1; }
|
||||||
|
echo ">> zaaktype: $zt_url"
|
||||||
|
|
||||||
|
echo ">> recreating the acl service pointed at the seeded zaaktype (host-consistent)"
|
||||||
|
ACL_ZAAKTYPE_URL="$zt_url" ACL_OPENZAAK_BASEURL="$oz_base/" docker compose -f "$compose" up -d acl
|
||||||
|
WAIT_TIMEOUT="${WAIT_TIMEOUT:-120}" bash "$here/wait-healthy.sh" acl
|
||||||
|
|
||||||
|
echo ">> submitting a registration to the domain"
|
||||||
|
loc="$(docker run --rm --network "$net" curlimages/curl:latest \
|
||||||
|
-fsS -D - -o /dev/null -X POST "http://$dom_ip:8080/registrations" \
|
||||||
|
-H 'Content-Type: application/json' -d '{"bsn":"123456782"}' \
|
||||||
|
| sed -n 's/\r$//; s/^[Ll]ocation: //p' | head -1)"
|
||||||
|
[ -n "$loc" ] || { echo "ERROR: POST /registrations returned no Location" >&2; exit 1; }
|
||||||
|
echo ">> registration accepted at $loc"
|
||||||
|
|
||||||
|
echo ">> polling the domain until the worker records the opened zaak"
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
body="$(docker run --rm --network "$net" curlimages/curl:latest \
|
||||||
|
-fsS "http://$dom_ip:8080$loc" 2>/dev/null || true)"
|
||||||
|
if echo "$body" | grep -q '/zaken/api/v1/zaken/'; then
|
||||||
|
echo "OK — the domain opened a zaak and recorded it on the registration:"
|
||||||
|
echo "$body" | cut -c1-300
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "FAIL — the registration never received a zaak URL" >&2
|
||||||
|
echo "--- domain log ---" >&2; docker logs "$dom" 2>&1 | tail -15 >&2
|
||||||
|
acl="$(docker ps -q --filter 'name=[-_]acl[-_]' | head -1)"
|
||||||
|
[ -n "$acl" ] && { echo "--- acl log ---" >&2; docker logs "$acl" 2>&1 | tail -15 >&2; }
|
||||||
|
exit 1
|
||||||
4
services/domain/.dockerignore
Normal file
4
services/domain/.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
**/bin
|
||||||
|
**/obj
|
||||||
|
**/*.user
|
||||||
|
StrykerOutput
|
||||||
34
services/domain/Dockerfile
Normal file
34
services/domain/Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Multi-stage build for the BIG Domain Service (.NET 10).
|
||||||
|
# Build context is services/domain (see infra/docker-compose.yml).
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Restore first (cached unless .csproj files change).
|
||||||
|
COPY Big.Api/Big.Api.csproj Big.Api/
|
||||||
|
COPY Big.Application/Big.Application.csproj Big.Application/
|
||||||
|
COPY Big.Infrastructure/Big.Infrastructure.csproj Big.Infrastructure/
|
||||||
|
COPY Big.Domain/Big.Domain.csproj Big.Domain/
|
||||||
|
RUN dotnet restore Big.Api/Big.Api.csproj
|
||||||
|
|
||||||
|
COPY Big.Api/ Big.Api/
|
||||||
|
COPY Big.Application/ Big.Application/
|
||||||
|
COPY Big.Infrastructure/ Big.Infrastructure/
|
||||||
|
COPY Big.Domain/ Big.Domain/
|
||||||
|
RUN dotnet publish Big.Api/Big.Api.csproj -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends curl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY --from=build /app/publish .
|
||||||
|
|
||||||
|
ENV ASPNETCORE_URLS=http://+:8080
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=5s --timeout=3s --start-period=10s --retries=5 \
|
||||||
|
CMD curl -fsS http://localhost:8080/health || exit 1
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet", "Big.Api.dll"]
|
||||||
Reference in New Issue
Block a user