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
@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
@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
@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
// PosicionGpsService.createBatch()
async createBatch(posiciones: CreatePosicionDto[]): Promise<void> {
// 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
// GeocercaService.checkGeofences()
async checkGeofences(posicion: PosicionGps): Promise<EventoGeocerca[]> {
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
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
- Batch inserts: Agrupar posiciones en lotes de 100-1000
- TimescaleDB: Particionamiento por tiempo para historico
- Redis cache: Ultimas posiciones por dispositivo
- Compresion: Eliminar posiciones redundantes (sin movimiento)
- 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