erp-transportistas-v2/docs/02-definicion-modulos/MAI-006-tracking/historias-usuario/US-MAI006-013-validar-posiciones-gps.md
Adrian Flores Cortes 6ed7f9e2ec [BACKUP] Pre-restructure workspace backup 2026-01-29
- Updated docs and inventory files
- Added new architecture docs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 17:35:54 -06:00

114 lines
6.2 KiB
Markdown

# US-MAI006-013: Validar posiciones GPS
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-MAI006-013 |
| **Epica** | EPIC-MAI-006 - Tracking en Tiempo Real |
| **Modulo** | tracking |
| **Prioridad** | P1 |
| **Story Points** | 5 |
| **Sprint** | Por asignar |
| **Estado** | Backlog |
## Historia de Usuario
**Como** administrador del sistema de tracking,
**quiero** que el sistema filtre automaticamente las posiciones GPS invalidas o anomalas,
**para** evitar que datos erroneos afecten el calculo de rutas, distancias y la visualizacion en el mapa.
## Descripcion Detallada
Los dispositivos GPS pueden reportar posiciones invalidas por diversas razones: perdida de senal satelital, interferencia, mal funcionamiento del dispositivo, o manipulacion. Estas posiciones anomalas pueden causar problemas graves en el sistema: rutas con "saltos" imposibles en el mapa, calculos de distancia incorrectos, alertas falsas de exceso de velocidad, y ETAs erroneos.
El sistema debe implementar un servicio de validacion que analice cada posicion recibida y determine si es valida o no. Las validaciones incluyen: coordenadas dentro de rangos validos, velocidad fisicamente posible, precision GPS aceptable (HDOP), numero minimo de satelites, y deteccion de "teleportacion" (saltos de posicion imposibles dado el tiempo transcurrido).
Las posiciones invalidas se almacenan marcadas con `valida = FALSE` para fines de auditoria y debugging, pero no se consideran para calculos de ruta, distancia, o visualizacion en el mapa.
## Criterios de Aceptacion
### Escenario 1: Rechazar coordenadas fuera de rango
**Dado** que se recibe una posicion GPS con latitud 95.0 (fuera del rango -90 a 90),
**Cuando** el sistema procesa la posicion,
**Entonces** la posicion se almacena con `valida = FALSE` y razon "Latitud fuera de rango", no se emite por WebSocket, y no se considera para calculos.
### Escenario 2: Detectar velocidad imposible
**Dado** que se recibe una posicion GPS con velocidad 350 km/h (configuracion maxima: 200 km/h para transporte de carga),
**Cuando** el sistema procesa la posicion,
**Entonces** la posicion se almacena con `valida = FALSE` y razon "Velocidad excesiva", y se genera una alerta informativa de "posicion anomala detectada".
### Escenario 3: Detectar salto de posicion (teleportacion)
**Dado** que la ultima posicion valida de la Unidad T-001 fue en CDMX hace 30 segundos,
**Cuando** se recibe una nueva posicion ubicada en Monterrey (1000 km de distancia),
**Entonces** el sistema calcula que seria imposible recorrer esa distancia en 30 segundos (requeriria velocidad de 120,000 km/h), marca la posicion como invalida con razon "Salto de posicion detectado".
### Escenario 4: Rechazar posicion con baja precision GPS
**Dado** que se recibe una posicion con HDOP = 25 (configuracion maxima: 10),
**Cuando** el sistema procesa la posicion,
**Entonces** la posicion se almacena con `valida = FALSE` y razon "Precision GPS baja (HDOP > 10)", permitiendo que la siguiente posicion con buena precision sea aceptada.
### Escenario 5: Rechazar posicion con pocos satelites
**Dado** que se recibe una posicion con solo 2 satelites (configuracion minima: 4),
**Cuando** el sistema procesa la posicion,
**Entonces** la posicion se almacena con `valida = FALSE` y razon "Satelites insuficientes".
### Escenario 6: Posicion valida se procesa normalmente
**Dado** que se recibe una posicion con: latitud 19.4326, longitud -99.1332, velocidad 65 km/h, HDOP 1.2, satelites 12, y la distancia desde la ultima posicion es coherente con el tiempo transcurrido,
**Cuando** el sistema procesa la posicion,
**Entonces** la posicion se almacena con `valida = TRUE`, se emite por WebSocket, y se utiliza para calculos de ruta y distancia.
### Escenario 7: Configurar reglas de validacion por tenant
**Dado** que el tenant configura velocidad maxima de 120 km/h (transporte especial de carga delicada),
**Cuando** se recibe una posicion con velocidad 130 km/h,
**Entonces** el sistema aplica la configuracion especifica del tenant y marca la posicion como invalida.
## Tareas Tecnicas
- **Database:** Agregar campo `valida BOOLEAN DEFAULT TRUE` y `razon_invalida VARCHAR(200)` a la tabla `tracking.posiciones_gps` si no existen. Crear indice parcial: `CREATE INDEX idx_posicion_valida ON tracking.posiciones_gps(unidad_id, timestamp_gps) WHERE valida = TRUE`.
- **Backend:** Crear `PositionValidatorService` con metodo `validate(position, lastPosition): ValidationResult`. Implementar validaciones: coordenadas en rango, velocidad maxima, HDOP maximo, satelites minimos, deteccion de salto. Integrar validador en `PositionIngestionService`.
- **Configuration:** Crear tabla `tracking.validation_config` o usar tenant_settings para configurar: max_speed_kmh (default 200), max_hdop (default 10), min_satellites (default 4), max_jump_factor (default 1.5).
- **Alerting:** Generar alerta informativa cuando se detectan multiples posiciones invalidas consecutivas del mismo dispositivo (posible falla de equipo).
- **Tests:** Tests unitarios de cada validacion. Tests con posiciones edge case. Tests de configuracion por tenant.
## Dependencias
- **Depende de:** US-MAI006-012 (recibir posiciones), MAI-001 (tenant settings)
- **Bloquea:** Ninguna (es una mejora transversal)
## Notas Tecnicas
- **Validaciones implementadas:**
| Validacion | Regla | Default |
|------------|-------|---------|
| Latitud | -90 <= lat <= 90 | Fijo |
| Longitud | -180 <= lon <= 180 | Fijo |
| Velocidad | speed <= max_speed | 200 km/h |
| HDOP | hdop <= max_hdop | 10 |
| Satelites | sat >= min_sat | 4 |
| Salto | dist <= max_possible * factor | factor 1.5 |
- **Formula de distancia maxima posible:**
```
tiempo_segundos = (timestamp_nuevo - timestamp_anterior)
max_distancia_km = (max_speed_kmh / 3600) * tiempo_segundos
distancia_real = haversine(pos_anterior, pos_nueva)
es_valida = distancia_real <= max_distancia_km * factor
```
- **Cache:** Mantener ultima posicion valida en Redis para comparacion rapida: `lastpos:{unidad_id}`
- **Logs:** Registrar posiciones invalidas en log estructurado para analisis posterior
- **Metricas:** Exponer metrica `gps_positions_invalid_total` con label por razon para monitoreo
---
*US-MAI006-013 - ERP Transportistas v1.0.0*