SQLite vs Realm para almacenamiento offline-first en apps de campo
Comparativa SQLite vs Realm para almacenamiento offline-first en apps de campo: migraciones, opciones de consulta, manejo de conflictos, herramientas de depuración y consejos prácticos de selección.

Lo que realmente necesitan las apps de campo offline-first
Offline-first no solo significa “funciona sin internet”. Significa que la app puede cargar datos útiles, aceptar nuevas entradas y mantener cada edición segura hasta que pueda sincronizarse.
El trabajo de campo añade un conjunto predecible de restricciones: la señal aparece y desaparece, las sesiones son largas, los dispositivos pueden ser antiguos y los modos de ahorro de batería son comunes. La gente se mueve rápido. Abren una tarea, recorren largas listas, toman fotos, rellenan formularios y pasan a la siguiente tarea sin pensar en el almacenamiento.
Lo que los usuarios notan es sencillo. Pierden confianza cuando las ediciones desaparecen, cuando las listas y la búsqueda van lentas sin conexión, cuando la app no puede responder claramente “¿mi trabajo está guardado?”, cuando los registros se duplican o faltan al reconectar, o cuando una actualización provoca comportamientos extraños.
Por eso elegir entre SQLite y Realm se trata sobre todo del comportamiento diario, no de benchmarks.
Antes de elegir una base local, aclara cuatro áreas: tu modelo de datos cambiará, tus consultas deben coincidir con los flujos reales, la sincronización offline generará conflictos y las herramientas determinarán qué tan rápido puedes diagnosticar problemas en campo.
1) Tus datos cambiarán
Incluso las apps estables evolucionan: nuevos campos, estados renombrados, nuevas pantallas. Si los cambios de modelo son dolorosos, o bien publicas menos mejoras o corres el riesgo de romper dispositivos reales con datos reales.
2) Las consultas deben coincidir con los flujos reales
Las apps de campo necesitan filtros rápidos como “trabajos de hoy”, “sitios cercanos”, “formularios no sincronizados” y “elementos editados en las últimas 2 horas”. Si la base de datos hace esas consultas incómodas, la interfaz se vuelve lenta o el código se convierte en un laberinto.
3) La sincronización offline crea conflictos
Dos personas pueden editar el mismo registro, o un dispositivo puede editar datos antiguos durante días. Necesitas un plan claro sobre qué gana, qué se fusiona y qué requiere decisión humana.
4) Las herramientas importan
Cuando algo falla en campo, necesitas inspeccionar datos, reproducir problemas y entender lo ocurrido sin conjeturas.
Migraciones: cambiar el modelo sin romper a los usuarios
Las apps de campo rara vez se quedan quietas. Tras unas semanas añades una casilla, renombras un estado o divides un campo “notas” en campos estructurados. Las migraciones son donde las apps offline suelen fallar, porque el teléfono ya contiene datos reales.
SQLite guarda datos en tablas y columnas. Realm guarda datos como objetos con propiedades. Esa diferencia aparece rápido:
- Con SQLite, normalmente escribes cambios de esquema explícitos (ALTER TABLE, nuevas tablas, copia de datos).
- Con Realm, suele bastar con incrementar la versión del esquema y ejecutar una función de migración que actualiza objetos cuando se acceden.
Añadir un campo es fácil en ambos sistemas: añade una columna en SQLite, añade una propiedad con valor por defecto en Realm. Los renombres y las divisiones son los más dolorosos. En SQLite, renombrar puede ser limitado según tu configuración, así que los equipos a menudo crean una tabla nueva y copian los datos. En Realm, puedes leer la propiedad antigua y escribir en las nuevas durante la migración, pero debes tener cuidado con tipos, valores por defecto y nulos.
Las actualizaciones grandes con datos en el dispositivo requieren precaución. Una migración que reescribe cada registro puede ser lenta en teléfonos antiguos, y un técnico no debería quedarse mirando un spinner en un aparcamiento. Planea el tiempo de migración y considera repartir transformaciones pesadas en varias versiones.
Para probar migraciones con justicia, trátalas como sincronizaciones:
- Instala una versión antigua, crea datos realistas y luego actualiza.
- Prueba con conjuntos de datos pequeños y grandes.
- Mata la app a mitad de migración y relánzala.
- Prueba escenarios con poco almacenamiento.
- Asume que puedes avanzar aunque no puedas retroceder.
Ejemplo: si “equipmentId” pasa a ser “assetId” y luego se divide en “assetType” más “assetNumber”, la migración debe mantener las inspecciones antiguas utilizables, no forzar un cierre de sesión o un borrado.
Flexibilidad de consultas: qué puedes pedir a tus datos
Las apps de campo viven o mueren por las pantallas de lista: trabajos de hoy, activos cercanos, clientes con tickets abiertos, piezas usadas la semana pasada. Tu elección de almacenamiento debe hacer que esas preguntas sean fáciles de expresar, rápidas de ejecutar y difíciles de malinterpretar dentro de seis meses.
SQLite te da SQL, que sigue siendo la forma más flexible de filtrar y ordenar grandes conjuntos de datos. Puedes combinar condiciones, unir tablas, agrupar resultados y añadir índices cuando una pantalla se ralentiza. Si tu app necesita “todas las inspecciones para activos en la Región A, asignadas al Equipo 3, con cualquier elemento de checklist fallado”, SQL suele expresarlo con claridad.
Realm se apoya en objetos y una API de consultas de más alto nivel. Para muchas apps esto se siente natural: consulta objetos Job, filtra por estado, ordena por fecha de vencimiento, sigue relaciones a objetos relacionados. La contrapartida es que algunas preguntas triviales en SQL (especialmente consultas estilo reportes a través de múltiples relaciones) pueden ser más difíciles de expresar, o terminas reestructurando datos para que se ajusten a las consultas necesarias.
Búsquedas y relaciones
Para búsqueda de texto parcial en múltiples campos (título del trabajo, nombre del cliente, dirección), SQLite a menudo te empuja hacia un indexado cuidadoso o un enfoque de texto completo dedicado. Realm también puede filtrar texto, pero igualmente debes pensar en rendimiento y en qué significa “contiene” a escala.
Las relaciones son otro punto práctico. SQLite maneja uno-a-muchos y muchos-a-muchos con tablas de unión, lo que facilita patrones como “activos etiquetados con estas dos etiquetas”. Los enlaces de Realm son fáciles de navegar en código, pero muchos-a-muchos y patrones de “consultar a través de” suelen necesitar más planificación para mantener las lecturas rápidas.
Consultas crudas vs mantenimiento legible
Un patrón amigable para mantenimiento es mantener un conjunto pequeño de consultas nombradas que mapeen directamente a pantallas e informes: los filtros y ordenamientos de la lista principal, una consulta de vista detalle (un registro más los relacionados), la definición de búsqueda, algunos contadores (insignias y totales offline) y cualquier consulta de exportación/reporting.
Si esperas preguntas ad hoc frecuentes desde negocio, el poder de consultas crudas de SQLite es difícil de superar. Si quieres que la mayor parte del acceso a datos se lea como trabajo con objetos normales, Realm puede resultar más rápido de construir, siempre que pueda responder a tus pantallas más complejas sin soluciones incómodas.
Resolución de conflictos y sincronización: qué soporte obtienes
Las apps offline-first de campo suelen soportar las mismas acciones básicas desconectadas: crear un registro, actualizarlo, eliminar algo inválido. La parte difícil no es guardar localmente. Es decidir qué pasa cuando dos dispositivos cambian el mismo registro antes de que cualquiera pueda sincronizar.
Los conflictos aparecen en situaciones simples. Un técnico actualiza una inspección en una tablet en un sótano sin señal. Más tarde, un supervisor corrige la misma inspección desde un portátil. Cuando ambos se reconectan, el servidor recibe dos versiones diferentes.
La mayoría de equipos optan por uno de estos enfoques:
- Última escritura gana (rápido, pero puede sobrescribir datos válidos silenciosamente)
- Fusionar por campo (más seguro cuando diferentes campos cambian, pero necesita reglas claras)
- Cola de revisión manual (más lento, mejor para cambios de alto riesgo)
SQLite te da una base local fiable, pero no provee sincronización por sí misma. Normalmente construyes el resto: rastrear operaciones pendientes, enviarlas a una API, reintentos seguros y hacer cumplir reglas de conflicto en el servidor.
Realm puede reducir la cantidad de cableado si usas sus funciones de sync, porque está diseñado en torno a objetos y seguimiento de cambios. Pero “sync incorporado” aún no decide tus reglas de negocio. Tú determinas qué cuenta como conflicto y qué datos pueden ganar.
Planea un rastro de auditoría desde el día uno. Los equipos de campo a menudo necesitan respuestas claras a “quién cambió qué, cuándo y desde qué dispositivo”. Incluso si eliges última escritura gana, almacena metadatos como ID de usuario, ID de dispositivo, marcas de tiempo y (cuando sea posible) una razón. Si tu backend se genera rápido, por ejemplo con una plataforma no-code como AppMaster, es más fácil iterar estas reglas temprano antes de tener cientos de dispositivos offline en el terreno.
Depuración e inspección: atrapar problemas antes de que los note el campo
Los errores offline son difíciles porque ocurren cuando no puedes observar la app hablando con un servidor. Tu experiencia de depuración suele reducirse a una pregunta: ¿qué tan fácil es ver qué hay en el dispositivo y cómo cambió con el tiempo?
SQLite es fácil de inspeccionar porque es un archivo. En desarrollo o QA puedes extraer la base de datos de un dispositivo de prueba, abrirla con herramientas SQLite comunes, ejecutar consultas ad hoc y exportar tablas a CSV o JSON. Esto te ayuda a confirmar “qué filas existen” frente a “qué muestra la UI”. La desventaja es que necesitas entender tu esquema, joins y cualquier andamiaje de migración que hayas creado.
Realm puede sentirse más “como la app” para inspeccionar. Los datos se guardan como objetos, y las herramientas de Realm suelen ser la forma más sencilla de explorar clases, propiedades y relaciones. Es genial para detectar problemas del grafo de objetos (enlaces faltantes, nulos inesperados), pero el análisis ad hoc es menos flexible si tu equipo está acostumbrado a la inspección basada en SQL.
Registro y reproducción de problemas offline
La mayoría de fallos en campo se reducen a errores de escritura silenciosos, lotes de sincronización parciales o una migración que sólo se terminó a medias. En cualquier caso, invierte en algunos básicos: marcas de tiempo “último cambio” por registro, un log de operaciones en el dispositivo, logs estructurados alrededor de migraciones y escrituras en background, una forma de habilitar logging verboso en builds de QA y una acción de “volcar y compartir” que exporte una instantánea redactada.
Ejemplo: un técnico informa que inspecciones completadas desaparecen tras un agotamiento de batería. Una instantánea compartida te ayuda a confirmar si los registros nunca fueron escritos, fueron escritos pero no consultados, o se revirtieron al iniciar.
Compartir una instantánea fallida
Con SQLite, compartir suele ser tan simple como compartir el archivo .db (más cualquier archivo WAL). Con Realm, normalmente compartes el archivo Realm junto con sus archivos secundarios. En ambos casos, define un proceso repetible para eliminar datos sensibles antes de que algo salga del dispositivo.
Fiabilidad en el mundo real: fallos, reinicios y actualizaciones
Las apps de campo fallan de maneras aburridas: la batería se agota durante un guardado, el SO mata la app en background o el almacenamiento se llena tras semanas de fotos y logs. Tu elección de base local afecta con qué frecuencia esos fallos se convierten en trabajo perdido.
Cuando ocurre un crash durante una escritura, tanto SQLite como Realm pueden ser seguros si se usan correctamente. SQLite es fiable cuando envuelves cambios en transacciones (el modo WAL puede ayudar con resiliencia y rendimiento). Las escrituras en Realm son transaccionales por defecto, así que normalmente obtienes guardados “todo o nada” sin trabajo extra. El riesgo común no es el motor de base de datos, sino el código de la app que escribe en varios pasos sin un punto de commit claro.
La corrupción es rara, pero necesitas un plan de recuperación. Con SQLite puedes ejecutar checks de integridad, restaurar desde una copia conocida buena o reconstruir desde una resync con el servidor. Con Realm, la corrupción a menudo pone en duda todo el archivo Realm, por lo que la ruta práctica de recuperación suele ser “eliminar local y resync” (bien si el servidor es la fuente de la verdad, doloroso si el dispositivo contiene datos únicos).
El crecimiento del almacenamiento es otra sorpresa. SQLite puede crecer tras deletes a menos que ejecutes VACUUM periódicamente. Realm también puede crecer y puede necesitar políticas de compactación, además de podar objetos antiguos (como trabajos completados) para que el archivo no crezca indefinidamente.
Las actualizaciones y reversiones son otra trampa. Si una actualización cambia el esquema o el formato de almacenamiento, un rollback puede dejar usuarios con un archivo más nuevo que no pueden leer. Planea las actualizaciones como unidireccionales, con migraciones seguras y una opción de “resetar datos locales” que no rompa la app.
Hábitos de fiabilidad que valen la pena:
- Maneja “disco lleno” y fallos de escritura con un mensaje claro y una ruta de reintento.
- Guarda la entrada del usuario en checkpoints, no solo al final de un formulario largo.
- Mantén un log de auditoría ligero local para recuperación y soporte.
- Podar y archivar registros viejos antes de que la base de datos crezca demasiado.
- Prueba actualizaciones de SO y kills en background en dispositivos de gama baja.
Ejemplo: una app de inspecciones que guarda checklists y fotos puede quedarse sin espacio en un mes. Si la app detecta espacio bajo temprano, puede pausar captura de fotos, subir cuando sea posible y mantener guardados los checklists sin importar qué base local uses.
Paso a paso: cómo elegir y configurar tu enfoque de almacenamiento
Trata el almacenamiento como parte del producto, no como una decisión de librería. La mejor opción es la que mantiene la app usable cuando la señal cae y predecible cuando vuelve.
Un camino de decisión simple
Anota primero tus flujos de usuario offline. Sé específico: “abrir trabajos de hoy, añadir notas, adjuntar fotos, marcar completado, capturar una firma”. Todo lo de esa lista debe funcionar sin red, siempre.
Luego recorre una secuencia corta: lista pantallas críticas offline y cuánta data necesita cada una (trabajos de hoy vs historial completo), esboza un modelo de datos mínimo y las relaciones que no puedes simular (Job -> ChecklistItems -> Answers), elige una regla de conflicto por entidad (no una regla para todo), decide cómo probarás fallos (migraciones en dispositivos reales, reintentos de sync, comportamiento forzado de logout/reinstalación) y construye un pequeño prototipo con datos realistas que puedas medir (cargar, buscar, guardar, sincronizar después de un día offline).
Ese proceso normalmente revela la restricción real: ¿necesitas consultas ad hoc flexibles e inspección fácil, o valoras acceso por objetos y una aplicación más estricta del modelo?
Qué validar en el prototipo
Usa un escenario realista, como un técnico que completa 30 inspecciones offline y luego vuelve a cobertura. Mide el tiempo de primera carga con 5.000 registros, si un cambio de esquema sobrevive una actualización, cuántos conflictos aparecen tras reconectar y si puedes explicar cada uno, y qué tan rápido puedes inspeccionar un “registro malo” cuando soporte llama.
Si quieres validar flujos rápido antes de comprometerte, un prototipo sin código en AppMaster puede ayudarte a fijar el flujo y el modelo de datos temprano, incluso antes de decidir la base de datos en el dispositivo.
Errores comunes que perjudican las apps offline-first
La mayoría de fallos offline-first no vienen del motor de base de datos. Vienen de saltarse las partes aburridas: actualizaciones, reglas de conflicto y manejo de errores claro.
Una trampa es asumir que los conflictos son raros. En trabajo de campo son normales: dos técnicos editan el mismo activo, o un supervisor cambia un checklist mientras un dispositivo está offline. Si no defines una regla (última escritura gana, mezclar por campo o conservar ambas versiones), acabarás sobrescribiendo trabajo real.
Otro fallo silencioso es tratar el modelo de datos como “terminado” y no practicar actualizaciones. Los cambios de esquema ocurren incluso en apps pequeñas. Si no versionas tu esquema y no pruebas actualizaciones desde builds antiguas, los usuarios pueden quedarse bloqueados tras una actualización con migraciones fallidas o pantallas en blanco.
Problemas de rendimiento también aparecen tarde. A veces los equipos descargan todo “por si acaso” y luego se preguntan por qué la búsqueda va lenta y la app tarda minutos en abrir en un teléfono de gama media.
Patrones a vigilar:
- No hay política de conflicto escrita, así que las ediciones se sobrescriben silenciosamente.
- Migraciones que funcionan en instalaciones nuevas pero fallan en actualizaciones reales.
- Caché offline que crece sin límites, ralentizando consultas.
- Fallos de sincronización ocultos tras un spinner, de modo que los usuarios asumen que los datos se enviaron.
- Depuración a base de conjeturas en lugar de un script reproducible y datos de muestra.
Ejemplo: un técnico completa una inspección offline, pulsa Sincronizar y no recibe confirmación. La subida falló por un problema de token de autenticación. Si la app oculta el error, el técnico deja el sitio pensando que el trabajo está hecho y la confianza se pierde.
Sea cual sea el almacenamiento que elijas, haz una prueba básica en “modo campo”: modo avión, batería baja, actualización de la app y dos dispositivos editando el mismo registro. Si estás construyendo rápido con una plataforma no-code como AppMaster, incorpora estas pruebas en el prototipo antes de que el flujo llegue a un equipo que no puede permitirse tiempo de inactividad.
Checklist rápido antes de comprometerte
Antes de elegir un motor, define qué significa “bueno” para tu app de campo y pruébalo con datos reales y dispositivos reales. Los equipos discuten sobre características, pero la mayoría de fallos vienen de lo básico: actualizaciones, pantallas lentas, reglas de conflicto poco claras y falta de manera de inspeccionar el estado local.
Usa esto como puerta de paso:
- Prueba actualizaciones: toma al menos dos builds antiguos, actualiza a la versión actual y confirma que los datos siguen abriendo, editando y sincronizando.
- Mantén las pantallas clave rápidas con volumen real: carga datos realistas y mide las pantallas más lentas en un teléfono de gama media.
- Escribe política de conflicto por tipo de registro: inspecciones, firmas, piezas usadas, comentarios.
- Haz que los datos locales sean inspeccionables y los logs coleccionables: define cómo soporte y QA capturan estado cuando están offline.
- Haz la recuperación predecible: decide cuándo reconstruir caché, volver a descargar o exigir inicio de sesión. No conviertas “reinstalar la app” en el plan.
Si prototipas en AppMaster, aplica la misma disciplina. Prueba actualizaciones, define conflictos y ensaya la recuperación antes de lanzar a un equipo que no puede permitirse caídas.
Escenario de ejemplo: una app de inspecciones con señal intermitente
Un técnico de campo empieza el día descargando 50 órdenes de trabajo a su teléfono. Cada trabajo incluye la dirección, los elementos de checklist requeridos y algunas fotos de referencia. Después de eso la señal fluctúa todo el día.
Durante cada visita, el técnico edita los mismos registros repetidamente: estado del trabajo (Llegó, En Progreso, Hecho), piezas usadas, firma del cliente y fotos nuevas. Algunas ediciones son pequeñas y frecuentes (estado). Otras son grandes (fotos) y no deben perderse.
El momento de sincronización: dos personas tocaron el mismo trabajo
A las 11:10 el técnico marca el Trabajo #18 como Hecho y añade una firma estando offline. A las 11:40 un despachador reasigna el Trabajo #18 porque en oficina aún parece abierto. Cuando el técnico se reconecta a las 12:05, la app sube los cambios.
Un buen flujo de conflicto no oculta esto. Lo muestra. Un supervisor debería ver un mensaje simple: “Existen dos versiones del Trabajo #18”, con campos clave uno al lado del otro (estado, técnico asignado, marca temporal, firma sí/no) y opciones claras: mantener la actualización del campo, mantener la actualización de oficina o fusionar por campo.
Aquí es donde tus decisiones de almacenamiento y sync se ven en la práctica: ¿puedes rastrear un historial limpio de cambios y reproducirlos de forma segura tras horas offline?
Cuando un trabajo “desaparece”, depurar se trata principalmente de probar qué pasó. Registra suficiente información para responder: mapeo de ID local y ID servidor (incluyendo cuándo se creó), cada escritura con marca de tiempo/usuario/dispositivo, intentos de sincronización y mensajes de error, decisiones de conflicto y el ganador, y el estado de subida de fotos separado del registro del trabajo.
Con esos logs puedes reproducir el problema en lugar de adivinar a partir de una queja.
Siguientes pasos: valida rápido y luego construye la solución completa
Antes de tomar partido en debates SQLite vs Realm, redacta una especificación de una página para tus flujos offline: las pantallas que ve un técnico, qué datos viven en el dispositivo y qué debe funcionar sin señal (crear, editar, fotos, firmas, cargas en cola).
Luego prototipa todo el sistema temprano, no solo la base de datos. Las apps de campo fallan en las uniones: un formulario móvil que guarda localmente no sirve si el equipo administrativo no puede revisar y corregir registros, o si el backend rechaza actualizaciones después.
Un plan práctico de validación:
- Construye una porción delgada de extremo a extremo: un formulario offline, una vista de lista, un intento de sincronización y una pantalla administrativa.
- Haz una prueba de cambio: renombra un campo, divide un campo en dos, publica un build de prueba y observa cómo se comporta la actualización.
- Simula conflictos: edita el mismo registro en dos dispositivos, sincroniza en órdenes distintas y apunta qué rompe.
- Practica la depuración en campo: decide cómo inspeccionarás datos locales, logs y cargas fallidas en un dispositivo real.
- Escribe una política de reset: cuándo borras caché local y cómo los usuarios se recuperan sin perder trabajo.
Si la velocidad importa, una primera pasada sin código puede ayudarte a validar el flujo rápido. AppMaster (appmaster.io) es una opción para construir la solución completa (servicios backend, panel web administrativo y apps móviles) temprano y luego regenerar código limpio conforme cambien los requisitos.
Elige el siguiente paso de validación según el riesgo. Si los formularios cambian semanalmente, prueba migraciones primero. Si varias personas tocan el mismo trabajo, prueba conflictos. Si te preocupa “funcionó en oficina”, prioriza tu flujo de depuración en campo.
FAQ
Offline-first significa que la app sigue siendo útil sin conexión: puede cargar los datos necesarios, aceptar nuevas entradas y mantener cada cambio a salvo hasta que sea posible sincronizar. La promesa clave es que los usuarios no pierdan trabajo ni confianza cuando la señal cae, el sistema operativo mata la app o la batería se agota a mitad de una tarea.
SQLite suele ser la opción más segura cuando necesitas filtros complejos, consultas tipo reporting, relaciones muchos-a-muchos y una inspección ad hoc sencilla con herramientas comunes. Realm encaja bien cuando prefieres acceso a datos por objetos, escrituras transaccionales por defecto y puedes alinear tus consultas con las fortalezas de Realm.
Trata las migraciones como una característica central, no como una tarea puntual. Instala una versión antigua, crea datos realistas en el dispositivo, luego actualiza y confirma que la app sigue abriendo, editando y sincronizando; además prueba con conjuntos grandes, poco almacenamiento y matando la app durante la migración.
Agregar un campo suele ser sencillo en ambos sistemas, pero renombrar y dividir campos es donde los equipos suelen tener problemas. Planea esos cambios con cuidado, establece valores por defecto sensatos, maneja nulos con atención y evita migraciones que reescriban todos los registros de una sola vez en dispositivos antiguos.
Las pantallas de listas y filtros que reflejan el trabajo real son la métrica principal: “trabajos de hoy”, “formularios no sincronizados”, “editados en las últimas 2 horas” y búsqueda rápida. Si expresar esas consultas resulta incómodo, la interfaz será lenta o el código se volverá difícil de mantener.
Ni SQLite ni Realm “resuelven” conflictos por sí mismos; necesitas reglas de negocio. Empieza eligiendo una regla clara por tipo de entidad (última escritura gana, mezclar por campo o cola de revisión manual) y haz que la app pueda explicar qué pasó cuando dos dispositivos cambian el mismo registro.
Registra suficiente metadato para explicar y reproducir cambios: ID de usuario, ID de dispositivo, marcas de tiempo y un marcador de “último cambio” por registro. Mantén un registro local de operaciones para ver qué se encoló, qué se envió, qué falló y qué aceptó el servidor.
SQLite es fácil de inspeccionar porque es un archivo que puedes extraer del dispositivo y consultar directamente, lo que ayuda con análisis ad hoc y exportaciones. La inspección de Realm suele resultar más natural para grafos de objetos y relaciones, pero los equipos acostumbrados a SQL pueden encontrarla menos flexible para análisis profundos.
Los mayores riesgos de fiabilidad suelen venir de la lógica de la app: escrituras en varios pasos sin un punto claro de commit, fallos de sincronización ocultos y ausencia de una ruta de recuperación ante disco lleno o corrupción. Usa transacciones/checkpoints, muestra el estado de guardado y sincronización claramente y ofrece una opción predecible de “reiniciar y re-sincronizar” que no requiera reinstalar.
Construye un escenario realista de extremo a extremo y mídelo: primera carga con miles de registros, búsqueda, guardado de formularios largos y “un día sin conexión y luego reconexión”. Valida actualizaciones desde al menos dos builds antiguos, simula conflictos con dos dispositivos y confirma que puedes inspeccionar el estado local y los logs cuando algo falla.


