07 — Component Library (WS / Realtime Module)
- 1.
AppRealtimeStatusDot - 2.
AppConnectionBanner - 3.
AppLiveList - 4.
AppNotificationToast - 5.
AppEventLog(debug, proposed) - 6.
RealtimeClient(non-visual core) - Composition rules
Components the realtime layer introduces. Base primitives come from 00-shared/03; these are module-level compositions with the wire contract baked in. Shared design-system mapping lives in 11 and 00-shared/04.
1. AppRealtimeStatusDot
| Field | Detail |
|---|---|
| Purpose | One-glance connection state, non-interactive by default |
| Props | state: RealtimeState (idle/connecting/connected/reconnecting/offline/error-auth) |
| Anatomy | 8 dp circle + optional 12 dp label |
| Colors | from 00-shared/02 status tokens (success/amber-warning/danger/neutral) |
| Behavior | pulse animation while connecting/reconnecting (m-fast); tooltip "Live" when connected |
| a11y | semantic label from state text; never color-only (00-shared/09) |
| Wire-up | consumes RealtimeBloc state (13); no direct socket access |
2. AppConnectionBanner
| Field | Detail |
|---|---|
| Purpose | Non-blocking offline/error surface under the app bar |
| Props | state (offline / error-auth), onRetry (optional) |
| Anatomy | 1-line banner: icon + message + optional "Retry" text button |
| States | offline: "Live updates paused"; error-auth: "Session expired — reconnecting" |
| Motion | slide-in m-fast; never blocks scroll content (fixed slot) |
| a11y | live-region announcement on show/hide |
| Rules | shown only in offline/error-auth; hidden otherwise (no persistent banner) |
3. AppLiveList
| Field | Detail |
|---|---|
| Purpose | Wrapper that merges socket events into an existing paginated list (06 §3.1) |
| Props | items, eventStream (filtered), entityIdOf(item), onRowEvent(item, event), refetch |
| Behavior | row-level in-place update + flash; miss → optional insert or bounded refetch; sort/aggregate locally |
| Limits | bounded refetch: 1 / 5 s / screen; never mutates during user edit (10 §2) |
| Reuse | wraps 00-shared/03 list + skeleton primitives |
| Testing | pure Dart logic (match/insert/refetch) — unit-testable without socket |
4. AppNotificationToast
| Field | Detail |
|---|---|
| Purpose | Transient high-priority notification surface |
| Props | event (envelope), onTap |
| Anatomy | AppSnackbar-based: icon + title + entity snippet; queueing; 5 s auto-dismiss |
| Dedup | by eventType+entityId within 30 s window (multi-tab, 02) |
| Rules | never steals focus; max 1 visible |
5. AppEventLog (debug, proposed)
| Field | Detail |
|---|---|
| Purpose | Monospace stream of received envelopes for the admin debug view (06 §5) |
| Props | events (last 500), filter |
| Anatomy | rows: `HH:mm:ss.SSS |
| Behavior | pause render (not capture); clear; substring filter |
| Rules | debug-only; guarded by admin route gate |
6. RealtimeClient (non-visual core)
| Field | Detail |
|---|---|
| Purpose | Owns the socket lifecycle, handshake, room membership, event stream (13) |
| API | connect(token), disconnect(), subscribe(room), unsubscribe(room), Stream<WsEnvelope> events, RealtimeState state |
| Contract | handshake token → auth.token or query.token (ws.gateway.ts:37-39); subscribe message = room string (ws.gateway.ts:63-68) |
| Security | token from secure store only; never logged (15 §8) |
| Reuse | one instance per app run (singleton scope), injected via DI |
Composition rules
- Visual components never import the socket library; they consume
RealtimeClient/RealtimeBlocstreams only. AppLiveListis the only list component aware of events; plain lists stay REST-only.- All components work with zero server changes — they render the existing bridge
envelope (
ws-bridge.service.ts:17-21).