04 oct. 2026
2 min de lecture
- Offline-first
- Next.js
- PWA
- EdTech
- Architecture
Dans beaucoup d'écoles congolaises, la connexion tombe plusieurs fois par jour. Voici comment j'ai conçu Masomo pour que l'appel, les notes et la caisse n'attendent jamais le réseau.

Quand j'ai commencé à travailler sur Masomo, une plateforme de gestion scolaire pour la RDC, la première vraie contrainte n'était pas une fonctionnalité. C'était le réseau.
Un enseignant fait l'appel à 7h30. Le secrétaire encaisse les frais au portail. Le préfet imprime les bulletins en fin de période. Si l'une de ces actions affiche un spinner parce que la connexion est tombée, les gens reviennent au papier — et ils ne reviennent plus.
La règle est donc devenue simple : le réseau est une optimisation, pas une condition.
Le serveur est une cible de synchronisation, pas la source de vérité de l'interface
L'application web classique lit l'API puis affiche. L'offline-first inverse cela :
- L'interface lit et écrit dans un stockage local (IndexedDB dans le navigateur).
- Chaque écriture est aussi ajoutée à une file d'attente d'opérations.
- Une boucle de synchronisation envoie la file quand la connexion revient, puis récupère ce qui a changé côté serveur.
type Op = {
id: string; // UUID généré côté client → idempotent côté serveur
entity: 'attendance' | 'payment' | 'grade';
action: 'create' | 'update';
payload: unknown;
createdAt: number; // horloge de l'appareil, uniquement pour l'ordre
};
L'id généré côté client compte plus qu'il n'y paraît : si la requête expire après que le serveur a enregistré le paiement, le nouvel essai ne doit pas créer de doublon.
Modéliser les données pour que les conflits soient rares
La plupart des problèmes de « résolution de conflits » sont en réalité des problèmes de modèle de données.
- Ajouter, ne pas écraser. Un paiement est un événement immuable. Les corrections sont de nouveaux événements (remboursement, ajustement), jamais une modification de l'original.
- Chaque donnée a un propriétaire. L'appel d'une classe pour un jour donné appartient à l'enseignant de cette classe. Deux appareils modifient rarement la même chose.
- « La dernière écriture gagne » seulement quand c'est sans risque, comme le numéro de téléphone d'un élève.
Avec ça, la boucle de synchronisation reste ennuyeuse — et c'est exactement ce qu'on veut.
L'argent a besoin d'un contexte figé
Les écoles congolaises facturent en francs et en dollars. Si un parent paie en francs le lundi et que le reçu est imprimé le mercredi au taux du mercredi, les montants ne correspondent plus à ce que le parent a vu.
Chaque paiement enregistre donc le taux utilisé au moment du paiement, et le reçu est généré à partir de cet instantané — en ligne ou non. (J'en parle plus en détail dans un article sur la gestion de deux devises.)
Montrer l'état de synchronisation, honnêtement
Les gens font confiance à une application hors ligne quand ils voient ce qui se passe :
- un petit badge : synchronisé, 3 en attente, hors ligne ;
- l'heure de la dernière synchronisation réussie ;
- les éléments en attente marqués dans les listes, jamais cachés.
Si l'utilisateur ne sait pas si son travail est enregistré, il supposera que non.
Ce que je dirais à moi-même au début
- Commencer en offline-first dès le premier jour. L'ajouter à une application en ligne, c'est une réécriture.
- Rendre chaque écriture idempotente avant d'écrire la moindre ligne de synchronisation.
- Tester sur un vrai téléphone Android d'entrée de gamme avec une mauvaise 3G, pas sur un laptop avec la limitation de DevTools.
L'offline-first demande plus de travail au départ. Mais là où le réseau n'est pas fiable, c'est la différence entre un logiciel qu'on essaie et un logiciel qu'on utilise.