Real-time Flows
SignalR Hub Group Map
flowchart LR
subgraph BouquetHub
RG["radius:{lat}:{lng}:{radius}\n(Customer: nearby bouquet updates)"]
OG["order:{orderId}\n(Customer: order status updates)"]
VG["vendor:{vendorId}\n(Vendor Portal: order + vase dashboard)"]
end
Customer -->|JoinRadiusGroup| RG
Customer -->|JoinOrderGroup| OG
VendorPortal -->|JoinVendorGroup| VG
Outbox → EventBus → SignalR Dispatch
sequenceDiagram
participant Handler as Command Handler
participant UoW as UnitOfWork (EF Core)
participant DB as PostgreSQL (outbox_messages)
participant Dispatcher as OutboxDispatcherService (BackgroundService)
participant Bus as InMemoryEventBus
participant Hub as BouquetHub (SignalR)
participant Client as Connected Client
Handler->>UoW: SaveChangesAsync()
UoW->>DB: INSERT aggregate change + INSERT outbox_messages in same transaction
loop Every 5s
Dispatcher->>DB: SELECT top 20 WHERE processed_at IS NULL ORDER BY created_at
DB-->>Dispatcher: [OutboxMessage]
Dispatcher->>Dispatcher: Deserialize IDomainEvent from payload
Dispatcher->>Bus: InMemoryEventBus.PublishAsync(event)
Bus->>Hub: Matching event handler calls Hub.Clients.Group(...).SendAsync("OrderStatusChanged", ...)
Hub-->>Client: Real-time message (WebSocket)
Dispatcher->>DB: UPDATE outbox_messages SET processed_at = now
end
⚠️ Known gap (EP-09):
RabbitMQEventBus.PublishAsyncreturnsTask.CompletedTask— all events are silently dropped when RabbitMQ bus is active.InMemoryEventBusis the real implementation currently in use. Fix: wire real RabbitMQ publish in EP-09 S-09-06.
⚠️ Known gap (EP-06):
DeviceRegistrationaggregate and repository are implemented. FCM push notification dispatch (INotificationServiceClient) is a stub — push notifications are not delivered to mobile devices. Fix planned in EP-06.
Bouquet View Counter
sequenceDiagram
participant App as Mobile App
participant API as REST API
participant Counter as BouquetViewCounterService
participant Hub as BouquetHub (SignalR)
participant Vendor as Vendor Portal (subscribed to vendor group)
App->>Hub: SignalR: StartViewingBouquet(bouquetId)
Hub->>Counter: BouquetViewCounterService.IncrementViewCount(bouquetId, connectionId)
Counter->>Hub: SendAsync("BouquetViewCountChanged", bouquetId, count)
Hub-->>Vendor: Real-time view count update on dashboard