WebSocket Integration Layer
This document describes the WebSocket integration for the Analytics Dashboard.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Analytics Dashboard (Frontend) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ useWebSocket │────▶│ WebSocket │────▶│ Zustand │ │
│ │ Hook │ │ Service │ │ Store │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
│ │ │ │ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Connection │ │ Event │ │ React │ │
│ │ Status │ │ Handlers │ │ Components │ │
│ └──────────────┘ └──────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
│
│ WebSocket (ws://localhost:3456)
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Analytics Daemon (Backend) │
│ packages/analytics-daemon │
└─────────────────────────────────────────────────────────────┘
Components
1. Types (src/types/analytics.ts)
Defines all event types and connection states:
AnalyticsEvent: Union type of all possible events
plugin.activation: Plugin activatedskill.trigger: Agent skill triggeredllm.call: LLM API calledcost.update: Cost calculation updatedrate_limit.warning: Rate limit warningconversation.created: New conversationconversation.updated: Conversation modifiedserver.connected: Welcome message from server
ConnectionStatus:
'connecting' | 'connected' | 'disconnected'
2. WebSocket Service (src/services/websocket.ts)
Low-level WebSocket connection management:
Features:
- Automatic reconnection with configurable delay (default: 3 seconds)
- Infinite retry attempts (configurable)
- Event-based architecture with handlers
- Connection lifecycle management
Key Methods:
connect(): void // Connect to WebSocket server
disconnect(): void // Disconnect and stop reconnection
onEvent(handler): () => void // Subscribe to events (returns unsubscribe)
onStatusChange(handler): () => void // Subscribe to status changes
onError(handler): () => void // Subscribe to errors
getStatus(): ConnectionStatus // Get current connection status
Configuration:
const service = new WebSocketService({
url: 'ws://localhost:3456',
reconnectDelay: 3000, // 3 seconds
maxReconnectAttempts: Infinity // Unlimited retries
});
3. Zustand Store (src/store/analyticsStore.ts)
Global state management for analytics data:
State:
interface AnalyticsState {
// Connection
connectionStatus: ConnectionStatus;
lastEventTimestamp: number | null;
// Events
events: AnalyticsEvent[];
maxEvents: number; // Default: 1000
// Metrics
pluginActivations: Map<string, number>;
skillTriggers: Map<string, number>;
totalCost: number;
// Actions
setConnectionStatus(status): void;
addEvent(event): void;
clearEvents(): void;
getEventsByType(type): AnalyticsEvent[];
}
Usage:
import { useAnalyticsStore } from './store/analyticsStore';
const MyComponent = () => {
const connectionStatus = useAnalyticsStore((state) => state.connectionStatus);
const events = useAnalyticsStore((state) => state.events);
const { addEvent } = useAnalyticsStore();
// Component logic...
};
4. useWebSocket Hook (src/hooks/useWebSocket.ts)
React hook for WebSocket integration:
Features:
- Automatic connection on mount
- Cleanup on unmount
- Integration with Zustand store
- Error handling
Usage:
import { useWebSocket } from './hooks';
const MyComponent = () => {
const { status, lastEventTimestamp } = useWebSocket();
return (
<div>
<p>Status: {status}</p>
<p>Last event: {lastEventTimestamp}</p>
</div>
);
};
Lifecycle:
- On mount: Creates WebSocketService instance
- Connects to
ws://localhost:3456 - Subscribes to events → calls
addEvent()in store - Subscribes to status changes → calls
setConnectionStatus()in store - On unmount: Unsubscribes all handlers and disconnects
5. ConnectionStatus Component (src/components/shared/ConnectionStatus.tsx)
Visual connection indicator:
Features:
- Fixed position (top-right corner)
- Color-coded status:
- Green: Connected (with pulse animation)
- Yellow: Connecting (with pulse animation)
- Red: Disconnected (no animation)
- Shows last event timestamp
- Responsive design
- Dark mode support
Display Logic:
if (diff < 1s) → "Just now"
if (diff < 60s) → "Xs ago"
if (diff < 3600s) → "Xm ago"
else → HH:MM:SS
6. ErrorBoundary Component (src/components/shared/ErrorBoundary.tsx)
React error boundary for graceful error handling:
Features:
- Catches React errors during render
- Displays user-friendly error messages
- Shows error details and component stack
- Provides "Try Again" and "Reload Page" buttons
- Troubleshooting tips for common issues
- Dark mode support
Usage:
<ErrorBoundary>
<App />
</ErrorBoundary>
Event Flow
1. Backend broadcasts event
↓
2. WebSocket.onmessage fires
↓
3. JSON.parse(event.data)
↓
4. WebSocketService.handleEvent()
↓
5. Calls all registered event handlers
↓
6. useWebSocket hook's event handler
↓
7. analyticsStore.addEvent()
↓
8. State updated, React components re-render
Auto-Reconnect Logic
1. Connection lost (network error, server restart)
↓
2. ws.onclose fires
↓
3. Check if manual close (isManualClose)
↓
4. If NOT manual: scheduleReconnect()
↓
5. Wait reconnectDelay (3 seconds)
↓
6. Attempt reconnect
↓
7. On success: Reset reconnectAttempts to 0
↓
8. On failure: Increment reconnectAttempts, repeat from step 5
Connection States
Connecting
status = 'connecting'
- Yellow indicator with pulse
- "Connecting..." text
- Attempting to establish connection
Connected
status = 'connected'
- Green indicator with pulse
- "Connected" text
- Ready to receive events
Disconnected
status = 'disconnected'
- Red indicator (no pulse)
- "Disconnected" text
- Will auto-reconnect unless manually closed
Testing
1. Start Backend Server
cd packages/analytics-daemon
pnpm build
pnpm start
Expected output:
Analytics server listening on ws://localhost:3456
2. Start Frontend
cd packages/analytics-dashboard
pnpm dev
Expected output:
VITE v6.0.11 ready in X ms
Local: http://localhost:5173/
3. Test Connection
Open browser to http://localhost:5173/
Console logs (should see):
[useWebSocket] Connecting to ws://localhost:3456
WebSocket connected to ws://localhost:3456
[useWebSocket] Status changed: connected
UI should show:
- Green connection indicator (top-right)
- "Connected" status
- "Waiting for events..." message
4. Test Event Reception
Trigger a test event from backend:
# In analytics-daemon directory
pnpm test:event
Console logs (should see):
Received event: plugin.activation { ... }
[useWebSocket] Event received: plugin.activation
UI should update:
- Last event timestamp updates
- Event appears in "Recent Events" list
- Metrics update accordingly
5. Test Auto-Reconnect
- Stop backend server (Ctrl+C)
- Observe UI:
- Status changes to "disconnected" (red)
- Console shows reconnection attempts
- Restart backend server
- Observe UI:
- Status changes to "connected" (green)
- Console shows successful reconnection
Error Handling
Network Errors
- Caught in
ws.onerror - Triggers auto-reconnect
- Logged to console
JSON Parse Errors
- Caught in
ws.onmessage - Invalid JSON logged to console
- Connection remains active
React Errors
- Caught by ErrorBoundary
- Displays user-friendly error UI
- Provides recovery options
Configuration
WebSocket URL
Default: ws://localhost:3456
To change:
// src/hooks/useWebSocket.ts
const WS_URL = 'ws://your-server:port';
Reconnect Settings
// src/hooks/useWebSocket.ts
const service = new WebSocketService({
url: WS_URL,
reconnectDelay: 3000, // Milliseconds between retries
maxReconnectAttempts: Infinity // Max retry attempts
});
Event Storage
// src/store/analyticsStore.ts
maxEvents: 1000 // Keep last 1000 events in memory
Completion Criteria
All criteria have been met:
- WebSocket connects to ws://localhost:3456
- Connection status displays in UI (ConnectionStatus component)
- Events logged to console when received
- Auto-reconnect works after disconnect (3-second delay)
- Error states handled gracefully (ErrorBoundary)
Files Created
packages/analytics-dashboard/
├── src/
│ ├── types/
│ │ ├── analytics.ts # Event types and interfaces
│ │ └── index.ts # Type exports
│ ├── services/
│ │ ├── websocket.ts # WebSocket service layer
│ │ └── index.ts # Service exports
│ ├── store/
│ │ └── analyticsStore.ts # Zustand state management
│ ├── hooks/
│ │ ├── useWebSocket.ts # WebSocket React hook
│ │ └── index.ts # Hook exports
│ ├── components/
│ │ └── shared/
│ │ ├── ConnectionStatus.tsx # Connection indicator
│ │ ├── ErrorBoundary.tsx # Error boundary
│ │ └── index.ts # Component exports
│ ├── App.tsx # Main app component (with test UI)
│ ├── main.tsx # Entry point
│ └── index.css # Global styles
├── index.html # HTML template
└── WEBSOCKET-INTEGRATION.md # This document
Next Steps
Integration with Metrics Components: The WebSocket layer is now ready to be consumed by the metrics dashboard components (ActiveSessionsCard, CostTrackerCard, etc.)
Backend Event Generation: Implement conversation file watching and event emission in analytics-daemon
Advanced Features:
- Event filtering and search
- Historical data persistence
- Export analytics data
- Custom event subscriptions
- Real-time charts and graphs