RD-18 established that a ticket reference inside a path to a document that still exists is a pointer, not provenance, and exempted one. RD-19 did not re-run that check against `backend/`, and asserted a target of 0. Two such paths existed, so the agent described the two documents in prose instead. The path no longer resolves and the reader must search. Restore both paths, correct the ticket's decision 1 and acceptance target to 2, and record the miss as the eighth in the README's list. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
122 lines
4.6 KiB
Markdown
122 lines
4.6 KiB
Markdown
# BIG-register BFF (ASP.NET Core)
|
|
|
|
The backend that hosts the **business rules** for the BIG-register portal. The
|
|
frontend renders the decisions this service computes; it does not recompute them
|
|
(BFF-lite + decision DTOs — see `../docs/reference/architecture/0001-bff-lite-decision-dtos.md`).
|
|
|
|
No real BRP/DUO: the reference data they'd return (registration, person, diplomas,
|
|
notes — `Data/SeedData.cs`) is in-memory and seeded, but the endpoints, DTOs,
|
|
status codes and error envelope are production-shaped.
|
|
|
|
**Applications, documents and the brief persist** to a SQLite file
|
|
(`src/BigRegister.Api/bigregister.db`, EF Core-backed — `Data/AppDbContext.cs`,
|
|
`Data/Db.cs`) created and migrated on first run; restarting the process (or
|
|
`docker compose restart api` — the existing `./backend:/src` bind mount already
|
|
covers it, see `docker-compose.yml`) does **not** lose data. Delete the file to
|
|
reset demo data back to empty, the same state a fresh clone starts from. This is
|
|
a deliberate, right-sized choice for a POC (SQLite, no external DB service) — see
|
|
`docs/project/backlog/WP-22-durable-persistence.md`.
|
|
|
|
## Run
|
|
|
|
### Everything (docker-compose, from repo root)
|
|
|
|
```bash
|
|
docker compose up
|
|
```
|
|
|
|
- App: <http://localhost:4200>
|
|
- Swagger UI: <http://localhost:5000/swagger>
|
|
|
|
### Backend only (local)
|
|
|
|
```bash
|
|
cd backend
|
|
dotnet run --project src/BigRegister.Api
|
|
# → http://localhost:5000/swagger
|
|
```
|
|
|
|
### Frontend against a local backend
|
|
|
|
```bash
|
|
npm start # ng serve, proxies /api → http://localhost:5000 (proxy.conf.json)
|
|
```
|
|
|
|
### Tests
|
|
|
|
```bash
|
|
cd backend && dotnet test # rule unit tests + endpoint integration tests
|
|
```
|
|
|
|
## API
|
|
|
|
| Method | Route | Purpose |
|
|
|---|---|---|
|
|
| GET | `/api/dashboard-view` | registration + person + computed herregistratie decision |
|
|
| GET | `/api/notes` | specialisms / aantekeningen |
|
|
| GET | `/api/brp/address` | BRP address lookup (`gevonden:false` = no address) |
|
|
| GET | `/api/duo/diplomas` | diplomas with derived profession + applicable policy questions, + manual fallback |
|
|
| GET | `/api/intake/policy` | scholing threshold (config value) |
|
|
| POST | `/api/registrations` | submit registration → reference, or 422 (manual diploma) |
|
|
|
|
Rejections use **ProblemDetails (RFC 7807)** with status **422**. Every request
|
|
carries an `X-Correlation-Id` (set by the FE fetch adapter); the backend echoes it
|
|
into a no-PII submit-audit log line (`kind`, `outcome`, `reference`, correlation id)
|
|
— the seam for real structured logging / an audit store.
|
|
|
|
### Versioning
|
|
|
|
Endpoints live under **`/api/v1`**. Additive changes (a new optional field) stay on
|
|
v1: the NSwag-generated client and the FE `parse*` boundary ignore unknown fields,
|
|
so old clients keep working. A breaking change (renamed/removed field, changed
|
|
semantics) is introduced as **`/api/v2`** served alongside v1 until clients migrate.
|
|
|
|
## Where the rules live (`src/BigRegister.Api/Domain/`)
|
|
|
|
- `Diplomas/DiplomaRules.cs` — profession derivation + which policy questions apply.
|
|
- `Registrations/HerregistratieRule.cs` — eligibility + reason + status invariant.
|
|
- `Intake/IntakePolicy.cs` — scholing threshold + completeness re-validation on submit
|
|
(`RejectIncompleteScholing`).
|
|
- `Submissions/SubmissionRules.cs` — submit rejections + reference generation.
|
|
|
|
## Typed client (NSwag)
|
|
|
|
The frontend calls this API through a generated TypeScript client. Regenerate it
|
|
from the contract after a **shape** change:
|
|
|
|
```bash
|
|
npm run gen:api # builds backend → swagger.json → src/app/shared/infrastructure/api-client.ts
|
|
```
|
|
|
|
## Maintainability: changing a policy is one backend change
|
|
|
|
**Goal:** require every *Verpleegkundige* diploma to confirm a Dutch skills
|
|
assessment. This is a new policy question on a diploma type.
|
|
|
|
Edit **one file** — `Domain/Diplomas/DiplomaRules.cs`:
|
|
|
|
```diff
|
|
public static IReadOnlyList<PolicyQuestion> QuestionsFor(Diploma d)
|
|
{
|
|
var questions = new List<PolicyQuestion>();
|
|
if (d.Engelstalig)
|
|
questions.Add(NlTaalEngelstalig);
|
|
+ if (d.Opleiding == "verpleegkunde")
|
|
+ questions.Add(new PolicyQuestion(
|
|
+ "bekwaamheid",
|
|
+ "Heeft u in de afgelopen vijf jaar een bekwaamheidstoets afgelegd?",
|
|
+ QuestionType.JaNee));
|
|
return questions;
|
|
}
|
|
```
|
|
|
|
Rebuild the backend (`docker compose up` or `dotnet run`). The new question now
|
|
appears in the registration wizard for HBO-Verpleegkunde.
|
|
|
|
- **No frontend change.** The FE renders whatever questions the API returns.
|
|
- **No client regeneration.** The wire shape (`PolicyQuestionDto`) is unchanged —
|
|
only the data behind it. `npm run gen:api` is only needed when a DTO *shape* changes.
|
|
|
|
Add a unit test for the new rule in `tests/BigRegister.Tests/RuleTests.cs` and
|
|
you're done.
|