WebSocket Architecture Plan
Related Documentation:
- Platform Vision - Mission, actors, business model
- Data Model - Entities, relationships, access control
- Actors & Workflows - User journeys, workflow diagrams
- API Design - REST conventions, endpoints
Overview
Real-time collaboration for audio production workflow. Users need instant updates for:
- Comments on tracks (the primary use case)
- Notification delivery
- Collaborator activity (online status, role changes)
- File updates (new versions, playback sync)
Technology Choice: Socket.io
| Option | Pros | Cons | Verdict |
|---|---|---|---|
| Socket.io | Battle-tested, auto-reconnect, rooms, NestJS gateway support, fallbacks | Slightly larger bundle | ✅ Recommended |
| Pusher | Managed service, simple | Monthly costs, external dependency | ❌ |
| Native WebSocket | Smallest bundle | Manual reconnection, no rooms | ❌ |
Why Socket.io: NestJS has built-in @nestjs/websockets with Socket.io adapter. Handles reconnections, namespaces, and rooms natively.
Real-Time Event Types
1. Comment Events (Wave View)
| Event | Trigger | Payload | Recipients |
|---|---|---|---|
comment:new | New comment created | {commentId, content, owner, timeStart} | All track viewers |
comment:reply | Reply added | {parentId, replyId, content, owner} | All track viewers |
comment:like | Comment liked | {commentId, likes, userId} | Comment owner |
comment:resolved | Comment resolved | {commentId, resolvedBy} | All track viewers |
comment:deleted | Comment deleted | {commentId} | All track viewers |
2. Notification Events
| Event | Trigger | Payload | Recipients |
|---|---|---|---|
notification:new | Any notification | {id, type, message, slug} | Recipient only |
notification:count | Unread count change | {count} | User only |
3. Collaboration Events
| Event | Trigger | Payload | Recipients |
|---|---|---|---|
collaborator:invited | New invite | {email, role, resource} | Resource owner |
collaborator:joined | Accept invite | {userId, name, role} | All collaborators |
collaborator:role-changed | Role update | {userId, oldRole, newRole} | Affected user + admins |
collaborator:removed | User removed | {userId} | All collaborators |
collaborator:online | Presence update | {userId, isOnline} | Resource viewers |
4. File/Track Events
| Event | Trigger | Payload | Recipients |
|---|---|---|---|
file:uploaded | New version | {fileId, version, name} | Track collaborators |
track:updated | Track metadata changed | {trackId, changes} | Track collaborators |
playback:sync | Playhead position | {trackId, position, userId} | Track viewers |
Room Strategy
Namespace: /
├── Room: user:{userId} # Personal notifications
├── Room: track:{trackId} # Comments, playback sync
├── Room: project:{projectId} # File updates, collaborator changes
└── Room: artist:{artistId} # High-level activityJoin Logic:
- User connects → auto-join
user:{userId} - Navigate to Wave view → join
track:{trackId} - Navigate to Project → join
project:{projectId}
Backend Integration Points
Files to Modify:
- New Module:
src/modules/websocket/websocket.gateway.ts - Inject Gateway: Comment, Notification, Collaboration, File services
- Frontend:
src/lib/socket-provider.tsx
Implementation Phases
Phase 1: Foundation (Priority: High)
- [ ] Install Socket.io:
npm install @nestjs/websockets socket.io - [ ] Create WebSocket gateway with JWT auth
- [ ] Add room join/leave handlers
- [ ] Create frontend socket provider
Phase 2: Comments Real-Time (Priority: High)
- [ ] Emit events from CommentService
- [ ] Update Wave view to subscribe to track room
- [ ] Show new comments without refresh
- [ ] Live likes/resolved updates
Phase 3: Notifications (Priority: Medium)
- [ ] Push notifications to user room
- [ ] Update notification bell count instantly
- [ ] Toast for high-priority notifications
Phase 4: Collaboration (Priority: Medium)
- [ ] Collaborator joined/left events
- [ ] Online presence indicator
- [ ] Role change notifications
Phase 5: File Activity (Priority: Low)
- [ ] New file version alerts
- [ ] Playback sync (advanced)
Frontend Integration
tsx
// src/lib/socket-provider.tsx
'use client';
import { io, Socket } from 'socket.io-client';
import { useSession } from 'next-auth/react';
import { createContext, useContext, useEffect, useState } from 'react';
export const SocketContext = createContext<Socket | null>(null);
export function SocketProvider({ children }) {
const { data: session } = useSession();
const [socket, setSocket] = useState<Socket | null>(null);
useEffect(() => {
if (session?.accessToken) {
const newSocket = io(process.env.NEXT_PUBLIC_API_BASE_URL, {
auth: { token: session.accessToken },
});
setSocket(newSocket);
return () => { newSocket.close(); };
}
}, [session]);
return (
<SocketContext.Provider value={socket}>
{children}
</SocketContext.Provider>
);
}User Review Required
IMPORTANT
Decision Needed: Playback sync feature
- Option A: Simple - Users manually sync playhead
- Option B: Real-time - Broadcast playhead position to all viewers (complex, potentially noisy)
NOTE
Scalability: For production with 1000+ concurrent users, consider Redis adapter for Socket.io to share state across multiple backend instances.
Verification Plan
Phase 1 Tests:
- [ ] WebSocket connects with valid JWT
- [ ] Invalid JWT rejected
- [ ] Rooms join/leave correctly
Phase 2 Tests:
- [ ] Create comment → appears in other browser
- [ ] Like comment → owner sees update
- [ ] Resolve comment → all viewers see status change