Notifications Infrastructure
Architectural Context
The Notifications Subsystem inside
MILTON.DocumentGeneratorbridges the gap between the headless Document Processing Saga and the user interface. It is responsible for publishing document-level progress, completion, and error states.
Business Logic Intent
Because the MILTON.DocumentGenerator worker is a disconnected backend service processing intensive AI generation tasks over long periods, it cannot communicate with the React frontend directly via WebSockets. Instead, it relies on Wolverine messaging and RabbitMQ.
The primary intent of this infrastructure is to emit purely Document-level status updates. Fine-grained block or section-level notifications are intentionally left out; those are emitted by the API when it applies the generated block results to the database.
Architecture & Integration
The Document Generator implements an inverted dependency model for notifications:
IUserNotifierInterface: Exposes simple asynchronous methods:NotifyProgressAsync,NotifyCompletedAsync, andNotifyErrorAsync. This decouples the core Saga logic from the messaging transport.WolverineUserNotifier: The concrete implementation that translates interface calls into WolverineIMessageBus.PublishAsynccalls.- Message Identity Parity: The published messages (
NotifyProgressMessage,NotifyCompletedMessage,NotifyErrorMessage) are annotated with Wolverine[MessageIdentity]attributes (e.g.,notify-progress). TheMILTON.NotificationServicehas structurally identical records and consumes these messages to broadcast them over SignalR.
Mermaid Sequence Diagram
The following sequence illustrates how the Document Generator notifies the end user of its progress.
sequenceDiagram autonumber participant Saga as DocumentProcessingSaga participant Notifier as WolverineUserNotifier participant Bus as Wolverine IMessageBus participant Rabbit as RabbitMQ participant SignalR as MILTON.NotificationService Saga->>Notifier: NotifyProgressAsync(docId, "Processing...") Notifier->>Bus: PublishAsync(NotifyProgressMessage) Bus->>Rabbit: Route via MessageIdentity("notify-progress") Note over Rabbit, SignalR: Asynchronous message queue Rabbit->>SignalR: Consume(NotifyProgressMessage) SignalR->>SignalR: Map to SignalR event SignalR-->>UI: WebSocket Push