Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bookovia.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The WebSocket Real-Time Streaming API provides persistent, low-latency connections for real-time fleet monitoring, live vehicle tracking, instant event notifications, and continuous telemetry streaming. Perfect for building live dashboards, real-time alerts, and responsive fleet management applications.

Authentication

WebSocket connections require authentication via query parameters or initial message:

Query Parameter Authentication

wss://api.bookovia.com/v1/streaming/websocket?api_key=YOUR_API_KEY&fleet_id=fleet_001

Message-Based Authentication

{
  "type": "auth",
  "payload": {
    "api_key": "YOUR_API_KEY",
    "fleet_id": "fleet_001",
    "subscriptions": ["vehicle_locations", "trip_events", "alerts"]
  }
}

Connection Endpoints

Fleet Streaming

wss://api.bookovia.com/v1/streaming/websocket/fleet/{fleet_id}

Vehicle Streaming

wss://api.bookovia.com/v1/streaming/websocket/vehicle/{vehicle_id}

Trip Streaming

wss://api.bookovia.com/v1/streaming/websocket/trip/{trip_id}

Multi-Channel Streaming

wss://api.bookovia.com/v1/streaming/websocket

Subscription Types

TypeDescriptionUpdate Frequency
vehicle_locationsReal-time vehicle GPS positions1-30 seconds
trip_eventsTrip lifecycle events (start, stop, waypoint)Event-driven
alertsSafety alerts and notificationsImmediate
telemetryVehicle diagnostics and sensor data5-60 seconds
fleet_metricsAggregated fleet performance metrics1-5 minutes
driver_statusDriver availability and activityEvent-driven
route_progressRoute execution and ETA updates30-60 seconds
maintenance_alertsVehicle maintenance notificationsEvent-driven

Message Format

Outbound Messages (Client → Server)

{
  "type": "message_type",
  "id": "unique_message_id",
  "timestamp": "2024-03-15T14:30:00Z",
  "payload": {
    "action": "subscribe|unsubscribe|request",
    "data": {}
  }
}

Inbound Messages (Server → Client)

{
  "type": "message_type",
  "id": "correlation_id",
  "timestamp": "2024-03-15T14:30:00Z",
  "channel": "subscription_channel",
  "payload": {
    "event": "event_name",
    "data": {}
  }
}

Real-Time Data Streams

Vehicle Location Updates

{
  "type": "location_update",
  "timestamp": "2024-03-15T14:30:00Z",
  "channel": "vehicle_locations",
  "payload": {
    "vehicle_id": "vehicle_001",
    "trip_id": "trip_12345",
    "location": {
      "latitude": 40.7128,
      "longitude": -74.0060,
      "accuracy": 5.2,
      "altitude": 12.0,
      "heading": 245.5,
      "speed": 35.2
    },
    "telemetry": {
      "fuel_level": 75.5,
      "engine_rpm": 2100,
      "odometer": 45678.2,
      "engine_temp": 92.3
    },
    "driver_status": "driving",
    "route_progress": {
      "distance_completed": 15.3,
      "distance_remaining": 8.7,
      "eta": "2024-03-15T15:15:00Z",
      "next_stop": "dest_003"
    }
  }
}

Trip Events

{
  "type": "trip_event",
  "timestamp": "2024-03-15T14:30:00Z",
  "channel": "trip_events",
  "payload": {
    "event": "waypoint_reached",
    "trip_id": "trip_12345",
    "vehicle_id": "vehicle_001",
    "driver_id": "driver_456",
    "waypoint": {
      "waypoint_id": "dest_002",
      "location": {
        "latitude": 40.7489,
        "longitude": -73.9857,
        "address": "123 Customer St, New York, NY"
      },
      "arrival_time": "2024-03-15T14:30:00Z",
      "planned_time": "2024-03-15T14:25:00Z",
      "delay_minutes": 5,
      "activity_type": "delivery"
    },
    "route_update": {
      "completed_stops": 2,
      "remaining_stops": 6,
      "updated_eta": "2024-03-15T17:45:00Z"
    }
  }
}

