# ARQUITECTURA-OFFLINE.md - App de Conductores **Proyecto:** erp-transportistas **Modulo:** MAI-006-tracking / App Conductor **Version:** 1.0.0 **Fecha:** 2026-01-27 **GAP Relacionado:** GAP-003 (Modo Offline para Conductores) --- ## 1) Objetivos ### 1.1 Objetivo Principal Permitir que los conductores operen la aplicacion movil sin conexion a internet durante sus viajes en carretera, garantizando la captura de todos los datos operativos y su sincronizacion automatica al recuperar conectividad. ### 1.2 Objetivos Especificos | Objetivo | Descripcion | Metrica de Exito | |----------|-------------|------------------| | Operacion continua | La app funciona 100% sin conexion | 0 bloqueos por falta de red | | Sin perdida de datos | Todos los eventos se almacenan localmente | 0% perdida de datos | | Sincronizacion automatica | Datos se envian al reconectar | Sync < 30s post-conexion | | Transparencia al usuario | El conductor sabe que esta offline | Indicador visible en UI | | Resiliencia | Recuperacion ante fallos de sync | Retry automatico con backoff | ### 1.3 Casos de Uso Criticos Offline 1. **Registro de eventos de viaje** (arribo, carga, descarga, salida) 2. **Captura de firma POD** (Proof of Delivery) 3. **Toma de fotos con evidencia** (carga, dano, sello) 4. **Checklist de inspeccion pre-viaje** 5. **Consulta de informacion del viaje** (rutas, paradas, instrucciones) 6. **Registro de incidencias** (accidente, retraso, dano) --- ## 2) Stack Tecnologico ### 2.1 Componentes Principales | Componente | Tecnologia | Proposito | |------------|------------|-----------| | Storage Local | WatermelonDB | Base de datos offline-first reactiva | | Storage Secundario | IndexedDB (Dexie.js) | Almacenamiento de blobs (fotos, firmas) | | Intercepcion HTTP | Service Workers | Cache de requests y offline fallback | | Sincronizacion | Background Sync API | Push de datos cuando hay conexion | | Deteccion de Red | Network Information API | Estado de conectividad en tiempo real | | Queue de Tareas | Workbox | Gestion de cola de sincronizacion | ### 2.2 Arquitectura de Capas ``` +--------------------------------------------------+ | UI LAYER | | (React Native / Expo) | +--------------------------------------------------+ | | v v +-------------------+ +----------------------+ | SYNC MANAGER | | OFFLINE DETECTOR | | - Queue Manager | | - Network Status | | - Conflict Res. | | - Connectivity Test | +-------------------+ +----------------------+ | | v v +--------------------------------------------------+ | LOCAL DATA LAYER | | +-------------------+ +---------------------+ | | | WatermelonDB | | IndexedDB (Blobs) | | | | - Viajes | | - Fotos | | | | - Eventos | | - Firmas | | | | - Checklists | | - Documentos PDF | | | +-------------------+ +---------------------+ | +--------------------------------------------------+ | v +--------------------------------------------------+ | SYNC TRANSPORT LAYER | | +-------------------+ +---------------------+ | | | Background Sync | | Retry Queue | | | | - Push events | | - Exponential back. | | | | - Upload files | | - Priority queue | | | +-------------------+ +---------------------+ | +--------------------------------------------------+ | v +--------------------------------------------------+ | REMOTE API | | (Backend NestJS - erp-transportistas) | +--------------------------------------------------+ ``` ### 2.3 Dependencias NPM ```json { "dependencies": { "@nozbe/watermelondb": "^0.27.1", "@nozbe/with-observables": "^1.6.0", "dexie": "^4.0.0", "workbox-window": "^7.0.0", "workbox-background-sync": "^7.0.0", "workbox-strategies": "^7.0.0", "@react-native-community/netinfo": "^9.0.0", "uuid": "^9.0.0" } } ``` --- ## 3) Datos Almacenados Localmente ### 3.1 Datos del Viaje Activo | Entidad | Campos Principales | Tamano Estimado | |---------|-------------------|-----------------| | Viaje | id, numero, estado, fechas, origen, destino | ~2 KB | | Paradas | id, secuencia, ubicacion, tipo, ventanas | ~500 B/parada | | Instrucciones | id, tipo, contenido, prioridad | ~1 KB/instruccion | | Contactos | nombre, telefono, email, rol | ~200 B/contacto | | Mercancia | descripcion, peso, volumen, unidades | ~300 B/item | | Documentos | tipo, nombre, url_local, checksum | ~50 KB/doc (metadata) | ### 3.2 Datos Capturados Offline | Entidad | Campos | Tamano Estimado | Prioridad Sync | |---------|--------|-----------------|----------------| | EventoTracking | id, tipo, timestamp, lat, lng, viaje_id | ~200 B | ALTA | | PosicionGPS | lat, lng, velocidad, rumbo, timestamp | ~100 B | MEDIA | | ChecklistItem | pregunta, respuesta, evidencia_id, timestamp | ~500 B | ALTA | | Foto | id, blob, metadata, lat, lng, timestamp | ~500 KB-2 MB | BAJA | | FirmaPOD | id, svg_path, receptor_nombre, timestamp | ~50 KB | ALTA | | Incidencia | tipo, descripcion, fotos_ids, timestamp | ~1 KB | ALTA | ### 3.3 Cache de Referencia (Read-Only Offline) | Dato | Proposito | Actualizacion | |------|-----------|---------------| | Catalogos de eventos | Tipos de eventos permitidos | Cada login | | Checklist templates | Plantillas de inspeccion | Cada login | | Datos de unidad asignada | Placa, capacidad, documentos | Cada asignacion | | Datos del operador | Licencia, permisos, vigencias | Cada login | | Rutas precalculadas | Polylines, waypoints | Al asignar viaje | ### 3.4 Limites de Almacenamiento | Tipo | Limite Recomendado | Limite Maximo | |------|-------------------|---------------| | Base de datos WatermelonDB | 50 MB | 100 MB | | IndexedDB (Blobs) | 200 MB | 500 MB | | Cache de documentos | 50 MB | 100 MB | | **Total por viaje activo** | **300 MB** | **700 MB** | --- ## 4) Sincronizacion ### 4.1 Flujo Push (Local a Server) ``` +-------------+ +---------------+ +----------------+ | CAPTURA | --> | LOCAL QUEUE | --> | SYNC MANAGER | | (Evento) | | (Pending) | | (Background) | +-------------+ +---------------+ +----------------+ | v +----------------+ | CONNECTIVITY | | CHECK | +----------------+ | +-------------+-------------+ | | v v +-----------+ +---------------+ | OFFLINE | | ONLINE | | (Queue) | | (Send Now) | +-----------+ +---------------+ | | | v | +---------------+ | | SERVER | | | RESPONSE | | +---------------+ | | | +-------------+-------------+ | | | | v v | +-----------+ +---------------+ | | SUCCESS | | ERROR | | | (Remove) | | (Retry/Log) | | +-----------+ +---------------+ | | +------------------<----------------------+ (Retry with backoff) ``` ### 4.2 Flujo Pull (Server a Local) ``` +----------------+ +----------------+ +----------------+ | CONNECTIVITY | --> | SYNC MANAGER | --> | FETCH CHANGES | | (Online) | | (Trigger) | | (Delta Sync) | +----------------+ +----------------+ +----------------+ | v +----------------+ | COMPARE | | TIMESTAMPS | +----------------+ | v +----------------+ | APPLY CHANGES | | TO LOCAL DB | +----------------+ | v +----------------+ | NOTIFY UI | | (Reactive) | +----------------+ ``` ### 4.3 Datos a Sincronizar #### Push (Local a Server) | Dato | Prioridad | Frecuencia | Retry Policy | |------|-----------|------------|--------------| | Eventos de viaje | CRITICA | Inmediato | 5 intentos, backoff 1-30s | | Posiciones GPS | ALTA | Batch cada 1 min | 3 intentos, backoff 5-60s | | Firmas POD | CRITICA | Inmediato | 10 intentos, backoff 1-60s | | Fotos evidencia | MEDIA | Background | 5 intentos, backoff 30-300s | | Checklist completado | ALTA | Inmediato | 5 intentos, backoff 1-30s | | Incidencias | CRITICA | Inmediato | 10 intentos, backoff 1-60s | #### Pull (Server a Local) | Dato | Frecuencia | Trigger | |------|------------|---------| | Cambios en viaje | Cada 5 min online | Polling + Push notification | | Nuevas instrucciones | Inmediato | Push notification | | Actualizacion de paradas | Cada 5 min | Polling | | Cancelacion de viaje | Inmediato | Push notification | | Cambio de asignacion | Inmediato | Push notification | ### 4.4 Estrategia de Retry (Exponential Backoff) ``` Intento 1: Inmediato Intento 2: 1 segundo Intento 3: 2 segundos Intento 4: 4 segundos Intento 5: 8 segundos Intento 6: 16 segundos Intento 7: 32 segundos Intento 8: 60 segundos (max) ... Intento N: 60 segundos (cap) Maximo tiempo total de retry: 1 hora Despues: Marcar como fallido, notificar soporte ``` --- ## 5) Conflict Resolution ### 5.1 Estrategias por Tipo de Dato | Tipo de Dato | Estrategia | Razon | |--------------|------------|-------| | Estado del viaje | Server Wins | Estado oficial controlado por dispatch | | Eventos de tracking | Append-Only (Merge) | Nunca se borran, solo se agregan | | Posiciones GPS | Client Wins | El dispositivo es la fuente de verdad | | Fotos y firmas | Client Wins | Evidencia local es oficial | | Instrucciones | Server Wins | Dispatch controla instrucciones | | Datos del operador | Server Wins | RRHH controla datos oficiales | ### 5.2 Diagrama de Resolucion de Conflictos ``` +------------------+ | CONFLICTO | | DETECTADO | +------------------+ | v +------------------+ | IDENTIFICAR | | TIPO DE DATO | +------------------+ | +----+----+----+----+ | | | v v v +-------+ +-------+ +-------+ | STATE | | EVENT | | BLOB | +-------+ +-------+ +-------+ | | | v v v +-------+ +-------+ +-------+ | SERVER| | MERGE | |CLIENT | | WINS | |(Append| | WINS | | | | Only) | | | +-------+ +-------+ +-------+ | | | +----+----+----+----+ | v +------------------+ | APLICAR | | RESOLUCION | +------------------+ | v +------------------+ | REGISTRAR EN | | AUDIT LOG | +------------------+ ``` ### 5.3 Reglas de Merge para Eventos (Append-Only) 1. Cada evento tiene un UUID unico generado en cliente 2. El timestamp es el momento de captura en dispositivo 3. Si el servidor ya tiene el UUID, ignorar (idempotente) 4. El orden de eventos se determina por timestamp del cliente 5. Eventos duplicados se detectan por UUID + viaje_id ### 5.4 Manejo de Conflictos en Estados ```typescript // Matriz de transicion de estados permitidos (cliente) const TRANSICIONES_VALIDAS = { 'EN_TRANSITO': ['ARRIBADO', 'INCIDENCIA'], 'ARRIBADO': ['EN_CARGA', 'EN_DESCARGA'], 'EN_CARGA': ['CARGADO'], 'EN_DESCARGA': ['DESCARGADO', 'ENTREGADO'], 'CARGADO': ['EN_TRANSITO'], 'DESCARGADO': ['EN_TRANSITO', 'ENTREGADO'] }; // Si el estado del servidor es diferente: // 1. Aceptar estado del servidor // 2. Revertir UI al estado correcto // 3. Notificar al usuario del cambio ``` --- ## 6) Indicadores UI ### 6.1 Componentes de Estado | Indicador | Ubicacion | Estados | |-----------|-----------|---------| | Icono de conexion | Header (esquina superior derecha) | Online (verde), Offline (rojo), Sincronizando (amarillo) | | Contador de pendientes | Header (junto a icono) | Badge numerico (0-99+) | | Ultima sincronizacion | Drawer / Settings | Timestamp legible | | Barra de progreso | Toast inferior | Durante sync activa | | Alertas de error | Modal / Banner | Errores de sync criticos | ### 6.2 Mockup ASCII del Header ``` +----------------------------------------------------------+ | VIAJE #VJ-2026-00123 [12] (o) 4G/LTE | | En transito a: Monterrey | +----------------------------------------------------------+ Leyenda: - [12] = 12 eventos pendientes de sincronizar - (o) = Icono de estado (o=online, x=offline, ~=sync) - 4G/LTE = Tipo de conexion Estados del icono: - Verde (o) : Online, sincronizado - Amarillo (~): Sincronizando - Rojo (x) : Offline - Naranja (!): Error de sync ``` ### 6.3 Panel de Estado de Sincronizacion ``` +----------------------------------------------------------+ | ESTADO DE SINCRONIZACION [X] | +----------------------------------------------------------+ | | | Estado de conexion: OFFLINE (desde hace 15 min) | | Ultima sync exitosa: 2026-01-27 14:35:22 | | | | PENDIENTES DE ENVIAR: | | +----------------------------------------------------+ | | | Tipo | Cantidad | Tamano | Estado | | | +----------------------------------------------------+ | | | Eventos | 5 | 2 KB | [Cola] | | | | Posiciones GPS | 45 | 5 KB | [Cola] | | | | Fotos | 3 | 4.5 MB | [Cola] | | | | Firma POD | 1 | 32 KB | [Cola] | | | +----------------------------------------------------+ | | | TOTAL | 54 | 4.6 MB | | | | +----------------------------------------------------+ | | | | [!] 2 fotos fallaron al subir - Reintentando... | | | | [ FORZAR SINCRONIZACION ] [ VER ERRORES ] | | | +----------------------------------------------------------+ ``` ### 6.4 Notificaciones al Usuario | Evento | Tipo | Mensaje | |--------|------|---------| | Perdida de conexion | Toast | "Modo offline activado. Tus datos se guardaran localmente." | | Conexion restaurada | Toast | "Conexion restaurada. Sincronizando datos..." | | Sync completada | Toast | "Sincronizacion completada. 12 eventos enviados." | | Error de sync | Banner | "Error al sincronizar. Reintentando automaticamente..." | | Sync critica fallida | Modal | "No se pudo enviar la firma POD. Verifica tu conexion." | | Almacenamiento lleno | Modal | "Almacenamiento casi lleno. Sincroniza para liberar espacio." | --- ## 7) Diagrama de Flujo Completo ### 7.1 Flujo de Captura de Evento Offline ``` +-----------------------------------------------------------------------+ | FLUJO: CAPTURA DE EVENTO OFFLINE | +-----------------------------------------------------------------------+ CONDUCTOR APP LOCAL DB | | | | [Toca "Arribado"] | | |------------------------>| | | | | | | Generar UUID | | | Capturar timestamp | | | Obtener GPS actual | | | | | | Validar datos | | |------------------------+ | | | | | | |<-----------------------+ | | | | | | Guardar evento local | | |----------------------------->| | | | | | Evento guardado | | |<-----------------------------| | | | | | Agregar a cola de sync | | |----------------------------->| | | | | | Actualizar UI | | | (badge +1) | | | | | [UI actualizada] | | |<------------------------| | | "Arribado registrado | | | (pendiente de sync)" | | | | | | | Check conectividad | | |------------------------+ | | | | | | |<-----------------------+ | | | (OFFLINE - no hacer nada) | | | | +-----------------------------------------------------------------------+ ``` ### 7.2 Flujo de Sincronizacion al Reconectar ``` +-----------------------------------------------------------------------+ | FLUJO: SINCRONIZACION AL RECONECTAR | +-----------------------------------------------------------------------+ NETWORK SYNC MANAGER LOCAL DB SERVER | | | | | [Conexion OK] | | | |--------------------->| | | | | | | | | Obtener pendientes | | | |--------------------->| | | | | | | | [Lista de items] | | | |<---------------------| | | | | | | | Ordenar por prioridad | | | (CRITICA > ALTA > MEDIA > BAJA) | | | | | | | POST /api/sync/events | | |----------------------------------------->| | | | | | | | 200 OK | | |<-----------------------------------------| | | | | | | Marcar como enviado | | | |--------------------->| | | | | | | | POST /api/sync/files (fotos) | | |----------------------------------------->| | | | | | | | 200 OK | | |<-----------------------------------------| | | | | | | Borrar blobs locales| | | |--------------------->| | | | | | | | GET /api/sync/pull?since=timestamp | | |----------------------------------------->| | | | | | | | [Cambios] | | |<-----------------------------------------| | | | | | | Aplicar cambios | | | |--------------------->| | | | | | | | Notificar UI | | | | (Sync completa) | | | | | | +-----------------------------------------------------------------------+ ``` --- ## 8) Consideraciones de Seguridad ### 8.1 Proteccion de Datos Locales | Aspecto | Implementacion | |---------|----------------| | Cifrado en reposo | SQLCipher para WatermelonDB | | Cifrado de blobs | AES-256 para fotos/firmas | | Autenticacion | JWT con refresh token offline (7 dias) | | Borrado seguro | Wipe de datos al logout/desasignacion | | Integridad | Checksums SHA-256 para archivos | ### 8.2 Limites de Seguridad - Maximo 7 dias de operacion offline sin re-autenticar - Datos locales se borran si el dispositivo reporta compromiso - Fotos contienen watermark invisible con ID de operador - Firmas incluyen timestamp y coordenadas GPS inmutables --- ## 9) Metricas y Monitoreo ### 9.1 Metricas a Capturar | Metrica | Descripcion | Alerta | |---------|-------------|--------| | sync_queue_size | Tamano de cola de sync | > 100 items | | sync_latency_ms | Tiempo de sincronizacion | > 30000 ms | | offline_duration_min | Tiempo offline | > 60 min | | sync_failures | Errores de sync | > 5 consecutivos | | storage_used_mb | Almacenamiento usado | > 80% limite | | conflict_count | Conflictos detectados | > 10/dia | ### 9.2 Logs para Debugging ```typescript // Formato de log para eventos offline { "timestamp": "2026-01-27T14:35:22.123Z", "level": "INFO", "module": "OfflineSync", "event": "EVENT_CAPTURED", "data": { "event_id": "uuid-xxx", "event_type": "ARRIBADO", "viaje_id": "VJ-2026-00123", "is_online": false, "queue_position": 5, "storage_used_mb": 45.2 } } ``` --- ## 10) Referencias - [WatermelonDB Documentation](https://watermelondb.dev/docs) - [Background Sync API](https://developer.mozilla.org/en-US/docs/Web/API/Background_Synchronization_API) - [Workbox Background Sync](https://developer.chrome.com/docs/workbox/modules/workbox-background-sync) - [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) - erp-mecanicas-diesel/Field Service (arquitectura de referencia) - REQ-GIRO-TRANSPORTISTA.md (RF-4.5.2 - App movil operador con modo offline) --- *ARQUITECTURA-OFFLINE.md v1.0.0 - erp-transportistas - Sistema SIMCO v4.0.0*