docs(architecture): add diagrams and implementation playbook

Added three new documents with nine Mermaid diagrams to make the strangler
fig strategy visible:

- README: container topology diagram at the start, with the proxy entry point
  and three seams labelled
- docs/architecture.md: five diagrams tracing the exact implementation:
  - The four seams and who holds authority at each boundary
  - How by-id read goes through the resolver, but list-read bypasses it
  - Case lifecycle state machine (the strategy in one picture)
  - Take-ownership sequence with failure windows annotated
  - Write-through error round-trip showing zero validation logic crossed
- docs/playbook.md: how to apply this to a production system:
  - Write-path decision tree (five read/write patterns)
  - Cutover ordering diagram (side-effects-free first, least recoverable last)
  - Seven transferable rules with pointers to the files that demonstrate them
  - Scope diagram of what's proven vs. left as your decisions

Resolved all 13 dangling § citations (to an absent spec doc) by linking to
the actual files or dropping them. Replaced portal-frontend/README.md
boilerplate with accurate content. All diagrams parse and link-check clean.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-08-01 09:15:39 +02:00
co-authored by Claude Haiku 4.5
parent 5f22156e6d
commit ddec15ccb2
10 changed files with 351 additions and 67 deletions
@@ -7,7 +7,8 @@ Accepted.
`case-framework` (seam D, a stand-in for a maintained vendor case-management
framework) refuses `POST /cases/{id}/closure-request` with **409 Conflict**
while any task on the case is still open. That rule belongs to the framework
and is not ours to change — it is a conformist integration by design (§6).
and is not ours to change — it is a conformist integration by design
(seam D, `New.Infrastructure.CaseFramework/CaseFrameworkGateway.cs`).
The new domain's own rule is different: once an assessment (approve/reject) is
recorded on a `RegistrationApplication`, that decision is legally in effect
@@ -7,7 +7,7 @@ Accepted.
Seam B lets a user edit a **legacy-owned** case's applicant details (name,
address, contact) from the new portal, without the new system taking
ownership of that case. The legacy system remains the authority on this data
until ownership is explicitly taken (§7.5).
until ownership is explicitly taken ([ADR-003](ADR-003-ownership-is-taken-per-case.md)).
It is tempting, once a translation layer exists between the portal's request
shape and legacy's `PUT /api/aanvragen/{id}/gegevens` shape, to also smuggle
@@ -28,13 +28,14 @@ derived values, no defaulting. It only:
(logged as a warning, never dropped or guessed at).
If a rule needs to be enforced on this data from the new portal, that is a
signal the capability should be taken into ownership instead (§7.5), not
signal the capability should be taken into ownership instead, not
patched into the translator.
## Consequences
- The portal cannot offer a better validation experience than legacy already
has for this seam — by design. The `Gevalideerd door het legacy systeem`
notice on the write-through form (§8.3) exists specifically so the user
notice on the write-through form (`portal-frontend/src/app/case-detail/edit-applicant-details/`)
exists specifically so the user
knows why: this is the honest version of a seamless UI, not a limitation to
hide.
- Rule 11 in Architecture.Tests (no `New.Api` type both constructs a legacy
@@ -22,7 +22,7 @@ their keep.
## Decision
Ship now with ownership taken **one legacy case at a time**, via
`POST /api/worklist/legacy/{aanvraagId}/take-ownership` (§7.5), triggered by
`POST /api/worklist/legacy/{aanvraagId}/take-ownership`, triggered by
an explicit user action in the portal. This is the interim mechanism, not the
final one for every process.
@@ -43,11 +43,12 @@ This is deliberately the right building block either way:
- Until bulk tooling exists, full legacy retirement for a process happens
case-by-case, which is slower than a scheduled cutover — accepted as the
cost of shipping the seam mechanics now rather than waiting.
- Reversal (§7.6) stays per-case and gated on `domain_writes_since` for the
- Reversal (`ReleaseOwnershipHandler`) stays per-case and gated on `domain_writes_since` for the
same reason a bulk reversal would be unsafe absent a sync
(`docs/sync-not-implemented.md`): undoing adoption after edits would
silently discard them.
- This demo's non-goals (§3) exclude building the bulk migration tool itself
- This demo's non-goals (README, "Deliberate substitutions and omissions")
exclude building the bulk migration tool itself
— that's future work, not a rejected idea.
## Future work