Realtime Gateway
Socket.IO WebSocket gateway for realtime collaboration
The BoardGateway is a NestJS WebSocket gateway using Socket.IO. It handles the realtime collaboration protocol defined in @hfu.digital/boardkit-core.
Gateway Configuration
@WebSocketGateway({ namespace: '/board' })
class BoardGateway implements OnGatewayConnection, OnGatewayDisconnect { }The gateway listens on the /board namespace. Connect your Socket.IO client to ws://your-server/board.
Message Handlers
join
Authenticates the client, joins the collaboration session, and sends sync data.
- Validates the token via
BoardAuthGuard.validateConnection() - Checks access via
PermissionService.checkAccess()(requiresviewerrole) - Determines the user's effective role (
viewer,editor, orowner) - Joins the Socket.IO room for the board
- Calls
CollaborationService.joinSession() - Sends
joinedmessage with participant list - Sends either
sync:deltaorsync:fullbased on reconnection state - Broadcasts
participant:joinedto other clients
mutate
Applies element mutations from editors.
- Checks the client's role (requires
editoror higher) - Calls
CollaborationService.applyMutations() - Sends
mutation:ackto the sender - Broadcasts
mutation:broadcastto all other clients in the room
cursor
Broadcasts cursor position to other participants.
- Updates the cursor in
PresenceManager - Broadcasts
cursor:broadcastto all other clients
ping
Responds with a pong message containing the server timestamp. Useful for latency measurement.
Disconnection
When a client disconnects:
- Calls
CollaborationService.leaveSession()to remove the participant - Removes the participant from
PresenceManager - Broadcasts
participant:leftto remaining clients - Cleans up internal client-to-board/user/role mappings
Supporting Services
PresenceManager
Tracks which participants are in each board session and their cursor positions.
class PresenceManager {
addParticipant(boardId: string, participant: Participant): void;
removeParticipant(boardId: string, userId: string): void;
updateCursor(boardId: string, userId: string, position: Point, pageId: string): void;
getParticipants(boardId: string): Participant[];
}SyncRelay
Manages Socket.IO room broadcasting with exclusion support.
class SyncRelay {
registerClient(clientId: string, socket: Socket, boardId: string): void;
broadcast(boardId: string, message: ServerMessage, excludeClientId?: string): void;
}ReconnectionHandler
Handles delta and full sync delivery to reconnecting clients.
class ReconnectionHandler {
sendDelta(client: Socket, mutations: ElementMutation[], fromSeq: number, toSeq: number): Promise<void>;
sendFullSync(client: Socket, boardId: string, currentSequence: number): Promise<void>;
}Error Codes
| Code | When | Action |
|---|---|---|
AUTH_FAILED | Token validation fails | Client disconnected |
FORBIDDEN | Insufficient permissions (e.g., viewer tries to mutate) | Error message sent |
SESSION_MISMATCH | Stale session detected | Error message sent |