# 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*