From 0904df8db0103a883892e908d3920134ccaa8b34 Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Tue, 21 Jul 2026 12:15:33 +0000 Subject: [PATCH] feat(acl): diploma upload stored in the ZGW Documenten API (S-10b, closes #103) (#108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What & why S-10b: the self-service **diploma upload** is now real. After submitting, the citizen picks a PDF and uploads it; the portal base64-encodes it client-side → BFF → domain → **ACL**, which stores it in the ZGW **Documenten (DRC) API** as an `enkelvoudiginformatieobject` and relates it to the zaak, then the `WachtOpDocumenten` wait completes and the case advances to beoordeling. Per §8.1 only the ACL talks to ZGW. Closes #103 Mechanism in **ADR-0018** (proposal #107). Builds on S-10a (#102). The zaak-close-on-expiry item is carved to **#106 (S-10c)**. ## Definition of Done - [x] Linked Gitea issue (above). - [x] Failing test committed before the implementation (red→green per layer). - [x] Conventional Commits referencing the issue (`refs #103`). - [ ] CI green — all Gitea Actions jobs (pending on this PR). - [x] `docker compose up` health unaffected (ACL boots on a placeholder informatieobjecttype URL; the real one is injected by verify-domain). - [x] Docs updated (ADR-0018, demo-script, BACKLOG + S-10c). - [x] ADR added (`docs/architecture/adr-0018-diploma-upload-via-acl-documenten.md`). - [x] Demo note in `docs/demo-script.md`. ## Notes for reviewers - **ACL** (`OpenZaakGateway.StoreDocumentAsync` + `AclService.StoreDiplomaAsync` + `POST /documenten`) reuses the existing gateway patterns (ZGW Bearer, buffered non-chunked body, **no CRS** — Documenten isn't geo). Unit-tested via the stub handler; an **integration test** stores a real document against live OpenZaak (verify-acl). - **Transport:** base64 JSON on every hop (portal encodes client-side) — I deviated from proposal #107's multipart to keep one contract shape and avoid `IFormFile`/antiforgery/multipart-client plumbing; fine at diploma size (ADR-0018 §Alternatives). - **Infra:** `seed_catalogus.py` seeds + publishes a "Diploma" `informatieobjecttype` and relates it to the zaaktype (while both concept); `verify-domain` injects its URL into the ACL. No new ZGW scopes (seed applicatie has `heeft_alle_autorisaties`). - **e2e:** uploads a real PDF (`setInputFiles`) after the openbaar INGEDIEND row confirms the zaak is open (so storage doesn't race the OpenZaak worker). - **Scope boundary:** the ZGW zaak is not set to a cancellation status on 30-day expiry — that's #106 (S-10c). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://git.labs.respellion.tech/eho/register-referentie/pulls/108 --- BACKLOG.md | 8 +- .../app/registration/registration-page.html | 11 +- .../registration/registration-page.spec.ts | 17 ++- .../src/app/registration/registration-page.ts | 57 ++++++--- ...-0018-diploma-upload-via-acl-documenten.md | 74 ++++++++++++ docs/demo-script.md | 28 +++++ infra/docker-compose.yml | 3 + infra/openzaak/seed_catalogus.py | 62 ++++++++++ infra/run-domain-check.sh | 11 +- libs/api-client/src/lib/generated/bff-api.ts | 26 +++-- services/acl/Acl.Api/Program.cs | 11 ++ services/acl/Acl.Application/AclDefaults.cs | 4 + services/acl/Acl.Application/AclService.cs | 29 +++++ .../acl/Acl.Application/DocumentRequest.cs | 17 +++ services/acl/Acl.Application/IZaakGateway.cs | 7 ++ .../acl/Acl.Infrastructure/OpenZaakGateway.cs | 75 ++++++++++++ .../Acl.IntegrationTests/OpenZaakFixture.cs | 12 ++ .../OpenZaakGatewayIntegrationTests.cs | 54 +++++++++ services/acl/Acl.Tests/AclServiceTests.cs | 47 ++++++++ .../acl/Acl.Tests/OpenZaakGatewayTests.cs | 110 ++++++++++++++++++ services/bff/Bff.Api/DownstreamClients.cs | 15 ++- services/bff/Bff.Api/Program.cs | 10 +- services/bff/Bff.Tests/BffFactory.cs | 6 +- .../bff/Bff.Tests/SelfServiceEndpointTests.cs | 21 +++- services/bff/openapi.json | 33 ++++++ services/domain/Big.Api/Program.cs | 13 ++- services/domain/Big.Application/Ports.cs | 7 ++ .../Big.Application/ProvideDocuments.cs | 29 +++-- .../Big.Infrastructure/AclHttpClient.cs | 26 +++++ services/domain/Big.Tests/Fakes.cs | 9 ++ .../domain/Big.Tests/ProvideDocumentsTests.cs | 47 +++++--- tests/acceptance/Steps/EenZaakOpenenSteps.cs | 1 + tests/acceptance/Support/BffAcceptanceHost.cs | 3 +- .../acceptance/Support/InMemoryDomainPorts.cs | 8 ++ .../acceptance/Support/InMemoryZaakGateway.cs | 3 + tests/e2e/registration.spec.ts | 5 + 36 files changed, 823 insertions(+), 76 deletions(-) create mode 100644 docs/architecture/adr-0018-diploma-upload-via-acl-documenten.md create mode 100644 services/acl/Acl.Application/DocumentRequest.cs diff --git a/BACKLOG.md b/BACKLOG.md index db28395..c1c90a3 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -209,9 +209,13 @@ Split (issue #11 closed) into two independently-demoable slices per §13 — the #### S-10b · Real diploma upload stored via the ACL Documenten API — #103 -**Outcome:** the self-service "Documenten aanleveren" action becomes a real file upload; the document is stored in the ZGW Documenten (DRC) API and related to the zaak, with all document calls routed through the ACL (§8.1), and the zaak is set to a cancellation status on timeout expiry. Builds on the S-10a trigger/wait. Depends on #102. +**Outcome:** the self-service "Documenten aanleveren" action becomes a real file upload; the file (base64-encoded end-to-end) is stored in the ZGW Documenten (DRC) API as an `enkelvoudiginformatieobject` and related to the zaak, with all document calls routed through the ACL (§8.1, ADR-0018). Builds on the S-10a trigger/wait. Depends on #102. -**Acceptance:** ACL Documenten gateway integration test; Playwright e2e uploads a real document; the openbaar/zaak reflects the stored document. +**Acceptance:** ACL Documenten gateway integration test (real OpenZaak); Playwright e2e uploads a real PDF. + +#### S-10c · Close the ZGW zaak on document-timeout expiry — #106 + +**Outcome:** when the 30-day term lapses (S-10a `RegistratieVerlopen`), the ZGW zaak is set to a cancellation status (not just the domain aggregate → `Verlopen`). Adds a cancellation statustype/resultaattype to the seed + an ACL method + expiry-worker wiring. Carved from S-10b (ADR-0017/0018). Depends on #103. ### S-11 · Withdrawal (Flow 3) diff --git a/apps/self-service/src/app/registration/registration-page.html b/apps/self-service/src/app/registration/registration-page.html index 6910880..255dba4 100644 --- a/apps/self-service/src/app/registration/registration-page.html +++ b/apps/self-service/src/app/registration/registration-page.html @@ -19,11 +19,20 @@ Het aanleveren van uw documenten is niet gelukt. Probeer het opnieuw.

} +

Lever uw diploma aan (PDF).

+ +