Safety Alerts

{
  "type": "safety_alert",
  "timestamp": "2024-03-15T14:30:00Z",
  "channel": "alerts",
  "payload": {
    "alert_id": "alert_789",
    "severity": "high",
    "category": "harsh_braking",
    "vehicle_id": "vehicle_001",
    "driver_id": "driver_456",
    "trip_id": "trip_12345",
    "location": {
      "latitude": 40.7128,
      "longitude": -74.0060,
      "address": "Broadway & 42nd St, New York, NY"
    },
    "event_data": {
      "deceleration": -0.8,
      "speed_before": 45.2,
      "speed_after": 12.1,
      "duration": 2.3
    },
    "recommended_actions": [
      "Review driving behavior with driver",
      "Check vehicle brake system",
      "Monitor future driving patterns"
    ],
    "auto_resolved": false
  }
}

Fleet Metrics

{
  "type": "fleet_metrics",
  "timestamp": "2024-03-15T14:30:00Z",
  "channel": "fleet_metrics",
  "payload": {
    "fleet_id": "fleet_001",
    "metrics": {
      "active_vehicles": 42,
      "total_trips": 67,
      "completed_deliveries": 89,
      "average_speed": 28.5,
      "fuel_efficiency": 12.3,
      "on_time_percentage": 94.2,
      "safety_score": 87.1
    },
    "alerts_summary": {
      "critical": 0,
      "high": 2,
      "medium": 5,
      "low": 12
    },
    "performance_trends": {
      "utilization_trend": "+2.3%",
      "efficiency_trend": "+1.8%",
      "safety_trend": "-0.5%"
    }
  }
}

Client Implementation Examples

class BookoviaWebSocket {
  constructor(apiKey, fleetId) {
    this.apiKey = apiKey;
    this.fleetId = fleetId;
    this.ws = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.subscriptions = new Set();
    this.messageHandlers = new Map();
  }

  connect() {
    const wsUrl = `wss://api.bookovia.com/v1/streaming/websocket?api_key=${this.apiKey}&fleet_id=${this.fleetId}`;
    
    this.ws = new WebSocket(wsUrl);
    
    this.ws.onopen = () => {
      console.log('WebSocket connected');
      this.reconnectAttempts = 0;
      this.authenticate();
      this.resubscribeAll();
    };
    
    this.ws.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data);
        this.handleMessage(message);
      } catch (error) {
        console.error('Failed to parse message:', error);
      }
    };
    
    this.ws.onclose = (event) => {
      console.log('WebSocket disconnected:', event.code, event.reason);
      this.handleDisconnect();
    };
    
    this.ws.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
  }

  authenticate() {
    this.send({
      type: 'auth',
      payload: {
        api_key: this.apiKey,
        fleet_id: this.fleetId
      }
    });
  }

  subscribe(channel, handler) {
    this.subscriptions.add(channel);
    this.messageHandlers.set(channel, handler);
    
    if (this.isConnected()) {
      this.send({
        type: 'subscribe',
        payload: {
          action: 'subscribe',
          channel: channel
        }
      });
    }
  }

  unsubscribe(channel) {
    this.subscriptions.delete(channel);
    this.messageHandlers.delete(channel);
    
    if (this.isConnected()) {
      this.send({
        type: 'subscribe',
        payload: {
          action: 'unsubscribe',
          channel: channel
        }
      });
    }
  }

  send(message) {
    if (this.isConnected()) {
      message.id = this.generateMessageId();
      message.timestamp = new Date().toISOString();
      this.ws.send(JSON.stringify(message));
    } else {
      console.warn('WebSocket not connected, message queued');
    }
  }

  handleMessage(message) {
    const handler = this.messageHandlers.get(message.channel);
    if (handler) {
      handler(message.payload);
    }
    
    // Handle system messages
    switch (message.type) {
      case 'auth_success':
        console.log('Authentication successful');
        break;
      case 'auth_error':
        console.error('Authentication failed:', message.payload);
        break;
      case 'error':
        console.error('Server error:', message.payload);
        break;
    }
  }

  handleDisconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      const delay = Math.pow(2, this.reconnectAttempts) * 1000; // Exponential backoff
      console.log(`Reconnecting in ${delay}ms...`);
      
      setTimeout(() => {
        this.reconnectAttempts++;
        this.connect();
      }, delay);
    } else {
      console.error('Max reconnection attempts reached');
    }
  }

  resubscribeAll() {
    for (const channel of this.subscriptions) {
      this.send({
        type: 'subscribe',
        payload: {
          action: 'subscribe',
          channel: channel
        }
      });
    }
  }

  isConnected() {
    return this.ws && this.ws.readyState === WebSocket.OPEN;
  }

  generateMessageId() {
    return Math.random().toString(36).substr(2, 9);
  }

  disconnect() {
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }
}

