feat(openzaak): per-document-type confidentialiteit config (WP-59)

Drives the DRC upload's vertrouwelijkheidaanduiding from a new stamdata
table instead of the hardcoded "openbaar", following the existing
config-as-code pattern (ADR-0004). Adds the referential-integrity check
StamdataValidationTests was missing for the new table.
This commit is contained in:
eho
2026-07-30 17:30:25 +02:00
parent 3e983bd2cc
commit 67abc58052
8 changed files with 91 additions and 14 deletions
@@ -0,0 +1,12 @@
namespace BigRegister.Stamdata;
/// <summary>
/// One row of the document-confidentialiteit stamdata (config-as-code, ADR-0004): the ZGW
/// <c>vertrouwelijkheidaanduiding</c> to register a DRC document with, per upload category
/// (<see cref="BigRegister.Domain.Documents.DocumentCategory.CategoryId"/>). The first
/// property (<see cref="CategoryId"/>) is the table key by convention (see
/// <c>StamdataTable</c>). Non-temporal — a category's sensitivity doesn't change over time.
/// A category absent from this table falls back to <c>"openbaar"</c> (see
/// <c>OpenZaakDocumentSource</c>) rather than failing the upload.
/// </summary>
public sealed record DocumentConfidentialiteit(string CategoryId, string Vertrouwelijkheidaanduiding);
@@ -14,6 +14,7 @@ public static class StamdataCatalog
StamdataTable.Of<Beroep>("beroepen", "Beroepen (BIG)"),
StamdataTable.Of<Opleiding>("opleidingen", "Opleidingen → beroep"),
StamdataTable.Of<Specialisme>("specialismen", "Specialismen → beroep"),
StamdataTable.Of<DocumentConfidentialiteit>("documentconfidentialiteit", "Documenttype → vertrouwelijkheidaanduiding"),
// PolicyQuestions and future tables migrate here, same one-liner each.
};
@@ -0,0 +1,7 @@
[
{ "categoryId": "identiteit", "vertrouwelijkheidaanduiding": "vertrouwelijk" },
{ "categoryId": "diploma", "vertrouwelijkheidaanduiding": "openbaar" },
{ "categoryId": "taalvaardigheid", "vertrouwelijkheidaanduiding": "openbaar" },
{ "categoryId": "werkervaring", "vertrouwelijkheidaanduiding": "openbaar" },
{ "categoryId": "nascholing", "vertrouwelijkheidaanduiding": "openbaar" }
]
@@ -3,6 +3,7 @@ using System.Text.Json.Serialization;
using BigRegister.Api.Contracts;
using BigRegister.Api.Data;
using BigRegister.Domain.Authorization;
using BigRegister.Stamdata;
namespace BigRegister.Api.Zgw;
@@ -23,6 +24,15 @@ public sealed class OpenZaakDocumentSource(HttpClient http, ZgwTokenProvider tok
{
private readonly ZgwHttpClient zgw = new(http, tokens);
// WP-59: per-document-type confidentiality (stamdata, ADR-0004) — "openbaar" if the
// category isn't in the table, so an unconfigured category never fails the upload.
private static readonly IReadOnlyDictionary<string, string> ConfidentialiteitByCategory =
StamdataFile.Load<DocumentConfidentialiteit>("documentconfidentialiteit")
.ToDictionary(r => r.CategoryId, r => r.Vertrouwelijkheidaanduiding);
private static string ConfidentialiteitFor(string categoryId) =>
ConfidentialiteitByCategory.GetValueOrDefault(categoryId, "openbaar");
// ponytail: sync-over-async — IDocumentSource is sync to match the local store + the
// existing sync upload/submit endpoints, same reasoning as OpenZaakZaakSource.
public UploadResponse Upload(
@@ -52,10 +62,7 @@ public sealed class OpenZaakDocumentSource(HttpClient http, ZgwTokenProvider tok
Inhoud: Convert.ToBase64String(content),
Informatieobjecttype: informatieobjecttypeUrl,
Identificatie: doc.DocumentId,
// ponytail: hardcoded "openbaar" (public) — real usage would likely vary the
// confidentiality level per category (e.g. an identity document is more sensitive
// than a diploma); a fixed value is enough to prove the seam end-to-end.
Vertrouwelijkheidaanduiding: "openbaar"), caller);
Vertrouwelijkheidaanduiding: ConfidentialiteitFor(categoryId)), caller);
DocumentStore.SetDrcUrl(doc.DocumentId, eio.Url);
return new UploadResponse(doc.DocumentId, doc.LocalId);