Thibaud.
← Retour au blog
10 mars 202618 min de lecture

Récolt'IQ : pourquoi j'ai codé pour mon père

PWA, Capacitor, offline-first dans les champs — architecture données, sync, et pourquoi viser « suffisamment bon » plutôt que « parfait » quand les utilisateurs sont dans la boue.

PWACapacitorJavaScriptFirebaseOfflineService Worker

Mon père a toujours géré la moisson avec des papiers. Carnets griffonnés, feuilles qui s’envolent avec le vent, tableurs Excel qu’il était presque le seul à lire correctement. J’ai grandi avec ce bruit de fond. Un premier jet, c’était un site fait uniquement pour lui — un prototype privé. Puis l’évidence : le problème n’était pas « son » organisation, c’était un pattern métier. J’ai tout recadré pour une app utilisable par d’autres exploitations, sans perdre le flux réel d’une récolte.

Le problème terrain que le papier ne résout pas

Une moisson, ce n’est pas une ligne dans un tableur. Ce sont plusieurs parcelles actives, plusieurs camions qui se succèdent, des pesées à enregistrer à la volée, un stock qui bouge en temps réel et des décisions le soir même (« combien il reste à vendre ? »). Le papier scale mal : erreurs de retranscription, pas d’historique fiable, pas de partage propre entre personnes sur le terrain.

Le deuxième problème, c’est géographique. Les champs, c’est souvent mal couvert. Pas de 4G stable, parfois rien du tout pendant des heures. Une app « online only » est une app morte au moment où tu en as le plus besoin. D’où le choix d’une architecture offline-first : l’outil doit rester utilisable quand le réseau disparaît, et rattraper le retard quand il revient.

Pourquoi PWA + Capacitor plutôt que Swift natif d’entrée

Je maîtrisais déjà JavaScript et l’écosystème web. Partir sur SwiftUI ou UIKit pour un premier produit complet, c’était des mois de montée en puissance avant la moindre release utile. La PWA m’a permis de valider le produit vite : même codebase pour le navigateur et la logique métier, service worker pour le hors-ligne, et itération continue avec des utilisateurs qui testent sur leurs propres téléphones.

Capacitor est entré en jeu pour la distribution App Store : empaqueter le shell web dans une WebView native, accéder aux APIs iOS (splash, statut bar, plugins réseau / stockage natif quand nécessaire) sans réécrire toute l’UI. Ce n’est pas la solution « pure perf » qu’un puriste natif choisirait — c’est le bon compromis quand le risque principal était de ne jamais shipper.

Offline-first : concrètement, ça veut dire quoi

Ça commence par une règle d’or : toute action métier critique doit pouvoir être enregistrée localement sans attendre une réponse HTTP. Les pesées, les mises à jour de stock, les notes de passage camion — tout ça part dans une couche locale (IndexedDB via des abstractions JS, ou stockage structuré selon ce que j’avais branché à l’époque) avec un horodatage et un identifiant client.

Quand le réseau revient, une file de synchronisation rejoue les opérations vers Firebase. Là où ça devient délicat, c’est les conflits : deux personnes modifient la même parcelle hors ligne, ou une pesée locale contredit une règle métier côté serveur. J’ai fini par une stratégie pragmatique basée sur les timestamps et l’ordre d’arrivée côté client, avec des garde-fous pour ne pas écraser silencieusement des données plus récentes.

javascript
// Idée de flux (simplifié) : écrire d'abord local, marquer 'pending'
async function enregistrerPeseeLocale(payload) {
  const id = crypto.randomUUID();
  await localStore.put({
    id,
    ...payload,
    status: "pending",
    createdAt: Date.now(),
  });
  await syncQueue.enqueue({ type: "pesee", localId: id });
  trySyncWhenOnline();
}

Le service worker joue le rôle de filet : mettre en cache les assets de l’app, intercepter certaines routes pour répondre depuis le cache, et laisser passer les appels API quand la connectivité le permet. Le piège classique, c’est de cacher trop agressivement et de servir une vieille version de l’app — j’ai versionné les caches et invalidé sur déploiement.

Modèle de données et temps réel quand ça existe

Côté cloud, Firebase (Firestore + Auth) pour le compte utilisateur, le partage de parcelles entre membres d’une exploitation, et les agrégats de stock. Le modèle tourne autour des entités métier : parcelles, camions, pesées, cultures, stock restant. Les règles de sécurité Firestore segmentent par utilisateur / exploitation pour éviter qu’un exploitant lise les données d’un autre.

Quand la connexion est là, les écouteurs Firestore mettent à jour l’UI — tableau de bord, graphiques simplifiés, alertes de seuil. Quand elle n’y est pas, l’UI reste alimentée par le cache local et les files en attente ; l’utilisateur voit un état cohérent avec ce qu’il vient de saisir, pas un spinner infini.

Qui utilise l’app, et à quelle échelle

Pas des milliers d’utilisateurs. Ma famille, les collègues et amis de mon père — un réseau proche, des retours directs, des bugs signalés par SMS. C’est une échelle modeste mais honnête : les personas ne sont pas inventés en salle de réunion, ce sont des gens qui ramassent du grain et qui s’énervent si un bouton est au mauvais endroit.

Exports, Excel, et le monde réel

Les agriculteurs vivent encore avec Excel pour la compta et les déclarations. J’ai branché des exports (CSV / tableurs) pour ne pas les enfermer dans mon UI : l’app accélère la saisie et la centralisation, le tableur reste l’outil de fin de chaîne qu’ils connaissent. C’est un détail produit plus important qu’un dark mode parfait.

Ce que j’ai appris — au-delà du technique

Le logiciel n’est jamais fini. Il y aura toujours des bugs à corriger, des cas limites découverts en conditions réelles, des téléphones plus vieux que prévu. J’ai arrêté de chercher la version parfaite avant de sortir : j’ai visé une version suffisamment fiable pour ne pas bloquer le travail sur le terrain, puis j’ai itéré avec les retours.

C’est mon premier vrai projet dev mené seul de bout en bout jusqu’au store et à des utilisateurs réels. La leçon la plus personnelle, ce n’est pas une astuce Firestore — c’est que coder pour quelqu’un que tu connais change la manière dont tu priorises. Tu ne peux pas te cacher derrière une spec floue : la spec, c’est ton père qui gèle dans la cabine du camion.

Je n'ai pas fait cette app pour la mettre sur mon CV. Je l'ai faite parce que mon père en avait besoin. C'est cette différence — coder pour quelqu'un de réel plutôt que pour un brief — qui m'a appris ce que ça veut dire de finir un projet.