feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles

- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -0,0 +1,395 @@
# TODO - Cache Web pour tuiles Mapbox
## Contexte
**Problème** : En PROD, les admins travaillent intensivement sur la plateforme web et la carte. Actuellement, les tuiles Mapbox ne sont pas mises en cache sur le web, ce qui provoque :
- Téléchargements répétés des mêmes tuiles
- Consommation excessive de bande passante
- Navigation peu fluide
- Coûts API Mapbox potentiellement élevés
**Cause** : Mapbox envoie des headers `Cache-Control: no-cache` qui empêchent le cache navigateur par défaut, et `flutter_map_cache` ne supporte pas la plateforme web.
**Solution** : Implémenter un cache manuel des tuiles via IndexedDB en Dart, uniquement pour le web.
## Architecture technique
### Flux de données
```
flutter_map demande une tuile
CachedWebTileProvider (nouveau)
WebTileCacheService.getTile()
Vérifie IndexedDB
┌─────────────┴─────────────┐
│ │
Cache HIT Cache MISS
│ │
Retourne image Télécharge depuis Mapbox
depuis IndexedDB ↓
Stocke dans IndexedDB
Retourne image
```
### Composants
1. **WebTileCacheService** (Singleton)
- Gère IndexedDB pour stocker les tuiles
- Méthodes : `getTile()`, `storeTile()`, `clearCache()`, `clearExpiredTiles()`
- Durée de cache : 30 jours (aligné avec mobile/desktop)
2. **CachedWebTileProvider** (Custom TileProvider)
- Implémente `TileProvider` de `flutter_map`
- Utilise `WebTileCacheService` pour récupérer/stocker
- Fallback sur téléchargement direct si erreur
3. **MapboxMap** (Modifié)
- Utilise `CachedWebTileProvider` sur web
- Garde `HiveCacheStore` sur mobile/desktop
## Fichiers à créer/modifier
### ✅ Fichiers à créer
#### 1. `lib/core/services/web_tile_cache_service.dart`
Service singleton pour gérer le cache IndexedDB des tuiles Mapbox.
**Responsabilités** :
- Initialiser la base IndexedDB `mapbox_tiles_cache`
- Stocker les tuiles avec clé unique (URL de la tuile)
- Récupérer les tuiles depuis le cache
- Gérer l'expiration (30 jours)
- Nettoyer les tuiles expirées
**Structure IndexedDB** :
```
Database: mapbox_tiles_cache
ObjectStore: tiles
- key: String (URL de la tuile)
- value: Object {
data: Uint8List (bytes de l'image)
timestamp: int (millisecondsSinceEpoch)
}
```
**API publique** :
```dart
class WebTileCacheService {
static final instance = WebTileCacheService._();
Future<void> initialize();
Future<Uint8List?> getTile(String url);
Future<void> storeTile(String url, Uint8List data);
Future<void> clearCache();
Future<void> clearExpiredTiles();
}
```
**Dépendances** :
- `dart:indexed_db` (natif web)
- `dart:typed_data`
- `package:flutter/foundation.dart` (kIsWeb)
#### 2. `lib/presentation/widgets/cached_web_tile_provider.dart`
TileProvider custom qui utilise le cache IndexedDB.
**Responsabilités** :
- Implémenter `TileProvider` de `flutter_map`
- Vérifier le cache avant téléchargement
- Télécharger et stocker si absent du cache
- Fallback sur comportement par défaut si erreur
**API publique** :
```dart
class CachedWebTileProvider extends TileProvider {
final String accessToken;
final String styleId;
CachedWebTileProvider({
required this.accessToken,
required this.styleId,
});
@override
ImageProvider getImage(TileCoordinates coordinates, TileLayer options);
}
```
**Logique** :
1. Construire l'URL de la tuile
2. Appeler `WebTileCacheService.getTile(url)`
3. Si trouvée → `MemoryImage(cachedData)`
4. Sinon → Télécharger → Stocker → `MemoryImage(downloadedData)`
**Dépendances** :
- `flutter_map`
- `WebTileCacheService`
- `dart:typed_data`
- `package:http/http.dart` (ou `Dio` si préféré)
### ✅ Fichiers à modifier
#### 3. `lib/presentation/widgets/mapbox_map.dart`
Modifier pour utiliser le nouveau provider sur web.
**Modifications** :
- Lignes 96-139 : Refactoriser `_initializeCache()`
- Utiliser `CachedWebTileProvider` quand `kIsWeb == true`
- Garder `HiveCacheStore` pour mobile/desktop
- Initialiser `WebTileCacheService` au démarrage sur web
**Avant** (lignes 98-103) :
```dart
if (kIsWeb) {
// Pas de cache sur Web (non supporté)
setState(() {
_cacheInitialized = true;
});
return;
}
```
**Après** :
```dart
if (kIsWeb) {
// Cache manuel via IndexedDB
await WebTileCacheService.instance.initialize();
setState(() {
_cacheInitialized = true;
});
return;
}
```
**TileLayer config** (ligne ~180) :
```dart
TileLayer(
urlTemplate: 'https://api.mapbox.com/styles/v1/mapbox/$styleId/tiles/256/{z}/{x}/{y}@2x?access_token=$accessToken',
tileProvider: kIsWeb
? CachedWebTileProvider(
accessToken: accessToken,
styleId: styleId,
)
: (_cacheStore != null
? CachedTileProvider(store: _cacheStore!)
: NetworkTileProvider()),
// ...
),
```
## Étapes d'implémentation
### Phase 1 : Service de cache IndexedDB
**Tâche 1.1** : Créer `web_tile_cache_service.dart`
- [ ] Créer la classe singleton
- [ ] Implémenter `initialize()` avec création de la DB IndexedDB
- [ ] Implémenter `getTile(url)` avec vérification d'expiration
- [ ] Implémenter `storeTile(url, data)` avec timestamp
- [ ] Implémenter `clearCache()` pour vider toute la DB
- [ ] Implémenter `clearExpiredTiles()` pour le nettoyage automatique
- [ ] Ajouter des logs de debug (`debugPrint`)
**Tâche 1.2** : Gestion des erreurs
- [ ] Try/catch sur toutes les opérations IndexedDB
- [ ] Fallback gracieux si IndexedDB indisponible
- [ ] Logs d'erreur explicites
**Tâche 1.3** : Tests unitaires
- [ ] Tester `initialize()` crée bien la DB
- [ ] Tester `storeTile()` + `getTile()` roundtrip
- [ ] Tester expiration (mock timestamp)
- [ ] Tester `clearCache()`
### Phase 2 : TileProvider custom
**Tâche 2.1** : Créer `cached_web_tile_provider.dart`
- [ ] Créer la classe qui extend `TileProvider`
- [ ] Implémenter `getImage()` avec logique de cache
- [ ] Gérer le téléchargement des tuiles manquantes
- [ ] Stocker les tuiles téléchargées dans le cache
- [ ] Ajouter des logs de performance (cache hit/miss)
**Tâche 2.2** : Gestion des erreurs réseau
- [ ] Try/catch sur téléchargement
- [ ] Retry logic (3 tentatives max)
- [ ] Placeholder si échec total
- [ ] Logs d'erreur explicites
**Tâche 2.3** : Tests
- [ ] Tester avec tuile en cache → Pas de requête réseau
- [ ] Tester avec tuile absente → Téléchargement + stockage
- [ ] Tester avec erreur réseau → Fallback gracieux
### Phase 3 : Intégration dans MapboxMap
**Tâche 3.1** : Modifier `mapbox_map.dart`
- [ ] Importer `CachedWebTileProvider` et `WebTileCacheService`
- [ ] Modifier `_initializeCache()` pour initialiser le service web
- [ ] Modifier `TileLayer` pour utiliser le bon provider selon la plateforme
- [ ] Tester sur web que le nouveau provider est bien utilisé
**Tâche 3.2** : Validation visuelle
- [ ] Lancer l'app en mode web DEV
- [ ] Ouvrir DevTools → Console pour voir les logs
- [ ] Naviguer sur la carte → Vérifier logs "Cache MISS" au premier passage
- [ ] Revenir sur la même zone → Vérifier logs "Cache HIT"
- [ ] Vérifier dans DevTools → Application → IndexedDB que les tuiles sont stockées
**Tâche 3.3** : Tests de performance
- [ ] Mesurer le temps de chargement initial (sans cache)
- [ ] Mesurer le temps de chargement avec cache
- [ ] Vérifier qu'il n'y a plus de requêtes réseau pour les tuiles en cache
- [ ] Tester sur une session longue (plusieurs déplacements sur la carte)
### Phase 4 : Nettoyage et documentation
**Tâche 4.1** : Nettoyage automatique
- [ ] Appeler `clearExpiredTiles()` au démarrage de l'app (dans `initialize()`)
- [ ] Ajouter un bouton admin pour vider manuellement le cache (optionnel)
**Tâche 4.2** : Logs et monitoring
- [ ] Ajouter des statistiques de cache (hit rate, taille totale)
- [ ] Logger les performances (temps de chargement moyen)
**Tâche 4.3** : Documentation
- [ ] Commenter le code (dartdoc)
- [ ] Mettre à jour `FLOW-*.md` si nécessaire
- [ ] Ajouter section dans README technique
## Tests de validation
### Tests fonctionnels
1. **Cache vide → Premier chargement**
- [ ] Ouvrir l'app web en mode incognito
- [ ] Naviguer sur la carte
- [ ] Vérifier que les tuiles se chargent
- [ ] Vérifier les logs "Cache MISS" + "Storing tile"
2. **Cache rempli → Rechargement**
- [ ] Recharger la page (F5)
- [ ] Revenir sur la même zone de carte
- [ ] Vérifier que les tuiles se chargent instantanément
- [ ] Vérifier les logs "Cache HIT"
- [ ] Vérifier dans Network tab : pas de requêtes Mapbox pour les tuiles en cache
3. **Navigation étendue**
- [ ] Se déplacer sur plusieurs zones de la carte
- [ ] Revenir sur les zones précédentes
- [ ] Vérifier mix de "Cache HIT" et "Cache MISS"
4. **Gestion de l'expiration**
- [ ] Modifier temporairement l'expiration à 10 secondes (pour test)
- [ ] Charger des tuiles
- [ ] Attendre 15 secondes
- [ ] Recharger → Vérifier que les tuiles sont re-téléchargées
5. **Gestion d'erreur réseau**
- [ ] Désactiver le réseau en plein chargement
- [ ] Vérifier que les tuiles en cache s'affichent quand même
- [ ] Vérifier que les tuiles manquantes ne bloquent pas l'app
### Tests de performance
6. **Mesure de bande passante**
- [ ] Vider le cache
- [ ] Naviguer sur une zone avec ~100 tuiles visibles
- [ ] Noter la bande passante consommée (DevTools Network)
- [ ] Recharger la page et revenir sur la même zone
- [ ] Vérifier que la bande passante est ~0 KB
7. **Mesure de vitesse**
- [ ] Mesurer le temps de chargement initial : ____ ms
- [ ] Mesurer le temps de chargement avec cache : ____ ms
- [ ] Objectif : >50% de réduction
### Tests multi-plateformes
8. **Mobile/Desktop non régressé**
- [ ] Lancer sur Android → Vérifier que HiveCacheStore fonctionne toujours
- [ ] Lancer sur iOS → Vérifier que HiveCacheStore fonctionne toujours
- [ ] Vérifier les logs "Cache initialized with HiveCacheStore"
9. **Web multi-navigateurs**
- [ ] Tester sur Chrome
- [ ] Tester sur Firefox
- [ ] Tester sur Safari (si IndexedDB supporté)
- [ ] Tester sur Edge
## Checklist de validation finale
- [ ] Aucune nouvelle dépendance ajoutée au `pubspec.yaml`
- [ ] Code compatible web uniquement (guards `kIsWeb`)
- [ ] Mobile/Desktop non impactés (toujours HiveCacheStore)
- [ ] Logs de debug présents et clairs
- [ ] Gestion d'erreur complète (try/catch)
- [ ] Expiration automatique (30 jours)
- [ ] Performance mesurée et améliorée
- [ ] Tests manuels passés
- [ ] Code documenté (dartdoc)
- [ ] Pas de régression sur les autres plateformes
## Notes techniques
### Pourquoi IndexedDB et pas localStorage ?
- **localStorage** : Limite de 5-10 MB → Insuffisant pour des tuiles (1 tuile = ~60 KB)
- **IndexedDB** : Limite de ~50% de l'espace disque disponible → Largement suffisant
### Structure de la clé de cache
Format recommandé : `{styleId}_{z}_{x}_{y}@{scale}x`
Exemple : `streets-v11_15_16234_11378@2x`
Cela permet :
- Identification unique de chaque tuile
- Support multi-styles (streets, satellite, etc.)
- Support multi-résolutions (@1x, @2x)
### Taille estimée du cache
- 1 tuile Mapbox @2x : ~60 KB
- Carte complète niveau zoom 15 : ~500 tuiles
- Total pour une zone : ~30 MB
- IndexedDB peut stocker plusieurs GB → Pas de souci
### Maintenance du cache
Le nettoyage automatique (`clearExpiredTiles()`) s'exécute :
- Au démarrage de l'app
- Évite l'accumulation de vieilles tuiles
- Garde le cache sous contrôle
## Dépendances
### Packages Flutter (déjà présents)
- `flutter_map: ^7.0.2` → Fournit `TileProvider`
- `flutter_map_cache: ^1.5.1` → Pour mobile/desktop uniquement
### Bibliothèques Dart natives (aucun ajout)
- `dart:indexed_db` → Pour IndexedDB (web seulement)
- `dart:typed_data` → Pour manipuler les bytes
- `package:flutter/foundation.dart` → Pour `kIsWeb`
### Pas de nouvelle dépendance externe ✅
## Estimation
- **Temps de développement** : 2-3 heures
- **Complexité** : Moyenne
- **Risque** : Faible (fallback sur comportement actuel)
- **Gain** : Important pour les admins PROD
## Prochaine étape
**Attente de validation utilisateur** pour démarrer l'implémentation.