using EventSubscriber.Application; using Projection.ReadModel; var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("Projection") ?? throw new InvalidOperationException("Missing connection string 'ConnectionStrings:Projection'"); // The exact Authorization header value Open Notificaties sends on each abonnement callback. // NRC probes the callback during registration and refuses it unless it returns 401 without // this value (ADR-0007), so the webhook enforces it. var webhookToken = builder.Configuration["EventSubscriber:Webhook:AuthToken"] ?? throw new InvalidOperationException("Missing configuration 'EventSubscriber:Webhook:AuthToken'"); builder.Services.AddProjectionReadModel(connectionString); builder.Services.AddProjectionWriteSide(); var app = builder.Build(); // Apply migrations on start so a fresh stack reaches a usable schema unattended. await app.Services.MigrateProjectionAsync(); app.MapGet("/health", () => "Healthy"); // The NRC abonnement callback. Open Notificaties POSTs a notification here; we project it. // Auth-on-callback is mandatory: without the configured Authorization, return 401 (NRC's // registration probe depends on this — ADR-0007). app.MapPost("/notifications", async ( HttpRequest request, NotificationDto body, NotificationProjector projector, CancellationToken ct) => { if (request.Headers.Authorization != webhookToken) return Results.Unauthorized(); await projector.HandleAsync(body.ToNotification(), ct); return Results.NoContent(); }); // Admin: rebuild the projection from the durable notification log (PRD §8.4 — rebuildable). app.MapPost("/admin/rebuild", async (NotificationProjector projector, CancellationToken ct) => { await projector.RebuildAsync(ct); return Results.NoContent(); }); await app.RunAsync(); /// The NRC notification body, as Open Notificaties POSTs it. Only the fields the /// projection needs are bound; aanmaakdatum/kenmerken are ignored for the minimal slice. public sealed record NotificationDto(string Kanaal, string Resource, string Actie, Uri ResourceUrl) { public Notification ToNotification() => new(Kanaal, Resource, Actie, ResourceUrl); } public partial class Program;