Files
register-referentie/services/projection-api/Projection.ReadModel/EfNotificationLog.cs
Niek Otten 566fc9bcea feat(event-subscriber): enrich the projection with the zaak reference via the ACL (refs #78)
On each notification the subscriber reads the zaak's reference (identificatie)
through the ACL — the only code allowed to talk to ZGW (§8.1) — and persists it on
the register_projection row and in the processed_notifications replay log. Storing
it in the log keeps rebuild log-only (ADR-0008): no ACL/ZGW access on rebuild.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:46:48 +02:00

42 lines
1.5 KiB
C#

using EventSubscriber.Application;
using Microsoft.EntityFrameworkCore;
namespace Projection.ReadModel;
/// <summary>EF Core implementation of the notification log. Idempotency is enforced atomically
/// by the primary key on <c>key</c>: a duplicate insert raises a unique violation, which is
/// caught and reported as "already recorded" rather than failing the request.</summary>
public sealed class EfNotificationLog(ProjectionDbContext db) : INotificationLog
{
public async Task<bool> TryRecordAsync(RecordedNotification notification, CancellationToken ct = default)
{
db.ProcessedNotifications.Add(new ProcessedNotificationRow
{
Key = notification.Key,
Actie = notification.Actie,
ZaakId = notification.ZaakId,
Resource = notification.Resource,
Reference = notification.Reference,
ReceivedAt = DateTimeOffset.UtcNow,
});
try
{
await db.SaveChangesAsync(ct);
return true;
}
catch (DbUpdateException)
{
// Already recorded by an earlier (or concurrent) delivery — drop this duplicate.
db.ChangeTracker.Clear();
return false;
}
}
public async Task<IReadOnlyList<RecordedNotification>> AllAsync(CancellationToken ct = default)
=> await db.ProcessedNotifications
.OrderBy(r => r.ReceivedAt)
.Select(r => new RecordedNotification(r.Key, r.Actie, r.ZaakId, r.Resource, r.Reference))
.ToListAsync(ct);
}