// Usage example
const wsClient = new BookoviaWebSocket('your-api-key', 'fleet_001');

// Connect
wsClient.connect();

// Subscribe to vehicle locations
wsClient.subscribe('vehicle_locations', (data) => {
  console.log('Vehicle location update:', data);
  updateVehicleOnMap(data.vehicle_id, data.location);
});

// Subscribe to trip events
wsClient.subscribe('trip_events', (data) => {
  console.log('Trip event:', data);
  updateTripStatus(data.trip_id, data.event);
});

// Subscribe to alerts
wsClient.subscribe('alerts', (data) => {
  console.log('Alert received:', data);
  if (data.severity === 'high' || data.severity === 'critical') {
    showNotification(data);
  }
});

// Subscribe to fleet metrics
wsClient.subscribe('fleet_metrics', (data) => {
  console.log('Fleet metrics:', data);
  updateDashboard(data.metrics);
});

function updateVehicleOnMap(vehicleId, location) {
  // Update vehicle position on map
  const marker = vehicleMarkers[vehicleId];
  if (marker) {
    marker.setPosition(new google.maps.LatLng(location.latitude, location.longitude));
  }
}

function updateTripStatus(tripId, event) {
  // Update trip status in UI
  const tripElement = document.getElementById(`trip-${tripId}`);
  if (tripElement) {
    tripElement.textContent = `Status: ${event}`;
  }
}

function showNotification(alert) {
  // Show high-priority alert notification
  new Notification(`${alert.category} Alert`, {
    body: `Vehicle ${alert.vehicle_id}: ${alert.category}`,
    icon: '/icons/alert.png'
  });
}

function updateDashboard(metrics) {
  // Update dashboard metrics
  document.getElementById('active-vehicles').textContent = metrics.active_vehicles;
  document.getElementById('on-time-rate').textContent = `${metrics.on_time_percentage}%`;
  document.getElementById('safety-score').textContent = metrics.safety_score;
}

Use Cases

Real-Time Fleet Dashboard

Build live dashboards with real-time vehicle tracking and fleet metrics.
class FleetDashboard {
  constructor(apiKey, fleetId) {
    this.wsClient = new BookoviaWebSocket(apiKey, fleetId);
    this.vehicles = new Map();
    this.metrics = {};
    
    this.initializeSubscriptions();
    this.setupUI();
  }
  
  initializeSubscriptions() {
    // Vehicle tracking
    this.wsClient.subscribe('vehicle_locations', (data) => {
      this.updateVehiclePosition(data);
    });
    
    // Fleet metrics
    this.wsClient.subscribe('fleet_metrics', (data) => {
      this.updateFleetMetrics(data.metrics);
    });
    
    // Trip events
    this.wsClient.subscribe('trip_events', (data) => {
      this.handleTripEvent(data);
    });
    
    // Safety alerts
    this.wsClient.subscribe('alerts', (data) => {
      this.handleSafetyAlert(data);
    });
  }
  
  updateVehiclePosition(data) {
    const { vehicle_id, location, telemetry, route_progress } = data;
    
    // Update vehicle marker on map
    const marker = this.getVehicleMarker(vehicle_id);
    marker.setPosition({
      lat: location.latitude,
      lng: location.longitude
    });
    
    // Update vehicle info panel
    this.updateVehicleInfo(vehicle_id, {
      location,
      telemetry,
      route_progress
    });
    
    // Store vehicle data
    this.vehicles.set(vehicle_id, data);
  }
  
