test(event-subscriber): the projection is sourced from register records (refs #153)
Ports, schema and failing tests for the subscriber half of S-19b-2, ahead of the implementation. The subscriber now listens on the `objecten` kanaal instead of `zaken`. An Objecten notification carries no record data — only the object URL — so the record is read back through the ACL (§8.1), and the zaak-shaped surface goes away: IsZaakCreated / IsZaakStatusSet / ZaakUrl / ZaakId and ToEntry's `Resource == "status"` mapping are replaced by IsRegisterRecordWritten + ObjectUrl. The notification log now holds the projected row itself (register id, status, reference), so a rebuild is a replay with no mapping rules and no upstream reads. The migration drops the old columns rather than renaming them — EF scaffolded renames that would have carried ZGW values into columns meaning something else — and empties both tables, since a pre-slice row is neither reprojectable nor re-derivable from the new source. Red: HandleAsync recognises a register write but does not yet read or project it, so the seven projection assertions fail on an empty store.
This commit is contained in:
@@ -4,7 +4,7 @@ namespace EventSubscriber.Application;
|
||||
/// The durable log of notifications the subscriber has accepted. It is both the idempotency
|
||||
/// guard (a replayed notification is recognised and dropped) and the rebuild source: the
|
||||
/// projection is a derived artefact (PRD §8.4) regenerated by replaying this log, so a rebuild
|
||||
/// needs no access to OpenZaak (CLAUDE.md §8.1). Implemented in Infrastructure over Postgres.
|
||||
/// needs no access to Objecten or ZGW (CLAUDE.md §8.1). Implemented in Infrastructure over Postgres.
|
||||
/// </summary>
|
||||
public interface INotificationLog
|
||||
{
|
||||
@@ -19,22 +19,29 @@ public interface INotificationLog
|
||||
Task<IReadOnlyList<RecordedNotification>> AllAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>A notification that has been accepted, retaining what a rebuild needs to recompute its
|
||||
/// projection row — the ZGW <c>resource</c> (zaak-create → INGEDIEND vs status-set → INGESCHREVEN) and
|
||||
/// the zaak <c>reference</c> (identificatie), so a rebuild reproduces the row without re-reading ZGW (#78).</summary>
|
||||
public sealed record RecordedNotification(string Key, string Actie, string ZaakId, string Resource, string? Reference);
|
||||
/// <summary>
|
||||
/// An accepted notification, retaining exactly the projection row it produced — so a rebuild
|
||||
/// reproduces the row by replaying the log, without re-reading Objecten (S-19b-2, ADR-0030).
|
||||
/// </summary>
|
||||
public sealed record RecordedNotification(string Key, string RegisterId, string Status, string? Reference);
|
||||
|
||||
/// <summary>
|
||||
/// Port to the Anti-Corruption Layer. The subscriber enriches the projection with the zaak's
|
||||
/// public-safe reference (its identificatie) by asking the ACL — the only code that may read ZGW
|
||||
/// (§8.1) — rather than reading OpenZaak itself (adr-proposal #78).
|
||||
/// Port to the Anti-Corruption Layer. An Objecten notification carries only the object URL, so the
|
||||
/// subscriber reads the register record back through the ACL — the only code that may talk to
|
||||
/// Objecten (§8.1, ADR-0028) — rather than reading Objecten itself.
|
||||
/// </summary>
|
||||
public interface IAclClient
|
||||
{
|
||||
/// <summary>The zaak's reference (identificatie) for the read projection.</summary>
|
||||
Task<string> GetZaakReferenceAsync(Uri zaakUrl, CancellationToken ct = default);
|
||||
/// <summary>The register record the object at <paramref name="objectUrl"/> holds, or
|
||||
/// <c>null</c> if it holds none — the object may be gone by the time a redelivered
|
||||
/// notification is handled, which is not an error (§8.6).</summary>
|
||||
Task<RegisterRecord?> GetRegisterRecordAsync(Uri objectUrl, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>The public-safe register record as the ACL returns it — the RegisterRecord objecttype's
|
||||
/// schema (ADR-0027). No bsn, no name: the register is world-readable.</summary>
|
||||
public sealed record RegisterRecord(string Id, string Status, string? Reference);
|
||||
|
||||
/// <summary>The read projection store. Owned by the projection bounded context (ADR-0008); the
|
||||
/// subscriber writes to it and the projection-api reads it.</summary>
|
||||
public interface IProjectionStore
|
||||
|
||||
Reference in New Issue
Block a user