Hubs: Managing WebSocket Connections
The Hubs module encapsulates the SignalR endpoints that form the direct, stateful lifeline to the React frontend. In MILTON’s architecture, the hub serves as a purely reactive conduit: it maintains active client connections, organizes them into logical groupings, and pushes out events without performing any domain logic itself.
Business Logic Intent
The goal of the DocumentHub is to eliminate the necessity for clients to repeatedly HTTP-poll the main API to learn about document processing status. By establishing a persistent WebSocket connection through the YARP gateway, the hub allows the Notification Service to instantly notify specific clients the exact moment a background AI worker completes a section or encounters an error.
A critical design constraint is data minimization via Group Routing. If five users are currently online, but only one is viewing Project A’s dashboard, only that specific user should receive Project A’s updates. Broadcasts are selectively targeted to preserve bandwidth and reduce client-side rendering overhead.
Client Subscription & Group Routing
Rather than pushing all events to all connected clients (Clients.All), the DocumentHub utilizes SignalR Groups to segregate traffic based on client context.
When a client navigates to a specific screen, it explicitly invokes a Hub method to subscribe to the relevant updates:
| Hub Method | Client Context | Underlying Group Key | Purpose |
|---|---|---|---|
JoinDocumentGroup(Guid) | Detailed Document Editor | doc-{documentId} | Receive deep updates like specific block content changes or section additions for the currently active document. |
LeaveDocumentGroup(Guid) | Navigating away from Editor | doc-{documentId} | Unsubscribe to conserve resources. |
JoinProjectGroup(int) | Project Dashboard / Doc List | project-{projectId} | Receive high-level aggregate progress or document status changes for all documents within a project. |
LeaveProjectGroup(int) | Navigating away from Project | project-{projectId} | Unsubscribe. |
Network Flow & Authorization
The DocumentHub operates firmly behind MILTON’s reverse proxy, meaning clients never connect directly to the service port.
- YARP Routing: The React client initiates a WebSocket connection to
https://api.milton.local/hubs/document. - TLS Termination & Headers: YARP terminates TLS, authenticates the session via Keycloak, and injects internal headers (e.g.,
X-Internal-Principal). It then proxies the upgraded WebSocket connection to the Notification Service. - Hub Authorization: The
[Authorize]attribute on theDocumentHubguarantees that connections are only established for strongly authenticated users, relying on the ambient identity resolved from YARP’s headers.
sequenceDiagram participant React as React Client participant YARP as YARP Gateway participant Hub as DocumentHub (SignalR) React->>YARP: Connect w/ Auth Cookie (/hubs/document) YARP->>YARP: Validate JWT/Cookie YARP->>Hub: Upgrade to WebSocket (inject X-Internal-* headers) Hub-->>React: 101 Switching Protocols React->>Hub: JoinDocumentGroup(Guid) Hub->>Hub: Add ConnectionId to 'doc-Guid' Hub-->>React: Acknowledgement