- Updated docs and inventory files - Added new architecture docs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.9 KiB
6.9 KiB
Mapa de Tracking en Tiempo Real - Documentacion Tecnica
Feature: tracking Sprint: S7 Estado: Funcional (mapas pendientes) Fecha: 2026-01-28
1. Vision General
El sistema de tracking en tiempo real permite:
- Visualizar posicion actual de unidades en mapa
- Ver historial de ruta recorrida
- Monitorear eventos y alertas
- Calcular y mostrar ETA dinamico
- Recibir actualizaciones via WebSocket
2. Arquitectura de Componentes
ViajeTrackingView
├── MapSection (mapa con ruta)
│ ├── RoutePolyline (ruta planificada)
│ ├── HistoryPolyline (ruta recorrida)
│ ├── CurrentPositionMarker
│ ├── OriginMarker
│ └── DestinationMarker
├── ETAProgressBar
│ ├── MilestoneIndicators
│ └── ProgressLine
└── EventTimeline
├── EventCards (17 tipos)
└── TimelineConnector
3. Tipos Principales
3.1 ENUMs
enum TipoEventoTracking {
// GPS
POSICION = 'POSICION',
GPS_POSICION = 'GPS_POSICION',
// Geocercas
GEOCERCA_ENTRADA = 'GEOCERCA_ENTRADA',
GEOCERCA_SALIDA = 'GEOCERCA_SALIDA',
// Flujo de viaje
INICIO_VIAJE = 'INICIO_VIAJE',
ARRIBO_ORIGEN = 'ARRIBO_ORIGEN',
INICIO_CARGA = 'INICIO_CARGA',
FIN_CARGA = 'FIN_CARGA',
SALIDA = 'SALIDA',
ARRIBO_DESTINO = 'ARRIBO_DESTINO',
INICIO_DESCARGA = 'INICIO_DESCARGA',
FIN_DESCARGA = 'FIN_DESCARGA',
ENTREGA_POD = 'ENTREGA_POD',
FIN_VIAJE = 'FIN_VIAJE',
// Incidentes
PARADA = 'PARADA',
DESVIO = 'DESVIO',
INCIDENTE = 'INCIDENTE'
}
enum FuenteEvento {
GPS = 'GPS',
APP_OPERADOR = 'APP_OPERADOR',
SISTEMA = 'SISTEMA',
MANUAL = 'MANUAL',
GEOCERCA = 'GEOCERCA'
}
3.2 Interfaces
interface PosicionActual {
lat: number;
lng: number;
velocidad: number;
rumbo: number;
timestamp: string;
precision: number;
}
interface EventoTracking {
id: string;
viajeId: string;
tipo: TipoEventoTracking;
fuente: FuenteEvento;
timestampEvento: string;
ubicacion: { lat: number; lng: number } | null;
descripcion: string;
metadata: Record<string, unknown>;
}
interface TrackingData {
viajeId: string;
posicionActual: PosicionActual;
rutaPlanificada: [number, number][];
rutaRecorrida: [number, number][];
eventos: EventoTracking[];
eta: {
llegadaEstimada: string;
distanciaRestante: number;
tiempoRestante: string;
};
}
4. WebSocket Integration
4.1 Hook useTrackingWebSocket
// hooks/useTrackingWebSocket.ts
export function useTrackingWebSocket(viajeId: string) {
const [isConnected, setIsConnected] = useState(false);
const [lastPosition, setLastPosition] = useState<PosicionActual | null>(null);
const [eventos, setEventos] = useState<EventoTracking[]>([]);
useEffect(() => {
const ws = new WebSocket(`${WS_URL}/tracking/${viajeId}`);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'position') {
setLastPosition(data.payload);
} else if (data.type === 'event') {
setEventos(prev => [...prev, data.payload]);
}
};
// Auto-reconnect logic included
}, [viajeId]);
return { isConnected, lastPosition, eventos };
}
4.2 Mensajes WebSocket
// Posicion
{
type: 'position',
payload: {
lat: 19.4326,
lng: -99.1332,
velocidad: 85,
rumbo: 45,
timestamp: '2026-01-28T10:30:00Z'
}
}
// Evento
{
type: 'event',
payload: {
id: 'evt-123',
tipo: 'ARRIBO_DESTINO',
fuente: 'GPS',
timestamp: '2026-01-28T10:30:00Z',
descripcion: 'Unidad arribo a destino'
}
}
5. ETAProgressBar Component
5.1 Milestones
const milestones = [
{ id: 'origin', label: 'Origen', icon: 'MapPin' },
{ id: 'loaded', label: 'Cargado', icon: 'Package' },
{ id: 'transit', label: 'En Transito', icon: 'Truck' },
{ id: 'destination', label: 'Destino', icon: 'Flag' },
{ id: 'delivered', label: 'Entregado', icon: 'CheckCircle' }
];
5.2 Progress Calculation
function calculateProgress(eventos: EventoTracking[]): number {
const weights = {
INICIO_VIAJE: 0,
ARRIBO_ORIGEN: 10,
FIN_CARGA: 25,
SALIDA: 30,
EN_TRANSITO: 50, // Interpolado por distancia
ARRIBO_DESTINO: 80,
FIN_DESCARGA: 90,
ENTREGA_POD: 100
};
const lastEvent = eventos[eventos.length - 1];
return weights[lastEvent?.tipo] || 0;
}
6. EventTimeline Component
6.1 Iconos por Tipo
const eventIcons: Record<TipoEventoTracking, React.ComponentType> = {
POSICION: MapPin,
GPS_POSICION: Satellite,
GEOCERCA_ENTRADA: LogIn,
GEOCERCA_SALIDA: LogOut,
INICIO_VIAJE: PlayCircle,
ARRIBO_ORIGEN: MapPin,
INICIO_CARGA: Package,
FIN_CARGA: PackageCheck,
SALIDA: Truck,
ARRIBO_DESTINO: Flag,
INICIO_DESCARGA: PackageOpen,
FIN_DESCARGA: PackageCheck,
ENTREGA_POD: FileCheck,
FIN_VIAJE: CheckCircle,
PARADA: PauseCircle,
DESVIO: AlertTriangle,
INCIDENTE: AlertOctagon
};
6.2 Colores por Tipo
const eventColors: Record<TipoEventoTracking, string> = {
INICIO_VIAJE: 'bg-green-500',
FIN_VIAJE: 'bg-green-600',
INCIDENTE: 'bg-red-500',
PARADA: 'bg-yellow-500',
DESVIO: 'bg-orange-500',
// ... otros
default: 'bg-blue-500'
};
7. API Endpoints
| Endpoint | Metodo | Descripcion |
|---|---|---|
/api/v1/tracking/viajes/:id |
GET | Datos de tracking de viaje |
/api/v1/tracking/viajes/:id/eventos |
GET | Historial de eventos |
/api/v1/tracking/viajes/:id/ruta |
GET | Ruta planificada y recorrida |
/api/v1/gps/posiciones/ultima/:dispositivoId |
GET | Ultima posicion |
WS /tracking/:viajeId |
WS | Streaming de posiciones |
8. Integracion con Mapas (Pendiente)
8.1 Estado Actual
- Mapa placeholder con CSS gradient
- Polylines simplificados con SVG
- Marcadores posicionados con % relativo
8.2 Implementacion con Leaflet
import { MapContainer, Polyline, Marker, Popup } from 'react-leaflet';
const TrackingMap = ({ data }: { data: TrackingData }) => (
<MapContainer center={data.posicionActual} zoom={12}>
<TileLayer url="..." />
{/* Ruta planificada */}
<Polyline
positions={data.rutaPlanificada}
color="blue"
dashArray="5,10"
/>
{/* Ruta recorrida */}
<Polyline
positions={data.rutaRecorrida}
color="green"
weight={4}
/>
{/* Posicion actual */}
<Marker position={[data.posicionActual.lat, data.posicionActual.lng]}>
<Popup>
<span>Velocidad: {data.posicionActual.velocidad} km/h</span>
</Popup>
</Marker>
</MapContainer>
);
9. Performance Considerations
- Throttle WebSocket updates: Maximo 1 update por segundo en UI
- Virtualized EventTimeline: Para viajes con 100+ eventos
- Route simplification: Usar Douglas-Peucker para rutas largas
- Map tile caching: Service worker para tiles frecuentes
Sprint S7 - TASK-007 | Sistema SIMCO v4.0.0