SQLite vs Realm pour le stockage offline‑first dans les applications de terrain
SQLite vs Realm pour le stockage offline‑first dans les applis terrain : migrations, options de requête, gestion des conflits, outils de débogage et conseils pratiques pour choisir.

De quoi les applications de terrain « offline‑first » ont réellement besoin
« Offline‑first » ne signifie pas seulement « fonctionne sans Internet ». Cela signifie que l'app peut charger des données utiles, accepter des saisies et garantir chaque modification jusqu'à la synchronisation.
Le travail sur le terrain ajoute un ensemble de contraintes prévisibles : le signal coupe et revient, les sessions sont longues, les appareils peuvent être anciens et les modes économie d'énergie sont courants. Les gens bougent vite. Ils ouvrent une tâche, parcourent de longues listes, prennent des photos, remplissent des formulaires et passent à la suivante sans penser au stockage.
Ce que les utilisateurs remarquent est simple. Ils perdent confiance lorsque des modifications disparaissent, lorsque les listes et la recherche sont lentes hors ligne, lorsque l'app ne peut pas clairement répondre « mon travail est‑il enregistré ? », quand des enregistrements se dupliquent ou manquent après reconnexion, ou lorsqu'une mise à jour provoque un comportement étrange.
C'est pourquoi choisir entre SQLite et Realm tient surtout au comportement au quotidien, pas aux benchmarks.
Avant de choisir une base locale, clarifiez quatre points : votre modèle de données va évoluer, vos requêtes doivent refléter les workflows réels, la synchronisation hors ligne génèrera des conflits, et les outils détermineront la rapidité avec laquelle vous pourrez diagnostiquer les problèmes sur le terrain.
1) Vos données vont changer
Même les applis stables évoluent : nouveaux champs, statuts renommés, écrans ajoutés. Si les migrations sont pénibles, vous limitez les améliorations ou vous risquez de casser de vrais appareils avec de vraies données.
2) Les requêtes doivent correspondre aux workflows
Les applis de terrain ont besoin de filtres rapides comme « tâches d'aujourd'hui », « sites à proximité », « formulaires non synchronisés » et « éléments modifiés dans les 2 dernières heures ». Si la base rend ces requêtes maladroites, l'UI devient lente ou le code devient un casse‑tête.
3) La synchronisation hors ligne crée des conflits
Deux personnes peuvent modifier le même enregistrement, ou un appareil peut modifier des données anciennes pendant des jours. Il faut un plan clair sur ce qui l'emporte, ce qui se fusionne et ce qui nécessite une décision humaine.
4) Les outils comptent
Quand quelque chose casse sur le terrain, il faut pouvoir inspecter les données, reproduire les problèmes et comprendre ce qui s'est passé sans deviner.
Migrations : changer le modèle sans casser les utilisateurs
Les applis de terrain bougent rarement pas du tout. Après quelques semaines, vous ajoutez une case à cocher, renommez un statut ou découpez un champ « notes » en champs structurés. Les migrations sont souvent le point de défaillance, car le téléphone contient déjà des données réelles.
SQLite stocke les données en tables et colonnes. Realm stocke les données comme des objets avec des propriétés. Cette différence se voit rapidement :
- Avec SQLite, vous écrivez généralement des changements de schéma explicites (ALTER TABLE, nouvelles tables, copie de données).
- Avec Realm, vous augmentez la version du schéma et exécutez une fonction de migration qui met à jour les objets lorsqu'ils sont accédés.
Ajouter un champ est simple dans les deux systèmes : une colonne en SQLite, une propriété avec une valeur par défaut en Realm. Les renommages et les scissions sont les plus douloureux. En SQLite, renommer peut être limité selon votre configuration, donc les équipes créent souvent une nouvelle table et copient les données. En Realm, vous pouvez lire l'ancienne propriété et écrire dans les nouvelles pendant la migration, mais il faut être attentif aux types, aux valeurs par défaut et aux nulls.
Les grosses mises à jour sur des données locales demandent de la prudence. Une migration qui réécrit chaque enregistrement peut être lente sur les vieux téléphones, et un technicien ne doit pas rester devant une roue qui tourne sur un parking. Prévoyez le temps de migration et envisagez d'étaler les transformations lourdes sur plusieurs versions.
Pour tester les migrations de manière réaliste, traitez‑les comme une synchronisation :
- Installez une ancienne build, créez des données réalistes, puis mettez à jour.
- Testez petits et gros jeux de données.
- Tuez l'app en plein milieu d'une migration et relancez.
- Testez les scénarios de faible espace de stockage.
- Supposez que vous pouvez avancer la migration même si vous ne pouvez pas revenir en arrière.
Exemple : si « equipmentId » devient « assetId » puis se scinde en « assetType » et « assetNumber », la migration doit garder les anciennes inspections exploitables, pas forcer une déconnexion ou une réinitialisation complète.
Flexibilité des requêtes : ce que vous pouvez demander à vos données
Les applis de terrain vivent ou meurent sur les écrans de liste : tâches d'aujourd'hui, actifs à proximité, clients avec tickets ouverts, pièces utilisées cette semaine. Votre choix de stockage doit rendre ces questions faciles à exprimer, rapides à exécuter et difficiles à mal interpréter six mois plus tard.
SQLite vous donne le SQL, qui reste le moyen le plus flexible pour filtrer et trier de gros jeux de données. Vous pouvez combiner des conditions, joindre des tables, grouper des résultats et ajouter des index quand un écran ralentit. Si votre app a besoin de « toutes les inspections pour les actifs de la Région A, assignées à l'Équipe 3, avec un quelconque item de checklist en échec », SQL l'exprimera généralement clairement.
Realm mise sur les objets et une API de requête de plus haut niveau. Pour beaucoup d'apps, cela paraît naturel : requêter des objets Job, filtrer par statut, trier par date d'échéance, suivre les relations vers des objets liés. Le compromis, c'est que certaines questions triviales en SQL (surtout des requêtes de type reporting à travers plusieurs relations) peuvent être plus difficiles à exprimer, ou vous amener à remodeler les données pour servir les requêtes dont vous avez besoin.
Recherche et relations
Pour une recherche textuelle partielle sur plusieurs champs (titre du job, nom du client, adresse), SQLite vous pousse souvent vers un indexage soigné ou une approche full‑text dédiée. Realm peut aussi filtrer du texte, mais il faut penser performance et ce que « contains » signifie à grande échelle.
Les relations sont un autre point pratique. SQLite gère un‑à‑plusieurs et plusieurs‑à‑plusieurs avec des tables de jointure, ce qui rend des patterns comme « actifs tagués avec ces deux tags » simples. Les liens Realm sont faciles à suivre en code, mais les many‑to‑many et les « requêtes à travers » demandent souvent plus de planification pour garder les lectures rapides.
Requêtes brutes vs maintenabilité lisible
Un modèle maintenable consiste à garder un petit jeu de requêtes nommées qui correspondent directement aux écrans et rapports : filtres et tris principaux, requête de détail (un enregistrement et ses liés), la définition de recherche, quelques compteurs (badges et totaux hors ligne) et les requêtes d'export/reporting.
Si vous prévoyez des questions ad hoc fréquentes du business, la puissance des requêtes SQL est difficile à battre. Si vous voulez que l'accès aux données se lise comme du travail avec des objets normaux, Realm peut être plus rapide à développer, tant qu'il répond à vos écrans les plus exigeants sans bricolages maladroits.
Résolution des conflits et synchronisation : quel support vous obtenez
Les applis offline‑first de terrain permettent généralement les mêmes actions de base hors ligne : créer, mettre à jour, supprimer. La difficulté n'est pas la sauvegarde locale. C'est de décider ce qui se passe quand deux appareils changent la même fiche avant qu'un seul ne puisse synchroniser.
Les conflits apparaissent dans des situations simples. Un technicien met à jour une inspection sur une tablette dans un sous‑sol sans signal. Plus tard, un superviseur corrige la même inspection depuis un poste de travail. Quand les deux se reconnectent, le serveur reçoit deux versions différentes.
La plupart des équipes adoptent une de ces approches :
- Last write wins (rapide, mais peut écraser des données valables sans prévenir)
- Fusion par champ (plus sûr quand différents champs changent, mais nécessite des règles claires)
- File d'examen manuelle (la plus lente, la meilleure pour les changements à haut risque)
SQLite vous donne une base locale fiable, mais n'offre pas la synchronisation. Vous construisez généralement le reste : suivre les opérations en attente, les envoyer à une API, retenter en sécurité et appliquer les règles de conflit côté serveur.
Realm peut réduire la plomberie si vous utilisez ses fonctions de sync, puisqu'il est conçu autour d'objets et du suivi des changements. Mais la « sync intégrée » ne décide toujours pas de vos règles métier. C'est à vous de définir ce qui constitue un conflit et quelles données peuvent l'emporter.
Prévoyez une piste d'audit dès le départ. Les équipes de terrain ont souvent besoin de répondre clairement à « qui a changé quoi, quand et depuis quel appareil ». Même si vous choisissez last write wins, stockez des métadonnées comme l'ID utilisateur, l'ID appareil, les horodatages et (si possible) une raison. Si votre backend est généré rapidement, par exemple avec une plateforme no‑code comme AppMaster, il est plus simple d'itérer sur ces règles tôt, avant d'avoir des centaines d'appareils hors ligne en production.
Débogage et inspection : attraper les problèmes avant qu'ils n'atteignent le terrain
Les bugs hors ligne sont difficiles parce qu'ils surviennent quand vous ne pouvez pas observer l'app parler au serveur. L'expérience de débogage se résume souvent à une question : à quel point pouvez‑vous voir ce qui est sur l'appareil et comment cela a changé dans le temps ?
SQLite est facile à inspecter car c'est un fichier. En dev ou QA vous pouvez extraire la base d'un appareil de test, l'ouvrir avec des outils SQLite courants, lancer des requêtes ad hoc et exporter les tables en CSV ou JSON. Cela vous aide à confirmer « quelles lignes existent » versus « ce que l'UI affiche ». L'inconvénient est qu'il faut comprendre votre schéma, les jointures et tout scaffolding de migration que vous avez créé.
Realm peut paraître plus « applicatif » à inspecter. Les données sont stockées comme des objets, et les outils Realm permettent souvent de parcourir classes, propriétés et relations facilement. C'est excellent pour repérer les problèmes de graphe d'objets (liens manquants, null inattendus), mais l'analyse ad hoc est moins flexible si votre équipe est habituée à l'inspection SQL.
Journalisation et reproduction des problèmes hors ligne
La plupart des pannes sur le terrain se résument à des erreurs d'écriture silencieuses, des lots de sync partiels ou une migration incomplète. Investissez dans quelques bases : horodatages « dernier modifié » par enregistrement, un journal d'opérations côté appareil, des logs structurés autour des migrations et des écritures en arrière‑plan, un moyen d'activer la journalisation détaillée dans les builds QA et une action « exporter et partager » qui produit un instantané anonymisé.
Exemple : un technicien signale que des inspections complètes disparaissent après une décharge de batterie. Un instantané partagé vous aide à confirmer si les enregistrements n'ont jamais été écrits, ont été écrits mais non interrogés, ou ont été annulés au démarrage.
Partager un instantané en échec
Avec SQLite, le partage se fait souvent en partageant le fichier .db (et les fichiers WAL s'il y en a). Avec Realm, vous partagez typiquement le fichier Realm et ses fichiers annexes. Dans les deux cas, définissez un processus répétable pour supprimer les données sensibles avant toute sortie de l'appareil.
Fiabilité dans le monde réel : pannes, réinitialisations et mises à jour
Les applis terrain échouent de façons banales : la batterie meurt pendant une sauvegarde, l'OS tue l'app en arrière‑plan, ou le stockage se remplit après des semaines de photos et de logs. Votre choix de base locale influence la fréquence à laquelle ces pannes deviennent des travaux perdus.
Quand un crash survient en plein écrit, SQLite et Realm peuvent être sûrs s'ils sont bien utilisés. SQLite est fiable si vous encapsulez les changements dans des transactions (le mode WAL aide pour la résilience et la performance). Les écritures Realm sont transactionnelles par défaut, donc vous obtenez souvent des sauvegardes « tout ou rien » sans travail supplémentaire. Le risque commun n'est pas le moteur : c'est le code qui écrit en plusieurs étapes sans point de commit clair.
La corruption est rare, mais il faut un plan de récupération. Avec SQLite, vous pouvez lancer des vérifications d'intégrité, restaurer depuis une sauvegarde connue ou reconstruire via une resynchronisation serveur. Avec Realm, la corruption met souvent en doute tout le fichier Realm, donc la récupération pratique est souvent « supprimer le local et resynchroniser » (acceptable si le serveur est source de vérité, pénible si l'appareil contient des données uniques).
La croissance du stockage surprend aussi. SQLite peut gonfler après des suppressions à moins de lancer VACUUM périodiquement. Realm peut aussi croître et nécessiter des politiques de compactage, plus la suppression d'objets anciens (jobs terminés) pour éviter que le fichier n'explose.
Les mises à jour et rollbacks sont un autre piège. Si une mise à jour change le schéma ou le format de stockage, un rollback peut laisser des utilisateurs sur un fichier trop récent pour être lu. Planifiez les mises à jour comme unidirectionnelles, avec des migrations sûres et une option « réinitialiser les données locales » qui ne casse pas l'app.
Bonnes pratiques de fiabilité :
- Gérer « disque plein » et les échecs d'écriture avec un message clair et une voie de nouvelle tentative.
- Sauvegarder les saisies utilisateur par points de contrôle, pas seulement à la fin d'un long formulaire.
- Conserver un journal d'audit léger local pour la récupération et le support.
- Élaguer et archiver les anciens enregistrements avant que la base ne devienne trop grosse.
- Tester les mises à jour d'OS et les kills en arrière‑plan sur des appareils bas de gamme.
Exemple : une app d'inspection qui stocke checklists et photos peut atteindre un faible espace en un mois. Si l'app détecte le manque d'espace tôt, elle peut suspendre la capture de photos, uploader quand possible et garantir les sauvegardes de checklists, quel que soit le stockage local choisi.
Étape par étape : comment choisir et configurer votre approche de stockage
Considérez le stockage comme faisant partie du produit, pas juste un choix de bibliothèque. La meilleure option est celle qui garde l'app utilisable quand le signal chute, et prévisible quand il revient.
Un chemin de décision simple
Rédigez d'abord vos flux utilisateurs hors ligne. Soyez précis : « ouvrir les tâches d'aujourd'hui, ajouter des notes, joindre des photos, marquer comme terminé, capturer une signature ». Tout ce qui figure doit fonctionner sans réseau, à tout moment.
Ensuite, suivez une courte séquence : listez les écrans critiques hors ligne et la quantité de données dont chacun a besoin (tâches d'aujourd'hui vs historique complet), esquissez un modèle de données minimal et les relations que vous ne pouvez pas simuler (Job -> ChecklistItems -> Answers), choisissez une règle de conflit par entité (pas une règle globale), décidez comment vous testerez les pannes (migrations sur de vrais appareils, réessais de sync, comportement après déconnexion/réinstallation), et construisez un petit prototype avec des données réalistes que vous pouvez chronométrer (chargement, recherche, sauvegarde, synchro après un jour hors ligne).
Ce processus révèle généralement la contrainte réelle : avez‑vous besoin de requêtes ad hoc flexibles et d'une inspection facile, ou préférez‑vous un accès orienté objet et une meilleure enforcement du modèle ?
Ce qu'il faut valider dans le prototype
Utilisez un scénario réaliste, par exemple un technicien qui complète 30 inspections hors ligne puis revient en zone couverte. Mesurez le temps du premier chargement avec 5 000 enregistrements, vérifiez si un changement de schéma survit à une mise à jour, comptez les conflits après reconnexion et si vous pouvez expliquer chacun, et testez la rapidité pour inspecter un « mauvais enregistrement » quand le support appelle.
Si vous voulez valider vite avant de vous engager, un prototype no‑code dans AppMaster peut vous aider à verrouiller le workflow et le modèle de données tôt, même avant de finaliser le choix de la base sur l'appareil.
Erreurs courantes qui nuisent aux applis offline‑first
La plupart des échecs ne viennent pas du moteur mais de l'oubli des basiques : mises à jour, règles de conflit et gestion claire des erreurs.
Un piège est de supposer que les conflits sont rares. Sur le terrain ils sont normaux : deux techniciens modifient le même actif, ou un superviseur change une checklist pendant qu'un appareil est hors ligne. Sans règle (last write wins, fusion par champ, garder les deux versions), vous écraserez du travail réel.
Une autre défaillance silencieuse est de considérer le modèle de données comme « fini » et de ne pas pratiquer les mises à jour. Les changements de schéma surviennent même dans de petites apps. Sans versionnage de schéma et tests de mises à jour depuis d'anciennes builds, les utilisateurs se bloqueront après une update avec migrations échouées ou écrans vides.
Les problèmes de performance apparaissent tard aussi. Certaines équipes téléchargent tout « au cas où », puis s'étonnent que la recherche soit lente et que l'app mette des minutes à s'ouvrir sur un téléphone milieu de gamme.
Schémas à surveiller :
- Pas de politique de conflit écrite, donc des modifications écrasées en silence.
- Migrations qui fonctionnent sur installations propres mais échouent sur de vraies mises à jour.
- Cache hors ligne qui grossit sans limite, rendant les requêtes lentes.
- Échecs de sync cachés derrière une roue, l'utilisateur pense que la donnée est envoyée.
- Débogage par conjecture au lieu d'un script de repro reproductible et de jeux de données exemples.
Exemple : un technicien termine une inspection hors ligne, appuie sur Sync et n'obtient pas de confirmation. L'upload a échoué à cause d'un token d'auth, et si l'app cache l'erreur, il repart en supposant que le travail est fait — la confiance est perdue.
Quoi que vous choisissiez, exécutez un test « mode terrain » basique : mode avion, batterie faible, mise à jour de l'app et deux appareils éditant la même fiche. Si vous construisez rapidement avec une plateforme no‑code comme AppMaster, intégrez ces tests au prototype avant que le workflow n'atteigne une équipe qui ne peut pas se permettre des temps d'arrêt.
Liste de contrôle rapide avant de vous engager
Avant de choisir un moteur, définissez ce que « bon » signifie pour votre app terrain, puis testez‑le avec de vraies données et de vrais appareils. Les équipes se disputent les fonctionnalités, mais la plupart des échecs viennent des basiques : mises à jour, écrans lents, règles de conflit floues et impossibilité d'inspecter l'état local.
Utilisez ceci comme porte d'entrée go/no‑go :
- Prouvez les mises à jour : prenez au moins deux anciennes builds, mettez à jour vers la build actuelle et confirmez que les données s'ouvrent, s'éditent et se synchronisent.
- Gardez les écrans principaux rapides à volume réel : chargez des données réalistes et chronométrez les écrans les plus lents sur un téléphone milieu de gamme.
- Écrivez une politique de conflit par type d'enregistrement : inspections, signatures, pièces utilisées, commentaires.
- Rendez les données locales inspectables et les logs collectables : définissez comment le support et la QA capturent l'état hors ligne.
- Rendez la récupération prévisible : décidez quand reconstruire le cache, retélécharger ou demander une reconnexion. Ne faites pas de « réinstaller l'app » le plan de secours.
Si vous prototypez dans AppMaster, appliquez la même discipline : testez les mises à jour, définissez les conflits et répétez la récupération avant de déployer à une équipe qui ne peut pas se permettre d'interruption.
Scénario exemple : une appli d'inspection avec signal aléatoire
Un technicien commence la journée en téléchargeant 50 ordres de travail sur son téléphone. Chaque job inclut l'adresse, la checklist requise et quelques photos de référence. Ensuite le signal saute toute la journée.
À chaque visite, le technicien édite souvent les mêmes fiches : statut du job (Arrivé, En cours, Terminé), pièces utilisées, signature client et nouvelles photos. Certaines modifications sont petites et fréquentes (statut). D'autres sont volumineuses (photos) et ne doivent pas être perdues.
Le moment de la synchronisation : deux personnes ont touché le même job
À 11:10, le technicien marque le Job #18 comme Terminé et ajoute une signature hors ligne. À 11:40, un répartiteur réassigne le Job #18 parce qu'il semble encore ouvert au bureau. Quand le technicien se reconnecte à 12:05, l'app envoie les changements.
Un bon flux de conflit ne cache pas cela. Il le met en évidence. Un superviseur doit voir un message simple : « Deux versions du Job #18 existent », avec les champs clés côte à côte (statut, technicien assigné, horodatage, signature oui/non) et des options claires : garder la mise à jour du terrain, garder la mise à jour du bureau, ou fusionner par champ.
C'est là que vos choix de stockage et de sync se manifestent : pouvez‑vous garder un historique net des changements et les rejouer en toute sécurité après des heures hors ligne ?
Quand un job « disparaît », le débogage consiste surtout à prouver ce qui s'est passé. Journalisez assez pour répondre : correspondance ID local/ID serveur (y compris lors de la création), chaque écriture avec horodatage/utilisateur/appareil, tentatives de sync et messages d'erreur, décisions de conflit et vainqueur, et statut d'upload des photos suivi séparément du job.
Avec ces logs, vous pouvez reproduire le problème au lieu de deviner à partir d'une plainte.
Étapes suivantes : valider rapidement, puis construire la solution terrain complète
Avant de prendre parti dans le débat SQLite vs Realm, rédigez une page qui spécifie vos flux hors ligne : les écrans qu'un technicien voit, quelles données vivent sur l'appareil et ce qui doit fonctionner sans signal (création, édition, photos, signatures, uploads en file d'attente).
Puis prototypez le système entier tôt, pas seulement la base. Les applis terrain échouent aux jonctions : un formulaire mobile qui sauvegarde localement n'aide pas si l'équipe admin ne peut pas revoir et corriger les enregistrements, ou si le backend rejette plus tard les mises à jour.
Un plan de validation pratique :
- Construisez une tranche fine bout en bout : un formulaire hors ligne, une vue de liste, une tentative de sync et un écran admin.
- Faites un test de changement : renommez un champ, scindez un champ en deux, publiez une build de test et observez le comportement de la mise à jour.
- Simulez des conflits : éditez la même fiche sur deux appareils, synchronisez dans des ordres différents et notez ce qui casse.
- Entraînez le débogage sur le terrain : décidez comment vous inspecterez les données locales, les logs et les payloads de sync échoués sur un appareil réel.
- Écrivez une politique de réinitialisation : quand vous videz le cache local, et comment les utilisateurs récupèrent sans perdre de travail.
Si la vitesse importe, une première passe no‑code peut vous aider à valider rapidement le workflow. AppMaster (appmaster.io) est une option pour bâtir la solution complète (services backend, panneau admin web et applis mobiles) tôt, puis régénérer du code propre lorsque les besoins changent.
Choisissez l'étape de validation suivante en fonction du risque. Si les formulaires changent chaque semaine, testez d'abord les migrations. Si plusieurs personnes touchent le même job, testez les conflits. Si vous craignez le « ça marchait au bureau », priorisez votre flux de débogage terrain.
FAQ
Offline-first signifie que l'application reste utile sans connexion : elle peut charger les données nécessaires, accepter de nouvelles saisies et garantir chaque modification jusqu'à ce que la synchronisation soit possible. La promesse clé est que les utilisateurs ne perdent pas leur travail ni leur confiance lorsque le réseau disparaît, que l'OS ferme l'application ou que la batterie s'épuise en cours de tâche.
SQLite est généralement un choix sûr quand vous avez besoin de filtres complexes, de requêtes de type reporting, de relations many-to-many et d'inspection ad hoc facile avec des outils standards. Realm convient souvent quand vous voulez un accès aux données orienté objet, des écritures transactionnelles par défaut, et que vos besoins de requête restent alignés avec les points forts de Realm.
Considérez les migrations comme une fonctionnalité centrale, pas comme une tâche ponctuelle. Installez une ancienne version, créez des données réalistes sur l'appareil, puis mettez à jour et vérifiez que l'app s'ouvre toujours, édite et synchronise ; testez aussi les gros jeux de données, le faible espace de stockage et l'arrêt de l'app en pleine migration.
Ajouter un champ est en général simple dans les deux systèmes, mais les renommages et les scissions (split) sont les plus risqués. Planifiez ces changements, définissez des valeurs par défaut raisonnables, gérez soigneusement les nulls et évitez les migrations qui réécrivent tous les enregistrements d'un coup sur des appareils anciens.
Les écrans de liste et les filtres qui reflètent le travail réel sont le principal critère : « tâches d'aujourd'hui », « formulaires non synchronisés », « édités au cours des 2 dernières heures », et une recherche réactive. Si exprimer ces requêtes est maladroit, l'interface deviendra lente ou le code difficile à maintenir.
Ni SQLite ni Realm ne « résolvent » les conflits à votre place : vous devez définir des règles métier. Commencez par choisir une règle claire par type d'entité (last write wins, fusion par champs ou revue manuelle) et faites en sorte que l'application puisse expliquer ce qui s'est passé quand deux appareils modifient la même fiche.
Enregistrez suffisamment de métadonnées pour expliquer et rejouer les modifications : ID utilisateur, ID appareil, horodatages et un marqueur « dernier modifié » par enregistrement. Conservez un journal d'opérations local pour voir ce qui a été mis en file, envoyé, échoué et accepté par le serveur.
SQLite est facile à inspecter car c'est un fichier que l'on peut extraire d'un appareil et requêter directement, ce qui aide pour l'analyse ad hoc et les exports. L'inspection Realm est souvent plus naturelle pour les graphes d'objets et les relations, mais les équipes habituées au SQL peuvent trouver l'analyse approfondie moins flexible.
Les risques de perte de données viennent le plus souvent de la logique applicative : écritures en plusieurs étapes sans point de commit clair, échecs de synchronisation cachés et absence de plan de récupération pour disque plein ou corruption. Utilisez des transactions/checkpoints, affichez clairement l'état d'enregistrement et de synchronisation, et proposez une option de « réinitialiser et resynchroniser » prévisible.
Construisez un scénario bout en bout réaliste et mesurez-le : premier chargement avec des milliers d'enregistrements, recherche, sauvegardes de formulaires longs et un « jour hors ligne puis reconnexion ». Validez les mises à jour à partir d'au moins deux versions antérieures, simulez des conflits avec deux appareils et confirmez que vous pouvez inspecter l'état local et les journaux quand il y a un problème.


