Files
register-referentie/docs/PRD.md

215 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BIG-Register Reference Application — PRD
**Status:** v1 draft
**Owner:** Respellion
**Primary remote:** Gitea (self-hosted, Respellion)
**Purpose:** A reference application that demonstrates Respellion's Common Ground architecture pattern — using OpenZaak and other Common Ground modules behind a loose-coupling anti-corruption layer, with workflow, scheduling, and data governance as peer modules. It serves as a Foundations playbook artefact and as a credible, runnable demonstrator for Dutch public-sector engagements.
---
## 1. Goals
1. Demonstrate that a domain-specific case management application (a BIG-style register) can be built **on top of unforked Common Ground modules** by isolating all domain shaping in an Anti-Corruption Layer.
2. Show **four end-user portals** (self-service, public register, back-office, maintenance) sharing one domain layer through a BFF.
3. Show **process orchestration via Flowable** as a peer module, with BPMN + DMN governing the registration workflow.
4. Show **data governance and GDPR lineage** as a separate, integratable module (later iteration).
5. Be **fully runnable locally** with `docker compose up`, including all upstream Common Ground modules, identity, workflow engine, and synthetic data.
6. Encode Respellion craft defaults: TDD, DDD, BDD, mutation testing, trunk-based development, Conventional Commits, ADRs, and CI gates.
7. **Run end-to-end on Gitea infrastructure** — source, issues, CI, container registry, releases, wiki — to demonstrate EU-sovereign tooling.
## 2. Non-goals
- Not a certified production system. No real DigiD/eHerkenning/eIDAS — mocked via Keycloak.
- Not a multi-tenant SaaS. One instance, one client persona, per deployment.
- Not feature-complete to the real Dutch BIG-register. Modelled as a plausible analogue, not a copy.
- Not optimised for production scale; correctness and architectural clarity beat throughput.
- Not dependent on GitHub. The repository lives on a Respellion Gitea instance; GitHub mirroring is explicitly out of scope unless added later as an outreach measure.
## 3. Architecture summary
Refer to `docs/architecture/` for diagrams. Briefly:
- **Portals (Angular, NL Design System):** self-service, openbaar register, behandel-portal, beheer-portal — four apps in an Nx monorepo with a shared component library.
- **BFF (.NET):** per-portal aggregation, OIDC token validation, audit, rate-limiting.
- **BIG Domain Service (.NET):** DDD aggregates, registration workflow, eligibility rules, orchestrates ACL and workflow engine.
- **Anti-Corruption Layer (.NET):** the only code that knows about ZGW APIs. Default-fills schema-mandatory fields, maps domain ↔ ZGW vocabulary.
- **Workflow Client (.NET):** REST client to Flowable; acts as external-task job worker so BPMN never reaches into OpenZaak.
- **Event Subscriber (.NET):** consumes NRC webhooks, updates the read projection, correlates events to running Flowable processes.
- **Read Projection Store:** denormalised, public-safe view feeding the openbaar register portal.
- **Scheduler (Quartz.NET):** fleet-wide sweeps (expiry, reminders).
- **Common Ground modules (upstream, unforked):** OpenZaak, Open Notificaties, Open Klant, Objecten + Objecttypen, Autorisaties.
- **Flowable:** BPMN + DMN engines with Postgres-backed jobs.
- **Identity:** Keycloak realms standing in for DigiD, eHerkenning, eIDAS, and a medewerker-IdP.
- **Data Governance (later):** OpenMetadata as a separate module, ingesting from read replicas and via a lineage SDK.
## 4. User types and primary scenarios
| User type | Auth | Portal | Primary scenario |
|---|---|---|---|
| Zorgprofessional | DigiD (mock) | Self-Service | Submit registration, upload diploma, track status |
| Werkgever / Onderwijsinstelling | eHerkenning (mock) | Self-Service | Register on behalf of a professional (machtiging) |
| EU-professional | eIDAS (mock) | Self-Service | Foreign diploma registration with extra checks |
| Burger / Werkgever-check | anonymous | Openbaar Register | Lookup a professional's registration status |
| Behandelaar / Jurist | medewerker-IdP | Behandel-Portal | Review cases, request additional documents, decide |
| Beheerder | medewerker-IdP + MFA | Beheer-Portal | Manage catalogus, configure default-fill rules, monitor |
## 5. Functional scope — flows for v1
1. **Happy path registration** — DigiD login, submit, upload diploma, automatic verification passes, behandelaar approves, register entry published.
2. **Document timeout** — registration submitted, no diploma uploaded within 30 days, automatic cancellation.
3. **Withdrawal** — applicant withdraws before decision; case cancelled with audit trail.
4. **Foreign diploma escalation** — eIDAS login, diploma flagged as foreign, additional CBGV-style assessment step.
5. **Beoordeling escalation** — behandelaar does not pick up within 14 days, case escalates to teamlead.
The five flows form the BDD acceptance backbone (Gherkin scenarios in `tests/acceptance/`).
## 6. Synthetic data
- Fixed seed loaded on first start: 510 hand-crafted personas covering all five flows, plus ~50 register entries with diverse statuses to populate the openbaar register.
- Dutch-realistic names; **valid test-BSN range** documented in `docs/synthetic-data.md`.
- Diplomas: PDF placeholders with deterministic content, generated by a small data-loader service on first compose-up.
- Re-seeding: a `make seed` / `pwsh ./tools/seed.ps1` target rebuilds from scratch.
## 7. Non-functional requirements
- **Local startup:** `docker compose up` brings everything green within 3 minutes on a developer machine.
- **CI gates (Gitea Actions):** lint, unit, integration, mutation (with ratchet), e2e for the current flow, container build pushed to Gitea Container Registry, compose-up smoke test.
- **TDD discipline:** red → green → refactor commits visible in history.
- **Mutation testing:** Stryker.NET (backend) and Stryker (Angular), baseline-ratcheted on `main`.
- **Coverage:** not a target; mutation score is the quality signal.
- **Observability:** structured logs (Serilog), OpenTelemetry traces, Prometheus metrics; a local Grafana with pre-built dashboards.
- **Security:** all secrets in Gitea repository/organisation secrets or local `.env` (gitignored); no secrets in repo. OWASP dependency scanning step in the Gitea Actions pipeline.
- **Conventional Commits + git-cliff** generated changelog. CalVer versioning.
## 8. Technology choices (locked)
- **Source control & collaboration:** **Gitea** (Respellion self-hosted) — repository, issues, milestones, labels, projects, releases, container registry, wiki, packages.
- **CI/CD:** **Gitea Actions** running on Respellion-hosted `act_runner` instances. Workflow files live in `.gitea/workflows/`. Marketplace actions are referenced via absolute URLs (`uses: https://github.com/actions/checkout@v4` or Gitea-hosted equivalents where available) for reproducibility.
- **Backend:** .NET 10 (LTS at iteration time), C#, minimal APIs for BFF, MediatR for in-process messaging within Domain Service, EF Core for the projection store and domain DB.
- **Frontend:** Angular (latest LTS) + TypeScript, standalone components + signals, Nx monorepo, NL Design System component library, Angular Testing Library + Playwright.
- **Workflow:** Flowable (BPMN + DMN) via Docker image; Postgres for engine store.
- **Identity:** Keycloak with pre-seeded realms.
- **Common Ground:** official upstream Docker images for OpenZaak, Open Notificaties, Open Klant, Objecten, Objecttypen, Autorisaties.
- **Datastore:** Postgres for all .NET services; one schema per service.
- **Scheduler:** Quartz.NET inside the Domain Service deployment.
- **Container registry:** Gitea's built-in container registry; image references in compose pin to `gitea.respellion.local/big-reference/<service>:<tag>`.
- **Containers:** Docker for all components; compose for local; Helm chart sketch for production aspirations (not deployed as part of v1).
- **Docs:** MkDocs Material **plus** Gitea's built-in wiki for living operational pages. See §10.
- **Languages of artefacts:** code, commits, ADRs, docs in **English**; user-facing portal copy and glossary terms in **Dutch**.
## 9. Repository structure (high-level)
```
/
├── apps/ # Angular portals (Nx)
│ ├── self-service/
│ ├── openbaar/
│ ├── behandel/
│ └── beheer/
├── libs/ # shared Angular libs (UI, auth, api-client)
├── services/ # .NET services
│ ├── bff/
│ ├── domain/ # BIG Domain Service
│ ├── acl/ # standalone ACL library + service
│ ├── event-subscriber/
│ └── projection-api/
├── workflows/ # BPMN + DMN sources, exported and version-controlled
├── infra/
│ ├── docker-compose.yml
│ ├── keycloak/
│ ├── opennotificaties/
│ ├── openzaak/
│ ├── objecten/
│ ├── flowable/
│ └── seed/ # data loader
├── tests/
│ ├── acceptance/ # Gherkin / Reqnroll BDD scenarios
│ └── e2e/ # Playwright
├── docs/ # static docs (MkDocs source)
│ ├── PRD.md
│ ├── architecture/ # diagrams + ADRs
│ ├── runbooks/
│ ├── synthetic-data.md
│ └── gitea-workflow.md # how we use Gitea for issues/milestones/projects
├── .gitea/
│ ├── workflows/ # Gitea Actions YAML
│ └── ISSUE_TEMPLATE/ # issue templates (slice, bug, ADR-proposal)
├── CLAUDE.md # working agreements
├── BACKLOG.md # pointer + mirror of the active Gitea milestone backlog
└── README.md
```
## 10. Documentation strategy — split between static and living docs
Two surfaces, each with a clear role:
**Static, versioned documentation — `docs/` rendered by MkDocs Material.**
- The PRD, architecture diagrams (Mermaid sources in repo), ADRs, glossary, synthetic-data spec, and runbooks live here.
- Source of truth, versioned with the code, reviewed via PR.
- Published artefact: an MkDocs site built by a Gitea Actions workflow on every push to `main` and exposed via Gitea Pages (or a static-files job uploading to a Respellion-hosted location).
- ADRs use the Nygard template, one decision per file (`adr-NNNN-title.md`). First ADR (`adr-0001-loose-coupling.md`) is provided as a template.
**Living, operational documentation — Gitea Wiki.**
- The Gitea project's built-in **Wiki** holds operational pages that change frequently and where in-place editing matters: the day-to-day runbook, "known issues right now," the on-call rota, environment URLs, and the human-readable view of the iteration backlog.
- The Wiki is **not** the source of truth for architecture or ADRs — those stay in `docs/`. The Wiki points at them.
- The Wiki is part of the deliverable and is reviewed alongside the code.
**Why split:** versioned docs benefit from PR review and ship with the code; operational pages benefit from in-UI editing and don't need a full PR cycle. Treating both as legitimate gives each its proper home.
## 11. Story and backlog management — Gitea is the system of record
User stories, defects, technical debt, and ADR proposals are tracked in **Gitea Issues**. The `BACKLOG.md` file in the repo is a curated mirror of the *current* milestone — it exists so that Claude Code and contributors can read the iteration plan without opening the web UI, but the **system of record is Gitea**.
Concrete conventions:
- **Each slice in `BACKLOG.md` corresponds 1:1 to a Gitea issue** with the same `S-NN` identifier in the title (e.g. `S-04 · ACL skeleton with one operation: open a zaak`).
- **Milestones** group slices into iterations: `Iteration 0 — Foundations`, `Iteration 1 — Walking Skeleton`, etc.
- **Labels** classify work: `type:slice`, `type:bug`, `type:adr-proposal`, `type:chore`, plus area labels (`area:acl`, `area:domain`, `area:portal-self-service`, `area:infra`, `area:docs`).
- **Projects** (Gitea's kanban-style project boards) visualise an iteration as a board: `Todo / In progress / In review / Done`.
- **Issue templates** live in `.gitea/ISSUE_TEMPLATE/` with three forms: `slice.md`, `bug.md`, `adr-proposal.md`. The slice template encodes the Definition of Done from `CLAUDE.md` §3 as a checklist.
- **Commits and PRs reference issues** with `#NN` (e.g. `feat(acl): default-fill bronorganisatie (refs #14)`). Closing keywords on the merging commit (`closes #14`) move the issue to Done automatically.
- **Pull Requests** are the unit of code review. Trunk-based, squash-merged, with the PR description summarising the slice's acceptance.
- **Releases** are cut on tags via `git-cliff`-generated changelogs and published to Gitea Releases. Container images are tagged matching the release.
`BACKLOG.md` is regenerated (manually or by a small script) whenever a milestone is opened or closed. Treat it as a snapshot, not the source of truth.
## 12. Iteration shape — walking skeleton first
The first iteration is a **walking skeleton** that proves the spine end-to-end with minimal features. Each subsequent iteration is a **vertical slice** that adds one capability, deployable on its own. See `BACKLOG.md` for the slice list.
The skeleton: zorgprofessional logs in via mock DigiD → self-service portal submits a registration → BFF calls Domain Service → Domain Service starts a Flowable BPMN process and opens a zaak via the ACL → status event flows via NRC to the Event Subscriber → projection updated → openbaar register portal shows the entry.
Everything in the skeleton is real (no mocks beyond the IdP). Subsequent slices flesh out scenarios, edge cases, and the remaining portals/modules.
## 13. Definition of Done (per slice)
A slice is done when:
- Red → green → refactor commits visible in history (Conventional Commits).
- All CI gates pass on Gitea Actions (lint, unit, integration, mutation baseline, e2e for the slice's scenario, container build + push to Gitea Container Registry, compose-up smoke test).
- `docker compose up` from a fresh clone yields green health checks within 3 minutes.
- The Gherkin scenario(s) that define the slice pass.
- An ADR is added in `docs/architecture/` if a non-obvious decision was made.
- The relevant runbook section is updated (in `docs/runbooks/` or the Wiki, as appropriate per §10).
- A short demo note appended to `docs/demo-script.md`.
- The corresponding Gitea issue is closed via the merging commit's footer (`closes #NN`).
## 14. Open risks tracked
- **OpenZaak version drift.** Pin upstream image tags; document the upgrade procedure.
- **Flowable + .NET integration friction.** External-task worker pattern via REST; mitigate by isolating in Workflow Client.
- **NL Design System completeness.** Some components may need polyfills; record gaps in `docs/frontend-decisions.md`.
- **NRC ordering and duplication.** Event Subscriber must be idempotent; verified by acceptance tests that replay events.
- **Gitea Actions ↔ GitHub Marketplace action drift.** Some marketplace actions assume GitHub-specific APIs. Workflows pin actions to known-good versions; gaps are recorded in `docs/runbooks/gitea-actions-gotchas.md`.
## 15. Out of scope for v1
- OpenMetadata data governance module (v3 slice).
- Objecten as the authoritative register record store (v2 slice — v1 uses OpenZaak zaak-eigenschappen as a placeholder).
- Production-grade Helm chart (sketch only).
- Multi-tenancy.
- Real outbound notifications (email/SMS) — logged to console in v1.
- GitHub mirroring or any GitHub-hosted automation.