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:
@@ -2,11 +2,16 @@ namespace EventSubscriber.Application;
|
||||
|
||||
/// <summary>
|
||||
/// An inbound NRC (Open Notificaties) notification, as Open Notificaties POSTs it to an
|
||||
/// abonnement callback. Only the fields the projection needs are modelled; the full ZGW
|
||||
/// "Notificatie" resource also carries <c>aanmaakdatum</c> and <c>kenmerken</c> which the
|
||||
/// minimal projection ignores (bsn is deferred — see ADR-0008). For a <c>zaken</c>/<c>zaak</c>/<c>create</c>
|
||||
/// notification <c>hoofdObject</c> and <c>resourceUrl</c> are both the created zaak's URL.
|
||||
/// abonnement callback. Only the fields the projection needs are modelled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Since S-19b-2 the subscriber listens on the <c>objecten</c> kanaal, not <c>zaken</c>: the
|
||||
/// register record in Objecten is what the projection is derived from (ADR-0030), so the
|
||||
/// projection is a cache of the register rather than a re-derivation of the case system. An
|
||||
/// Objecten notification carries <b>no record data</b> — only the object URL (as both
|
||||
/// <c>hoofdObject</c> and <c>resourceUrl</c>) and the objecttype as a kenmerk — so the record
|
||||
/// itself is read back through the ACL.
|
||||
/// </remarks>
|
||||
public sealed record Notification(
|
||||
string Kanaal,
|
||||
string Resource,
|
||||
@@ -14,28 +19,12 @@ public sealed record Notification(
|
||||
Uri ResourceUrl,
|
||||
Uri? HoofdObject = null)
|
||||
{
|
||||
/// <summary>A zaak being created — projected as INGEDIEND.</summary>
|
||||
public bool IsZaakCreated =>
|
||||
Kanaal == "zaken" && Resource == "zaak" && Actie == "create";
|
||||
/// <summary>A register record written to Objecten — <c>create</c> on submit, <c>update</c> on
|
||||
/// approval, since the ACL upserts the same object for a registration (§8.6).</summary>
|
||||
public bool IsRegisterRecordWritten =>
|
||||
Kanaal == "objecten" && Resource == "object" && Actie is "create" or "update";
|
||||
|
||||
/// <summary>A status being set on a zaak — the approval, projected as INGESCHREVEN (S-09b). In the
|
||||
/// walking skeleton the only status ever set after creation is the approval, and the subscriber may
|
||||
/// not read OpenZaak (§8.1), so any status-create is taken as the approval.</summary>
|
||||
public bool IsZaakStatusSet =>
|
||||
Kanaal == "zaken" && Resource == "status" && Actie == "create";
|
||||
|
||||
/// <summary>The zaak URL this notification concerns — <c>hoofdObject</c> (the zaak) for a status
|
||||
/// notification, else the resource URL (which, for a zaak-create, is the zaak).</summary>
|
||||
public Uri ZaakUrl => HoofdObject ?? ResourceUrl;
|
||||
|
||||
/// <summary>The zaak UUID used as the projection key — the trailing segment of <see cref="ZaakUrl"/>.</summary>
|
||||
public string ZaakId => ZaakUrl.Segments[^1].Trim('/');
|
||||
|
||||
/// <summary>
|
||||
/// A deterministic dedup key. Open Notificaties carries no notification id and may
|
||||
/// redeliver, so the key is derived from the immutable notification content: two
|
||||
/// deliveries of the same zaak-create collapse to one. (NRC may also deliver
|
||||
/// out of order; the projector tolerates that — order does not change the outcome.)
|
||||
/// </summary>
|
||||
public string IdempotencyKey => $"{Kanaal}:{Resource}:{Actie}:{ResourceUrl}";
|
||||
/// <summary>The object holding the register record. Objecten sets both fields to the object;
|
||||
/// <c>hoofdObject</c> is the main resource by definition, so prefer it.</summary>
|
||||
public Uri ObjectUrl => HoofdObject ?? ResourceUrl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user