WebSocket Implementation Plan
1. Overview for Non-Technical Stakeholders
Imagine our robotics tournament application needs to show live scores and match updates to everyone watching – referees, teams, and the audience – all at the exact same time, without anyone needing to refresh their page. That's what WebSockets do for us!
Think of it like a live phone call instead of sending letters back and forth. Once a connection is made, information can flow instantly in both directions.
Key Benefits:
- Real-time Updates: Scores change on everyone's screen the moment they are entered. Timers count down live for all viewers.
- Instant Notifications: Important announcements or match state changes (e.g., match starting, match paused) are broadcast immediately.
- Interactive Control: Referees can control matches (start/stop timers, submit scores) and these actions are reflected live on other interfaces like the audience display.
In short, WebSockets make our application feel alive and interactive, ensuring everyone has the most up-to-date information instantly.
2. Technical Deep Dive
This section details the technical implementation of WebSocket communication within the Robotics Tournament Management System. It leverages Socket.IO, a library that enables real-time, bidirectional, and event-based communication.
2.1. Backend (NestJS - EventsGateway)
The core of the backend WebSocket functionality resides in backend/src/websockets/events.gateway.ts.
Key Responsibilities:
- Connection Management: Handles client connections and disconnections.
- Room Management: Uses Socket.IO rooms to broadcast messages to specific groups of clients. Typically, clients join rooms based on
tournamentIdand potentiallyfieldIdto receive relevant updates.join_tournament: Client requests to join a room for a specific tournament.leave_tournament: Client requests to leave a tournament room.joinFieldRoom: Client requests to join a room for a specific field display (e.g., audience display for Field 1).leaveFieldRoom: Client requests to leave a field room.
- Message Handling (
@SubscribeMessage): Listens for specific events emitted by clients and processes them. Key events include:scoreUpdateRealtime: Handles incoming real-time score adjustments from a client (e.g., a referee's tablet). This typically involves broadcasting the update to other clients in the same tournament/match room but does not persist to the database directly through this event. The DTO used isScoreUpdateDto.persistScores: Handles requests from clients to save scores to the database. This is a separate event fromscoreUpdateRealtimeto clearly distinguish between transient updates and final persistence. The DTO used isPersistScoresDto. After attempting persistence, the gateway emits apersistenceResultevent back to the originating client (and potentially others) withPersistenceResultDto.timer_update,start_timer,pause_timer,reset_timer: Manage match timers.match_state_change: Handles changes in the match state (e.g., SCHEDULED, RUNNING, PAUSED, COMPLETED).display_mode_change: Updates audience display settings.announcement: Broadcasts announcements.
- Broadcasting Events (
server.to(room).emit()): Emits events to all clients in a specific room or globally. This is how real-time updates are disseminated.broadcastToTournament(tournamentId, event, payload): Helper to send to a specific tournament room.emitToField(fieldId, event, payload): Helper to send to a specific field room.
DTOs (Data Transfer Objects) in backend/src/websockets/dto/:
BaseScoreDto.ts: A base DTO likely containing common score fields (red/blue scores for auto/drive/total). (Assumption, as its content is not provided)ScoreUpdateDto.ts: ExtendsBaseScoreDto. Used forscoreUpdateRealtimeevents. Includes atype: 'realtime'field.PersistScoresDto.ts: ExtendsBaseScoreDto. Used forpersistScoresevents. Includestype: 'persist',finalScores: boolean, andsubmittedBy: stringfields.PersistenceResultDto.ts: Used to inform clients about the outcome of a score persistence attempt. ContainsmatchId,success, optionaldataorerror, andtimestamp.
Workflow Example (Score Update & Persist):
- Referee UI (Client): Referee increments a score element.
- Client Emits
scoreUpdateRealtime: The frontend sends aScoreUpdateDtoto theEventsGatewaywith the new (transient) score. EventsGatewayBroadcasts: The gateway broadcasts thisScoreUpdateDtoto all clients in the relevant tournament/match room (e.g., other referees, audience display).- Clients Update UI: Connected clients receive the
scoreUpdateRealtimeevent and update their displays with the new transient score. - Referee UI (Client): Referee confirms final scores for the match.
- Client Emits
persistScores: The frontend sends aPersistScoresDtoto theEventsGateway. EventsGatewayProcesses: The gateway calls theMatchScoresService(or similar) to save the scores to the database.EventsGatewayEmitspersistenceResult: The gateway sends aPersistenceResultDtoback to the client indicating success or failure of the database operation.
2.2. Frontend (Next.js)
The frontend WebSocket integration is primarily managed through custom hooks and services.
Key Files & Responsibilities:
frontend/src/lib/websocket.ts(Main WebSocket Service -WebSocketServiceclass):- Singleton Instance: Provides a global singleton instance (
webSocketService) for managing the WebSocket connection and event handling throughout the application. - Connection Management (
IConnectionManager): Handlesconnect,disconnect,isConnected,getConnectionStatus,forceReconnect. It also exposesonConnectionStatusfor other parts of the app to react to connection changes. - Event Emission/Subscription (
IEventEmitter): Provides genericemit,on, andoffmethods for sending and receiving any WebSocket event. - Score Management (
IScoreManager): Offers specialized methods for score-related WebSocket interactions:sendRealtimeScoreUpdate(data: BaseScoreData): Emits ascoreUpdateRealtimeevent (likely usingScoreUpdateDto).persistScores(data: BaseScoreData): Emits apersistScoresevent (likely usingPersistScoresDto) and probably handles thepersistenceResultresponse via a Promise or callback.onScoreUpdate(callback): Subscribes to incomingscoreUpdateRealtimeevents.onScoresPersisted(callback): Subscribes to incomingpersistenceResultevents.
- Legacy Support (
ILegacySupport): Provides methods for older event structures or specific event emissions likejoinTournament,sendDisplayModeChange, etc. This seems to be a bridge or an abstraction layer over the basicemit. - Structure: This service is well-structured using composition, with internal classes like
ConnectionManager,EventEmitter,ScoreManager, andLegacySupporteach handling a single responsibility. It also uses interfaces for better abstraction (IConnectionManager,IEventEmitter, etc.).
- Singleton Instance: Provides a global singleton instance (
frontend/src/services/websocket-service.ts(Alternative/Potentially Older Service):- This file also defines a
WebSocketServiceusing aSocketIOConnectionclass. It appears to be an alternative or perhaps an earlier version of the WebSocket service compared tolib/websocket.ts. - It also provides methods for connecting, disconnecting, emitting, and subscribing to events, as well as specific convenience methods like
sendMatchUpdate,sendScoreUpdate. - Note: It's important to clarify which of these two services (
lib/websocket.tsorservices/websocket-service.ts) is the current, canonical one being used throughout the application to avoid confusion. The one inlib/websocket.tsappears more recent and robust due to its SOLID principles application and clear interface segregation.
- This file also defines a
frontend/src/hooks/common/websocket-context.tsx(WebSocketProvider,useWebSocketContext):- Provides a React Context for the main
websocketServiceinstance (fromlib/websocket.ts). WebSocketProviderwraps parts of the application (likely the root) to make the WebSocket service and connection status available via theuseWebSocketContexthook.- This avoids prop drilling and allows any component to access WebSocket functionalities.
- Manages and broadcasts connection status (
isConnected,connectionAttempts).
- Provides a React Context for the main
frontend/src/hooks/common/use-optimized-websocket.ts(useOptimizedWebSocket):- A custom hook that consumes
useWebSocketContext. - Aims to provide memoized actions to prevent unnecessary re-renders in components that use WebSocket functionalities.
- Separates actions into
coreActions(connection, generic subscribe/unsubscribe),tournamentActions(join/leave tournament), andcontextualActions(actions that depend on the current tournament, like sending tournament-specific data).
- A custom hook that consumes
frontend/src/hooks/features/use-websocket-subscriptions.ts:- A higher-level hook designed for components that need to subscribe to multiple common WebSocket events related to a tournament, field, or match (e.g., timer updates, score updates, match state changes).
- Takes
tournamentId,selectedFieldId,selectedMatchId, and callbacks (onTimerUpdate,onScoreUpdate, etc.) as props. - Uses
useWebSocket(likelyuseOptimizedWebSocketor a similar hook deriving from the context) to get connection and subscription capabilities. - Manages joining/leaving tournament and field rooms based on props.
- Sets up
useEffecthooks to subscribe to specific events (timer_update,score_update,match_update,match_state_change) and calls the provided callbacks or updates TanStack Query cache when data is received.
frontend/src/hooks/features/use-realtime-scores.ts:- A specialized hook for managing and displaying real-time scores for a specific
matchId. - Internally manages
realtimeScoresstate andconnectionState(including fallback mode). - Likely uses
websocketService.onScoreUpdate()(fromlib/websocket.ts) to listen for live score broadcasts. - Implements a
FallbackManagerfor polling scores via HTTP if the WebSocket connection is down or unreliable, ensuring data can still be fetched (graceful degradation). - Uses a
ScoreUpdaterto abstract the logic of updating the local score state from either WebSocket events or database polling results.
- A specialized hook for managing and displaying real-time scores for a specific
Frontend Workflow Summary:
WebSocketProviderinitializeswebsocketServiceand makes it available via context.- Components or feature-specific hooks like
useWebSocketSubscriptionsoruseRealtimeScoresuseuseWebSocketContext(often viauseOptimizedWebSocket) to access the service. - They use methods like
joinTournament,joinFieldRoomto subscribe to relevant server-side rooms. - They use
subscribe(or specialized methods likeonScoreUpdate) to listen for events from the server. - When events are received, callbacks are triggered, which might update local component state, TanStack Query cache, or perform other UI actions.
- To send data, they use
emit(or specialized methods likesendRealtimeScoreUpdate,persistScores).
2.3. Key WebSocket Events (Client <-> Server)
(This is a summary based on observed SubscribeMessage decorators and frontend service methods)
Client to Server:
join_tournament(payload:{ tournamentId: string })leave_tournament(payload:{ tournamentId: string })joinFieldRoom(payload:{ fieldId: string })leaveFieldRoom(payload:{ fieldId: string })scoreUpdateRealtime(payload:ScoreUpdateDto)persistScores(payload:PersistScoresDto)start_timer(payload:TimerData- structure inferred)pause_timer(payload:TimerData)reset_timer(payload:TimerData)match_state_change(payload:MatchStateData- structure inferred)display_mode_change(payload:AudienceDisplaySettings- structure inferred)announcement(payload:AnnouncementData- structure inferred)match_update(payload:MatchData- structure inferred, less common for client to send full match updates, might be for specific control actions)
Server to Client:
score_update(payload:ScoreUpdateDtoor similarScoreData)persistenceResult(payload:PersistenceResultDto)timer_update(payload:TimerData)match_state_change(payload:MatchStateData)match_update(payload:MatchData)display_mode_update(payload:AudienceDisplaySettings- event name assumed)announcement(payload:AnnouncementData)connect,disconnect(standard Socket.IO events)error(generic error messages)
3. Data Flow Diagram (Simplified Score Update)
sequenceDiagram
participant RefereeUI as Referee Client
participant FrontendService as Frontend WebSocket Service
participant EventsGateway as Backend EventsGateway
participant OtherClients as Other Connected Clients
participant Database
RefereeUI->>FrontendService: User updates score (e.g., +1)
FrontendService->>EventsGateway: emit('scoreUpdateRealtime', ScoreUpdateDto)
EventsGateway->>OtherClients: broadcast('score_update', ScoreUpdateDto)
OtherClients->>OtherClients: Update UI with transient score
EventsGateway->>FrontendService: (Implicit ack or no direct response for realtime)
alt Referee Confirms Final Scores
RefereeUI->>FrontendService: User submits final scores
FrontendService->>EventsGateway: emit('persistScores', PersistScoresDto)
EventsGateway->>Database: Save scores (via MatchScoresService)
Database-->>EventsGateway: Persistence success/failure
EventsGateway->>FrontendService: emit('persistenceResult', PersistenceResultDto)
FrontendService->>RefereeUI: Update UI with persistence status
end
4. Future Considerations / Improvements
- Scalability: For very large tournaments, investigate more advanced Socket.IO scaling strategies (e.g., Redis adapter).
- Error Handling: Enhance client-side and server-side error handling and reporting for WebSocket operations.
- Security: Review CORS origins for production. Implement stricter validation and sanitization on all incoming WebSocket messages on the backend.
- Message Schema Versioning: For long-term maintenance, consider a strategy for versioning WebSocket message schemas if significant changes are anticipated.
- Consolidate Frontend Services: Clarify and potentially merge the functionalities of
frontend/src/lib/websocket.tsandfrontend/src/services/websocket-service.tsif there's an overlap to maintain a single source of truth for WebSocket interactions. - Testing: Implement comprehensive automated tests for WebSocket event handling on both frontend and backend.
This document provides a foundational understanding of the WebSocket implementation. Refer to the specific source code files for the most detailed and up-to-date information.