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 Objecten or ZGW (CLAUDE.md §8.1). Implemented in Infrastructure over Postgres.
///
public interface INotificationLog
{
///
/// Record a notification. Returns true if it was newly recorded, false if an
/// entry with the same key already existed (a duplicate delivery). Must be atomic so that
/// concurrent duplicate deliveries cannot both observe true.
///
Task TryRecordAsync(RecordedNotification notification, CancellationToken ct = default);
/// Every accepted notification, for rebuilding the projection.
Task> AllAsync(CancellationToken ct = default);
}
///
/// 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).
///
public sealed record RecordedNotification(string Key, string RegisterId, string Status, string? Reference);
///
/// 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.
///
public interface IAclClient
{
/// The register record the object at holds, or
/// null if it holds none — the object may be gone by the time a redelivered
/// notification is handled, which is not an error (§8.6).
Task GetRegisterRecordAsync(Uri objectUrl, CancellationToken ct = default);
}
/// 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.
public sealed record RegisterRecord(string Id, string Status, string? Reference);
/// The read projection store. Owned by the projection bounded context (ADR-0008); the
/// subscriber writes to it and the projection-api reads it.
public interface IProjectionStore
{
/// Insert or update the row for . Idempotent on the id.
Task UpsertAsync(RegisterEntry entry, CancellationToken ct = default);
/// Remove every row — the first step of a rebuild.
Task ClearAsync(CancellationToken ct = default);
/// Every projection row (used by tests and the rebuild verification).
Task> AllAsync(CancellationToken ct = default);
}