# RB-06 — delete the dead `POST /registrations` Status: **implemented** · 2026-08-27 · Source findings: `07-bio2-compliance.md` BIO-010 · `99-backlog.md` RB-06 ## What was wrong `POST /registrations` took a `Documents` list and passed it straight to `Submit`, which calls `DocumentStore.Link(...)` on every digital `documentId` in it. Linking a document **blocks its owner from deleting it** (`DeleteOwned` → 409 `Linked`). There was no `ForeignIds` ownership check on that path. The real submit endpoint, `POST /applications/{id}/submit`, has had one since it was written: ```csharp if (documentIds is { Count: > 0 } && DocumentStore.ForeignIds(documentIds, ctx.Zorgverlener().Bsn) is { Count: > 0 } foreignIds) return Results.Problem(detail: $"Onbekend of niet-eigen document(en): …", statusCode: 400); ``` So any authenticated citizen could post another citizen's document id and permanently block them from deleting their own diploma scan. ## Deleted rather than guarded The ticket allowed either. Deleted, because the endpoint is dead: no frontend caller (the generated client's `registrations` method was unreferenced), and the whole registratie flow goes through `POST /applications/{id}/submit`. | File | Change | | -------------------------------------------- | ------------------------------------------------- | | `Program.cs` | endpoint deleted | | `Contracts/Dtos.cs` | `RegistratieRequest` deleted (no other reference) | | `Domain/Submissions/SubmissionRules.cs` | `RejectRegistratie` deleted — see below | | `backend/swagger.json`, `api-client.ts` | regenerated (`npm run gen:api`) | | `EndpointTests.cs`, `SubmissionRuleTests.cs` | retargeted, see below | ### Why `RejectRegistratie` went with it It was reachable only from this endpoint, and the live path deliberately **contradicts** it. `RejectRegistratie("handmatig")` returned a 422 rejection; the modern submit does ```csharp "registratie" => (null, req.DiplomaHerkomst == "duo"), ``` — a manual diploma is not rejected, it simply does not auto-approve and goes to a behandelaar. Its own message even said so ("doorgestuurd voor handmatige beoordeling") while being returned as a rejection. Leaving it behind would have left an obsolete rule with a passing spec, which is exactly how it gets reintroduced. **This is the one judgement call in this ticket** — the backlog row says "delete the dead endpoint", not "delete the rule". Reverting just the `SubmissionRules`/`SubmissionRuleTests` hunks restores it without touching anything else. ### Test coverage that moved rather than vanished - `Registration_with_manual_diploma_is_rejected_with_problem_details` was the only test asserting the `Submit` helper's `application/problem+json` rejection shape. That assertion moved into `Change_request_with_bad_phone_is_rejected_with_problem_details` — `/change-requests` is the other endpoint on the same helper. - `User_delete_blocked_with_409_once_linked_to_submission` covered `DocumentStore.Link` blocking a delete. Retargeted to `POST /applications/{id}/submit`, i.e. the path that is actually in use. `POST /registrations` was the only other caller of `Link`. - `Registration_with_duo_diploma_succeeds` was deleted outright — `Change_request_with_valid_phone_succeeds` is the same assertion on the same helper. ## Verification `npm run ci`. `dotnet test`: **249 passed, 1 failed** — the pre-existing `OpenZaakIntegrationTests.Admin_cases_…`, which needs a live container.