Overview
The realtime layer is fragmented across three independent implementations: src/lib/websocketManager.ts (socket.io), src/lib/notifications/socket.ts (a hand-rolled reconnecting socket), and src/lib/graphql/subscriptions.ts (GraphQL subscriptions). Each re-implements its own connect/reconnect loop with inconsistent backoff, no shared heartbeat, and no backpressure. Consumer hooks (src/hooks/useWebSocket.ts, src/hooks/useCollaboration.ts, src/hooks/useRealTimeAnalytics.ts) therefore receive different connection-status shapes, and any message emitted while a transport is disconnected is silently dropped. There is no jittered backoff (so reconnect storms can hammer the backend), no automatic resubscribe after a reconnect, and store convergence in src/store/synchronizationEngine.ts can permanently miss events that occurred during the reconnect gap.
This issue introduces a transport-agnostic connection supervisor that all three transports delegate to, adds a bounded outbound queue with backpressure, inbound sequence tracking with catch-up, automatic resubscribe, and reconnection health metrics/alerts. It is a cross-cutting change spanning ~14 files and ~900 lines including tests.
Specifications
Features:
A ConnectionSupervisor (src/lib/realtime/connectionSupervisor.ts) providing a transport-agnostic lifecycle — connect, exponential backoff with full jitter, heartbeat with ping-timeout detection, and a single unified ConnectionStatus shape
An outbound send queue with bounded backpressure (documented drop-oldest vs block policy) that flushes in order on reconnect, plus inbound sequence tracking to detect and request events missed during a gap
Automatic resubscribe of GraphQL subscriptions and socket rooms after a reconnect, and an onReconnect catch-up callback used to backfill the gap window
Reconnection and health metrics plus an alert threshold via src/lib/monitoring/metrics.ts and src/lib/monitoring/alerts.ts, with graceful degradation to offline mode (signalled through src/serviceWorker.ts) once max attempts are exceeded
Tasks:
Implement ConnectionSupervisor and refactor websocketManager, notifications/socket, and graphql/subscriptions to delegate their lifecycle to it
Add a bounded outbound queue and inbound sequence/ack handling, exposing subscribe()/publish() with documented delivery guarantees
Add a resubscribe registry so rooms and subscriptions are restored on reconnect, and wire an onReconnect catch-up hook consumed by synchronizationEngine
Expose a single useRealtimeConnection status object and adopt it in useWebSocket, useCollaboration, and useRealTimeAnalytics
Emit metrics (reconnect_attempt, reconnect_success, heartbeat_timeout, queue_dropped) and wire an alert on repeated reconnect failure
Write tests for the backoff-with-jitter schedule, heartbeat-timeout-triggered reconnect, queue flush ordering, and resubscribe after a drop
Impacted Files:
src/lib/realtime/connectionSupervisor.ts (new)
src/lib/websocketManager.ts
src/lib/notifications/socket.ts
src/lib/graphql/subscriptions.ts
src/lib/graphql/subscriptionQueries.ts
src/hooks/useWebSocket.ts
src/hooks/useCollaboration.ts
src/hooks/useRealTimeAnalytics.ts
src/store/synchronizationEngine.ts
src/lib/monitoring/metrics.ts
src/lib/monitoring/alerts.ts
src/serviceWorker.ts
src/constants/app.constants.ts
src/lib/realtime/tests/connectionSupervisor.test.ts (new)
Acceptance Criteria
All three transports reconnect through the single supervisor using exponential backoff with jitter and a shared heartbeat/ping-timeout
Messages sent while disconnected are queued within the bounded limit and flushed in order on reconnect; overflow follows the documented policy
GraphQL subscriptions and socket rooms are automatically restored after a reconnect, and the catch-up path recovers events missed during the gap
A single unified connection status is available to all consumer hooks, and reconnection metrics plus an alert are emitted
Tests cover the backoff schedule, heartbeat-triggered reconnect, queue flush ordering, and resubscribe, with >80% coverage on connectionSupervisor.ts
Overview
The realtime layer is fragmented across three independent implementations:
src/lib/websocketManager.ts(socket.io),src/lib/notifications/socket.ts(a hand-rolled reconnecting socket), andsrc/lib/graphql/subscriptions.ts(GraphQL subscriptions). Each re-implements its own connect/reconnect loop with inconsistent backoff, no shared heartbeat, and no backpressure. Consumer hooks (src/hooks/useWebSocket.ts,src/hooks/useCollaboration.ts,src/hooks/useRealTimeAnalytics.ts) therefore receive different connection-status shapes, and any message emitted while a transport is disconnected is silently dropped. There is no jittered backoff (so reconnect storms can hammer the backend), no automatic resubscribe after a reconnect, and store convergence insrc/store/synchronizationEngine.tscan permanently miss events that occurred during the reconnect gap.This issue introduces a transport-agnostic connection supervisor that all three transports delegate to, adds a bounded outbound queue with backpressure, inbound sequence tracking with catch-up, automatic resubscribe, and reconnection health metrics/alerts. It is a cross-cutting change spanning ~14 files and ~900 lines including tests.
Specifications
Features:
A
ConnectionSupervisor(src/lib/realtime/connectionSupervisor.ts) providing a transport-agnostic lifecycle — connect, exponential backoff with full jitter, heartbeat with ping-timeout detection, and a single unifiedConnectionStatusshapeAn outbound send queue with bounded backpressure (documented drop-oldest vs block policy) that flushes in order on reconnect, plus inbound sequence tracking to detect and request events missed during a gap
Automatic resubscribe of GraphQL subscriptions and socket rooms after a reconnect, and an
onReconnectcatch-up callback used to backfill the gap windowReconnection and health metrics plus an alert threshold via
src/lib/monitoring/metrics.tsandsrc/lib/monitoring/alerts.ts, with graceful degradation to offline mode (signalled throughsrc/serviceWorker.ts) once max attempts are exceededTasks:
Implement
ConnectionSupervisorand refactorwebsocketManager,notifications/socket, andgraphql/subscriptionsto delegate their lifecycle to itAdd a bounded outbound queue and inbound sequence/ack handling, exposing
subscribe()/publish()with documented delivery guaranteesAdd a resubscribe registry so rooms and subscriptions are restored on reconnect, and wire an
onReconnectcatch-up hook consumed bysynchronizationEngineExpose a single
useRealtimeConnectionstatus object and adopt it inuseWebSocket,useCollaboration, anduseRealTimeAnalyticsEmit metrics (
reconnect_attempt,reconnect_success,heartbeat_timeout,queue_dropped) and wire an alert on repeated reconnect failureWrite tests for the backoff-with-jitter schedule, heartbeat-timeout-triggered reconnect, queue flush ordering, and resubscribe after a drop
Impacted Files:
src/lib/realtime/connectionSupervisor.ts (new)
src/lib/websocketManager.ts
src/lib/notifications/socket.ts
src/lib/graphql/subscriptions.ts
src/lib/graphql/subscriptionQueries.ts
src/hooks/useWebSocket.ts
src/hooks/useCollaboration.ts
src/hooks/useRealTimeAnalytics.ts
src/store/synchronizationEngine.ts
src/lib/monitoring/metrics.ts
src/lib/monitoring/alerts.ts
src/serviceWorker.ts
src/constants/app.constants.ts
src/lib/realtime/tests/connectionSupervisor.test.ts (new)
Acceptance Criteria
All three transports reconnect through the single supervisor using exponential backoff with jitter and a shared heartbeat/ping-timeout
Messages sent while disconnected are queued within the bounded limit and flushed in order on reconnect; overflow follows the documented policy
GraphQL subscriptions and socket rooms are automatically restored after a reconnect, and the catch-up path recovers events missed during the gap
A single unified connection status is available to all consumer hooks, and reconnection metrics plus an alert are emitted
Tests cover the backoff schedule, heartbeat-triggered reconnect, queue flush ordering, and resubscribe, with >80% coverage on
connectionSupervisor.ts