  updateFleetMetrics(metrics) {
    this.metrics = metrics;
    
    // Update dashboard widgets
    document.getElementById('active-vehicles').textContent = metrics.active_vehicles;
    document.getElementById('total-trips').textContent = metrics.total_trips;
    document.getElementById('on-time-rate').textContent = `${metrics.on_time_percentage}%`;
    document.getElementById('safety-score').textContent = metrics.safety_score;
    
    // Update progress bars
    this.updateProgressBar('utilization', metrics.active_vehicles / 50 * 100);
    this.updateProgressBar('safety', metrics.safety_score);
  }
  
  handleTripEvent(data) {
    const { event, trip_id, vehicle_id } = data;
    
    // Update trip status in UI
    const tripElement = document.querySelector(`[data-trip-id="${trip_id}"]`);
    if (tripElement) {
      tripElement.querySelector('.status').textContent = event;
      tripElement.classList.add('updated');
      
      setTimeout(() => {
        tripElement.classList.remove('updated');
      }, 2000);
    }
    
    // Show notification for important events
    if (['trip_started', 'trip_completed', 'waypoint_reached'].includes(event)) {
      this.showNotification(`${event.replace('_', ' ')}: Trip ${trip_id}`, 'info');
    }
  }
  
  handleSafetyAlert(data) {
    const { alert_id, severity, category, vehicle_id, location } = data;
    
    // Add alert to alerts panel
    this.addAlertToPanel(data);
    
    // Show immediate notification for high-priority alerts
    if (severity === 'high' || severity === 'critical') {
      this.showNotification(
        `${category} alert for vehicle ${vehicle_id}`,
        'error'
      );
      
      // Flash vehicle marker
      this.flashVehicleMarker(vehicle_id);
      
      // Play alert sound
      this.playAlertSound(severity);
    }
  }
}

Live Vehicle Tracking

