Skip to content

Étape 1 – Mise à jour PWA fiable (sans casser Android / iOS)

0. Contexte & contraintes

Objectif de cette étape :

  • Rendre la mise à jour de la PWA (structure Flutter web : JS/HTML/CSS + service worker) fiable et prévisible.
  • Ne pas casser les autres plateformes : Android et iOS doivent continuer à builder et fonctionner comme avant.

Contraintes importantes :

  • Le code spécifique Web (PWA, dart:html, Service Worker, etc.) doit être isolé pour ne pas casser les builds Android/iOS.
  • Les scripts de build existants (Android/iOS) ne doivent pas être modifiés de manière à introduire des régressions.
  • Les tests automatiques (flutter test) doivent continuer à passer sur toutes les plateformes.

1. Décisions à prendre (questions)

Ces décisions conditionnent la forme exacte des tâches techniques. On les clarifie ensemble, question par question.

Q1 – Source de vérité de la « version front »

Pour comparer la version locale de l’app Flutter (côté client) avec le version.txt déployé sur DreamHost, il faut choisir ce que représente la version locale.

Options possibles :

  • Option A – Version pubspec.yaml
  • La version affichée à l’utilisateur (ex : 1.2.3+45) vient de pubspec.yaml.
  • Avantages :
    • Alignée avec Android/iOS (même version logique sur toutes les plateformes).
    • Déjà gérée via version-manager.sh.
  • Inconvénients :

    • version.txt basé sur git describe peut ne pas être toujours exactement égal à la version pubspec (mais on peut comparer en mode "égal/pas égal" plutôt qu’en sémantique stricte).
  • Option B – Identifiant Git (git describe --tags --always)

  • La version locale web est un identifiant Git (tag ou hash court), identique à ce qui est écrit dans version.txt.
  • Avantages :
    • Comparaison directe avec version.txt (égalité stricte simple).
    • Très proche de ce que fait déjà le script de déploiement.
  • Inconvénients :
    • Moins lisible pour l’utilisateur final (si on l’affiche).
    • Nécessite d’être sûr que ce mécanisme reste valable aussi pour Android/iOS si on veut unifier.

Décision à prendre :

  • [x] Choix retenu : Option A (pubspec) comme source de vérité pour la comparaison avec version.txt (la version web utilisera la version définie dans pubspec.yaml).
  • [ ] Option B (Git) non retenue pour l’instant (complexité supplémentaire jugée inutile pour le besoin PWA).

Q2 – Comportement utilisateur lors d’une nouvelle version

Quand l’app détecte qu’une nouvelle version est disponible (via version.txt + Service Worker), quel comportement UX souhaites‑tu ?

Options principales :

  • Option 1 – Dialog bloquant
  • "Une nouvelle version de Yin Shi est disponible. Mettre à jour maintenant ?"
  • Boutons :

    • Mettre à jour → reload immédiat.
    • Plus tard → laisser l’ancienne version tourner, mais on peut garder un petit indicateur.
  • Option 2 – Snackbar discrète

  • Bandeau en bas de l’écran : "Nouvelle version disponible" avec un bouton Recharger.

  • Option 3 – Auto‑reload (surtout utile en environnement test)

  • Dès qu’une nouvelle version est détectée → reload automatique sans demander.

Décision à prendre :

  • [x] Production : utiliser Option 1 – Dialog bloquant avec deux actions : Mettre à jour (reload immédiat) et Plus tard (l’utilisateur reste sur l’ancienne version, mais un bouton ou indicateur dans l’UI permettra de relancer la mise à jour facilement).
  • [x] Environnement de test : pas d’auto‑reload spécifique pour l’instant, on garde le même comportement que la production (dialog bloquant).

Q3 – Fréquence de la vérification de version

Quand vérifier si une nouvelle version est disponible ?

Options :

  • Au démarrage uniquement
  • Simple et prévisible.
  • Suffisant pour la plupart des cas.

  • Au démarrage + périodiquement (ex. toutes les X minutes)

  • Utile pour les sessions très longues.
  • Ajoute un peu de complexité côté state management.

Décision à prendre :

  • [x] Démarrage uniquement pour l’étape 1 : la vérification de version.txt se fait au lancement/reload de la PWA.
  • [ ] Démarrage + check périodique (option conservée pour une étape ultérieure si besoin est identifié).

Q4 – Affichage de la version sur Android / iOS

Souhaites‑tu que la version utilisée pour la comparaison (version.txt) soit également :

  • affichée quelque part dans l’app mobile (ex : écran "À propos"),
  • ou uniquement utilisée en interne côté Web ?

Décision à prendre :

  • [x] La version est déjà visible pour l’utilisateur sur toutes les plateformes (Android / iOS / Web) via l’écran Réglages (SettingsScreen) qui utilise PackageInfo.fromPlatform() pour afficher version (buildNumber).
  • [x] Pour l’étape 1, aucune évolution spécifique Android/iOS n’est nécessaire : la logique de comparaison avec version.txt reste interne au Web (PWA) et ne change pas l’UI mobile.

2. Tâches techniques – Web (PWA)

⚠️ Toutes les tâches ci‑dessous concerneront uniquement la plateforme Web. On veillera à isoler le code Web (conditional imports, kIsWeb, etc.) pour ne pas casser Android/iOS.

2.1 Exposer la version locale pour Web

  • [x] T1.1 – Mettre en place un mécanisme pour exposer une AppVersion côté Flutter via AppVersionInfo.fromPackageInfo() qui encapsule PackageInfo.fromPlatform() (source unique : pubspec.yaml).
  • [x] T1.2 – Créer une petite classe immuable du type AppVersionInfo (plateforme‑agnostique) pour représenter la version.
  • [ ] T1.3 – Vérifier que cette structuration ne casse aucun code existant sur Android/iOS (classe neutre, sans import web).

