# Arquitectura del Modulo GPS - ERP Transportistas **Sistema:** SIMCO v4.0.0 **Modulo:** GPS (backend/src/modules/gps) **Sprint:** S1 **Version:** 1.0.0 **Fecha:** 2026-01-28 --- ## 1. Vision General El modulo GPS proporciona capacidades de rastreo vehicular en tiempo real para la flota de transporte, incluyendo: - Gestion de dispositivos GPS - Captura y almacenamiento de posiciones - Definicion y monitoreo de geocercas - Generacion de eventos por entrada/salida de geocercas - Segmentacion de rutas para analisis --- ## 2. Arquitectura de Componentes ``` GPS Module ├── Entities │ ├── DispositivoGps # Dispositivos de rastreo │ ├── PosicionGps # Posiciones historicas │ ├── Geocerca # Zonas geograficas │ ├── EventoGeocerca # Eventos entrada/salida │ └── SegmentoRuta # Segmentos de viaje ├── Services │ ├── DispositivoGpsService # CRUD dispositivos │ ├── PosicionGpsService # Captura posiciones │ ├── GeocercaService # CRUD geocercas │ └── SegmentoRutaService # Analisis de rutas └── Controllers ├── DispositivoGpsController ├── PosicionGpsController ├── GeocercaController └── SegmentoRutaController ``` --- ## 3. Modelo de Datos ### 3.1 DispositivoGps ```typescript @Entity('dispositivos_gps', { schema: 'tracking' }) class DispositivoGps { @PrimaryGeneratedColumn('uuid') id: string; @Column() tenantId: string; @Column() imei: string; // Identificador unico @Column() marca: string; @Column() modelo: string; @Column({ enum: TipoDispositivo }) tipo: TipoDispositivo; // FIJO | PORTATIL | OBD @Column({ enum: EstadoDispositivo }) estado: EstadoDispositivo; // ACTIVO | INACTIVO | MANTENIMIENTO @ManyToOne(() => Unidad) unidad: Unidad; // Unidad asignada @Column() ultimaPosicionLat: number; @Column() ultimaPosicionLng: number; @Column() ultimoReporte: Date; } ``` ### 3.2 PosicionGps ```typescript @Entity('posiciones_gps', { schema: 'tracking' }) class PosicionGps { @PrimaryGeneratedColumn('uuid') id: string; @Column() tenantId: string; @ManyToOne(() => DispositivoGps) dispositivo: DispositivoGps; @Column('decimal') latitud: number; @Column('decimal') longitud: number; @Column('decimal') velocidad: number; // km/h @Column('decimal') rumbo: number; // 0-360 grados @Column('decimal') altitud: number; // metros @Column('decimal') precision: number; // metros @Column() timestampDispositivo: Date; // Hora del GPS @Column() timestampServidor: Date; // Hora de recepcion } ``` ### 3.3 Geocerca ```typescript @Entity('geocercas', { schema: 'tracking' }) class Geocerca { @PrimaryGeneratedColumn('uuid') id: string; @Column() tenantId: string; @Column() nombre: string; @Column({ enum: TipoGeocerca }) tipo: TipoGeocerca; // CLIENTE | PROVEEDOR | ZONA_RIESGO | etc. @Column('decimal') centroLat: number; @Column('decimal') centroLng: number; @Column('decimal') radioMetros: number; // Para geocercas circulares @Column('jsonb') geometria: GeoJSON; // Para geocercas poligonales @Column() alertaEntrada: boolean; @Column() alertaSalida: boolean; @Column() activa: boolean; } ``` --- ## 4. Flujo de Datos ### 4.1 Captura de Posiciones ``` ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Dispositivo │────>│ Gateway │────>│ Backend │ │ GPS │ │ (protocolo) │ │ API REST │ └─────────────┘ └─────────────┘ └─────────────┘ │ ┌──────────────────────────┼──────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Validar │ │ Guardar │ │ Verificar │ │ Posicion │ │ en BD │ │ Geocercas │ └─────────────┘ └─────────────┘ └─────────────┘ │ ▼ ┌─────────────┐ │ Generar │ │ Eventos │ └─────────────┘ ``` ### 4.2 Procesamiento Batch ```typescript // PosicionGpsService.createBatch() async createBatch(posiciones: CreatePosicionDto[]): Promise { // 1. Validar formato de datos const valid = posiciones.filter(p => this.isValidPosition(p)); // 2. Insertar en batch await this.posicionRepo.insert(valid); // 3. Actualizar ultima posicion del dispositivo const byDevice = groupBy(valid, 'dispositivoId'); for (const [deviceId, positions] of Object.entries(byDevice)) { const latest = maxBy(positions, 'timestampDispositivo'); await this.dispositivoService.updateLastPosition(deviceId, latest); } // 4. Verificar geocercas para cada posicion for (const pos of valid) { await this.geocercaService.checkGeofences(pos); } } ``` --- ## 5. Geocercas ### 5.1 Tipos de Geocerca | Tipo | Uso | Alertas Tipicas | |------|-----|-----------------| | CLIENTE | Ubicacion de entrega | Arribo, Salida | | PROVEEDOR | Punto de carga | Arribo, Demora | | ZONA_RIESGO | Area peligrosa | Entrada | | CASETA | Peaje | Paso registrado | | GASOLINERA | Combustible | Parada larga | | PATIO | Base de operaciones | Entrada/Salida | | PUNTO_CONTROL | Inspeccion | Paso registrado | ### 5.2 Algoritmo de Deteccion ```typescript // GeocercaService.checkGeofences() async checkGeofences(posicion: PosicionGps): Promise { const eventos: EventoGeocerca[] = []; // 1. Obtener geocercas activas del tenant const geocercas = await this.geocercaRepo.find({ where: { tenantId: posicion.tenantId, activa: true } }); // 2. Obtener ultima posicion previa const anterior = await this.getLastPosition(posicion.dispositivoId); // 3. Verificar cada geocerca for (const geo of geocercas) { const dentroAhora = this.isInside(posicion, geo); const dentroAntes = anterior ? this.isInside(anterior, geo) : false; // Entrada: estaba fuera, ahora dentro if (!dentroAntes && dentroAhora && geo.alertaEntrada) { eventos.push(this.createEvento('ENTRADA', posicion, geo)); } // Salida: estaba dentro, ahora fuera if (dentroAntes && !dentroAhora && geo.alertaSalida) { eventos.push(this.createEvento('SALIDA', posicion, geo)); } } return eventos; } // Deteccion punto-en-circulo (Haversine) isInsideCircle(punto: Coordenada, centro: Coordenada, radioMetros: number): boolean { const distancia = this.haversineDistance(punto, centro); return distancia <= radioMetros; } ``` --- ## 6. API Endpoints ### 6.1 Dispositivos | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | `/api/v1/gps/dispositivos` | Listar dispositivos | | POST | `/api/v1/gps/dispositivos` | Crear dispositivo | | GET | `/api/v1/gps/dispositivos/:id` | Obtener dispositivo | | PATCH | `/api/v1/gps/dispositivos/:id` | Actualizar dispositivo | | DELETE | `/api/v1/gps/dispositivos/:id` | Eliminar dispositivo | | POST | `/api/v1/gps/dispositivos/:id/asignar` | Asignar a unidad | ### 6.2 Posiciones | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | POST | `/api/v1/gps/posiciones` | Registrar posicion | | POST | `/api/v1/gps/posiciones/batch` | Registrar batch | | GET | `/api/v1/gps/posiciones` | Historial (paginado) | | GET | `/api/v1/gps/posiciones/ultima/:dispositivoId` | Ultima posicion | | POST | `/api/v1/gps/posiciones/ultimas` | Multiples ultimas | | GET | `/api/v1/gps/posiciones/track/:dispositivoId` | Track completo | ### 6.3 Geocercas | Metodo | Endpoint | Descripcion | |--------|----------|-------------| | GET | `/api/v1/gps/geocercas` | Listar geocercas | | POST | `/api/v1/gps/geocercas` | Crear geocerca | | GET | `/api/v1/gps/geocercas/:id` | Obtener geocerca | | PATCH | `/api/v1/gps/geocercas/:id` | Actualizar geocerca | | DELETE | `/api/v1/gps/geocercas/:id` | Eliminar geocerca | | POST | `/api/v1/gps/geocercas/verificar` | Verificar punto en geocercas | --- ## 7. Integracion con Providers ### 7.1 Providers Soportados | Provider | Protocolo | Estado | |----------|-----------|--------| | Plataforma propia | REST API | Implementado | | Queclink | TCP/IP | Planificado | | Teltonika | TCP/IP | Planificado | | CalAmp | TCP/IP | Planificado | ### 7.2 Arquitectura Multi-Provider ``` ┌─────────────────────────────────────────────────────────────┐ │ GPS Gateway Service │ ├─────────────┬─────────────┬─────────────┬─────────────────┤ │ Queclink │ Teltonika │ CalAmp │ REST API │ │ Adapter │ Adapter │ Adapter │ (nativo) │ └──────┬──────┴──────┬──────┴──────┬──────┴────────┬────────┘ │ │ │ │ └─────────────┴─────────────┴───────────────┘ │ ▼ ┌─────────────────────┐ │ Normalized Position │ │ { lat, lng, │ │ speed, ...} │ └─────────────────────┘ ``` Ver: [INTEGRACION-GPS-PROVIDERS.md](../30-integraciones/INTEGRACION-GPS-PROVIDERS.md) --- ## 8. Consideraciones de Performance ### 8.1 Volumen de Datos | Metrica | Valor Tipico | Maximo | |---------|--------------|--------| | Posiciones/dispositivo/dia | 1,440 (1/min) | 86,400 (1/seg) | | Dispositivos activos | 100-500 | 5,000 | | Posiciones/dia total | 144,000-720,000 | 432M | ### 8.2 Estrategias de Optimizacion 1. **Batch inserts**: Agrupar posiciones en lotes de 100-1000 2. **TimescaleDB**: Particionamiento por tiempo para historico 3. **Redis cache**: Ultimas posiciones por dispositivo 4. **Compresion**: Eliminar posiciones redundantes (sin movimiento) 5. **Indices**: tenant_id, dispositivo_id, timestamp --- ## 9. DDL Relacionado - `database/ddl/03-tracking-schema-ddl.sql` - Tablas base - `database/ddl/03a-gps-devices-ddl.sql` - Extension dispositivos --- *Sprint S1 - TASK-007 | Sistema SIMCO v4.0.0*