Implement real-time vehicle tracking with route visualization.
class LiveVehicleTracker:
    def __init__(self, api_key: str, fleet_id: str):
        self.ws_client = BookoviaWebSocketClient(api_key, fleet_id)
        self.vehicle_positions = {}
        self.route_traces = {}
        
    async def start_tracking(self):
        """Start live vehicle tracking"""
        await self.ws_client.subscribe('vehicle_locations', self.handle_location_update)
        await self.ws_client.subscribe('trip_events', self.handle_trip_event)
        await self.ws_client.connect()
    
    async def handle_location_update(self, data):
        """Handle real-time location updates"""
        vehicle_id = data['vehicle_id']
        location = data['location']
        
        # Update vehicle position
        self.vehicle_positions[vehicle_id] = {
            'latitude': location['latitude'],
            'longitude': location['longitude'],
            'heading': location['heading'],
            'speed': location['speed'],
            'timestamp': data.get('timestamp')
        }
        
        # Add point to route trace
        if vehicle_id not in self.route_traces:
            self.route_traces[vehicle_id] = []
            
        self.route_traces[vehicle_id].append({
            'lat': location['latitude'],
            'lng': location['longitude'],
            'timestamp': data.get('timestamp')
        })
        
        # Limit trace length (keep last 100 points)
        if len(self.route_traces[vehicle_id]) > 100:
            self.route_traces[vehicle_id] = self.route_traces[vehicle_id][-100:]
        
        # Update route progress if available
        if 'route_progress' in data:
            await self.update_route_progress(vehicle_id, data['route_progress'])
        
        # Emit update event
        await self.emit_position_update(vehicle_id, data)
    
    async def handle_trip_event(self, data):
        """Handle trip lifecycle events"""
        trip_id = data['trip_id']
        vehicle_id = data['vehicle_id']
        event = data['event']
        
        if event == 'trip_started':
            # Initialize new route trace
            self.route_traces[vehicle_id] = []
            await self.emit_trip_started(trip_id, vehicle_id)
            
        elif event == 'trip_completed':
            # Save route trace
            await self.save_route_trace(trip_id, vehicle_id)
            await self.emit_trip_completed(trip_id, vehicle_id)
            
        elif event == 'waypoint_reached':
            waypoint = data.get('waypoint', {})
            await self.emit_waypoint_reached(trip_id, vehicle_id, waypoint)
    
    async def update_route_progress(self, vehicle_id: str, route_progress: dict):
        """Update route progress visualization"""
        progress_data = {
            'vehicle_id': vehicle_id,
            'distance_completed': route_progress['distance_completed'],
            'distance_remaining': route_progress['distance_remaining'],
            'eta': route_progress['eta'],
            'next_stop': route_progress['next_stop'],
            'completion_percentage': (
                route_progress['distance_completed'] / 
                (route_progress['distance_completed'] + route_progress['distance_remaining']) * 100
            )
        }
        
        await self.emit_progress_update(progress_data)
    
    async def get_vehicle_status(self, vehicle_id: str) -> dict:
        """Get current vehicle status"""
        position = self.vehicle_positions.get(vehicle_id)
        trace = self.route_traces.get(vehicle_id, [])
        
        if not position:
            return {'status': 'unknown', 'message': 'No recent location data'}
        
        # Determine status based on movement and time
        last_update = position.get('timestamp')
        current_speed = position.get('speed', 0)
        
        if current_speed > 5:  # Moving
            status = 'moving'
        elif current_speed == 0:  # Stopped
            status = 'stopped'
        else:
            status = 'idle'
        
        return {
            'status': status,
            'position': position,
            'route_trace': trace,
            'trace_length': len(trace)
        }
    
    async def emit_position_update(self, vehicle_id: str, data: dict):
        """Emit position update event (implement based on your event system)"""
        # Implementation depends on your event system (WebSocket, message queue, etc.)
        pass
    
    async def emit_trip_started(self, trip_id: str, vehicle_id: str):
        """Emit trip started event"""
        pass
    
    async def emit_trip_completed(self, trip_id: str, vehicle_id: str):
        """Emit trip completed event"""
        pass
    
    async def emit_waypoint_reached(self, trip_id: str, vehicle_id: str, waypoint: dict):
        """Emit waypoint reached event"""
        pass
    
    async def emit_progress_update(self, progress_data: dict):
        """Emit route progress update event"""
        pass
    
    async def save_route_trace(self, trip_id: str, vehicle_id: str):
        """Save route trace to database"""
        trace = self.route_traces.get(vehicle_id, [])
        if trace:
            # Save to database or file system
            print(f"Saving route trace for trip {trip_id}: {len(trace)} points")

Alert Management System

Implement comprehensive alert handling with escalation and notification rules.
type AlertManager struct {
    wsClient        *WebSocketClient
    alertRules      map[string]AlertRule
    notificationSvc NotificationService
    escalationSvc   EscalationService
    alertHistory    []Alert
    mutex           sync.RWMutex
}

type AlertRule struct {
    Severity        string                 `json:"severity"`
    Category        string                 `json:"category"`
    NotifyChannels  []string               `json:"notify_channels"`
    EscalationDelay time.Duration          `json:"escalation_delay"`
    AutoResolve     bool                   `json:"auto_resolve"`
    Actions         []string               `json:"actions"`
}

type Alert struct {
    ID              string                 `json:"id"`
    Timestamp       time.Time              `json:"timestamp"`
    Severity        string                 `json:"severity"`
    Category        string                 `json:"category"`
    VehicleID       string                 `json:"vehicle_id"`
    DriverID        string                 `json:"driver_id"`
    Location        map[string]interface{} `json:"location"`
    Data            map[string]interface{} `json:"data"`
    Status          string                 `json:"status"`
    Acknowledged    bool                   `json:"acknowledged"`
    AcknowledgedBy  string                 `json:"acknowledged_by"`
    ResolvedAt      *time.Time             `json:"resolved_at"`
}

