## TODO-APP.md ## 📋 Liste des tĂąches Ă  effectuer sur l'application GEOSECTOR ## đŸ§Ș Tests unitaires Flutter Ă  implĂ©menter ### 📁 Structure des tests Le dossier `/test` doit contenir des tests unitaires pour valider le comportement de l'application. ### 📝 Tests prioritaires Ă  crĂ©er #### 1\. **Tests des Repositories** (`test/repositories/`) `test/repositories/membre_repository_test.dart` - Test de crĂ©ation d'un membre avec succĂšs - Test de crĂ©ation avec email dĂ©jĂ  existant (409) - Test de mise Ă  jour d'un membre - Test de suppression d'un membre - Test de gestion des erreurs rĂ©seau - Test du cache Hive local `test/repositories/user_repository_test.dart` - Test de connexion rĂ©ussie - Test de connexion avec mauvais identifiants - Test de mise Ă  jour du profil utilisateur - Test de synchronisation des donnĂ©es - Test de gestion de session `test/repositories/operation_repository_test.dart` - Test de crĂ©ation d'opĂ©ration - Test d'activation/dĂ©sactivation - Test de rĂ©cupĂ©ration des opĂ©rations par amicale - Test de suppression avec transfert de passages #### 2\. **Tests des Services** (`test/services/`) `test/services/api_service_test.dart` - Test de dĂ©tection d'environnement (DEV/REC/PROD) - Test de gestion des sessions - Test de conversion DioException vers ApiException - Test des diffĂ©rents codes d'erreur HTTP - Test du retry automatique `test/services/logger_service_test.dart` - Test de dĂ©sactivation des logs en PROD - Test des diffĂ©rents niveaux de log - Test du formatage des messages `test/services/hive_service_test.dart` - Test d'initialisation des boĂźtes Hive - Test de sauvegarde et rĂ©cupĂ©ration - Test de suppression de donnĂ©es - Test de migration de schĂ©ma #### 3\. **Tests des Models** (`test/models/`) `test/models/membre_model_test.dart` - Test de sĂ©rialisation JSON - Test de dĂ©sĂ©rialisation JSON - Test de conversion vers UserModel - Test des valeurs par dĂ©faut `test/models/amicale_model_test.dart` - Test de sĂ©rialisation/dĂ©sĂ©rialisation - Test des nouveaux champs boolĂ©ens (chk_mdp_manuel, chk_username_manuel) - Test de validation des donnĂ©es #### 4\. **Tests des Widgets** (`test/widgets/`) `test/widgets/user_form_test.dart` - Test d'affichage conditionnel des champs (username/password) - Test de validation du mot de passe (regex) - Test de validation de l'username (pas d'espaces) - Test de gĂ©nĂ©ration automatique d'username - Test du mode crĂ©ation vs modification `test/widgets/membre_table_widget_test.dart` - Test d'affichage responsive (mobile vs web) - Test de masquage des colonnes sur mobile - Test des icĂŽnes de statut - Test du tri et filtrage #### 5\. **Tests d'intĂ©gration** (`test/integration/`) `test/integration/auth_flow_test.dart` - Test du flow complet de connexion - Test de persistance de session - Test de dĂ©connexion - Test de redirection aprĂšs expiration `test/integration/membre_management_test.dart` - Test de crĂ©ation complĂšte d'un membre - Test de modification avec validation - Test de suppression avec transfert - Test de gestion des erreurs ### đŸ› ïž Configuration des tests #### Fichier `test/test_helpers.dart` ```plaintext import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:dio/dio.dart'; import 'package:hive_flutter/hive_flutter.dart'; // Mocks nĂ©cessaires class MockDio extends Mock implements Dio {} class MockBox extends Mock implements Box {} class MockApiService extends Mock implements ApiService {} // Helper pour initialiser Hive en tests Future setupTestHive() async { await Hive.initFlutter(); // Initialiser les boĂźtes de test } // Helper pour nettoyer aprĂšs les tests Future tearDownTestHive() async { await Hive.deleteFromDisk(); } // Helper pour crĂ©er des donnĂ©es de test class TestDataFactory { static UserModel createTestUser() { return UserModel( id: 1, username: 'test_user', email: 'test@example.com', // ... ); } static MembreModel createTestMembre() { return MembreModel( id: 1, fkEntite: 100, name: 'Test', firstName: 'User', // ... ); } } ``` ### 📋 Commandes de test ```plaintext # Lancer tous les tests flutter test # Lancer un test spĂ©cifique flutter test test/repositories/membre_repository_test.dart # Lancer avec coverage flutter test --coverage # GĂ©nĂ©rer un rapport HTML de couverture genhtml coverage/lcov.info -o coverage/html open coverage/html/index.html ``` ### 🎯 Objectifs de couverture - **Repositories** : 80% minimum - **Services** : 90% minimum - **Models** : 95% minimum - **Widgets critiques** : 70% minimum - **Couverture globale** : 75% minimum ### 📚 DĂ©pendances de test Ă  ajouter Dans `pubspec.yaml` : ```plaintext dev_dependencies: flutter_test: sdk: flutter mockito: ^5.4.4 build_runner: ^2.4.8 test: ^1.25.2 flutter_lints: ^4.0.0 coverage: ^1.7.2 ``` ### 🔄 IntĂ©gration CI/CD Ajouter dans le pipeline CI : ```plaintext test: stage: test script: - flutter test --coverage - genhtml coverage/lcov.info -o coverage/html artifacts: paths: - coverage/ coverage: '/lines\.*: \d+\.\d+\%/' ``` ### 📝 Bonnes pratiques 1. **Isolation** : Chaque test doit ĂȘtre indĂ©pendant 2. **Mocking** : Utiliser des mocks pour les dĂ©pendances externes 3. **Nommage** : Utiliser des noms descriptifs (test_should_xxx_when_yyy) 4. **AAA** : Suivre le pattern Arrange-Act-Assert 5. **Edge cases** : Tester les cas limites et erreurs 6. **Performance** : Les tests unitaires doivent ĂȘtre rapides (\<100ms) ## 💬 Module Chat en ligne GEOSECTOR ### 📋 Vue d'ensemble Le module chat est partiellement implĂ©mentĂ© avec une architecture MQTT pour les notifications en temps rĂ©el. Il nĂ©cessite des dĂ©veloppements supplĂ©mentaires pour ĂȘtre pleinement fonctionnel. ### đŸ—ïž Architecture existante ```plaintext lib/chat/ ├── models/ # ✅ ModĂšles créés avec Hive │ ├── conversation_model.dart # Conversations (one-to-one, groupe, annonce) │ ├── message_model.dart # Messages avec piĂšces jointes │ ├── participant_model.dart # Participants aux conversations │ └── audience_target_model.dart # Cibles pour les annonces ├── repositories/ # ⚠ À complĂ©ter │ └── chat_repository.dart # Logique mĂ©tier du chat ├── services/ # ⚠ Partiellement implĂ©mentĂ© │ ├── chat_api_service.dart # Communication avec l'API │ ├── offline_queue_service.dart # File d'attente hors ligne │ └── notifications/ # 🔧 MQTT configurĂ© │ ├── mqtt_notification_service.dart │ └── mqtt_config.dart ├── widgets/ # ⚠ À implĂ©menter │ ├── chat_screen.dart # Écran principal du chat │ ├── conversations_list.dart # Liste des conversations │ ├── message_bubble.dart # Bulles de messages │ └── chat_input.dart # Zone de saisie └── pages/ # ⚠ À complĂ©ter └── chat_page.dart # Page principale ``` ### 📝 TĂąches de dĂ©veloppement Chat #### 1\. **Finalisation des modĂšles Hive** - ComplĂ©ter les adaptateurs Hive pour tous les modĂšles - Ajouter la gestion des piĂšces jointes (images, documents) - ImplĂ©menter le modĂšle `AnonymousUserModel` pour les utilisateurs temporaires - Ajouter les timestamps et statuts de lecture #### 2\. **Repository ChatRepository** - ImplĂ©menter `createConversation()` avec participants - ImplĂ©menter `sendMessage()` avec queue hors ligne - ImplĂ©menter `getConversations()` avec pagination - ImplĂ©menter `getMessages()` avec lazy loading - Ajouter la gestion des participants (ajout/suppression) - ImplĂ©menter les annonces ciblĂ©es par groupe #### 3\. **Services** - ComplĂ©ter `ChatApiService` avec endpoints REST - ImplĂ©menter la synchronisation bidirectionnelle - Configurer `OfflineQueueService` pour messages en attente - ImplĂ©menter le retry automatique avec exponential backoff - Ajouter la compression des images avant envoi #### 4\. **Notifications MQTT** - Installer et configurer Mosquitto dans le container Incus - Configurer SSL/TLS pour MQTT (port 8883) - ImplĂ©menter l'authentification par token JWT - CrĂ©er les topics par utilisateur/groupe/conversation - ImplĂ©menter le systĂšme de prĂ©sence (online/offline/typing) - Ajouter les ACLs pour sĂ©curiser les topics #### 5\. **Interface utilisateur** - CrĂ©er `ChatScreen` avec liste de messages - ImplĂ©menter `ConversationsList` avec badges non-lus - Designer `MessageBubble` (texte, images, documents) - CrĂ©er `ChatInput` avec: - Saisie de texte avec emoji picker - Bouton d'envoi de fichiers - Indicateur "en train d'Ă©crire" - Enregistrement vocal (optionnel) - Ajouter les animations (apparition messages, typing indicator) - ImplĂ©menter le swipe pour rĂ©pondre - Ajouter la recherche dans les conversations #### 6\. **FonctionnalitĂ©s avancĂ©es** - Notifications push locales via `flutter_local_notifications` - Chiffrement end-to-end des messages sensibles - RĂ©actions aux messages (emojis) - Messages Ă©phĂ©mĂšres avec auto-suppression - Partage de localisation en temps rĂ©el - Appels audio/vidĂ©o via WebRTC (phase 2) ### 🔧 Configuration backend requise #### Base de donnĂ©es ```plaintext -- Tables Ă  crĂ©er (voir chat_tables.sql) CREATE TABLE chat_conversations ( id INT PRIMARY KEY AUTO_INCREMENT, type ENUM('one_to_one', 'group', 'announcement'), created_by INT, created_at TIMESTAMP, updated_at TIMESTAMP ); CREATE TABLE chat_messages ( id INT PRIMARY KEY AUTO_INCREMENT, conversation_id INT, sender_id INT, content TEXT, type ENUM('text', 'image', 'file', 'location'), status ENUM('sent', 'delivered', 'read'), created_at TIMESTAMP ); CREATE TABLE chat_participants ( conversation_id INT, user_id INT, role ENUM('admin', 'member'), joined_at TIMESTAMP, last_read_message_id INT ); ``` #### Configuration MQTT ```plaintext # Installation Mosquitto apt-get install mosquitto mosquitto-clients # Configuration /etc/mosquitto/mosquitto.conf listener 1883 listener 8883 cafile /etc/mosquitto/ca.crt certfile /etc/mosquitto/server.crt keyfile /etc/mosquitto/server.key allow_anonymous false password_file /etc/mosquitto/passwd ``` ### 📩 DĂ©pendances Ă  ajouter ```plaintext dependencies: # MQTT et notifications mqtt5_client: ^4.0.0 flutter_local_notifications: ^17.0.0 # UI et UX emoji_picker_flutter: ^2.0.0 cached_network_image: ^3.3.1 photo_view: ^0.14.0 file_picker: ^6.1.1 # Utilitaires path_provider: ^2.1.2 image_picker: ^1.0.7 image: ^4.1.7 # Pour compression intl: ^0.19.0 # Pour formatage dates ``` ### đŸ§Ș Tests Ă  implĂ©menter - Tests unitaires des repositories - Tests d'intĂ©gration MQTT - Tests de performance (1000+ messages) - Tests hors ligne/online - Tests de sĂ©curitĂ© (injection, XSS) ## 💳 Module de paiement Stripe ### 📋 Vue d'ensemble IntĂ©gration de Stripe pour permettre aux amicales ayant activĂ© `chk_stripe` d'accepter les paiements par carte bancaire avec une commission de 1.4%. ### 🎯 Objectifs 1. Permettre le paiement en ligne lors des passages 2. GĂ©rer les comptes Stripe des amicales 3. Suivre les transactions et commissions 4. Offrir une expĂ©rience de paiement fluide ### 📝 TĂąches de dĂ©veloppement Stripe #### 1\. **Configuration initiale Stripe** - CrĂ©er un compte Stripe Connect Platform - Configurer les webhooks Stripe - Mettre en place l'environnement de test (sandbox) - Configurer les clĂ©s API (publishable/secret) - ImplĂ©menter la gestion sĂ©curisĂ©e des clĂ©s #### 2\. **Onboarding des amicales** - CrĂ©er un workflow d'inscription Stripe pour les amicales - ImplĂ©menter Stripe Connect Onboarding - GĂ©rer le KYC (Know Your Customer) requis par Stripe - Stocker de maniĂšre sĂ©curisĂ©e le `stripe_account_id` - CrĂ©er une page de statut du compte Stripe - GĂ©rer les documents requis (RIB, statuts, etc.) #### 3\. **ModĂšles de donnĂ©es** - CrĂ©er `StripeAccountModel` pour les comptes Connect - CrĂ©er `PaymentIntentModel` pour les intentions de paiement - CrĂ©er `TransactionModel` pour l'historique - Ajouter les champs Stripe dans `PassageModel` - ImplĂ©menter la table des commissions #### 4\. **Service StripeService** ```plaintext class StripeService { // Compte Connect Future createConnectAccount(AmicaleModel amicale); Future updateAccountStatus(String accountId); Future createAccountLink(String accountId); // Paiements Future createPaymentIntent({ required double amount, required String currency, required String connectedAccountId, }); Future confirmPayment(String paymentIntentId); Future refundPayment(String paymentIntentId); // Commissions double calculateApplicationFee(double amount); // 1.4% } ``` #### 5\. **Interface de paiement dans PassageForm** - DĂ©tecter si l'amicale accepte Stripe (`chk_stripe`) - Ajouter l'option "Paiement par carte" dans le dropdown - IntĂ©grer Stripe Elements pour la saisie de carte - ImplĂ©menter le flow de paiement 3D Secure - GĂ©rer les erreurs de paiement - Afficher le reçu de paiement - Permettre l'envoi du reçu par email #### 6\. **Widget StripePaymentSheet** ```plaintext class StripePaymentSheet extends StatefulWidget { final double amount; final String currency; final AmicaleModel amicale; final Function(String) onSuccess; final Function(String) onError; // UI avec: // - Montant Ă  payer // - Formulaire de carte (Stripe Elements) // - Bouton de validation // - Indicateur de traitement // - Gestion 3D Secure } ``` #### 7\. **Tableau de bord financier** - Page de suivi des transactions Stripe - Graphiques des paiements par pĂ©riode - Export des transactions (CSV/Excel) - Calcul automatique des commissions - Rapprochement bancaire - Dashboard temps rĂ©el des paiements #### 8\. **Webhooks Stripe** ```php // Backend PHP pour gĂ©rer les webhooks class StripeWebhookHandler { // Events Ă  gĂ©rer: - payment_intent.succeeded - payment_intent.failed - account.updated - payout.created - refund.created } ``` #### 9\. **SĂ©curitĂ©** - Chiffrement des donnĂ©es sensibles - Validation PCI DSS - Audit trail des transactions - DĂ©tection de fraude - Rate limiting sur les API - Tokenisation des cartes #### 10\. **Tests et conformitĂ©** - Tests avec cartes de test Stripe - Tests des cas d'erreur (carte refusĂ©e, etc.) - Tests 3D Secure - Tests de performance - ConformitĂ© RGPD pour les donnĂ©es de paiement - Documentation utilisateur ### 🔧 Configuration backend requise #### Tables base de donnĂ©es ```plaintext CREATE TABLE stripe_accounts ( id INT PRIMARY KEY AUTO_INCREMENT, fk_entite INT NOT NULL, stripe_account_id VARCHAR(255) ENCRYPTED, status ENUM('pending', 'active', 'restricted'), charges_enabled BOOLEAN DEFAULT FALSE, payouts_enabled BOOLEAN DEFAULT FALSE, created_at TIMESTAMP, updated_at TIMESTAMP ); CREATE TABLE stripe_transactions ( id INT PRIMARY KEY AUTO_INCREMENT, fk_passage INT, stripe_payment_intent_id VARCHAR(255), amount DECIMAL(10,2), currency VARCHAR(3), status VARCHAR(50), application_fee DECIMAL(10,2), created_at TIMESTAMP ); ``` #### Variables d'environnement ```plaintext STRIPE_PUBLISHABLE_KEY=pk_test_xxx STRIPE_SECRET_KEY=sk_test_xxx STRIPE_WEBHOOK_SECRET=whsec_xxx STRIPE_APPLICATION_FEE_PERCENT=1.4 ``` ### 📩 DĂ©pendances Stripe ```plaintext dependencies: # Stripe flutter_stripe: ^10.1.1 # SĂ©curitĂ© flutter_secure_storage: ^9.0.0 # UI shimmer: ^3.0.0 # Loading states lottie: ^3.1.0 # Animations succĂšs/Ă©chec ``` ### 🚀 Roadmap d'implĂ©mentation **Phase 1 (2 semaines)** - Configuration Stripe Connect - Onboarding basique des amicales - Tests en sandbox **Phase 2 (3 semaines)** - IntĂ©gration dans PassageForm - Gestion des paiements simples - Webhooks essentiels **Phase 3 (2 semaines)** - Dashboard financier - Export et rapports - Tests complets **Phase 4 (1 semaine)** - Mise en production - Monitoring - Documentation ### 💰 Estimation des coĂ»ts - **Stripe Connect** : 0.25€ par compte actif/mois - **Transactions** : 1.4% + 0.25€ par transaction - **Commission application** : 1.4% (reversĂ©e Ă  GEOSECTOR) - **CoĂ»t net pour l'amicale** : ~2.8% + 0.25€ par transaction **Date de crĂ©ation** : 2025-08-07 **Auteur** : Architecture Team **Version** : 1.3.0 ## đŸ§Ș Recette - Points Ă  corriger/amĂ©liorer ### 📊 Gestion des membres et statistiques #### Affichage et listes - [ ] **Ajouter la liste des membres avec leurs statistiques** comme dans l'ancienne version - [ ] **Historique avec choix des membres** - Permettre la sĂ©lection du membre dans l'historique - [ ] **Membres cochĂ©s en haut** - Dans la modification de secteur, afficher les membres sĂ©lectionnĂ©s en prioritĂ© - [ ] **Filtres sur la liste des membres** - Ajouter des filtres dans la page "Amicale et membres" #### Modification des secteurs - [x] **Bug : Changement de membre non pris en compte** - ✅ CORRIGÉ - La modification n'est pas sauvegardĂ©e lors du changement de membre sur un secteur ### 📝 Formulaires et saisie #### Passage - [x] **Nom obligatoire seulement si email** - ✅ CORRIGÉ - Le nom n'est obligatoire que si un email est renseignĂ© #### Membre - [ ] **Email non obligatoire** - Si identifiant et mot de passe sont saisis manuellement, l'email ne doit pas ĂȘtre obligatoire - [ ] **Helpers lisibles** - AmĂ©liorer les textes d'aide dans la fiche membre - [ ] **Modification de l'identifiant** - Permettre la modification de l'identifiant utilisateur - [ ] **Bug mot de passe gĂ©nĂ©rĂ©** - Le mot de passe gĂ©nĂ©rĂ© contient des espaces, ce qui pose problĂšme ### 💬 Module Chat - [ ] **Bouton "Envoyer un message"** - AmĂ©liorer la visibilitĂ© - [ ] **Police plus grasse** - Augmenter l'Ă©paisseur de la police pour une meilleure lisibilitĂ© ### đŸ—ș Carte et gĂ©olocalisation #### Configuration carte - [ ] **Zoom maximal** - DĂ©finir et implĂ©menter une limite de zoom maximum - [ ] **Carte type Snapchat** - Étudier l'utilisation d'un style de carte similaire Ă  Snapchat #### Mode terrain - [ ] **Revoir la gĂ©olocalisation** - AmĂ©liorer la prĂ©cision et le fonctionnement de la gĂ©olocalisation en mode terrain ### 📅 Historique et dates - [ ] **Dates de dĂ©but et fin** - Ajouter des sĂ©lecteurs de dates de dĂ©but et fin dans l'historique ### 🔐 Authentification et connexion #### Connexion - [ ] **Admin uniquement en web** - Restreindre l'accĂšs admin au web uniquement (pas sur mobile) - [ ] **Bug F5** - Corriger la dĂ©connexion lors du rafraĂźchissement de la page (F5) - [ ] **Connexion multi-rĂŽles** - En connexion utilisateur, permettre de se connecter soit comme admin, soit comme membre #### Inscription - [ ] **Double envoi email** - Envoyer 2 emails lors de l'inscription : un pour l'identifiant, un pour le mot de passe, avec informations complĂ©mentaires ### 💳 Module Stripe - [ ] **IntĂ©gration dans le formulaire de passage** - CrĂ©er la gestion du paiement en ligne au niveau du formulaire passage si l'amicale a un compte Stripe actif - [ ] **Mode hors connexion** - Étudier les possibilitĂ©s de paiement Stripe en mode hors ligne ### 👑 Mode Super Admin #### Gestion des amicales - [ ] **Bug suppression** - Corriger le ralentissement aprĂšs 3 suppressions d'amicales (problĂšme de purge) - [ ] **Filtres sur les amicales** - Ajouter des filtres de recherche/tri sur la liste des amicales - [ ] **Mode dĂ©mo** - ImplĂ©menter un mode dĂ©mo pour les prĂ©sentations - [ ] **Statuts actifs/inactifs** - Distinguer les amicales actives (qui ont rĂ©glĂ©) des autres #### Gestion des opĂ©rations - [ ] **Bug suppression opĂ©ration active** - Si suppression de l'opĂ©ration active, la prĂ©cĂ©dente doit redevenir active automatiquement ### ⏰ Deadline - **⚠ DATE BUTOIR : 08/10 pour le CongrĂšs** ## 🌐 Gestion du cache Flutter Web ### 📋 Vue d'ensemble StratĂ©gie de gestion du cache pour l'application Flutter Web selon l'environnement (DEV/REC/PROD). ### 🎯 Objectifs - **DEV/REC** : Aucun cache - rechargement forcĂ© Ă  chaque visite pour voir immĂ©diatement les changements - **PROD** : Cache intelligent avec versioning pour optimiser les performances ### 📝 Solution par environnement #### 1. **Environnements DEV et RECETTE** **StratĂ©gie : No-Cache radical** ##### Configuration serveur web (Apache) CrĂ©er/modifier le fichier `.htaccess` dans le dossier racine web : ```apache # .htaccess pour DEV/REC - Aucun cache # DĂ©sactiver complĂštement le cache Header set Cache-Control "no-cache, no-store, must-revalidate, private" Header set Pragma "no-cache" Header set Expires "0" # Forcer le rechargement pour tous les assets Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Pragma "no-cache" Header set Expires "0" # DĂ©sactiver le cache du navigateur via ETags FileETag None Header unset ETag ``` ##### Modification du service worker Dans `web/flutter_service_worker.js`, ajouter au dĂ©but : ```javascript // DEV/REC: Forcer le rechargement complet if (location.hostname === 'dapp.geosector.fr' || location.hostname === 'rapp.geosector.fr') { // Nettoyer tous les caches existants caches.keys().then(function(names) { for (let name of names) caches.delete(name); }); // Bypass le service worker pour toutes les requĂȘtes self.addEventListener('fetch', function(event) { event.respondWith(fetch(event.request)); }); // DĂ©sactiver le cache complĂštement return; } ``` ##### Headers Meta HTML Dans `web/index.html`, ajouter dans le `` : ```html ``` #### 2. **Environnement PRODUCTION** **StratĂ©gie : Cache intelligent avec versioning** ##### Configuration serveur web (Apache) ```apache # .htaccess pour PRODUCTION - Cache intelligent # Cache par dĂ©faut modĂ©rĂ© pour HTML Header set Cache-Control "public, max-age=3600, must-revalidate" # Cache long pour les assets statiques versionnĂ©s Header set Cache-Control "public, max-age=31536000, immutable" # Cache modĂ©rĂ© pour les images et fonts Header set Cache-Control "public, max-age=604800" # Pas de cache pour le service worker et manifeste Header set Cache-Control "no-cache, no-store, must-revalidate" # Activer ETags pour validation du cache FileETag MTime Size ``` ##### Script de build avec versioning CrĂ©er `build_web.sh` : ```bash #!/bin/bash # Script de build pour production avec versioning automatique # GĂ©nĂ©rer un hash de version basĂ© sur le timestamp VERSION=$(date +%Y%m%d%H%M%S) COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "no-git") # Build Flutter flutter build web --release --dart-define=APP_VERSION=$VERSION # Modifier index.html pour inclure la version sed -i "s/main.dart.js/main.dart.js?v=$VERSION/g" build/web/index.html sed -i "s/flutter.js/flutter.js?v=$VERSION/g" build/web/index.html # Ajouter version dans le service worker echo "const APP_VERSION = '$VERSION-$COMMIT_HASH';" | cat - build/web/flutter_service_worker.js > temp && mv temp build/web/flutter_service_worker.js # CrĂ©er un fichier version.json echo "{\"version\":\"$VERSION\",\"build\":\"$COMMIT_HASH\",\"date\":\"$(date -Iseconds)\"}" > build/web/version.json echo "Build completed with version: $VERSION-$COMMIT_HASH" ``` ##### Service worker intelligent Modifier `web/flutter_service_worker.js` pour production : ```javascript // PRODUCTION: Cache intelligent avec versioning const CACHE_VERSION = 'v1-' + APP_VERSION; // APP_VERSION injectĂ© par le build const RUNTIME = 'runtime'; // Installation : mettre en cache les ressources essentielles self.addEventListener('install', (event) => { event.waitUntil( caches.open(CACHE_VERSION).then((cache) => { return cache.addAll([ '/', 'main.dart.js', 'flutter.js', 'manifest.json' ]); }) ); self.skipWaiting(); }); // Activation : nettoyer les vieux caches self.addEventListener('activate', (event) => { event.waitUntil( caches.keys().then((cacheNames) => { return Promise.all( cacheNames.map((cacheName) => { if (cacheName !== CACHE_VERSION && cacheName !== RUNTIME) { return caches.delete(cacheName); } }) ); }) ); self.clients.claim(); }); // Fetch : stratĂ©gie cache-first pour assets, network-first pour API self.addEventListener('fetch', (event) => { const url = new URL(event.request.url); // Network-first pour API et donnĂ©es dynamiques if (url.pathname.startsWith('/api/')) { event.respondWith( fetch(event.request) .then((response) => { const responseClone = response.clone(); caches.open(RUNTIME).then((cache) => { cache.put(event.request, responseClone); }); return response; }) .catch(() => caches.match(event.request)) ); return; } // Cache-first pour assets statiques event.respondWith( caches.match(event.request).then((cachedResponse) => { return cachedResponse || fetch(event.request).then((response) => { return caches.open(RUNTIME).then((cache) => { cache.put(event.request, response.clone()); return response; }); }); }) ); }); ``` ### 🔧 DĂ©tection automatique de nouvelle version Ajouter dans l'application Flutter : ```dart // lib/services/version_check_service.dart class VersionCheckService { static const Duration _checkInterval = Duration(minutes: 5); Timer? _timer; String? _currentVersion; void startVersionCheck() { if (!kIsWeb) return; // VĂ©rifier la version toutes les 5 minutes _timer = Timer.periodic(_checkInterval, (_) => _checkVersion()); // VĂ©rification initiale _checkVersion(); } Future _checkVersion() async { try { final response = await http.get( Uri.parse('/version.json?t=${DateTime.now().millisecondsSinceEpoch}') ); if (response.statusCode == 200) { final data = jsonDecode(response.body); final newVersion = data['version']; if (_currentVersion != null && _currentVersion != newVersion) { // Nouvelle version dĂ©tectĂ©e _showUpdateDialog(); } _currentVersion = newVersion; } } catch (e) { print('Erreur vĂ©rification version: $e'); } } void _showUpdateDialog() { // Afficher une notification ou dialog showDialog( context: navigatorKey.currentContext!, barrierDismissible: false, builder: (context) => AlertDialog( title: Text('Nouvelle version disponible'), content: Text('Une nouvelle version de l\'application est disponible. ' 'L\'application va se recharger.'), actions: [ TextButton( onPressed: () { // Forcer le rechargement complet html.window.location.reload(); }, child: Text('Recharger maintenant'), ), ], ), ); } void dispose() { _timer?.cancel(); } } ``` ### 📋 Commandes de dĂ©ploiement ```bash # DEV/REC - DĂ©ploiement sans cache flutter build web --release rsync -av --delete build/web/ user@server:/var/www/dapp/ # PRODUCTION - DĂ©ploiement avec versioning ./build_web.sh rsync -av --delete build/web/ user@server:/var/www/app/ ``` ### đŸ§Ș Validation du no-cache Pour vĂ©rifier que le cache est dĂ©sactivĂ© en DEV/REC : 1. **Ouvrir Chrome DevTools** → Network 2. **VĂ©rifier les headers de rĂ©ponse** : - `Cache-Control: no-cache, no-store, must-revalidate` - `Pragma: no-cache` - `Expires: 0` 3. **Recharger la page** : tous les fichiers doivent ĂȘtre rechargĂ©s (status 200, pas 304) 4. **VĂ©rifier dans Application** → Storage → Clear site data ### 📝 Notes importantes - **DEV/REC** : Les utilisateurs verront toujours la derniĂšre version immĂ©diatement - **PROD** : Les utilisateurs bĂ©nĂ©ficient d'un cache optimisĂ© avec dĂ©tection automatique des mises Ă  jour - **Service Worker** : GĂ©rĂ© diffĂ©remment selon l'environnement - **Versioning** : Utilise timestamp + hash git pour identifier uniques les builds - **Fallback** : En cas d'Ă©chec rĂ©seau en PROD, utilise le cache pour maintenir l'app fonctionnelle **Date d'ajout** : 2025-09-23 **Auteur** : Solution de gestion du cache **Version** : 1.0.0