PWA offline-first para obra y campo: por qué una app nativa rara vez merece la pena
En obra pública, áridos o campo, la cobertura desaparece. La pregunta no es 'app nativa o web', es cómo conseguir que el operario pueda trabajar sin red. Explicamos el patrón offline-first que usamos en GPInfor.
- El escenario real: obra pública en zona sin cobertura
- Cómo se monta una PWA offline-first: las tres piezas
- La parte que parece trivial y casi nunca lo es: la reconciliación
- Lo que no recomendamos hacer
- ¿Funciona en iOS? Sí, con asteriscos
- ¿Cuánto cuesta y cuándo merece la pena?
Una pregunta recurrente cuando arrancamos una aplicación de movilidad para un cliente de construcción o agricultura: ¿app nativa para Android/iOS, o aplicación web?
La respuesta corta: salvo casos muy concretos (uso intensivo de cámara con filtros, integración profunda con NFC o Bluetooth, requisito explícito de estar en las tiendas de apps), una PWA offline-first bien hecha gana. Es más barata de mantener, sale antes a producción y se instala en el dispositivo sin pasar por Apple ni Google.
Lo que cambia el planteamiento es la palabra clave: offline-first. Una PWA mal hecha es una página web que falla en cuanto se pierde la red. Una PWA offline-first es una aplicación que asume que la red no estará ahí, y por eso funciona igual.
El escenario real: obra pública en zona sin cobertura
Tomemos un caso que llevamos a diario. Constructora con 60 frentes abiertos por la geografía rural andaluza. El jefe de obra abre por la mañana la app, ve qué partidas tiene asignadas, fichan los operarios, durante el día se registran avances, materiales consumidos, incidencias, fotos. Al final, todo eso sube al CGestion central.
Realidad técnica: media de 4 horas al día sin cobertura en ubicaciones rurales. Y cuando hay cobertura, es 3G lento. El operario no puede esperar a que la página cargue cada vez que toca una opción del menú.
Una app que dependa de la red en cada interacción es inservible. Tiene que funcionar como si el móvil estuviera en modo avión, y reconciliar con el servidor cuando vuelva la conexión.
Cómo se monta una PWA offline-first: las tres piezas
1. Service Worker. Es el script que vive entre el navegador y la
red. Lo registramos al cargar la app y a partir de ese momento
intercepta TODAS las peticiones de la pestaña. Para assets estáticos
(JS, CSS, fuentes, imágenes) lo configuramos en estrategia
CacheFirst: si hay copia local, se sirve sin tocar la red. Para
respuestas JSON dinámicas, NetworkFirst con fallback a caché —
intentamos red, y si falla devolvemos lo último que teníamos.
Lo escribimos con Workbox porque ahorra mucho código repetitivo y tiene precarga, expiración y limpieza ya resueltas.
2. IndexedDB para los datos del cliente. Cuando el operario abre la app, descargamos los datos de su jornada (partes asignados, fichas de personal de su cuadrilla, listas de materiales) y los guardamos en IndexedDB. La app lee de ahí, no de la red. Para volúmenes pequeños (cuadrilla de 8 personas, 30 partidas, mil items de catálogo) son unos pocos megabytes, perfectamente manejables.
Usamos Dexie.js como wrapper sobre IndexedDB porque la API nativa es engorrosa. Dexie da un cliente con queries declarativas y migraciones de esquema.
3. Cola de sincronización. Cuando el operario crea un parte, no se
envía al servidor inmediatamente. Se guarda en una tabla local
outbox con su payload y un estado pending. Un proceso en segundo
plano —Background Sync del Service Worker— intenta vaciar la cola
cuando detecta conexión. Si la API responde 200, se marca como
sent y se borra. Si falla con error transitorio, se reintenta.
Si la red vuelve después de horas y hay 47 partes pendientes, todos se mandan en orden y sin colisiones porque cada uno lleva un UUID generado en el cliente que sirve como clave de idempotencia.
La parte que parece trivial y casi nunca lo es: la reconciliación
Cuando dos operarios trabajan offline sobre la misma obra y los dos añaden un parte para la partida 47, ¿qué pasa cuando los dos suben?
Hay tres estrategias. Cuál se usa depende del tipo de dato:
-
Append-only. Si lo que añaden es un evento nuevo (un fichaje, una foto, una incidencia), no hay conflicto: ambos eventos son válidos. Patrón ideal cuando se puede modelar así.
-
Last-write-wins con timestamp. Si lo que actualizan es un estado (avance %, observaciones del jefe de obra), gana el último que llega según timestamp del cliente, ajustado a la zona horaria del servidor. Funciona si las modificaciones simultáneas son raras.
-
Conflict detection. Si las modificaciones son críticas (certificaciones, importes a facturar), no decidimos por el usuario: detectamos conflicto cuando los dos vienen con el mismo ETag base y mostramos una pantalla “tu compañero ha modificado este parte mientras estabas offline, ¿qué versión guardamos?”. Es UX pero es honesta.
Lo que no recomendamos hacer
-
No metas todo el ERP en IndexedDB. Es tentador querer que el operario pueda navegar por toda la información del cliente sin red. Pero descargar gigabytes de catálogo a un móvil con 32 GB es una receta para reclamaciones. Define qué necesita por jornada, descarga eso, y si necesita algo distinto que pida red explícitamente.
-
No te apoyes en cookies para auth offline. Las cookies se borran cuando el navegador hace limpieza. Usa token JWT en IndexedDB con refresh cuando hay red.
-
No subestimes el
disk quota. El navegador puede expulsar la caché si el dispositivo se queda sin espacio. Si tu app es crítica para el trabajo, pidenavigator.storage.persist()cuando el usuario ya ha demostrado que la usa.
¿Funciona en iOS? Sí, con asteriscos
iOS Safari soporta Service Workers y IndexedDB desde 2018. Las dos limitaciones reales:
-
Background Sync no funciona en iOS. La cola se vacía solo cuando el usuario abre la app. En la práctica los operarios abren la app varias veces al día y la cola sale sin problema, pero hay que diseñarlo asumiendo que no hay sincronización automática.
-
Las PWA en iOS tienen 7 días de “vida” en cache si no se abren. Si el operario está dos semanas de baja, al volver tendrá que iniciar sesión de nuevo. No es bloqueante pero sí un detalle a comunicar.
En Android todo funciona como en escritorio. iOS hay que diseñar contemplando esas excepciones desde el día uno.
¿Cuánto cuesta y cuándo merece la pena?
Una PWA offline-first típica para obra (login, gestión de jornada, partes, fichaje, sincronización contra CGestion) son 8-12 semanas de desarrollo. El mantenimiento es similar a una web normal: un empleado de IT del cliente puede actualizar el contenido del catálogo sin tocar código.
Frente a una app nativa equivalente (que requeriría dos versiones, Android e iOS, dos publicaciones por release, dos pipelines de CI) sale entre un 40% y un 60% más barata en mantenimiento al año.
Si estás valorando movilidad para obra, áridos o campo y quieres saber qué encaja en tu caso concreto, escríbenos. Te decimos honestamente si una PWA tiene sentido o si tu caso es uno de los pocos donde nativo está justificado.