Sincronización en apps de campo: cuando el dato llega tarde o dos veces

Offline, colas y conflictos. Lo que se rompe cuando la app sale de la oficina y cómo diseñar la sync antes de pintar pantallas.

  • 10 min
  • València

En la oficina la app va fina. En la nave, en la obra o en la furgoneta el dato llega tarde —o llega dos veces. El parte se guardó «en verde» y el servidor no lo tiene. El compañero del turno de tarde pisa el mismo registro. El Excel vuelve a circular por WhatsApp.

La sincronización apps de campo no es un interruptor de «modo offline». Es una política: qué se puede hacer sin red, cómo se encola, qué pasa cuando dos escrituras chocan. Si eso se decide después de pintar pantallas, la UI miente. El operario no culpa a la cola. Culpa a la app.

Este artículo cubre lo que se rompe cuando el producto sale de la oficina y cómo diseñar la sync antes del mockup. Es suelo de un proyecto de desarrollo de app, no un extra del sprint 8. Auth y API van en paralelo; aquí el foco es el dato que viaja tarde o duplicado.

El dato llega tarde
El check verde era local. El servidor aún no ha contestado. El supervisor abre el panel y el parte no está. Se llama a planta.
El dato llega dos veces
Reintento sin idempotencia. Dos partes, dos movimientos de stock, dos visitas. El last-write-wins borra el del compañero en silencio.
La sync se inventa en Figma
El prototipo solo tiene «guardado» y «error». No hay pendiente, conflicto ni reintento. El backend se pasa el proyecto parcheando promesas.

Qué es la sincronización apps de campo (y qué no)

Sincronización apps de campo es el contrato entre el dispositivo y el servidor cuando la red es intermitente: cobertura en sótano, Wi‑Fi de nave que cae, el modo avión del operario que no es un caso de borde —es el martes. No es cachear el último GET. Es decidir, por cada acción, si se lee stale, si se escribe en cola o si se bloquea hasta tener red.

Campo no es solo «fuera de la oficina». Es cualquier contexto donde el usuario no controla la red y el dato tiene consecuencia: un parte de calidad, un inventario, una visita, un ticket de puerta. Si fallas, no hay una review de store. Hay un turno que se cierra mal y un Excel que reaparece.

El backend que sostiene esto —auth, offline, APIs— lo desglosamos en el backend que tu app necesita. Aquí bajamos a la sync: colas, identidad de operación, conflictos visibles. Sin esa política, el diseño UX/UI inventa estados que el servidor no puede cumplir.

Offline no es un cache: es una política por acción

«Que funcione sin cobertura» no es una spec. Es una frase de brief. La spec es una tabla: leer ficha, crear parte, editar cantidad, cerrar turno, cobrar, expulsar. Cada fila: online only, cola o prohibida. Si todas son «cola», no has decidido. Has pospuesto el conflicto.

AcciónSuele serSi lo finges
Leer ficha o históricoCache + revalidarDato podrido sin aviso
Crear parte / visitaCola + id propioDuplicado al reintentar
Editar el mismo registroVersión o conflictoLast-write silencioso
Cerrar turno / stock vivoOnline onlyDos cierres, un inventario
Pago o expulsiónOnline onlyDoble cargo o hueco de seguridad

La UI tiene que decir la verdad. «Guardado» no es lo mismo que «en cola» ni que «confirmado por servidor». Un check único es una mentira cómoda en el prototipo y un incidente en planta. Diseña los tres estados desde el wireframe. El operario con guantes no va a interpretar un icono sutil.

Si mañana el usuario entra en un sótano sin cobertura, ¿qué tres acciones siguen siendo honestas? Si no las puedes listar, no tienes offline: tienes un cache accidental.

Colas, idempotencia y el dato que llega dos veces

El dato llega dos veces porque la red falló a mitad y la app reintentó sin identidad. El servidor vio dos POST. Creó dos registros. O peor: descontó stock dos veces. Offline no es magia. Es una cola de mutaciones con id propio y un servidor que las reconoce si aparecen otra vez.

Idempotencia: cada escritura crítica lleva un id generado en el cliente (UUID de operación, Idempotency-Key). El servidor guarda ese id y, si llega de nuevo, devuelve el mismo resultado. Sin eso, el botón de «reenviar» es una fábrica de duplicados. Con eso, el reintento es seguro y la cola puede ser agresiva.

01
Identidad
Cada mutación nace con id en el dispositivo, antes de tener red.
02
Cola
Orden, backoff, tope de reintentos. La UI muestra pendiente, no un check mentiroso.
03
Ack
El servidor confirma. El id se marca enviado. Un segundo POST no crea un segundo parte.
04
Conflicto
Si la versión del servidor no es la que el móvil creía, no se fusiona en silencio.

REST bien versionada cubre la mayoría de estas colas. GraphQL no te libra de la idempotencia: el transporte no es la política. Cuándo sí cambia el contrato lo tratamos en REST vs GraphQL en proyectos reales. En campo, la pregunta útil es otra: ¿puedes reenviar este write sin duplicar?

Conflictos: quién gana y cómo se ve

Dos dispositivos, el mismo parte. El de la mañana cambia la cantidad. El de la tarde cambia la incidencia. Last-write-wins elige un ganador y borra al otro. A veces es aceptable —si lo declaras—. Casi nunca lo es en calidad o en inventario. Un merge silencioso es peor: el dato «está», pero ya no es de nadie.

Last-write-wins sin aviso
El segundo dispositivo pisa al primero. Nadie se entera hasta el cierre. Decláralo o no lo uses en entidades críticas.
Conflicto invisible al operario
Si solo lo ve un log de backend, el turno no se corrige. El conflicto es una pantalla, no un ticket de IT a los tres días.
Relojes desfasados
No ordenes por la hora del móvil. Usa versión del servidor o un vector. El reloj del dispositivo en campo miente.

