É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 depubspec.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.txtbasé surgit describepeut ne pas être toujours exactement égal à la versionpubspec(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.
- Comparaison directe avec
- 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 danspubspec.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) etPlus 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.txtse 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 utilisePackageInfo.fromPlatform()pour afficherversion (buildNumber). - [x] Pour l’étape 1, aucune évolution spécifique Android/iOS n’est nécessaire : la logique de comparaison avec
version.txtreste 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
AppVersioncôté Flutter viaAppVersionInfo.fromPackageInfo()qui encapsulePackageInfo.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.txten 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.txtinaccessible). - [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 globalUpdateNotificationWidgetempilé dans lehomedeMaterialApp(main.dart). - [x] T3.2 – Ajouter un petit contrôleur/state (Provider, Riverpod, Bloc, etc. selon l’architecture existante) qui :
- appelle
VersionServiceau 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 duVersionServicecô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 boutonsMettre à jour(reload immédiat) etPlus 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(viadart:html), - appeler
registration.update()pour forcer la recherche d’une nouvelle version au démarrage. → Implémenté viaServiceWorkerClient.forceUpdate()(lib/services/web/service_worker_client.dart+ stub/web) et appelé au démarrage Web dansUpdateNotificationWidget. - [x] T4.2 – (Optionnel mais recommandé) Écouter
onUpdateFound+installing.onStateChangepour savoir quand un nouveau SW estinstalled. → Implémenté dansServiceWorkerClient.forceUpdate(version web) avec un callbackonNewWorkerInstalleddéclenché sur l’évènementupdatefound/statechangequand un nouveau SW estinstalled. - [x] T4.3 – (Si décidé) Coupler cet évènement avec l’UX de mise à jour (dialog/snackbar).
→ Le callback
onNewWorkerInstalledrelance uncheckVersion()et, si une nouvelle version est détectée, déclenche le dialog Web de mise à jour (_showWebUpdateDialog) dansUpdateNotificationWidget.
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:htmlou l’API Service Worker : - est placé dans des fichiers spécifiques Web (pas dans du code partagé mobile),
- est protégé par des
kIsWebou 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.txtet 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) :
- Valider les décisions Q1–Q4 (version, UX, fréquence, visibilité mobile).
- Implémenter T1.x + T2.x (version locale +
VersionService), sans encore toucher à l’UI. - Implémenter T3.x (intégration UI Web) selon l’UX choisie.
- Ajouter T4.x (interaction Service Worker) si souhaité à cette étape.
- 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.