feat(domain): withdraw a registration → INGETROKKEN via POST /registrations/{id}/withdraw (refs #12)
All checks were successful
CI / lint (pull_request) Successful in 1m13s
CI / build (pull_request) Successful in 57s
CI / unit (pull_request) Successful in 1m10s
CI / frontend (pull_request) Successful in 2m33s
CI / mutation (pull_request) Successful in 5m16s
CI / verify-stack (pull_request) Successful in 7m25s

Add the Ingetrokken terminal status, Registration.Withdraw() (open-only, idempotent), the

WithdrawRegistration handler, and the domain endpoint. Cancelling the running Flowable process

(so the case leaves the werkbak) and the owner-scoped BFF/self-service action are follow-up

sub-slices (S-11b/S-11c).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-16 10:53:31 +02:00
parent 98abba8b22
commit d966a198fb
4 changed files with 68 additions and 2 deletions

View File

@@ -0,0 +1,32 @@
using Big.Domain;
namespace Big.Application;
/// <summary>A zorgprofessional's request to withdraw their own registration ("trek aanvraag in").</summary>
public sealed record WithdrawRegistrationCommand(RegistrationId RegistrationId);
/// <summary>
/// The withdrawal use case (S-11): a zorgprofessional pulls a still-open registration back. It
/// advances the aggregate to INGETROKKEN and persists it. Idempotent — a repeated or redelivered
/// withdrawal of an already-withdrawn registration is a no-op (the aggregate is not persisted again).
/// Cancelling the running Flowable process (so the case leaves the behandelaar's werkbak) is a later
/// sub-slice (S-11b, via a BPMN message event); this sub-slice owns the domain transition only —
/// mirroring how the beoordeling's rejection deferred its zaak propagation.
/// </summary>
public sealed class WithdrawRegistration(IRegistrationStore store)
{
public async Task HandleAsync(WithdrawRegistrationCommand command, CancellationToken ct = default)
{
ArgumentNullException.ThrowIfNull(command);
var registration = await store.GetAsync(command.RegistrationId, ct)
?? throw new InvalidOperationException($"No registration {command.RegistrationId} to withdraw.");
// A repeated withdrawal is a no-op: don't persist the already-withdrawn aggregate again.
if (registration.Status == RegistrationStatus.Ingetrokken)
return;
registration.Withdraw();
await store.SaveAsync(registration, ct);
}
}