- Mise à jour VERSION vers 3.3.4 - Optimisations et révisions architecture API (deploy-api.sh, scripts de migration) - Ajout documentation Stripe Tap to Pay complète - Migration vers polices Inter Variable pour Flutter - Optimisations build Android et nettoyage fichiers temporaires - Amélioration système de déploiement avec gestion backups - Ajout scripts CRON et migrations base de données 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1011 lines
30 KiB
Markdown
1011 lines
30 KiB
Markdown
## 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<t> extends Mock implements Box<t> {}
|
|
class MockApiService extends Mock implements ApiService {}
|
|
|
|
// Helper pour initialiser Hive en tests
|
|
Future<void> setupTestHive() async {
|
|
await Hive.initFlutter();
|
|
// Initialiser les boîtes de test
|
|
}
|
|
|
|
// Helper pour nettoyer après les tests
|
|
Future<void> 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<string> createConnectAccount(AmicaleModel amicale);
|
|
Future<void> updateAccountStatus(String accountId);
|
|
Future<string> createAccountLink(String accountId);
|
|
|
|
// Paiements
|
|
Future<paymentintent> createPaymentIntent({
|
|
required double amount,
|
|
required String currency,
|
|
required String connectedAccountId,
|
|
});
|
|
|
|
Future<void> confirmPayment(String paymentIntentId);
|
|
Future<void> 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
|
|
<IfModule mod_headers.c>
|
|
# 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
|
|
<FilesMatch "\.(js|css|html|json|wasm|ttf|otf|woff|woff2|ico|png|jpg|jpeg|gif|svg)$">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
Header set Pragma "no-cache"
|
|
Header set Expires "0"
|
|
</FilesMatch>
|
|
</IfModule>
|
|
|
|
# Désactiver le cache du navigateur via ETags
|
|
FileETag None
|
|
<IfModule mod_headers.c>
|
|
Header unset ETag
|
|
</IfModule>
|
|
```
|
|
|
|
##### 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 `<head>` :
|
|
|
|
```html
|
|
<!-- DEV/REC: No-cache meta tags -->
|
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
<meta http-equiv="Expires" content="0">
|
|
|
|
<!-- Forcer le rechargement des ressources avec timestamp -->
|
|
<script>
|
|
// Ajouter un timestamp unique à toutes les ressources
|
|
if (location.hostname === 'dapp.geosector.fr' || location.hostname === 'rapp.geosector.fr') {
|
|
const timestamp = new Date().getTime();
|
|
window.flutterConfiguration = {
|
|
assetBase: './?t=' + timestamp,
|
|
canvasKitBaseUrl: 'canvaskit/?t=' + timestamp
|
|
};
|
|
}
|
|
</script>
|
|
```
|
|
|
|
#### 2. **Environnement PRODUCTION**
|
|
|
|
**Stratégie : Cache intelligent avec versioning**
|
|
|
|
##### Configuration serveur web (Apache)
|
|
|
|
```apache
|
|
# .htaccess pour PRODUCTION - Cache intelligent
|
|
<IfModule mod_headers.c>
|
|
# 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
|
|
<FilesMatch "\.(js|css|wasm)$">
|
|
Header set Cache-Control "public, max-age=31536000, immutable"
|
|
</FilesMatch>
|
|
|
|
# Cache modéré pour les images et fonts
|
|
<FilesMatch "\.(ttf|otf|woff|woff2|ico|png|jpg|jpeg|gif|svg)$">
|
|
Header set Cache-Control "public, max-age=604800"
|
|
</FilesMatch>
|
|
|
|
# Pas de cache pour le service worker et manifeste
|
|
<FilesMatch "(flutter_service_worker\.js|manifest\.json)$">
|
|
Header set Cache-Control "no-cache, no-store, must-revalidate"
|
|
</FilesMatch>
|
|
</IfModule>
|
|
|
|
# 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<void> _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
|