Registro de horas con captura offline y conflictos de sincronización
Una consultora de 40 desarrolladores registra horas en una app web. El cliente móvil debe funcionar sin conexión durante visitas a planta (hasta 3 días). Cada entrada tiene: id generado en el dispositivo (UUID), proyecto, fecha, horas (decimales de 15 min) y una marca de actualización. El backend actual usa un endpoint PUT /entries/{id} que sobrescribe la fila completa y devuelve 200. En pruebas, dos consultores que editaron la misma entrada desde dispositivos distintos reportaron que las horas del primero desaparecieron sin aviso. Además, el 8% de los envíos offline fallan con 409 y el cliente los descarta silenciosamente. La gerencia pide 'cero pérdida de datos' antes del cierre trimestral en 3 semanas.
1. Diagnostica la causa raíz de la pérdida de datos y propón el cambio mínimo de contrato de API que la elimine, justificando por qué.
Read the worked answer
Causa raíz: el PUT es una escritura de última-escritura-gana sobre el recurso completo. Quien sincroniza segundo envía su copia entera y pisa los campos que el otro ya había cambiado. El 409 descartado agrava el problema: el cliente interpreta un conflicto legítimo como error transitorio y borra la entrada local, perdiendo la edición.
Cambio mínimo:
- Enviar solo el delta con control de versión:
PATCH /entries/{id}con cabeceraIf-Match: <version>(oexpectedVersionen el cuerpo). El servidor responde 200 con la nueva versión si coincide, o 409 con el estado actual si no. - Tratar 409 como caso de negocio, no como fallo: el cliente no descarta, guarda la versión del servidor y encola la resolución.
Por qué: el PATCH condicional convierte la escritura ciega en una operación optimista verificada; el servidor es la única autoridad de versión y el cliente nunca sobrescribe lo que no vio.
Regla de merge sugerida: por campo (horas, proyecto), no por fila; si ambos cambian el mismo campo, marcar para revisión del consultor. Esto es determinista y auditable.
2. El 8% de los envíos offline recibe 409. Diseña la política de reintento y resolución en el cliente. ¿Qué NO debe hacer y por qué?
Read the worked answer
Política:
- No reintentar 409 automáticamente: es determinista; reintentar produce el mismo resultado y bucles. Solo se reintentan 5xx y timeouts, con backoff exponencial + jitter (p. ej. 1s, 2s, 4s… máx 60s, 5 intentos).
- Encolar el conflicto: mover la entrada a una cola
pending-resolutionpersistente (IndexedDB/SQLite), nunca descartarla. - Resolver en el dispositivo cuando sea seguro: si el conflicto es de campos distintos, hacer merge automático y reenviar con la versión nueva. Si es el mismo campo, mostrar al usuario ambas versiones y dejar que elija.
- Idempotencia: el UUID del cliente garantiza que un reintento de un envío ya aplicado no duplique; el servidor debe devolver 200 con el estado actual en lugar de crear otra fila.
Qué NO hacer:
- Descartar en 409 (lo que ocurre hoy) → pérdida silenciosa.
- Reintentar en bucle → el 8% se convierte en carga y nunca se resuelve.
- Resolver por 'gana el más reciente' sin avisar → repite el problema original con otra cara.
Métrica de aceptación: 0 entradas descartadas; todo 409 termina en resolved o needs-user visible en la UI.
3. Quedan 3 semanas. Prioriza qué entregar y qué posponer para cumplir 'cero pérdida de datos', distinguiendo entre pérdida y conflicto no resuelto.
Read the worked answer
Distinción clave: 'cero pérdida' significa que ningún dato aceptado por el usuario desaparece sin rastro. Un conflicto pendiente visible no es pérdida; un descarte silencioso sí.
Semana 1 (imprescindible):
- Quitar el descarte en 409; persistir la entrada en cola local con estado.
PATCHcondicional con versión en servidor.- Pruebas de integración: dos dispositivos, edición concurrente, sin red.
Semana 2: merge por campo para el caso seguro; UI mínima de 'conflicto pendiente' (lista + elegir versión).
Semana 3: hardening, telemetría (contador de conflictos y descartes = 0) y rollback.
Posponer: merge automático sofisticado, resolución en tiempo real entre dispositivos, historial completo de versiones. No son necesarios para no perder datos y añaden riesgo.
Riesgo a declarar: si el equipo intenta el merge automático completo en 3 semanas, probablemente incumpla lo imprescindible. Mejor entregar cola + PATCH + UI de conflicto y dejar el merge avanzado para el siguiente ciclo.