namespace Acl.Application; /// The ACL's single operation: open a zaak from a domain payload, /// default-filling the ZGW-mandatory fields (ADR-0003). public sealed class AclService( IZaakGateway gateway, IRegisterRecordGateway register, IDefaultFillStore fill, IZaaktypeCatalog catalog, IClock clock) { public async Task OpenZaakAsync(DomainRegistration registration, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(registration); // Read the current default-fill per zaak (not at construction), so a beheerder edit (S-15b) // takes effect on the next zaak without a restart. var defaults = fill.Current; var request = new ZaakRequest( defaults.Bronorganisatie, defaults.VerantwoordelijkeOrganisatie, defaults.Vertrouwelijkheidaanduiding, await catalog.GetZaaktypeUrlAsync(ct), clock.Today, registration.Reference); return await gateway.OpenZaakAsync(request, ct); } /// /// Approve a zaak: set it to the eindstatus of the BIG zaaktype (resolved by identificatie, S-27), /// then write the register record to Objecten (S-19a). The domain hands over only the zaak URL; the /// ACL owns which statustype means "approved" and what the register record looks like (§8.1). /// /// /// OpenZaak holds the process, Objecten holds the register (ADR-0028), so approval is two writes /// across two modules and is eventually consistent by construction. Both are idempotent — a status /// is a log entry, the record upsert is keyed on the zaak id — so a caller that retries a failed /// approval converges rather than duplicating. /// public async Task ApproveZaakAsync(Uri zaakUrl, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); await gateway.SetZaakToEindstatusAsync(zaakUrl, await catalog.GetZaaktypeUrlAsync(ct), clock.Today, ct); await register.UpsertAsync( new RegisterRecord( ZaakId(zaakUrl), RegisterRecordStatus.Ingeschreven, await gateway.GetZaakIdentificatieAsync(zaakUrl, ct)), ct); } /// The zaak's UUID — the key the register record and the read projection rows share. private static string ZaakId(Uri zaakUrl) => zaakUrl.Segments[^1].TrimEnd('/'); /// /// Cancel a zaak on document-timeout expiry (S-10c): set it to the BIG zaaktype's cancellation /// statustype + resultaat. The domain hands over only the zaak URL; the ACL owns which /// statustype/resultaat means "cancelled" (§8.1). /// public async Task CancelZaakAsync(Uri zaakUrl, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); await gateway.SetZaakToCancellationStatusAsync(zaakUrl, await catalog.GetZaaktypeUrlAsync(ct), clock.Today, ct); } /// The published zaaktypen, for the beheer catalogus viewer (S-15a). Read-only passthrough: /// no default-fill, the ACL is simply the only code allowed to read ZGW (§8.1). public Task> ListZaaktypenAsync(CancellationToken ct = default) => gateway.ListZaaktypenAsync(ct); /// The current default-fill settings, for the beheer config viewer (S-15b). public DefaultFillSettings GetDefaultFill() => fill.Current; /// Replace the default-fill settings from the beheer portal (S-15b). Takes effect on the /// next zaak (the fill is read per zaak, not cached). public void UpdateDefaultFill(DefaultFillSettings settings) { ArgumentNullException.ThrowIfNull(settings); fill.Update(settings); } /// The zaak's reference (its ZGW identificatie), for the read projection (#78). public Task GetZaakReferenceAsync(Uri zaakUrl, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); return gateway.GetZaakIdentificatieAsync(zaakUrl, ct); } /// /// Store an uploaded diploma against the zaak (S-10b): default-fill the ZGW-mandatory document /// fields (informatieobjecttype, bronorganisatie, vertrouwelijkheidaanduiding, taal, creatiedatum) /// and hand the file to the gateway, which creates the informatieobject and relates it to the zaak. /// The domain supplies only the zaak, the bytes, and the file's name/type (§8.1). /// public async Task StoreDiplomaAsync(Uri zaakUrl, byte[] content, string fileName, string contentType, CancellationToken ct = default) { ArgumentNullException.ThrowIfNull(zaakUrl); ArgumentNullException.ThrowIfNull(content); ArgumentException.ThrowIfNullOrWhiteSpace(fileName); ArgumentException.ThrowIfNullOrWhiteSpace(contentType); var defaults = fill.Current; var request = new DocumentRequest( defaults.Bronorganisatie, await catalog.GetInformatieobjecttypeUrlAsync(ct), defaults.Vertrouwelijkheidaanduiding, zaakUrl, clock.Today, Titel: "Diploma", Auteur: "zorgprofessional", Taal: "nld", Bestandsnaam: fileName, Formaat: contentType, Inhoud: content); return await gateway.StoreDocumentAsync(request, ct); } }