feat(infra): beheer portal in compose + e2e + ADR-0025 + demo note (refs #130)

This commit is contained in:
not
2026-07-24 10:59:20 +02:00
parent 4c702e324a
commit 5f5dfda1a0
7 changed files with 134 additions and 3 deletions
@@ -0,0 +1,58 @@
# ADR-0025: The BFF reads the catalogus directly from the ACL
- **Status:** Accepted
- **Date:** 2026-07-24
- **Deciders:** Respellion engineering
- **Slice:** S-15a (#130), first of the S-15 (#16) split
## Context
The beheer portal shows a read-only view of the ZTC catalogus (the published
zaaktypen). Two coupling rules constrain where that data can come from:
- **§8.1** — only the ACL may talk to the ZGW APIs (Catalogi included). So the
catalogus read *must* originate in the ACL.
- **§8.3** — portals talk only to the BFF. So the portal reaches the ACL only
through the BFF.
That leaves the question of *how the BFF gets the data*. Until now the BFF fanned
out to exactly two backends — the Domain Service and the read projection. The
catalogus is neither: it is not a registration (domain) nor a projected read model.
## Decision
**The BFF calls the ACL directly for the beheer catalogus read** — a new typed
`IAclClient` (`GET /catalogi/zaaktypen`), configured by `Downstream:Acl:BaseUrl`,
mirroring the existing `IDomainClient` / `IProjectionClient` pattern.
Rejected alternative — **route it through the Domain Service** (BFF → domain →
ACL): the catalogus is not a domain concern, so the domain would gain a
pass-through endpoint that owns no aggregate and no invariant, blurring the
domain's responsibility purely to avoid a new edge. That is worse coupling, not
better.
This adds one service-to-service edge (BFF → ACL) — an architecturally
significant boundary change (§14), hence this ADR. It does **not** bend §8: the
ACL stays the only code that reads ZGW, and the portal still talks only to the
BFF. The ACL endpoint is a plain read that trusts its callers (§8.3); the
beheerder authorization lives at the BFF (medewerker realm + `beheerder` role).
## Consequences
**Positive**
- The catalogus read follows the shortest honest path; the domain stays about
registrations.
- Symmetric with the other downstream clients — nothing new to learn.
**Negative / costs**
- The BFF now depends on three backends instead of two. The ACL must be reachable
for the beheer portal to load (it already is — the BFF is on the same network).
- A second consumer of the ACL (alongside the domain and event-subscriber), so
ACL read endpoints are now part of more than one caller's contract.
## Coupling rules touched (CLAUDE.md §8)
A new BFF → ACL edge. §8.1 and §8.3 remain intact; §14 (boundary change) is the
reason this ADR exists.