Live Loop is a modern video calling application built with a microservices-inspired architecture. The system uses WebRTC for peer-to-peer video communication, Socket.io for real-time signaling, and Redis for scalable user queue management.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Web Browser │ │ Web Browser │ │ Web Browser │
│ (Client A) │ │ (Client B) │ │ (Client C) │
└─────────┬───────┘ └─────────┬───────┘ └─────────┬───────┘
│ │ │
│ Socket.io │ Socket.io │ Socket.io
│ │ │
┌─────▼──────────────────────▼──────────────────────▼─────┐
│ Load Balancer │
└─────┬───────────────────────────────────────────────────┘
│
┌─────▼─────┐ ┌─────────────┐ ┌─────────────┐
│ Server │ │ Server │ │ Server │
│Instance 1 │ │ Instance 2 │ │ Instance N │
└─────┬─────┘ └─────┬───────┘ └─────┬───────┘
│ │ │
└────────────────┼──────────────────┘
│
┌──────▼──────┐
│ Redis │
│ Cluster │
└─────────────┘
App.jsx
├── NavbarHome.jsx
├── Router Outlet
│ ├── Home.jsx
│ │ ├── HomePageHome.jsx
│ │ ├── SetUpSection.jsx
│ │ └── ContactUsHome.jsx
│ ├── Studio.jsx
│ │ └── StudioHome.jsx
│ └── Call.jsx
│ └── CallPageHome.jsx
│ ├── ChatSection.jsx
│ └── MenuSidebar.jsx
└── Footer.jsx
// Context Providers
SocketContext (Socket.io connection)
├── StreamContext (Media streams & device management)
└── Application ComponentsUser Action → Component State → Context Update → Socket Emission → Server Processing → Socket Event → Context Update → Component Re-render
├── UserService (User management & matchmaking)
├── RoomService (Room creation & management)
├── RedisService (Data persistence & queuing)
└── Event Handlers (Socket.io event processing)
Socket Event → Event Handler → Service Layer → Data Layer → Response/Broadcast
User A Server User B
│ │ │
├─ request-room ─────────▶│ │
│ ├─ Add to queue │
│ │ │
│ │◀─ request-room ─────────┤
│ ├─ Match users │
│ │ │
│◀─ match-done ───────────┤─────── match-done ────▶│
│ │ │
├─ create offer ──────────▶│ │
│ ├─ forward offer ────────▶│
│ │ │
│ │◀─ create answer ───────┤
│◀─ receive answer ───────┤ │
│ │ │
├─ ICE candidates ────────▶│─ forward candidates ──▶│
│◀─ ICE candidates ───────┤◀─ ICE candidates ──────┤
│ │ │
│◀──── P2P Connection ─────────────────────────────▶│
Events/
├── matchmaking.ts
│ ├── request-room
│ ├── stop-call
│ └── disconnect
├── signaling.ts
│ ├── negotiation-call-offer
│ ├── negotiation-call-answer
│ └── send-new-ice-candidates
└── chatEvents.ts
└── newMessage
interface User {
socket: string; // Socket ID
userName: string; // Display name
userImage?: string; // Base64 thumbnail
joinedAt: Date; // Queue join time
}interface Room {
id: string; // Unique room identifier
user1: User; // First user
user2: User; // Second user
createdAt: Date; // Room creation time
status: 'active' | 'ended';
}interface ChatMessage {
from: string; // Sender socket ID
message: string; // Message content
timestamp: Date; // Send time
roomId: string; // Room identifier
}Keys:
├── queue:users # Sorted set of waiting users
├── rooms:{roomId} # Hash of room details
├── user:{socketId} # Hash of user information
└── metrics:daily # Application metrics
// User Queue (Sorted Set)
ZADD queue:users timestamp socketId
// Room Storage (Hash)
HSET rooms:room123 user1 "socketId1" user2 "socketId2" created "timestamp"
// User Data (Hash)
HSET user:socket123 name "John" image "base64..." joined "timestamp"Client Request → CORS Validation → Rate Limiting → Event Processing
// Input validation middleware
const validateMessage = (data) => {
if (!data.message || data.message.length > 1000) {
throw new Error('Invalid message');
}
};- CORS Configuration: Restrict allowed origins
- Rate Limiting: Prevent abuse
- Input Validation: Sanitize user data
- Error Handling: Prevent information leakage
// Code splitting
const CallPage = lazy(() => import('./pages/Call'));
// Memoization
const MemoizedChatMessage = memo(ChatMessage);
// Efficient re-renders
const { userName, isConnected } = useStreamContext();// Connection pooling
const redis = new Redis({
maxRetriesPerRequest: 3,
lazyConnect: true
});
// Event batching
const batchEvents = (events) => {
// Process multiple events together
};// ICE candidate optimization
const pcConfig = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:stun.l.google.com:19301' }
],
iceCandidatePoolSize: 10
};Load Balancer
├── App Server 1 (Socket.io)
├── App Server 2 (Socket.io)
└── App Server N (Socket.io)
│
└── Shared Redis Cluster
// Sticky sessions for Socket.io
const io = new Server(server, {
adapter: require('@socket.io/redis-adapter')(redisClient)
});Redis Cluster
├── Master Node 1 (Read/Write)
├── Master Node 2 (Read/Write)
└── Master Node 3 (Read/Write)
│
├── Slave Node 1 (Read)
├── Slave Node 2 (Read)
└── Slave Node 3 (Read)
// Custom metrics
const metrics = {
activeConnections: 0,
roomsCreated: 0,
messagesExchanged: 0,
connectionFailures: 0
};// Structured logging
const logger = winston.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'app.log' })
]
});// Health endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
services: {
redis: redisClient.status,
memory: process.memoryUsage()
}
});
});1. Network Errors (Connection timeouts)
2. WebRTC Errors (ICE failures)
3. Validation Errors (Invalid input)
4. System Errors (Redis unavailable)
// Centralized error handling
const errorHandler = (error, context) => {
logger.error('Error occurred', { error, context });
if (error.type === 'NETWORK_ERROR') {
// Retry logic
} else if (error.type === 'VALIDATION_ERROR') {
// User notification
}
};GET / # Health check
GET /api/status # System status
POST /api/rooms # Create room (if needed)
// Namespaced events
/matchmaking
├── request-room
└── stop-call
/signaling
├── negotiation-call-offer
├── negotiation-call-answer
└── send-new-ice-candidates
/chat
└── newMessage
Feature-based structure:
├── components/feature/
├── services/feature/
├── utils/feature/
└── types/feature/
Unit Tests (70%)
├── Service layer testing
├── Utility function testing
└── Component testing
Integration Tests (20%)
├── API endpoint testing
├── Socket.io event testing
└── Database integration testing
E2E Tests (10%)
├── User flow testing
├── WebRTC connection testing
└── Cross-browser testing
Developer Machine
├── Frontend (Vite dev server)
├── Backend (Node.js with nodemon)
└── Redis (Local instance)
CDN (Frontend assets)
├── Load Balancer
├── App Server Cluster
├── Redis Cluster
└── Monitoring Stack
Code Push → Tests → Build → Deploy → Health Check → Release
- Video Recording: Store call recordings
- Screen Sharing: WebRTC screen capture
- Group Calls: Multi-user video calls
- Mobile App: React Native implementation
- Analytics: User behavior tracking
- Test Coverage: Increase to 90%+
- Type Safety: Full TypeScript migration
- Performance: Bundle size optimization
- Documentation: API documentation automation
This architecture supports the current feature set while providing flexibility for future enhancements and scale.