# 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: 5–10 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 9 (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/:`. - **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.