ccae27b3da3340ea24982d7a4c1ae510c43c85d1
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ccae27b3da |
feat(workflow): diploma-eligibility DMN routes foreign diplomas via CBGV-advies (S-13, closes #14) (#101)
## What & why S-13: a diploma's origin decides its route. A **DMN** (`diploma-eligibility`) is evaluated inline by the registratie process as a **`businessRuleTask`**; an exclusive gateway routes a **foreign** (Buitenlands) diploma through a new **CBGVAdvies** user task before `Beoordelen`, a **domestic** one straight there (PRD flow 4). The domain's only new job is carrying the diploma origin and passing it as a process start variable. Chose **Option B (DMN in the BPMN)** over the issue's literal "evaluated by the Domain Service via Workflow Client" wording — keeps the decision a first-class workflow artefact and §8.2 clean. Rationale in **ADR-0016** (proposal #100); noted on this issue. Closes #14 ## Definition of Done - [x] Linked Gitea issue (above). - [x] Failing test committed before the implementation. - [x] Implementation makes the test pass. - [x] Conventional Commits referencing the issue (`refs #14`). - [ ] CI green — all Gitea Actions jobs. - [x] `docker compose up` from a fresh clone reaches green health checks within 3 minutes (additive; DMN deployed by flowable-init). - [x] Docs updated (ADR-0016, demo note). - [x] ADR added (`docs/architecture/adr-0016-diploma-eligibility-dmn.md`). - [x] Demo note in `docs/demo-script.md`. ## How it was built (TDD) - **Domain**: `DiplomaOrigin` on the aggregate + submit command; threaded through the process-start port so the Workflow Client emits a `diplomaOrigin` start variable. Red → green. - **DMN + BPMN**: `workflows/diploma-eligibility.dmn` (origin → route); `businessRuleTask` + exclusive gateway + `CBGVAdvies` user task in `registratie.bpmn`; DMN deployed to Flowable's DMN engine by `flowable-init`. - **Both paths**: `Een diploma op herkomst routeren` acceptance scenarios (origin carried into the process) + unit tests; verify-domain drives a foreign registration through CBGVAdvies→Beoordelen and the domestic one straight to Beoordelen — exercising both DMN branches live. ## Notes for reviewers - Deviation from the issue's Option-A wording is deliberate and recorded (ADR-0016); the outcome is unchanged. - The self-service eIDAS→foreign wiring is out of scope here (this slice is area:domain + area:workflow); the domain submit accepts an optional `diplomaOrigin` so the foreign path is drivable. - Local green: domain unit 109, acceptance 15, `dotnet format`, Release build (0 errors), **domain mutation 95.39%** (break 90). The DMN/`businessRuleTask` REST wiring is CI-verified on verify-stack (no local full-stack run here). Reviewed-on: #101 |
||
|
|
1f1c944a8b |
feat(domain): withdrawal — INGETROKKEN transition + endpoint (S-11a, refs #12) (#88)
## What & why First sub-slice of **S-11 · Withdrawal (Flow 3)** (#12). A zorgprofessional can withdraw a still-open registration ("trek aanvraag in"); this sub-slice delivers the **domain transition + endpoint**, mirroring how S-12a shipped the beoordeling decision model on its own (#82). - `RegistrationStatus.Ingetrokken` (terminal). - `Registration.Withdraw()` — allowed from INGEDIEND or IN_BEHANDELING, needs no zaak, idempotent, and rejected once the registration has been decided (INGESCHREVEN/AFGEWEZEN). - `WithdrawRegistration` application handler (load → withdraw → persist; repeated withdrawal is a no-op). - `POST /registrations/{id}/withdraw` on the domain API. Demoable: `POST /registrations/{id}/withdraw` → `GET /registrations/{id}` shows `INGETROKKEN`. Refs #12 (not closing — see below). ## Scope / follow-ups S-11 is bigger than one slice, so it is split (CLAUDE.md §13), like S-12 was: - **S-11a (this PR)** — domain withdrawal transition + endpoint. - **S-11b** — cancel the running Flowable process via a BPMN message event, so a withdrawn case leaves the behandelaar's werkbak. - **S-11c** — owner-scoped BFF self-service withdraw endpoint + "trek aanvraag in" button + e2e. Cancelling the Flowable process is deliberately deferred (documented in `WithdrawRegistration`), exactly as the beoordeling's rejection deferred its zaak propagation. #12 stays open until S-11c. ## Definition of Done - [x] Linked Gitea issue (#12). - [x] Failing test committed before the implementation. - [x] Implementation makes the test pass. - [x] Conventional Commits referencing the issue (`refs #12`). - [ ] CI green — all Gitea Actions jobs. - [x] `docker compose up` unaffected (no infra/contract change). - [x] Docs — none needed for this backend sub-slice; the user-visible demo note lands with S-11c. - [x] No ADR needed — mirrors existing aggregate/handler/endpoint patterns; no boundary change. ## Notes for reviewers - Verified locally: `Big.Tests` 89/89 pass; `Big.Api` builds clean. - The domain trusts its callers (§8.3); owner-scoping by the caller's bsn is enforced at the BFF in S-11c. Reviewed-on: #88 |
||
|
|
d4ed0ffc22 |
feat(#13): S-12a — beoordeling decision model (domain) (#82)
## What & why First sub-slice of **S-12 (#13)** — the **beoordeling decision model** in the Domain Service. Foundation for the behandel-portal: it gives the domain a proper decision lifecycle before any UI/Flowable/BFF work. - **Statuses:** add `InBehandeling` and `Afgewezen` to `RegistrationStatus`. - **Aggregate:** `TakeIntoBehandeling()` (`Ingediend → InBehandeling`, idempotent, guards terminal states); generalise the behandelaar decision — `Approve()` (requires a zaak) and new `Reject()` both act on an `Ingediend`/`InBehandeling` registration → `Ingeschreven`/`Afgewezen`. - **Use-case:** `BeoordeelRegistratie` (`goedkeuren` sets the zaak's final status via the ACL §8.1 → `Ingeschreven`; `afwijzen` → `Afgewezen`, domain-only for now). Idempotent. - **Endpoint:** `POST /registrations/{id}/decide` (`{ "besluit": "goedkeuren" | "afwijzen" }`), superseding the temporary `/approve` (retired when the portal lands, S-12d). - **BDD:** `EenRegistratieBeoordelen.feature` — goedkeuren + afwijzen scenarios (feature-scoped bindings). **Scoped out** to later S-12 sub-slices: Flowable user-task claim/complete + BPMN `userTask` (S-12b), BFF `/behandel/*` + medewerker authz (S-12c), the Angular behandel-portal + e2e (S-12d), and propagating a *rejection* to the zaak/projection via the ACL. ## Definition of Done - [x] Linked issue: #13 (umbrella; this PR `refs`, does not close) - [x] Tests first; red → green per behaviour - [x] Unit + acceptance green (`make unit`): domain 65, acceptance 9 - [x] Mutation ≥ break(90): domain 98.77%, no survivors in new code (the one unkilled mutant is the pre-existing `FlowableWorkflowClient` baseline) - [ ] CI green (pending) Part of #13. Reviewed-on: #82 |
||
|
|
1c185e6686 |
S-09b: Approval flow — temp admin endpoint + status transition to projection (#77)
## What & why S-09b (#75, split from #10) — the **approval flow** that completes the walking skeleton. A behandelaar can now approve a submitted registration; the entry flips from `INGEDIEND` to `INGESCHREVEN` in the public register. Flow: `POST /registrations/{id}/approve` (domain) → ACL sets the zaak eindstatus (ZGW `/statussen`) → OpenZaak → NRC → event-subscriber → projection → openbaar. ## Changes (bottom-up, each red→green TDD) - **Domain** — `RegistrationStatus.Ingeschreven` + `Registration.Approve()` (guards: opened zaak, only from INGEDIEND); `ApproveRegistration` use case (idempotent) + temp `POST /registrations/{id}/approve` endpoint; `IAclClient.ApproveZaakAsync`. - **ACL** — resolves the zaaktype's **eindstatus** from the catalogus (`isEindstatus` / highest volgnummer) and POSTs a ZGW status; exposed as `POST /statussen`. Unit + real-OpenZaak integration test. - **Event-subscriber** — binds NRC `hoofdObject`, projects a `status`/`create` as `INGESCHREVEN` keyed on the zaak (updates the existing row), **without reading OpenZaak** (§8.1). Retains the ZGW `resource` in the log (new column + EF migration) so a rebuild reproduces the status. - **e2e** — extended: submit → public INGEDIEND → approve → public INGESCHREVEN. - **Docs** — ADR-0011 (the two non-obvious decisions + the walking-skeleton assumption) + demo note. ## Key decisions (see ADR-0011) - **ACL discovers the eindstatus** (chosen over injecting a statustype URL): no new config/seed plumbing, domain stays ZGW-ignorant. - **Any post-creation status-set ⇒ INGESCHREVEN**: in the walking skeleton the only status ever set after creation is the approval, and the subscriber may not read ZGW — documented to tighten when more transitions arrive (S-12+). ## Verification - All .NET unit suites green locally (domain 47, acl 11, event-subscriber 14, bff 16, acceptance 7); Release build + `dotnet format` clean. - No new compose config (the eindstatus-discovery approach avoided it). - The real-OpenZaak integration test (ACL status-set) and the full submit→approve→visible e2e run in CI `verify-stack` (live NRC→projection + selectielijst egress, not reproducible locally). closes #75 Reviewed-on: #77 |
||
|
|
e9a873c152 |
test(domain): mutation baseline 90 (achieved 97.7%) + CI/Makefile wiring (refs #6)
Stryker.NET config for the domain service (break 90, the repo's ratchet floor), excluding the OpenZaakJobPump hosted-shell from mutation. Hardened the unit tests to kill survivors — Basic-credential value, variable types, null/failure response paths, option defaults, guard clauses, save counts and log output — leaving only two documented equivalent mutants (Stryker-disabled). make mutation runs the domain ratchet and CI uploads its report alongside the others. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
53751fd1bc |
feat(domain): implement the Registration aggregate invariants (refs #6)
Submit requires a bsn and starts the aggregate in INGEDIEND; the started process-instance id is recorded; AttachZaak stores the ACL's zaak URL, tolerating a duplicate (at-least-once worker delivery) and rejecting a conflicting URL, without advancing the status. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
cc9e7852e1 |
test(domain): Registration aggregate invariants (refs #6)
Failing unit tests for the Registration aggregate root: a submission starts in INGEDIEND carrying its bsn, an empty/whitespace/null bsn is rejected, the started process-instance id is remembered, and attaching the zaak the ACL opened records its URL idempotently (a conflicting URL is rejected) while the status stays INGEDIEND. The aggregate is a stub (no-op mutators, empty bsn) so the tests compile and fail on their assertions; the green commit implements the invariants. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |