Skip to content

Notifications (Phase 5 foundation)

Phase 5 lands the foundational notification bus that the new WinUI 3 shell will plug into. The goal is to let background components announce state changes (“retention export finished”, “detector trip”, etc.) without depending on UI assemblies.

Responsibilities

  • Provide a lightweight, in-process publisher that anyone can inject via DI.
  • Keep payloads immutable so multiple subscribers (toast host, history pane, logging adapter) can react safely.
  • Remain dependency free; callers light up logging/config on their side.

Contracts and service

  • NotificationLevel – severity (Info, Success, Warning, Error) so the UI can map to color/severity treatments.
  • Notification – record with Title (required), optional Message, IconKey, and When timestamp (defaults to DateTimeOffset.UtcNow).
  • INotificationService – exposes a NotificationPublished event plus Publish to raise a notification.
  • NotificationService – default implementation that stores no state and fires the event synchronously on the calling thread.

Publishing flow

  1. Publisher constructs a Notification (localize titles before publishing and keep the message concise).
  2. Call Publish. The default implementation immediately raises NotificationPublished so subscribers get the payload while it is still on the stack.
  3. Subscribers (HubWindow view models, tray popups, history backlog, logging bridges) react by enqueueing messages, triggering a toast, or logging the action.
  4. When running headless (e.g., Supervisor), subscribe with a small adapter that logs or forwards the payload to telemetry so important events do not vanish.
var svc = new NotificationService();
svc.NotificationPublished += (_, n) => Console.WriteLine($"[{n.Level}] {n.Title}");
svc.Publish(new Notification(NotificationLevel.Info, "Saved", IconKey: "Icon.Completed.Glyph"));

Threading and reliability notes

  • Publishing is synchronous; fire-and-forget expensive UI work on a dispatcher to keep publishers responsive.
  • Event handlers must swallow/handle their own exceptions—throwing will bubble back to the publisher.
  • For background workflows, wrap Publish in retry/backoff when the downstream host might be momentarily unavailable.

Testing and DI guidance

  • Use a simple test double for INotificationService to assert what publishers emit without spinning up the UI shell.
  • The DI container should expose a single singleton instance so every view model gets the same event stream.
  • Unit-test subscribers to ensure severity-specific styling stays in sync with NotificationLevel values.

Future phases will bolt the WinUI 3 toast host, history center, and persistence on top of this contract. Do not introduce UI-specific dependencies here; keep the surface purely domain level so additional hosts (CLI, Supervisor) can continue consuming it.