2.2 Créer un VersionService (Web)

  • [x] T2.1 – Créer un service dédié (par ex. lib/services/web/version_service.dart) qui :
  • lit la version locale (AppVersionInfo),
  • fait un HTTP GET sur version.txt (URL relative à la racine de l'app, qui devient /web/version.txt en production),
  • normalise la chaîne retournée (trim, \n, etc.),
  • renvoie un résultat typé, par ex. :
    • VersionStatus.sameVersion,
    • VersionStatus.remoteNewer,
    • VersionStatus.error (avec détails).
  • [x] T2.2 – Gérer proprement les erreurs réseau (pas de crash, comportement silencieux si version.txt inaccessible).
  • [x] T2.3 – Ajouter des tests unitaires ciblés pour ce service.

2.3 Intégration dans l’UI Web

  • [x] T3.1 – Choisir le point d’intégration dans l’app (ex. racine MyApp, AppShell, ou un widget global). → Implémenté via un widget global UpdateNotificationWidget empilé dans le home de MaterialApp (main.dart).
  • [x] T3.2 – Ajouter un petit contrôleur/state (Provider, Riverpod, Bloc, etc. selon l’architecture existante) qui :
  • appelle VersionService au moment décidé (cf. Q3),
  • expose un état updateAvailable / checking / error. → Implémenté via l’état interne de _UpdateNotificationWidgetState (_webVersionResult, _showWebUpdateReminder) qui encapsule le résultat du VersionService côté Web.
  • [x] T3.3 – Implémenter l’UX décidée en Q2 (dialog/snackbar/auto‑reload) en s’appuyant sur cet état. → Côté Web, un dialog de mise à jour est affiché (_showWebUpdateDialog), avec les boutons Mettre à jour (reload immédiat) et Plus tard (affiche une bannière discrète en haut de l’écran).

2.4 Interaction avec le Service Worker

  • [x] T4.1 – Ajouter une fonction Web dédiée pour :
  • récupérer le ServiceWorkerRegistration (via dart:html),
  • appeler registration.update() pour forcer la recherche d’une nouvelle version au démarrage. → Implémenté via ServiceWorkerClient.forceUpdate() (lib/services/web/service_worker_client.dart + stub/web) et appelé au démarrage Web dans UpdateNotificationWidget.
  • [x] T4.2 – (Optionnel mais recommandé) Écouter onUpdateFound + installing.onStateChange pour savoir quand un nouveau SW est installed. → Implémenté dans ServiceWorkerClient.forceUpdate (version web) avec un callback onNewWorkerInstalled déclenché sur l’évènement updatefound / statechange quand un nouveau SW est installed.
  • [x] T4.3 – (Si décidé) Coupler cet évènement avec l’UX de mise à jour (dialog/snackbar). → Le callback onNewWorkerInstalled relance un checkVersion() et, si une nouvelle version est détectée, déclenche le dialog Web de mise à jour (_showWebUpdateDialog) dans UpdateNotificationWidget.

2.5 Tests manuels Web

  • [x] T5.1 – Scénario "user en ancienne version" :
  • Ouvrir la PWA (vN) sur https://yinshi-test.yinshi.app/.
  • Déployer vN+1 via ./scripts/deploy_web.sh --env test [--force].
  • Forcer la détection du nouveau service worker (bouton Update dans DevTools → Application → Service workers si besoin).
  • Vérifier que l’app détecte la nouvelle version et affiche le dialog, puis la bannière en cas de clic sur "Plus tard".
  • [ ] T5.2 – Scénario "session longue" (si check périodique) :
  • Laisser l’app ouverte longtemps.
  • Déployer une nouvelle version.
  • Vérifier que l’utilisateur est informé.

3. Tâches de protection Android / iOS

3.1 Isolation du code Web

  • [ ] T6.1 – S’assurer que tout code utilisant dart:html ou l’API Service Worker :
  • est placé dans des fichiers spécifiques Web (pas dans du code partagé mobile),
  • est protégé par des kIsWeb ou des imports conditionnels (if (dart.library.html) ...).
  • [ ] T6.2 – Vérifier que le reste du code (services, modèles, widgets) reste compatible Android/iOS sans erreur de compilation.

3.2 Pipelines & scripts

  • [ ] T7.1 – Vérifier que les scripts de build Android/iOS (GitHub Actions, Fastlane éventuel, etc.) n’ont pas besoin de version.txt et ne sont pas impactés par le nouveau code.
  • [ ] T7.2 – Lancer un build minimal Android et iOS après ajout du nouveau code Web pour confirmer l’absence de régressions de compilation.

3.3 Tests fonctionnels rapides sur mobile

  • [ ] T8.1 – Lancer l’app sur Android (émulateur ou device) et vérifier :
  • démarrage OK,
  • aucun écran cassé lié aux nouveaux services.
  • [ ] T8.2 – Idem sur iOS (simulateur ou device).

4. Plan de livraison pour l’étape 1

Proposition de séquencement (peut être remaniée en fonction de tes réponses aux questions Q1–Q4) :

  1. Valider les décisions Q1–Q4 (version, UX, fréquence, visibilité mobile).
  2. Implémenter T1.x + T2.x (version locale + VersionService), sans encore toucher à l’UI.
  3. Implémenter T3.x (intégration UI Web) selon l’UX choisie.
  4. Ajouter T4.x (interaction Service Worker) si souhaité à cette étape.
  5. Vérifier T6.x + T7.x + T8.x pour s’assurer qu’Android/iOS restent OK.

Ce document est volontairement détaillé mais certaines tâches restent génériques tant que les décisions Q1–Q4 ne sont pas prises. On les précisera au fur et à mesure de la discussion.