func NewAlertManager(wsClient *WebSocketClient) *AlertManager {
    return &AlertManager{
        wsClient:     wsClient,
        alertRules:   make(map[string]AlertRule),
        alertHistory: make([]Alert, 0),
    }
}

func (am *AlertManager) Initialize() error {
    // Load alert rules
    am.loadAlertRules()
    
    // Subscribe to alerts
    return am.wsClient.Subscribe("alerts", am.handleAlert)
}

func (am *AlertManager) loadAlertRules() {
    // Critical safety alerts
    am.alertRules["harsh_braking"] = AlertRule{
        Severity:        "high",
        Category:        "safety",
        NotifyChannels:  []string{"sms", "email", "push"},
        EscalationDelay: 5 * time.Minute,
        AutoResolve:     false,
        Actions:         []string{"driver_notification", "manager_alert"},
    }
    
    am.alertRules["collision_risk"] = AlertRule{
        Severity:        "critical",
        Category:        "safety",
        NotifyChannels:  []string{"sms", "email", "push", "phone_call"},
        EscalationDelay: 2 * time.Minute,
        AutoResolve:     false,
        Actions:         []string{"emergency_contact", "dispatch_supervisor"},
    }
    
    am.alertRules["vehicle_breakdown"] = AlertRule{
        Severity:        "high",
        Category:        "maintenance",
        NotifyChannels:  []string{"email", "push"},
        EscalationDelay: 10 * time.Minute,
        AutoResolve:     false,
        Actions:         []string{"maintenance_team", "roadside_assistance"},
    }
    
    am.alertRules["route_deviation"] = AlertRule{
        Severity:        "medium",
        Category:        "operational",
        NotifyChannels:  []string{"push"},
        EscalationDelay: 15 * time.Minute,
        AutoResolve:     true,
        Actions:         []string{"route_optimization"},
    }
}

func (am *AlertManager) handleAlert(payload map[string]interface{}) error {
    alert := am.parseAlert(payload)
    
    // Store alert
    am.mutex.Lock()
    am.alertHistory = append(am.alertHistory, alert)
    am.mutex.Unlock()
    
    // Apply alert rule
    rule, exists := am.alertRules[alert.Category]
    if !exists {
        // Use default rule
        rule = am.getDefaultRule(alert.Severity)
    }
    
    // Process alert
    go am.processAlert(alert, rule)
    
    return nil
}

func (am *AlertManager) processAlert(alert Alert, rule AlertRule) {
    log.Printf("Processing alert: %s - %s - %s", alert.ID, alert.Category, alert.Severity)
    
    // Send immediate notifications
    for _, channel := range rule.NotifyChannels {
        am.sendNotification(alert, channel)
    }
    
    // Execute automated actions
    for _, action := range rule.Actions {
        am.executeAction(alert, action)
    }
    
    // Set up escalation timer
    if rule.EscalationDelay > 0 {
        time.AfterFunc(rule.EscalationDelay, func() {
            am.checkEscalation(alert.ID)
        })
    }
    
    // Set up auto-resolution timer
    if rule.AutoResolve {
        time.AfterFunc(30*time.Minute, func() {
            am.autoResolveAlert(alert.ID)
        })
    }
}

func (am *AlertManager) sendNotification(alert Alert, channel string) {
    message := am.formatAlertMessage(alert)
    
    switch channel {
    case "sms":
        am.notificationSvc.SendSMS(am.getContactsForAlert(alert), message)
    case "email":
        am.notificationSvc.SendEmail(am.getContactsForAlert(alert), "Fleet Alert", message)
    case "push":
        am.notificationSvc.SendPushNotification(message, alert.Severity)
    case "phone_call":
        am.notificationSvc.MakeEmergencyCall(am.getEmergencyContacts(alert), message)
    }
}

func (am *AlertManager) executeAction(alert Alert, action string) {
    switch action {
    case "driver_notification":
        am.sendDriverNotification(alert.DriverID, alert)
    case "manager_alert":
        am.alertManager(alert)
    case "emergency_contact":
        am.contactEmergencyServices(alert)
    case "dispatch_supervisor":
        am.dispatchSupervisor(alert)
    case "maintenance_team":
        am.alertMaintenanceTeam(alert)
    case "roadside_assistance":
        am.requestRoadsideAssistance(alert)
    case "route_optimization":
        am.triggerRouteOptimization(alert.VehicleID)
    }
}

