Tout le monde sait que les apps mobiles modernes peuvent “fonctionner hors ligne”. Les articles de blogue en parlent. Les vendeurs de logiciels en parlent. Les présentations de conférence en parlent.
Ce qu’ils ne disent pas, c’est que faire fonctionner une interface hors ligne est la partie facile. Ce qui est difficile — vraiment difficile — c’est de faire tourner la logique métier sans le serveur.
Voici ce que ça veut dire en pratique.
Un technicien en réfrigération, un toit, zéro barre
Un technicien de service en réfrigération commerciale arrive chez un client. Congélateurs de supermarché, systèmes de climatisation industriels. Il est sur un toit ou dans une salle mécanique sans WiFi et sans signal cellulaire fiable.
Il doit :
- Créer un bon de travail avec les pièces utilisées
- Calculer le temps travaillé avec les règles d’arrondi de la convention
- Configurer un système selon des paramètres qui dépendent du modèle d’équipement
- Valider que les pièces saisies sont compatibles avec l’équipement en question
- Faire signer le client
- Générer le PDF du rapport
Aucune de ces opérations ne peut attendre la reconnexion. Le technicien ne va pas retourner à son camion chercher du signal pour chaque étape.
C’est le problème réel qu’on a résolu.
La partie facile : stocker et synchroniser
La mécanique de base de l’offline-first est bien documentée et relativement bien comprise :
IndexedDB dans le navigateur (ou l’app PWA) stocke les données localement — bons de travail, historique client, catalogue de pièces, paramètres d’équipement. Tout ce dont le technicien a besoin pour sa journée est chargé au démarrage, pendant qu’il est encore connecté.
Service Worker intercepte les requêtes réseau. Quand la connexion est absente, il sert les données locales sans que l’app le “sache”. Pour le code de l’application, ça ressemble à une requête normale.
Sync queue : chaque action effectuée offline (créer un bon, ajouter une pièce, signer) est capturée comme un événement et mise en file d’attente dans IndexedDB. À la reconnexion, ces événements se rejouent dans l’ordre vers le serveur.
C’est le socle. C’est ce dont la plupart des articles parlent. Ce n’est pas là que les problèmes intéressants se posent.
La partie difficile : dupliquer la logique métier
Voici où ça devient sérieux. Chaque règle d’affaires qui existait côté serveur doit maintenant aussi exister côté client — dans le navigateur, en WebAssembly, sans aucun appel réseau.
Exemple 1 — L’arrondi au quart d’heure
Dans la convention collective, le temps de travail s’arrondit aux 15 minutes les plus proches. Simple à dire. Mais il y a des cas limites : qu’est-ce qui se passe si le technicien “poinçonne” deux fois dans la même minute? Si la journée couvre minuit? Si les pauses sont déduites différemment selon le type d’appel?
Cette logique doit être identique côté client et côté serveur. Si elle diverge, les bons de travail générés offline ne correspondent pas à ce que le bureau voit. Ça crée des erreurs de paie, des disputes avec les techniciens, des corrections manuelles.
On a choisi Blazor WebAssembly avec .NET précisément pour ça : la même librairie C# qui tourne côté serveur tourne côté client en WASM. Une seule implémentation. Zéro duplication, zéro divergence.
Exemple 2 — Le configurateur de produits
Quand un technicien remplace un composant, les options disponibles dépendent du modèle d’équipement, de l’année, de la configuration existante, et parfois des pièces déjà saisies dans le même bon de travail. C’est un arbre de décision avec des dizaines de branches.
Ce configurateur doit tourner offline. Le catalogue complet de logique de compatibilité — potentiellement des centaines de règles — doit être téléchargé et indexé localement. Et quand un technicien sélectionne une pièce incompatible, le message d’erreur doit être immédiat, pas “impossible de vérifier, pas de connexion”.
Exemple 3 — La validation “Smart Accordéon”
Dans un formulaire d’installation, certaines sections ne deviennent visibles qu’en fonction des réponses précédentes. Ce n’est pas juste de l’affichage conditionnel — les règles de validation changent selon le contexte. Une section peut être optionnelle dans un cas et obligatoire dans un autre.
Toutes ces règles doivent fonctionner sans serveur. La validation finale avant signature doit être identique qu’on soit en ligne ou offline.
La sync queue : le vrai défi
La synchronisation offline→online semble simple : on garde une liste d’actions et on les rejoue à la reconnexion.
En pratique :
L’ordre compte. Si le technicien crée d’abord un bon de travail puis ajoute des pièces, ces deux opérations doivent arriver au serveur dans le bon ordre. Mais si deux techniciens ont travaillé sur le même client offline, leurs queues peuvent entrer en conflit.
Les erreurs de replay. Une action qui était valide offline peut être invalide quand elle arrive au serveur — parce que quelqu’un d’autre a modifié le même enregistrement entre-temps. Il faut décider : rejeter silencieusement? Alerter l’utilisateur? Merger automatiquement?
Les actions dépendantes. “Ajouter une pièce à un bon de travail” dépend de l’existence du bon de travail. Si le bon n’a pas encore été synchronisé, il faut soit attendre, soit utiliser des identifiants temporaires offline qui seront résolus à la sync.
On a géré ça avec une architecture de event sourcing local : chaque action est un événement immuable avec ses métadonnées, un timestamp offline, et les références nécessaires à sa résolution. La sync engine rejoue et résout dans l’ordre, avec une gestion explicite des conflits.
Pourquoi Blazor plutôt que React ou Flutter
Pour une équipe .NET — et pour une app où la logique métier partagée client/serveur est critique — Blazor WebAssembly était le choix évident.
Un seul langage (C#), une seule logique de validation, des types partagés entre le client et l’API. Quand une règle d’affaires change, elle change à un seul endroit.
Flutter aurait donné de bonnes performances natives, mais aurait exigé de dupliquer la logique métier en Dart. React/TypeScript aurait requis de maintenir deux implémentations (TS côté client, C# côté serveur) en synchronisation.
Pour les PME de services terrain avec des conventions collectives, des règles de facturation complexes et des catalogues de pièces riches — la cohérence de la logique métier vaut plus que la flexibilité de la stack.
Ce que ça a changé pour les techniciens
Depuis le déploiement :
- Les bons de travail sont générés et signés sur le terrain, immédiatement après l’intervention
- Le bureau reçoit les données dès que le technicien reprend du signal — souvent dans l’heure
- Les erreurs de saisie manuelle (retranscription des bons papier) ont pratiquement disparu
- Les disputes sur les heures travaillées ont diminué — le calcul est automatique et transparent
L’app ne leur demande pas de “travailler différemment”. Elle fait ce qu’ils font déjà — mais sans les attentes, les formulaires papier et les re-saisies au bureau.