La regla por entidad se escribe en discovery. Partes: conflicto visible o bloqueo. Mensajes de un grupo: last-write o anexar. Stock: online only. Si todas las entidades heredan la misma regla, no has diseñado la sync. Has copiado un tutorial.

EIM Jeanología y Weddle: el mismo oficio, distinto riesgo

En EIM Jeanología el usuario no explora: opera. Entorno industrial, lógica propia, datos que no pueden duplicarse porque el proceso de planta no perdona un parte doble. La sync se diseña con quien hace el turno, no solo con quien encarga el proyecto. Una app interna de campo se mide por si el Excel desaparece, no por si el onboarding parece de store. Ese marco está en apps internas de empresa.

Weddle no es una app de nave, pero enseña el mismo oficio por otro lado: varios dispositivos, un grupo que dura unos días, escrituras que no pueden inventar un miembro o pisar un permiso. La sync es «estar en el grupo correcto a tiempo». Offline ayuda a no perder un mensaje a medias. No justifica un last-write que cambie quién está dentro. Pintar el hielo-breaking sin modelo de cola y de conflicto es la misma mentira, con mejor tipografía.

Pantallas primero
«Guardado» y ya
El prototipo no tiene pendiente ni conflicto. El backend improvisará un cache. En campo, el dato llega tarde o dos veces. El workaround es el grupo de WhatsApp.
Sync primero
Estados que el servidor puede cumplir
Tabla de acciones, ids de operación, regla de conflicto por entidad. La UI enseña cola y choque. El operario sabe qué está en el servidor y qué no.
Dani Marquina

La app de campo no se rompe en el pixel. Se rompe en un write que se envió dos veces o en un check verde que era local. Eso se decide antes de Figma. Si no, Figma está diseñando una mentira.

Dani Marquina · Founder, Truman Digital

Diseñar la sync en discovery, no en el sprint 8

Pedimos la tabla de acciones el mismo week que el mapa de roles. Observar un turno real —cobertura, dispositivo, cómo se anota hoy— vale más que un workshop de «user journeys» en una sala con fibra. Las excepciones del Excel son el producto. La sync tiene que cubrirlas o declararlas fuera de alcance.

Luego prototipamos los estados de sync, no solo el happy path. Pendiente, error, conflicto, «sin red: esto no se puede». Testeamos con el dispositivo real, no con el iPhone del diseñador. Solo entonces se pinta el resto. El orden inverso produce apps bonitas que duplican partes.

Tip técnico: versión en servidor, no timestamp del móvil

Cada entidad mutable lleva un version (o ETag) que incrementa el servidor. El write lleva la versión que el cliente creía tener. Si no coincide, 409 y pantalla de conflicto —o regla declarada. No ordenes por updatedAt del dispositivo: en campo el reloj se desvía, el usuario lo cambia y el último no es el último. La cola local persiste (SQLite, cola durable), no en un array en memoria que el SO mata a las dos horas.

Antes de pintar la app de campo

Checklist de sincronización
  • ¿Cada acción es online only, cola o prohibida —por escrito?
  • ¿Las escrituras críticas tienen id de idempotencia en el cliente?
  • ¿La UI distingue pendiente, enviado y confirmado por servidor?
  • ¿Hay regla de conflicto por entidad, no una sola para todo?
  • ¿El conflicto se ve en pantalla, no solo en un log?
  • ¿Has observado un turno real (cobertura, dispositivo, anotación actual)?
  • ¿El cierre de turno o el stock vivo son online only, a propósito?
  • ¿La cola sobrevive a que el sistema mate la app?

Preguntas frecuentes sobre sincronización en apps de campo

¿Toda app de campo tiene que funcionar offline?

No. Offline es un requisito de producto. Un cierre de inventario en vivo suele ser online only. Un parte o un borrador de visita sí pueden encolar. «Que funcione en la nave» no es una spec: lista las tres acciones honestas sin red y las que se bloquean.

¿Por qué el dato llega dos veces si el usuario pulsó una sola vez?

Porque la red cortó y la app reintentó sin id de operación. El servidor vio dos peticiones y creó dos registros. Se arregla con idempotencia, no con un spinner más largo.

¿Cuándo se diseña la sync respecto a las pantallas?

En discovery, en paralelo. Las pantallas dependen de estados reales (cola, conflicto, sin red). Si el diseño cierra primero, el backend parchea promesas. En Truman no abrimos UI de campo sin tabla de acciones.

¿Last-write-wins sirve para una app de planta?

Casi nunca en partes de calidad o stock. Puede valer en campos menores si lo declaras. Si dos operarios editan lo mismo, el conflicto tiene que verse. Un merge silencioso es un incidente aplazado.

Si tu app sale de la oficina y el dato llega tarde o dos veces, paramos en la sync. Las pantallas pueden esperar. La cola y el conflicto, no.
Revisamos la sync de tu app

Sobre el autor

Dani Marquina

Dani Marquina

Founder & CTO

Cuéntanos tu proyecto

Nos dices en qué punto estás y te contestamos con franqueza: si podemos ayudarte, te diremos por dónde empezaríamos. Sin compromiso.

Qué pasa después

  1. 01

    Leemos y analizamos tu proyecto

    Revisamos todo lo que nos cuentas y lo entendemos antes de responder. Equipo técnico desde el primer día, sin intermediarios.

  2. 02

    Preparamos una propuesta

    Personalizada, con alcance, enfoque y estimación. No genérica.

  3. 03

    Una llamada para alinear

    Sin presión. Aclaramos dudas y decidís si tiene sentido avanzar.

Hablamos por WhatsApp