func (am *AlertManager) checkEscalation(alertID string) {
    am.mutex.RLock()
    var alert *Alert
    for i := range am.alertHistory {
        if am.alertHistory[i].ID == alertID {
            alert = &am.alertHistory[i]
            break
        }
    }
    am.mutex.RUnlock()
    
    if alert != nil && !alert.Acknowledged && alert.Status == "active" {
        log.Printf("Escalating alert: %s", alertID)
        am.escalateAlert(*alert)
    }
}

func (am *AlertManager) escalateAlert(alert Alert) {
    // Escalate to next level
    supervisorContacts := am.getSupervisorContacts()
    message := fmt.Sprintf("ESCALATED ALERT: %s - %s\nOriginal time: %s\nVehicle: %s",
        alert.Category, alert.Severity, alert.Timestamp.Format(time.RFC3339), alert.VehicleID)
    
    am.notificationSvc.SendEmail(supervisorContacts, "Escalated Fleet Alert", message)
    am.notificationSvc.SendSMS(supervisorContacts, message)
}

func (am *AlertManager) AcknowledgeAlert(alertID, acknowledgedBy string) error {
    am.mutex.Lock()
    defer am.mutex.Unlock()
    
    for i := range am.alertHistory {
        if am.alertHistory[i].ID == alertID {
            am.alertHistory[i].Acknowledged = true
            am.alertHistory[i].AcknowledgedBy = acknowledgedBy
            log.Printf("Alert %s acknowledged by %s", alertID, acknowledgedBy)
            return nil
        }
    }
    
    return fmt.Errorf("alert not found: %s", alertID)
}

func (am *AlertManager) ResolveAlert(alertID, resolvedBy string) error {
    am.mutex.Lock()
    defer am.mutex.Unlock()
    
    for i := range am.alertHistory {
        if am.alertHistory[i].ID == alertID {
            now := time.Now()
            am.alertHistory[i].Status = "resolved"
            am.alertHistory[i].ResolvedAt = &now
            log.Printf("Alert %s resolved by %s", alertID, resolvedBy)
            return nil
        }
    }
    
    return fmt.Errorf("alert not found: %s", alertID)
}

// Utility functions (implement based on your notification system)
func (am *AlertManager) parseAlert(payload map[string]interface{}) Alert {
    // Parse WebSocket payload into Alert struct
    return Alert{} // Implementation needed
}

func (am *AlertManager) formatAlertMessage(alert Alert) string {
    return fmt.Sprintf("🚨 %s Alert: %s\nVehicle: %s\nTime: %s",
        strings.ToUpper(alert.Severity), alert.Category, alert.VehicleID, alert.Timestamp.Format(time.RFC3339))
}

func (am *AlertManager) getContactsForAlert(alert Alert) []string {
    // Return contact list based on alert and organizational structure
    return []string{}
}

func (am *AlertManager) getEmergencyContacts(alert Alert) []string {
    // Return emergency contact list
    return []string{}
}

Best Practices

Connection Management

  • Implement exponential backoff for reconnection attempts
  • Handle authentication errors gracefully
  • Monitor connection health with periodic heartbeats
  • Use connection pooling for high-volume applications

Message Handling

  • Implement message deduplication using message IDs
  • Handle out-of-order messages appropriately
  • Use structured error handling for malformed messages
  • Implement message acknowledgment for critical events

Performance Optimization

  • Subscribe only to necessary channels to reduce bandwidth
  • Implement client-side message buffering for high-frequency updates
  • Use compression for large message payloads
  • Batch updates when possible to improve UI performance

Error Recovery

  • Implement graceful degradation when WebSocket is unavailable
  • Cache critical data locally for offline scenarios
  • Provide fallback mechanisms (HTTP polling) when needed
  • Log connection issues for troubleshooting

Related Endpoints

Explore other real-time capabilities: