docs: archive the finished backlogs (RD-30)
Two backlog trees are complete: `docs/project/backlog/` (75 files, every WP done) and `docs/project/refactor-backlog-setup/` (the arc before it). Move both under `docs/project/archive/` with `git mv`, so history stays intact through `git log --follow`. `SHOWCASE-ROADMAP.md` moves with them, because it points at the now-archived backlog README. Add `docs/project/archive/README.md`. It states that these trees are historical and names the two directories that are still live. Repoint every inbound reference named in RD-30's Files table: CLAUDE.md, the root README, both backend READMEs, `LetterHtml.cs`, `a11y.mdx`, the `document-feature` and `new-ssp` skills, and the readable-codebase PLAN, README, and RD-19 ticket. Fix two upward-relative links inside the moved WP files (WP-68, WP-69) that gained a directory level and would otherwise break. Repoint `.prettierignore`'s two agent-prompt exclusions to their new path, so prettier keeps leaving those files' exact wording alone. Mark RD-30 done and check off its acceptance criteria; flip its README row to done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# RB-16 — `DateOnly.TryParse` on `?peildatum=`
|
||||
|
||||
Status: **implemented** · 2026-08-27 · Source findings: `07-bio2-compliance.md` BIO-019 · `99-backlog.md` RB-16
|
||||
|
||||
## What was wrong
|
||||
|
||||
`Program.cs:215` (pre-change) —
|
||||
`var rows = peildatum is { Length: > 0 } p ? t.RowsOn(DateOnly.Parse(p)) : t.Rows();`.
|
||||
`DateOnly.Parse` throws `FormatException` on anything unparseable; there was no
|
||||
`TryParse`, no 400 path, and `.Produces` on the endpoint declared only 200/403/404 — so
|
||||
an unparseable `?peildatum=` value 500'd, and in Development the exception detail was
|
||||
returned to the caller. §3c's baseline named `backend/Stamdata` 96.8% line but **71.7%
|
||||
branch** (BL-005) — this was one of the unentered branches.
|
||||
|
||||
## What changed
|
||||
|
||||
| File | Change |
|
||||
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Program.cs` — `GET /stamdata/{table}` | `DateOnly.Parse` replaced with `DateOnly.TryParse`; an unparseable value now returns `Results.Problem(detail: …, statusCode: 400)` instead of throwing; endpoint doc gained `.ProducesProblem(StatusCodes.Status400BadRequest)` |
|
||||
| `tests/BigRegister.Tests/StamdataEndpointTests.cs` | **new** `Unparseable_peildatum_is_400_not_500` |
|
||||
| `backend/swagger.json`, `libs/shared/src/infrastructure/api-client.ts` | regenerated (`npm run gen:api`) — the new 400 response is now part of the documented contract |
|
||||
|
||||
## What the fix looks like
|
||||
|
||||
```csharp
|
||||
DateOnly? peildatumWaarde = null;
|
||||
if (peildatum is { Length: > 0 } p)
|
||||
{
|
||||
if (!DateOnly.TryParse(p, out var parsed))
|
||||
return Results.Problem(detail: $"Ongeldige peildatum '{p}'.", statusCode: StatusCodes.Status400BadRequest);
|
||||
peildatumWaarde = parsed;
|
||||
}
|
||||
var rows = peildatumWaarde is { } d ? t.RowsOn(d) : t.Rows();
|
||||
```
|
||||
|
||||
Matches the shape every other bad-input check in this file already uses (e.g. the
|
||||
upload endpoint's `Results.Problem(detail: …, statusCode: 400)` for a malformed
|
||||
multipart request) — a `Results.Problem` with a Dutch detail message, not a bespoke
|
||||
response shape.
|
||||
|
||||
## Judgement calls
|
||||
|
||||
- **No FE change needed, and none made.** `libs/beheer/src/infrastructure/
|
||||
stamdata.adapter.ts`'s `load()` already routes every call through `runSubmit`
|
||||
(`libs/shared/src/application/submit.ts`), which try/catches any thrown
|
||||
`ApiException` — including the client's new 400 branch — into a generic `Result`
|
||||
error string via `problemDetail`. There is no status-code-specific branching to
|
||||
extend; ADR-0001's "the FE renders the decision, it does not recompute the rule"
|
||||
already covers "the server rejected this input" as a case the generic error path
|
||||
handles, same as the existing 403.
|
||||
- **Regenerated the API client and committed it in this ticket's diff**, rather than
|
||||
leaving it to drift. RB-09's implementation note records a real prior incident where
|
||||
a response-shape change (RB-08's 403 → `ProducesProblem`) landed without a
|
||||
regeneration and the drift went unnoticed until the next ticket's `gen:api` run. This
|
||||
ticket's `.ProducesProblem(400)` is exactly that same category of change, so
|
||||
`npm run gen:api` was run immediately as part of implementing it, not deferred.
|
||||
- **The Dutch detail message follows the file's own convention** (`$"Ongeldige
|
||||
peildatum '{p}'."`) rather than English — every other `Results.Problem(detail: …)`
|
||||
call in `Program.cs` (change-request rejection, upload validation, submit rejection)
|
||||
is Dutch; this is server-internal wire text, not `$localize`-wrapped UI copy (the FE
|
||||
never renders it verbatim — CLAUDE.md's `$localize` rule is about user-facing copy
|
||||
the FE owns, not backend `ProblemDetails.detail` strings), so no locale entry was
|
||||
needed.
|
||||
|
||||
## Verification
|
||||
|
||||
- **Reverted the fix only** (`DateOnly.Parse` restored, ternary un-nested, via Edit —
|
||||
test left in place) and ran `StamdataEndpointTests`:
|
||||
`Unparseable_peildatum_is_400_not_500` failed red (`Expected: BadRequest, Actual:
|
||||
InternalServerError` — confirming the endpoint really did 500, not some other status).
|
||||
Restored the fix (via Edit) and re-ran: all 6 tests in the class green.
|
||||
- `dotnet build`: clean, 0 warnings.
|
||||
- `dotnet format BigRegister.slnx --verify-no-changes`: clean.
|
||||
- `dotnet test --filter "Category!=Integration"`: **260 passed, 0 failed** (259 + 1
|
||||
new).
|
||||
- `npm run gen:api`: exit 0; `backend/swagger.json` gained the 400 response shape for
|
||||
this one endpoint; `libs/shared/src/infrastructure/api-client.ts` gained the
|
||||
matching `status === 400` branch. Both regenerated files committed alongside the
|
||||
code change.
|
||||
- `npm test` (all four Vitest projects — ssp/behandelportal/shared/beheer): **445
|
||||
passed, 0 failed**, confirming the regenerated client doesn't break any existing FE
|
||||
consumer of `stamdataTable(...)`.
|
||||
Reference in New Issue
Block a user