Mijn aanvragen (A): backend Aanvraag store + lifecycle endpoints

Adds the backend-owned Aanvraag aggregate (PRD 0001, phase A) — the system of
record the dashboard will read. In-memory static store mirroring DocumentStore.

- ApplicationStore: create/get/list/draft-sync/cancel/submit; status COMPUTED ON
  READ (Mappers.ToStatusDto(now)) so auto-approval is pure timestamp arithmetic,
  no timers/jobs (ProcessingWindow = 8s).
- Endpoints: GET /applications, GET/POST/PUT/DELETE /applications/{id},
  POST /applications/{id}/submit.
- Lifecycle: registratie duo -> auto (Goedgekeurd after window), handmatig ->
  manual pending (no 422); herregistratie/intake 0 uren -> Afgewezen else auto.
  Cancel blocks submitted aanvragen (409, no withdrawal in scope).
- Old /registrations endpoint + RejectRegistratie 422 left intact (retire in E).
- ApplicationTests: lifecycle + auto-approve window boundary (pure). 54/54 green.

Also checks in the PRD (docs/prd/0001).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-01 11:35:19 +02:00
co-authored by Claude Opus 4.8
parent a2cd7a0ac1
commit 8c3f4c22ee
6 changed files with 604 additions and 0 deletions
@@ -71,3 +71,39 @@ public sealed record HerregistratieRequest(int Uren, IReadOnlyList<DocumentRefDt
public sealed record ChangeRequestRequest(string Straat, string Postcode, string Woonplaats);
public sealed record ReferentieResponse(string Referentie);
// --- Applications (aanvragen): the system of record for the dashboard. ---
// Status is a discriminated union by Tag (Concept | InBehandeling | Goedgekeurd |
// Afgewezen); only the fields relevant to a tag are populated. Mirrors the FE union.
public sealed record AanvraagStatusDto(
string Tag,
int? StepIndex = null,
int? StepCount = null,
string? Referentie = null,
bool? Manual = null,
string? Reden = null);
public sealed record ApplicationSummaryDto(
string Id, string Type, AanvraagStatusDto Status,
IReadOnlyList<string> DocumentIds,
string CreatedAt, string UpdatedAt, string? SubmittedAt);
public sealed record ApplicationDetailDto(
string Id, string Type, AanvraagStatusDto Status,
System.Text.Json.JsonElement? Draft,
IReadOnlyList<string> DocumentIds,
string CreatedAt, string UpdatedAt, string? SubmittedAt);
public sealed record CreateApplicationRequest(string Type);
public sealed record DraftSyncRequest(
System.Text.Json.JsonElement Draft, int StepIndex, int StepCount,
IReadOnlyList<string>? DocumentIds = null);
// Submit carries only the fields the server re-validates per wizard type.
public sealed record SubmitApplicationRequest(
string? DiplomaHerkomst = null, int? Uren = null,
IReadOnlyList<DocumentRefDto>? Documents = null);
public sealed record SubmitApplicationResponse(string Referentie, AanvraagStatusDto Status);