01 — Product Overview (WS / Realtime Module)
The realtime push layer of StudyLyon. Not a product surface by itself — it is the delivery mechanism that makes notifications, dashboards and lists live on web clients. Authoritative conventions live in
00-shared/*; module specifics here.
1. What this module is
StudyLyon's WebSocket stack delivers server-pushed domain events to authenticated clients. Two moving parts in source:
| Piece | Source | Role |
|---|---|---|
WsGateway | src/modules/ws/ws.gateway.ts | Socket.io gateway on namespace /ws; JWT handshake, tenant rooms, subscribe/unsubscribe |
WsBridge | src/modules/ws/ws-bridge.service.ts | Hooks the in-process EventBus and broadcasts every domain event to the emitting tenant |
WsModule | src/modules/ws/ws.module.ts | Module wiring; registers JwtModule for handshake verification (ws.module.ts:7) |
End-to-end flow, per source:
domain service → EventBus.emit() (events/event-bus.service.ts:11)
→ WsBridge.onAny() (ws-bridge.service.ts:16)
→ WsGateway.broadcastToTenant() (ws.gateway.ts:76)
→ server.to(`tenant:{id}`).emit() → all sockets of that tenant
The blueprint defines the scope: "WebSockets under /ws for in-app notifications and
live dashboards" (studylyon-blueprint/02-Architecture/API_DESIGN.md:76).
2. Scope (in / out)
In scope today
- Authenticated connection handshake (JWT access token) —
ws.gateway.ts:35-57. - Implicit tenant room per connection —
client.join('tenant:...')(ws.gateway.ts:50). - Fan-out of all domain events to the tenant room —
ws-bridge.service.ts:16-22. - Client-driven
subscribe/unsubscribeto additional rooms —ws.gateway.ts:63-74.
Out of scope today (see gaps)
- REST surface: none; this module has no HTTP endpoints (see
12_API_Mapping.md). - Per-user rooms, per-room RBAC, event acknowledgement, error channel, heartbeat tuning.
- Redis pub/sub fan-out for horizontal scale — no socket.io adapter exists in
src/infrastructure/redis/(only the sharedREDIS_CLIENT,redis.constants.ts:1-2). - Native mobile push. PRD note: the PRD scopes the product to web clients; the
native app is excluded from realtime scope. Push notifications, device tokens and
session join links are forward-looking (
docs/IMPLEMENTATION_PLAN.md:231,769,859).
Planned consumers (per implementation plan)
- Communication module — realtime message delivery via this
WsModule(docs/IMPLEMENTATION_PLAN.md:119). - Transport live tracking —
docs/IMPLEMENTATION_PLAN.md:229(planned). - Notifications preferences/channels/device tokens —
docs/IMPLEMENTATION_PLAN.md:231(planned; WebSocket is one channel).
3. Goals
- Deliver domain events to the right tenant with low latency (single-hop in-process).
- Keep the connection layer invisible to users (reconnect handled by client + socket.io).
- Stay tenant-isolated: a socket may only receive events for the tenant in its JWT.
- Survive restarts: bridge is idempotent (
onModuleInit,ws-bridge.service.ts:15).
4. Non-goals
- Chat/messaging protocol design (Communication module owns it — planned).
- Guaranteed at-least-once delivery / replay; events are ephemeral fire-and-forget.
- Backfill of missed events while disconnected (clients refetch via REST — eventual consistency).
5. Success signals (proposed)
- Connection success rate ≥ 99.5% on stable networks.
- p95 event → client render < 1 s.
- Zero tenant-isolation incidents.
- 10k concurrent connections per instance load-tested
(
docs/IMPLEMENTATION_PLAN.md:842— plan calls this out as a scale risk).