## What & why Brings the engineer-facing FDS documentation next to the code it describes. Imported from `projects/open-register-fd/` in `Respellion/innovation-lab` and translated to Dutch: **six ADRs**, the ADR index and template, the **L3 component view**, and the **slice-1 proposal**. The architecture blueprint, the FDS gap analysis and the two privacy views stay in the lab repo — the OKRs cite them and they feed tender responses. Each side names the split in a "Wat ligt waar" table, so nothing is documented twice. Closes #159 ### Why `docs/architecture/fds/` and not `docs/architecture/` This repo's own ADR series now runs `adr-0001-loose-coupling` … `adr-0010-bff-oidc`. The imported set is numbered 0001–0006, so a flat import would collide across the whole imported range. The subfolder preserves the imported numbering, and with it roughly thirty `ADR-000N` cross-references inside the imported text that would otherwise all need rewriting. In the MkDocs sidebar the imported six appear as **FDS ADR-000N** so they are not confused with this repo's series. `docs/architecture/fds/README.md` explains the two series. ### Mermaid support was missing `pymdownx.superfences` had no `custom_fences`, so the imported diagrams would have published to Gitea Pages as raw code blocks. This PR adds the mermaid custom fence, the nav group, and one link under *Where to go* in the docs index. ## Definition of Done - [x] Linked Gitea issue (above). - [ ] Failing test committed before the implementation. — n/a, documentation only. - [ ] Implementation makes the test pass. — n/a, documentation only. - [x] Conventional Commits referencing the issue (`refs #159`). - [x] Rebased on current `main`; no conflicts. - [ ] CI green — n/a for content; the docs verification is below. - [ ] `docker compose up` reaches green health checks. — n/a, no runtime change. - [x] Docs updated if behaviour, contracts, or operations changed. - [x] ADR added in `docs/architecture/` if a non-obvious decision was made. — six imported, plus the numbering decision recorded in the folder README. - [ ] Demo note in `docs/demo-script.md`. — n/a, nothing user-visible. ## Verification run - `mkdocs build` — clean. No missing-nav warning for any `architecture/fds/` entry. The two remaining warnings are pre-existing on `main` and untouched here: the set of pages absent from `nav`, and a broken link in `runbooks/ci.md` to `services/acl/stryker-config.json`. - Mermaid renders as a diagram, not a code block: `site/architecture/fds/c4-component-view/index.html` contains `class="mermaid"`. - All relative markdown links in the repo resolve. ## Notes for reviewers - **Language.** The imported documents are Dutch; this repo's own documents remain English. Deliberate, not an oversight — the lab repo standardised on Dutch and these pages moved with it. Translating the rest is a separate decision. - **Ownership.** This repo sits in the `eho/` namespace while it now holds the canonical FDS architecture decisions that tender answers point at. Worth deciding whether it should move to `Respellion/`. - **Scope drift, not fixed here.** The imported text is faithful to its source, so the slice-1 proposal and the ADRs assume NHR/KVK for slice 1, while the lab-side blueprint still uses BAG as its example register. The lab-side documents carry a banner about this; Blueprint v2 (slice 5) is where the diagrams get corrected. - **Companion PR:** `Respellion/innovation-lab` #34 holds the lab-side half of this split.Reviewed-on: #160
128 lines
8.7 KiB
Markdown
128 lines
8.7 KiB
Markdown
# C4-componentview — register-applicatie en capability-laag
|
|
|
|
> Niveau 3, de componentview. Deze view zoomt in op de container van de .NET register-applicatie uit
|
|
> het L2-containerdiagram. Zij verbindt het geheel op componentniveau — domein, ports, adapters en de
|
|
> FDS-capability-componenten — en toont waar elk onderdeel externe tooling raakt.
|
|
>
|
|
> De hexagonale structuur is expliciet: het domein hangt alleen af van **ports** (interfaces). Elke
|
|
> concrete capability is een **adapter** die aan een port is gebonden.
|
|
>
|
|
> De containerview (L2), de blauwdruk en de privacy-datastroomviews staan in het Innovation Lab-repo,
|
|
> `Respellion/innovation-lab`, onder `projects/open-register-fd/`.
|
|
|
|
```mermaid
|
|
C4Component
|
|
title Componentview — register-applicatie (.NET) en de FDS-capability-laag
|
|
|
|
Person(user, "Behandelaar", "Behandelt zaken")
|
|
Container(spa, "Frontend", "Angular + NL Design System", "Zaakinterface")
|
|
|
|
Container_Boundary(app, "Register-applicatie (.NET, hexagonaal)") {
|
|
Component(api, "API / application services", ".NET", "Orkestreert use cases; verklaart doelbinding per vraag")
|
|
Component(domain, "Domeinmodel", ".NET / DDD", "Ubiquitous language; geen registervocabulaire")
|
|
|
|
Component(portReg, "Register Port", "interface", "De vraag van het domein: Personen / Organisaties")
|
|
Component(portPol, "Authorisation Port", "interface", "mag-deze-verwerking-doorgaan?")
|
|
Component(portLog, "Verwerking Port", "interface", "leg de verwerkingsgebeurtenis vast")
|
|
Component(portTm, "Terugmelding Port", "interface", "meld een vermoedelijke fout")
|
|
Component(portCache, "Cache Port", "interface", "doelgebonden lezen, schrijven en verwijderen")
|
|
|
|
Component(aclBrp, "BRP-adapter", ".NET", "Vertaalt domein<->BRP; minimale velden")
|
|
Component(aclKvk, "NHR/KVK-adapter", ".NET", "Vertaalt domein<->NHR; UBO-bewust")
|
|
Component(pdpClient, "PDP Client", ".NET -> OPA", "Roept de policy engine; geeft doel en grondslag mee")
|
|
Component(ldvEmit, "LDV Emitter", ".NET", "Bouwt het verwerkingsevent; publiceert naar Redpanda")
|
|
Component(fscClient, "FSC Client", ".NET", "Stuurt contractuele aanroepen via de outway")
|
|
Component(cacheMgr, "Cache Manager", ".NET", "TTL en verwijderen op subjectsleutel")
|
|
Component(tmHandler, "Terugmelding Handler", ".NET -> Flowable", "Start het terugmeldproces")
|
|
Component(procClient, "Process Client", ".NET -> Flowable", "Uitvoering van BPMN en DMN")
|
|
}
|
|
|
|
System_Ext(opa, "OPA (PDP)", "Policies geversioneerd in Gitea")
|
|
System_Ext(fsc, "FSC Outway", "EUPL-referentie-implementatie")
|
|
System_Ext(flowable, "Flowable", "BPMN + DMN")
|
|
ContainerDb_Ext(cache, "Begrensde cache", "PostgreSQL")
|
|
System_Ext(redpanda, "Redpanda", "LDV-topic + CDC")
|
|
System_Ext(brp, "BRP", "via FSC inway")
|
|
System_Ext(kvk, "NHR / KVK", "via FSC inway")
|
|
System_Ext(kanidm, "Kanidm", "OIDC")
|
|
|
|
Rel(user, spa, "Gebruikt")
|
|
Rel(spa, api, "REST/JSON")
|
|
Rel(kanidm, api, "OIDC", "authenticatie")
|
|
Rel(api, domain, "Roept aan")
|
|
Rel(api, portPol, "Controleert vóór de bevraging")
|
|
Rel(api, portReg, "Vraagt data")
|
|
Rel(api, portTm, "Dient melding in")
|
|
Rel(api, procClient, "Voert proces uit")
|
|
|
|
Rel(portPol, pdpClient, "gebonden aan")
|
|
Rel(pdpClient, opa, "besluitverzoek")
|
|
|
|
Rel(portReg, aclBrp, "gebonden aan")
|
|
Rel(portReg, aclKvk, "gebonden aan")
|
|
Rel(aclBrp, fscClient, "via")
|
|
Rel(aclKvk, fscClient, "via")
|
|
Rel(aclBrp, portLog, "stuurt event")
|
|
Rel(aclKvk, portLog, "stuurt event")
|
|
Rel(aclBrp, portCache, "leest en schrijft")
|
|
Rel(aclKvk, portCache, "leest en schrijft")
|
|
Rel(fscClient, fsc, "contractuele aanroep")
|
|
Rel(fsc, brp, "mTLS + contract")
|
|
Rel(fsc, kvk, "mTLS + contract")
|
|
|
|
Rel(portLog, ldvEmit, "gebonden aan")
|
|
Rel(ldvEmit, redpanda, "publiceert")
|
|
Rel(portCache, cacheMgr, "gebonden aan")
|
|
Rel(cacheMgr, cache, "slaat op")
|
|
Rel(portTm, tmHandler, "gebonden aan")
|
|
Rel(tmHandler, flowable, "start proces")
|
|
Rel(procClient, flowable, "voert uit")
|
|
```
|
|
|
|
## Hoe je dit leest
|
|
|
|
1. **De ports zijn de naad.** Het domein en de application services hangen af van de vijf interfaces,
|
|
en nooit van adapters. FSC wisselen voor DSP, of OPA voor de latere FTV-client, verandert een
|
|
adapter — geen port, en niet het domein. Dit is de clock-speed boundary, concreet gemaakt.
|
|
2. **De compliance-componenten zijn adapters, geen domeinlogica.** De PDP-client, de LDV-emitter, de
|
|
FSC-client en de cache manager staan allemaal aan de adapterzijde. Een bevraging kan er fysiek niet
|
|
langs, omdat de adapter die de Register Port vervult dezelfde code is die het LDV-event uitstuurt
|
|
en via FSC routeert.
|
|
3. **Slechts twee componenten raken de registers**: de BRP-adapter en de NHR/KVK-adapter. Beide
|
|
bereiken ze uitsluitend via de FSC-client. Er is geen vierde pad.
|
|
|
|
## Componenten tegenover verplichtingen
|
|
|
|
| Component | Omvang eigen bouw | Verplichting die het afdekt |
|
|
|---|---|---|
|
|
| Domeinmodel | het product | correctheid van de bedrijfsregels |
|
|
| BRP- en NHR-adapters | dun | dataminimalisatie: vertalen en velden versmallen |
|
|
| PDP Client | klein | handhaven van grondslag en doelbinding |
|
|
| LDV Emitter | klein | verwerkingenlog (AVG art. 30 en LDV) |
|
|
| FSC Client | klein | geautoriseerde, gelogde connectiviteit |
|
|
| Cache Manager | klein | grenzen aan bewaring, en verwijdering |
|
|
| Terugmelding Handler | klein | de terugmeldplicht van de afnemer |
|
|
|
|
---
|
|
|
|
## Aanvullende views die voor engineers waarde hebben
|
|
|
|
De diagrammen tot hier verklaren *structuur* en *compliance-intentie*. Engineers die dit bouwen,
|
|
hebben er nog een aantal nodig. Wij tekenen geen view voordat er iets echt is om te beschrijven, dus
|
|
elke regel noemt de trigger.
|
|
|
|
| # | View | Wat het toevoegt | Trigger |
|
|
|---|---|---|---|
|
|
| 1 | **Deploymentview** (C4 deployment, topologie) | Waar elke container op De Werf draait: k3s-namespaces, welke services sidecar zijn en welke een eigen pod (is OPA een sidecar of centraal? waar eindigt de FSC outway?), netwerkpolicies tussen de vlakken van de vertrouwensgrens, en beheer van secrets en mTLS-certificaten voor FSC. Hier worden de privacy*grenzen* echte firewall- en netwerkregels. | Vóór de eerste deploy met meerdere services. **Hoogste waarde als volgende.** |
|
|
| 2 | **Sequences voor de niet-gelukkige paden** | Wij hebben het gelukkige pad. Engineers hebben de lastige nodig: PDP-*deny* midden in een transactie, een verlopen of ingetrokken FSC-contract, een register-timeout terwijl er een verouderde cache-entry ligt, en een gedeeltelijk NHR-antwoord waarbij een UBO-veld is achtergehouden. Dit bepaalt de foutafhandeling, en hier verstoppen de compliance-randgevallen zich. | Direct na slice 1. |
|
|
| 3 | **Domeinmodel en ERD** | De bounded contexts en aggregates in het domein, plus het cacheschema: welke persoonsgegevens blijven staan, op welke sleutel, en met welke purge-kolom. Dit is tegelijk het artefact dat de FG beoordeelt voor bewaartermijnen. | Zodra het domein in slice 1 stabiliseert. |
|
|
| 4 | **Dataclassificatie- en catalogusview** | Elk veld dat een grens kruist, getagd — persoonsgegeven? bijzondere categorie? UBO-beperkt? — en gemapt op zijn classificatie in OpenMetadata. Dit stuurt de GDPR-scrubbingregels en de lineage-tags. | Beter *uit* OpenMetadata gegenereerd zodra die gevuld is, dan met de hand getekend. |
|
|
| 5 | **Toestandsdiagram: levensloop van een cache-entry** | `fetched` → `valid` (binnen TTL) → `stale` → `purged` (TTL verstreken \| zaak gesloten \| verwijderingsverzoek). Klein, maar het pint de bewaarsemantiek vast die "begrensde cache" nu alleen in prose beschrijft. | Samen met ADR-0004-vervolgwerk. |
|
|
| 6 | **BPMN-view: de terugmelding-workflow** | Het Flowable-proces zelf: ingediend → verstuurd naar bronhouder → bevestigd → opgelost of afgewezen. Dit is uitvoerbaar BPMN, dus het diagram en de implementatie zijn hetzelfde artefact. | Wanneer de terugmelding-slice start. |
|
|
| 7 | **Threat model en vertrouwensgrensview** (STRIDE-stijl) | Dreigingen over de vertrouwensgrens leggen: tokendiefstal, cache poisoning, replay tegen FSC, policy bypass, en manipulatie van logs. Past natuurlijk bij de FSC-zoom, en is het anker van het securitygesprek. | Vóór het verwerken van echte persoonsgegevens. |
|
|
| 8 | **CI/CD- en policy-promotieview** | Hoe OPA-policies en BPMN/DMN-modellen van een pull request naar draaiende configuratie gaan. "Toegangsbeheer is configuratie in Gitea" geldt alleen als er een pijplijn is die review en promotie handhaaft. | Samen met het vervolgwerk uit ADR-0003. |
|
|
|
|
**Voorstel voor de volgende twee.** De **deploymentview**, omdat die de privacygrenzen omzet in
|
|
handhaafbare netwerkpolicy. En de **sequences voor de niet-gelukkige paden**, omdat compliance daar
|
|
werkelijk breekt.
|