Ajout documentation
This commit is contained in:
@@ -0,0 +1,447 @@
|
|||||||
|
# Cahier des Charges — Application Utilisateur Mobile & Web
|
||||||
|
## Projet : Laverie Connectée — App Flutter
|
||||||
|
**Version :** 1.0
|
||||||
|
**Date :** 2026-06-27
|
||||||
|
**Stack principale :** Flutter 3.x (Android / iOS / Web)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Contexte & Objectifs
|
||||||
|
|
||||||
|
### 1.1 Contexte
|
||||||
|
Application grand public permettant aux utilisateurs de :
|
||||||
|
- Localiser les laveries disponibles
|
||||||
|
- Gérer leur porte-monnaie électronique
|
||||||
|
- Réserver un créneau machine
|
||||||
|
- Déclencher un lavage par QR code
|
||||||
|
- Suivre leurs lavages et consulter leur historique
|
||||||
|
|
||||||
|
### 1.2 Cibles plateformes
|
||||||
|
| Plateforme | Version minimale | Distribution |
|
||||||
|
|------------|-----------------|--------------|
|
||||||
|
| Android | 8.0 (API 26) | Google Play Store |
|
||||||
|
| iOS | 15.0 | Apple App Store |
|
||||||
|
| Web | Chrome 100+, Safari 15+, Firefox 100+ | PWA hébergée |
|
||||||
|
|
||||||
|
### 1.3 Contraintes
|
||||||
|
- L'app doit rester **utilisable hors-ligne** pour les fonctions de consultation (solde en cache, historique)
|
||||||
|
- Respect strict du **RGPD** : collecte minimale, consentements explicites, droit à l'effacement
|
||||||
|
- L'application doit rester **connectée en arrière-plan** pour recevoir les notifications push
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Stack Technique
|
||||||
|
|
||||||
|
| Composant | Technologie | Version | Justification |
|
||||||
|
|-----------|-------------|---------|---------------|
|
||||||
|
| Framework UI | Flutter | 3.x (stable) | Codebase unique Android/iOS/Web |
|
||||||
|
| Langage | Dart | 3.x | Null-safety, typage fort |
|
||||||
|
| State management | Riverpod | 2.x | Réactivité, testabilité, pas de BuildContext dependency |
|
||||||
|
| Navigation | GoRouter | 13.x | Deep links, routing déclaratif |
|
||||||
|
| HTTP Client | Dio | 5.x | Intercepteurs JWT, retry automatique |
|
||||||
|
| Cache local | Hive | 2.x | Clé-valeur rapide, offline-first |
|
||||||
|
| Auth persistence | flutter_secure_storage | 9.x | Stockage sécurisé tokens (Keychain / Keystore) |
|
||||||
|
| Notifications push | firebase_messaging | 15.x | FCM Android/Web + APNs iOS |
|
||||||
|
| QR Code scan | mobile_scanner | 5.x | Caméra native, performant |
|
||||||
|
| Paiement in-app | flutter_stripe | 10.x | Stripe SDK officiel |
|
||||||
|
| Géolocalisation | geolocator | 13.x | Localisation établissements |
|
||||||
|
| Cartes | flutter_map + OpenStreetMap | — | Affichage carte sans coût API Google |
|
||||||
|
| Internationalisation | flutter_localizations | (Flutter) | fr / en au minimum |
|
||||||
|
| Tests | flutter_test + Mockito | — | Unit + widget + integration tests |
|
||||||
|
| CI/CD | GitHub Actions + Fastlane | — | Build, test, déploiement stores |
|
||||||
|
| Monitoring | Firebase Crashlytics | — | Crashes prod |
|
||||||
|
| Analytics | Firebase Analytics | — | Entonnoirs, rétention |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Architecture de l'Application
|
||||||
|
|
||||||
|
### 3.1 Pattern architectural : Clean Architecture + Feature-first
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
├── core/
|
||||||
|
│ ├── api/
|
||||||
|
│ │ ├── api_client.dart # Instance Dio configurée
|
||||||
|
│ │ ├── interceptors/
|
||||||
|
│ │ │ ├── auth_interceptor.dart # Injection Bearer token
|
||||||
|
│ │ │ └── retry_interceptor.dart # Retry sur 401 avec refresh
|
||||||
|
│ │ └── api_exception.dart
|
||||||
|
│ ├── cache/
|
||||||
|
│ │ └── hive_service.dart # Abstraction cache local
|
||||||
|
│ ├── router/
|
||||||
|
│ │ └── app_router.dart # GoRouter centralisé
|
||||||
|
│ ├── theme/
|
||||||
|
│ │ ├── app_theme.dart
|
||||||
|
│ │ └── app_colors.dart
|
||||||
|
│ └── utils/
|
||||||
|
│ ├── currency_formatter.dart
|
||||||
|
│ └── date_formatter.dart
|
||||||
|
│
|
||||||
|
├── features/
|
||||||
|
│ ├── auth/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ │ ├── auth_repository.dart
|
||||||
|
│ │ │ └── models/auth_token.dart
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ │ └── providers/auth_provider.dart
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── login_screen.dart
|
||||||
|
│ │ └── register_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── wallet/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── wallet_screen.dart
|
||||||
|
│ │ ├── transaction_history_screen.dart
|
||||||
|
│ │ └── top_up_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── establishments/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── map_screen.dart
|
||||||
|
│ │ ├── establishment_list_screen.dart
|
||||||
|
│ │ └── establishment_detail_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── machines/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── machine_card_widget.dart
|
||||||
|
│ │ └── machine_detail_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── booking/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── slot_picker_screen.dart
|
||||||
|
│ │ ├── booking_confirm_screen.dart
|
||||||
|
│ │ └── my_bookings_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── wash/
|
||||||
|
│ │ ├── data/
|
||||||
|
│ │ ├── domain/
|
||||||
|
│ │ └── presentation/
|
||||||
|
│ │ ├── qr_scanner_screen.dart
|
||||||
|
│ │ ├── wash_confirm_screen.dart
|
||||||
|
│ │ └── wash_active_screen.dart
|
||||||
|
│ │
|
||||||
|
│ ├── notifications/
|
||||||
|
│ │ └── notification_service.dart
|
||||||
|
│ │
|
||||||
|
│ └── profile/
|
||||||
|
│ └── presentation/
|
||||||
|
│ ├── profile_screen.dart
|
||||||
|
│ └── gdpr_settings_screen.dart
|
||||||
|
│
|
||||||
|
└── main.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Flux d'authentification
|
||||||
|
|
||||||
|
```
|
||||||
|
App start
|
||||||
|
└── AuthProvider.check()
|
||||||
|
├── Token valide → HomeScreen
|
||||||
|
├── Token expiré → RefreshToken()
|
||||||
|
│ ├── Succès → HomeScreen
|
||||||
|
│ └── Échec → LoginScreen
|
||||||
|
└── Pas de token → OnboardingScreen
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Gestion du token JWT
|
||||||
|
|
||||||
|
- `AuthInterceptor` (Dio) : inject `Authorization: Bearer <token>` sur chaque requête
|
||||||
|
- Sur 401 : appel automatique à `/auth/refresh` → retry de la requête originale
|
||||||
|
- Tokens stockés dans `flutter_secure_storage` (Keychain iOS / Keystore Android)
|
||||||
|
- Sur Web : stockage en `sessionStorage` chiffré (pas de `localStorage` pour les tokens)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Écrans & Parcours Utilisateur
|
||||||
|
|
||||||
|
### 4.1 Navigation principale (Bottom Navigation Bar)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ 🗺 Carte │ 💰 Wallet │ 📅 Réservations │ 👤 Profil │
|
||||||
|
└─────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Onboarding & Inscription
|
||||||
|
|
||||||
|
**Écran 1 — Bienvenue**
|
||||||
|
- Logo + baseline
|
||||||
|
- CTA : "Se connecter" / "Créer un compte"
|
||||||
|
|
||||||
|
**Écran 2 — Inscription (multi-étapes)**
|
||||||
|
- Étape 1 : Email + mot de passe (+ confirmation)
|
||||||
|
- Étape 2 : Prénom, nom, téléphone, date de naissance
|
||||||
|
- Étape 3 : Consentements RGPD (cases à cocher individuelles, non pré-cochées)
|
||||||
|
- Traitement des données (obligatoire)
|
||||||
|
- Communications marketing (optionnel)
|
||||||
|
- Analyse d'utilisation (optionnel)
|
||||||
|
- Étape 4 : Code parrainage (optionnel)
|
||||||
|
- Confirmation email requise avant accès complet
|
||||||
|
|
||||||
|
**Règles de validation :**
|
||||||
|
- Email : format RFC 5322
|
||||||
|
- Mot de passe : 8 caractères minimum, 1 majuscule, 1 chiffre
|
||||||
|
- Téléphone : format E.164 (`+33XXXXXXXXX`)
|
||||||
|
- Date de naissance : 16 ans minimum
|
||||||
|
|
||||||
|
### 4.3 Carte & Établissements
|
||||||
|
|
||||||
|
**Écran Carte (`MapScreen`)**
|
||||||
|
- Carte OpenStreetMap centrée sur la position utilisateur
|
||||||
|
- Marqueurs pour chaque établissement (couleur selon disponibilité)
|
||||||
|
- 🟢 Machines disponibles
|
||||||
|
- 🟡 Toutes occupées, créneaux libres
|
||||||
|
- 🔴 Toutes occupées, aucun créneau proche
|
||||||
|
- Tap sur marqueur → sheet inférieure avec résumé
|
||||||
|
- Bouton liste (switch vue liste / carte)
|
||||||
|
|
||||||
|
**Écran Détail Établissement**
|
||||||
|
- Nom, adresse, horaires
|
||||||
|
- Liste des machines avec statut temps réel (polling 30s ou WebSocket si dispo)
|
||||||
|
- Pour chaque machine : type, statut, prochain créneau libre, tarif actuel
|
||||||
|
- CTA : "Réserver" ou "Scanner & Lancer"
|
||||||
|
|
||||||
|
### 4.4 Porte-monnaie
|
||||||
|
|
||||||
|
**Écran Wallet**
|
||||||
|
- Solde affiché en grand (avec animation de mise à jour)
|
||||||
|
- Bouton "Recharger" bien visible
|
||||||
|
- Historique des 10 dernières transactions
|
||||||
|
- Lien "Voir tout"
|
||||||
|
|
||||||
|
**Écran Historique**
|
||||||
|
- Liste paginée (infinite scroll)
|
||||||
|
- Filtres : Type (débit/crédit), Période
|
||||||
|
- Chaque entrée : icône type, montant coloré, source, date/heure, solde après
|
||||||
|
- Export CSV (optionnel, v2)
|
||||||
|
|
||||||
|
**Parcours Rechargement**
|
||||||
|
1. Saisie du montant (suggestions : 10€, 20€, 50€)
|
||||||
|
2. Sélection du fournisseur de paiement (si plusieurs disponibles)
|
||||||
|
3. Redirection vers Stripe Checkout (WebView sécurisée) ou SDK natif
|
||||||
|
4. Retour sur l'app via deep link `laverie://wallet/topup-result`
|
||||||
|
5. Confirmation animée + mise à jour du solde
|
||||||
|
6. Notification push de confirmation
|
||||||
|
|
||||||
|
**Contraintes :**
|
||||||
|
- Montant minimum : 5€, maximum : 150€ par rechargement
|
||||||
|
- Affichage du solde en cache si hors-ligne
|
||||||
|
|
||||||
|
### 4.5 Réservation d'un Créneau
|
||||||
|
|
||||||
|
**Écran Sélection de Créneau (`SlotPickerScreen`)**
|
||||||
|
- Sélecteur de date (calendrier scrollable, 14 jours maximum)
|
||||||
|
- Pour la date sélectionnée : grille horaire avec créneaux libres/occupés
|
||||||
|
- Mise en évidence du prix par créneau (heure creuse / heure pleine)
|
||||||
|
- Information : "Supplément réservation : +1.00€"
|
||||||
|
|
||||||
|
**Écran Confirmation Réservation**
|
||||||
|
- Récapitulatif : machine, date/heure, durée, prix total
|
||||||
|
- Solde actuel et solde après débit
|
||||||
|
- Mention pénalité no-show
|
||||||
|
- Bouton "Confirmer et débiter X.XX€"
|
||||||
|
|
||||||
|
**Écran Mes Réservations**
|
||||||
|
- Onglets : À venir / Passées
|
||||||
|
- Chaque réservation : statut badge, machine, créneau, montant
|
||||||
|
- Actions possibles : "Annuler", "Déplacer" (si > 2h)
|
||||||
|
- Countdown pour les réservations imminentes
|
||||||
|
|
||||||
|
**Règles métier UI :**
|
||||||
|
- Créneau non réservable si solde insuffisant → CTA "Recharger d'abord"
|
||||||
|
- Annulation : popup de confirmation avec montant remboursé affiché
|
||||||
|
- Déplacement : ouvre SlotPickerScreen avec le même contexte machine
|
||||||
|
|
||||||
|
### 4.6 Déclenchement d'un Lavage par QR Code
|
||||||
|
|
||||||
|
**Écran Scanner QR (`QrScannerScreen`)**
|
||||||
|
- Vue caméra plein écran avec cadre de scan
|
||||||
|
- Feedback visuel à la détection (vibration + flash vert)
|
||||||
|
- Fallback : saisie manuelle du code machine
|
||||||
|
|
||||||
|
**Flux post-scan :**
|
||||||
|
1. Identification de la machine via le QR
|
||||||
|
2. Appel API → vérification statut + tarif
|
||||||
|
3. Affichage récap : machine, programme, prix estimé, solde après
|
||||||
|
4. Bouton "Lancer le lavage"
|
||||||
|
5. Animation de confirmation (spinner → ✓)
|
||||||
|
6. Écran "Lavage en cours" avec countdown
|
||||||
|
|
||||||
|
**Écran Lavage Actif (`WashActiveScreen`)**
|
||||||
|
- Machine + établissement
|
||||||
|
- Barre de progression avec temps restant (mise à jour polling API 30s)
|
||||||
|
- Montant débité
|
||||||
|
- Notification push à la fin du cycle
|
||||||
|
|
||||||
|
### 4.7 Notifications Push
|
||||||
|
|
||||||
|
**Configuration :**
|
||||||
|
- Demande de permission notifications à l'inscription (après onboarding)
|
||||||
|
- Sur iOS : `UNUserNotificationCenter.requestAuthorization`
|
||||||
|
- Sur Android 13+ : `POST_NOTIFICATIONS` permission
|
||||||
|
- Token FCM/APNs envoyé à l'API à chaque démarrage de l'app (mise à jour si changé)
|
||||||
|
|
||||||
|
**Gestion en foreground :**
|
||||||
|
- Affichage d'une bannière in-app (snackbar stylisée)
|
||||||
|
- Tap → navigation vers l'écran pertinent
|
||||||
|
|
||||||
|
**Deep links depuis notification :**
|
||||||
|
| Notification | Deep link |
|
||||||
|
|---|---|
|
||||||
|
| Rechargement confirmé | `laverie://wallet` |
|
||||||
|
| Réservation confirmée | `laverie://bookings/{uuid}` |
|
||||||
|
| Rappel créneau | `laverie://bookings/{uuid}` |
|
||||||
|
| Lavage terminé | `laverie://washes/{uuid}` |
|
||||||
|
| Promo disponible | `laverie://establishments/{uuid}` |
|
||||||
|
|
||||||
|
### 4.8 Profil & Paramètres
|
||||||
|
|
||||||
|
**Écran Profil**
|
||||||
|
- Informations personnelles (modifiables)
|
||||||
|
- Mes statistiques : nombre de lavages, total dépensé, économies promos
|
||||||
|
- Code parrainage personnel (copiable, partageable)
|
||||||
|
- Gestion notifications (toggle par type)
|
||||||
|
- Paramètres RGPD
|
||||||
|
- Déconnexion
|
||||||
|
|
||||||
|
**Écran Paramètres RGPD**
|
||||||
|
- Visualisation des consentements donnés (avec date)
|
||||||
|
- Toggle individuel pour chaque consentement
|
||||||
|
- Bouton "Télécharger mes données" (export JSON, v2)
|
||||||
|
- Bouton "Supprimer mon compte" (confirmation en deux étapes + délai 30 jours)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Gestion de l'État (Riverpod)
|
||||||
|
|
||||||
|
### 5.1 Providers principaux
|
||||||
|
|
||||||
|
```dart
|
||||||
|
// Auth
|
||||||
|
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>
|
||||||
|
|
||||||
|
// Wallet
|
||||||
|
final walletProvider = FutureProvider<WalletData>
|
||||||
|
final transactionsProvider = StateNotifierProvider<TransactionsNotifier, TransactionsState>
|
||||||
|
|
||||||
|
// Establishments
|
||||||
|
final establishmentsProvider = FutureProvider.family<Establishment, String> // by uuid
|
||||||
|
final nearbyEstablishmentsProvider = FutureProvider<List<Establishment>>
|
||||||
|
|
||||||
|
// Machines
|
||||||
|
final machineStatusProvider = StreamProvider.family<Machine, String> // polling 30s
|
||||||
|
|
||||||
|
// Bookings
|
||||||
|
final bookingsProvider = StateNotifierProvider<BookingsNotifier, BookingsState>
|
||||||
|
final slotAvailabilityProvider = FutureProvider.family<List<TimeSlot>, SlotQuery>
|
||||||
|
|
||||||
|
// Active wash
|
||||||
|
final activeWashProvider = StreamProvider<Wash?> // null si aucun lavage en cours
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Stratégie offline-first (Hive)
|
||||||
|
|
||||||
|
| Donnée | Cache | TTL |
|
||||||
|
|--------|-------|-----|
|
||||||
|
| Solde wallet | Oui | Jusqu'au prochain refresh |
|
||||||
|
| Historique transactions | Oui (50 dernières) | 24h |
|
||||||
|
| Établissements (liste) | Oui | 1h |
|
||||||
|
| Disponibilités machines | Non | — |
|
||||||
|
| Réservations | Oui | 30 min |
|
||||||
|
|
||||||
|
En cas d'absence de réseau : affichage des données en cache avec badge "Données hors-ligne".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Sécurité
|
||||||
|
|
||||||
|
### 6.1 Stockage
|
||||||
|
- Tokens JWT : `flutter_secure_storage` (AES-256 sur Android, Keychain sur iOS)
|
||||||
|
- Aucune donnée sensible dans `SharedPreferences`
|
||||||
|
- Sur Web : pas de localStorage, session uniquement
|
||||||
|
|
||||||
|
### 6.2 Réseau
|
||||||
|
- Certificate pinning en production (via `dio` custom `HttpClient`)
|
||||||
|
- Timeout : 10s connexion, 30s réception
|
||||||
|
- Toutes les requêtes en HTTPS (TLS 1.3)
|
||||||
|
|
||||||
|
### 6.3 QR Code
|
||||||
|
- Vérification côté serveur (le QR code seul ne suffit pas à déclencher un lavage)
|
||||||
|
- Rate limiting API sur `/washes/start` : 3 req/min/user
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Performance & UX
|
||||||
|
|
||||||
|
- **Splash screen** natif (Android 12 Splash API, iOS UILaunchScreen)
|
||||||
|
- **Skeleton loaders** sur toutes les listes et cartes pendant le chargement
|
||||||
|
- **Optimistic UI** : affichage anticipé des mises à jour (ex: annulation réservation)
|
||||||
|
- **Pull-to-refresh** sur toutes les listes
|
||||||
|
- **Pagination infinie** sur l'historique des transactions
|
||||||
|
- **Animations** : transitions de pages fluides (Hero, Fade), animation solde wallet
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Tests
|
||||||
|
|
||||||
|
| Type | Outil | Portée |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Tests unitaires | `flutter_test` | Providers Riverpod, formatters, validators |
|
||||||
|
| Tests widgets | `flutter_test` | Tous les écrans principaux |
|
||||||
|
| Tests d'intégration | `integration_test` | Parcours critiques (inscription, rechargement, scan QR) |
|
||||||
|
| Tests golden | `golden_toolkit` | Composants UI clés (cohérence visuelle) |
|
||||||
|
|
||||||
|
**Parcours critiques à couvrir en intégration :**
|
||||||
|
1. Inscription complète → vérification email → connexion
|
||||||
|
2. Rechargement porte-monnaie (mock Stripe)
|
||||||
|
3. Réservation créneau → annulation → vérification remboursement
|
||||||
|
4. Scan QR → lancement lavage → fin de cycle
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. CI/CD
|
||||||
|
|
||||||
|
### 9.1 Pipeline GitHub Actions
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Sur chaque PR :
|
||||||
|
- flutter analyze # Linting strict
|
||||||
|
- flutter test # Tests unitaires + widgets
|
||||||
|
- flutter build apk --release # Vérification build Android
|
||||||
|
- flutter build ios --release # Vérification build iOS (macOS runner)
|
||||||
|
- flutter build web # Vérification build Web
|
||||||
|
|
||||||
|
# Sur merge main :
|
||||||
|
- Fastlane → TestFlight (iOS)
|
||||||
|
- Fastlane → Play Store Internal Track (Android)
|
||||||
|
- Deploy Web → hébergement (Firebase Hosting ou VPS)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 Flavors
|
||||||
|
|
||||||
|
| Flavor | API URL | Firebase projet | Build suffix |
|
||||||
|
|--------|---------|-----------------|--------------|
|
||||||
|
| dev | `http://localhost:8000` | laverie-dev | `.dev` |
|
||||||
|
| staging | `https://api-staging.laverie.app` | laverie-staging | `.staging` |
|
||||||
|
| production | `https://api.laverie.app` | laverie-prod | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Livrables attendus
|
||||||
|
|
||||||
|
- [ ] Code source Flutter (GitHub, repository dédié)
|
||||||
|
- [ ] Flavors configurés (dev / staging / prod)
|
||||||
|
- [ ] `README.md` avec instructions setup complet
|
||||||
|
- [ ] Fichiers de configuration Firebase (`google-services.json`, `GoogleService-Info.plist`)
|
||||||
|
- [ ] Fichiers de signature Android (`.keystore`) documentés
|
||||||
|
- [ ] Screenshots pour les stores (5 par plateforme minimum)
|
||||||
|
- [ ] Suite de tests (couverture > 70% sur la logique métier)
|
||||||
|
- [ ] Build release Android (`.aab`) + iOS (`.ipa`) prêts à soumettre
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
# Cahier des Charges — Application Utilisateur Mobile & Web
|
||||||
|
## Projet : Laverie Connectée — App Flutter
|
||||||
|
**Version :** 2.0
|
||||||
|
**Stack principale :** Flutter 3.x (Android / iOS / Web)
|
||||||
|
**Positionnement :** V1 démontrable, centrée sur les parcours critiques
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Contexte & Objectifs
|
||||||
|
|
||||||
|
### 1.1 Objectif produit
|
||||||
|
Application grand public permettant aux utilisateurs de :
|
||||||
|
- localiser les laveries disponibles,
|
||||||
|
- consulter l'état des machines,
|
||||||
|
- recharger leur porte-monnaie,
|
||||||
|
- réserver un créneau,
|
||||||
|
- lancer un lavage,
|
||||||
|
- suivre l'historique de leurs opérations.
|
||||||
|
|
||||||
|
### 1.2 Objectif projet V1
|
||||||
|
La V1 doit être :
|
||||||
|
- démontrable rapidement,
|
||||||
|
- cohérente côté métier,
|
||||||
|
- simple à maintenir,
|
||||||
|
- compatible avec une future montée en version sans refonte majeure.
|
||||||
|
|
||||||
|
### 1.3 Contraintes
|
||||||
|
- support Android / iOS en priorité,
|
||||||
|
- support Web utilitaire possible, sans promesse d'expérience équivalente à une app web dédiée,
|
||||||
|
- mode hors-ligne limité aux consultations simples,
|
||||||
|
- conformité RGPD minimale dès la V1,
|
||||||
|
- intégration machine pouvant être simulée pour la démo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Périmètre fonctionnel
|
||||||
|
|
||||||
|
### 2.1 MVP V1
|
||||||
|
- inscription / connexion,
|
||||||
|
- maintien de session,
|
||||||
|
- liste des laveries,
|
||||||
|
- détail d'une laverie,
|
||||||
|
- consultation des machines et de leur statut,
|
||||||
|
- wallet avec solde et historique simple,
|
||||||
|
- rechargement wallet,
|
||||||
|
- réservation d'un créneau,
|
||||||
|
- affichage des réservations,
|
||||||
|
- lancement d'un lavage,
|
||||||
|
- écran de lavage en cours,
|
||||||
|
- notifications transactionnelles,
|
||||||
|
- profil utilisateur,
|
||||||
|
- gestion simple des consentements.
|
||||||
|
|
||||||
|
### 2.2 V2 prévue
|
||||||
|
- fidélité,
|
||||||
|
- parrainage,
|
||||||
|
- abonnements,
|
||||||
|
- promotions marketing avancées,
|
||||||
|
- export de données,
|
||||||
|
- statistiques utilisateur plus poussées,
|
||||||
|
- expérience offline enrichie,
|
||||||
|
- recommandations de cycles.
|
||||||
|
|
||||||
|
### 2.3 Hors périmètre V1
|
||||||
|
- chat,
|
||||||
|
- avis,
|
||||||
|
- FAQ dynamique,
|
||||||
|
- IA / photo d'étiquette,
|
||||||
|
- moteur prédictif,
|
||||||
|
- marketing automation complexe.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Stack Technique
|
||||||
|
|
||||||
|
| Composant | Technologie | Version | Commentaire |
|
||||||
|
|-----------|-------------|---------|-------------|
|
||||||
|
| Framework UI | Flutter | 3.x | Base unique mobile + web |
|
||||||
|
| Langage | Dart | 3.x | Null-safety |
|
||||||
|
| State management | Riverpod | 2.x | Testable, clair |
|
||||||
|
| Navigation | GoRouter | 13.x | Routing déclaratif |
|
||||||
|
| HTTP | Dio | 5.x | Intercepteurs auth |
|
||||||
|
| Stockage sécurisé | flutter_secure_storage | 9.x | Tokens |
|
||||||
|
| Cache local | Hive | 2.x | Suffisant pour V1 |
|
||||||
|
| Push | firebase_messaging | 15.x | Android / iOS / Web |
|
||||||
|
| QR scan | mobile_scanner | 5.x | Scan machine |
|
||||||
|
| Paiement | flutter_stripe | 10.x | Si Stripe retenu en V1 |
|
||||||
|
| Géolocalisation | geolocator | 13.x | Recherche proximité |
|
||||||
|
| Cartographie | flutter_map + OSM | — | Coût faible |
|
||||||
|
| Crash reporting | Firebase Crashlytics | — | Monitoring mobile |
|
||||||
|
| Tests | flutter_test + integration_test | — | Couverture critique |
|
||||||
|
|
||||||
|
### 3.1 Remarque Web
|
||||||
|
Le support Flutter Web est accepté comme **surface utilitaire** pour V1. Il ne doit pas être présenté comme un site web marketing riche ou fortement orienté SEO.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Architecture applicative
|
||||||
|
|
||||||
|
### 4.1 Organisation recommandée
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
├── core/
|
||||||
|
│ ├── api/
|
||||||
|
│ ├── auth/
|
||||||
|
│ ├── cache/
|
||||||
|
│ ├── router/
|
||||||
|
│ ├── theme/
|
||||||
|
│ └── utils/
|
||||||
|
├── features/
|
||||||
|
│ ├── auth/
|
||||||
|
│ ├── establishments/
|
||||||
|
│ ├── machines/
|
||||||
|
│ ├── wallet/
|
||||||
|
│ ├── booking/
|
||||||
|
│ ├── wash/
|
||||||
|
│ ├── notifications/
|
||||||
|
│ └── profile/
|
||||||
|
└── main.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 Principes
|
||||||
|
- séparation claire data / state / presentation,
|
||||||
|
- providers Riverpod par domaine,
|
||||||
|
- toute logique réseau centralisée,
|
||||||
|
- aucune règle métier critique uniquement côté client,
|
||||||
|
- compatibilité avec un mode démonstration si l'intégration machine n'est pas prête.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Authentification
|
||||||
|
|
||||||
|
### 5.1 Flux attendu
|
||||||
|
```text
|
||||||
|
Lancement app
|
||||||
|
→ lecture des tokens
|
||||||
|
→ si access token valide : accès direct
|
||||||
|
→ sinon tentative refresh
|
||||||
|
→ sinon retour login
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 Règles
|
||||||
|
- access token court,
|
||||||
|
- refresh token persistant,
|
||||||
|
- déconnexion complète si refresh invalide,
|
||||||
|
- aucun stockage de token sensible dans SharedPreferences.
|
||||||
|
|
||||||
|
### 5.3 Web
|
||||||
|
Sur Web, éviter `localStorage` pour les tokens. Si le backend le permet, privilégier une stratégie plus sûre à long terme. Pour V1, une stratégie simple et limitée peut être tolérée, mais elle doit être documentée comme compromis technique.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Parcours utilisateur V1
|
||||||
|
|
||||||
|
## 6.1 Onboarding / inscription
|
||||||
|
|
||||||
|
### Écrans
|
||||||
|
- Bienvenue
|
||||||
|
- Connexion
|
||||||
|
- Inscription
|
||||||
|
- Vérification email si activée en V1
|
||||||
|
|
||||||
|
### Champs d'inscription
|
||||||
|
- prénom
|
||||||
|
- nom
|
||||||
|
- email
|
||||||
|
- téléphone
|
||||||
|
- mot de passe
|
||||||
|
- date de naissance
|
||||||
|
- consentements RGPD
|
||||||
|
|
||||||
|
### Règles
|
||||||
|
- consentement traitement données obligatoire,
|
||||||
|
- consentements marketing et analytics séparés,
|
||||||
|
- validations simples mais strictes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.2 Laveries et machines
|
||||||
|
|
||||||
|
### Écran liste / carte
|
||||||
|
- liste des établissements,
|
||||||
|
- carte facultative si le délai est tendu,
|
||||||
|
- indicateur de disponibilité globale.
|
||||||
|
|
||||||
|
### Écran détail établissement
|
||||||
|
- nom, adresse, horaires,
|
||||||
|
- liste des machines,
|
||||||
|
- statut de chaque machine,
|
||||||
|
- prochain créneau disponible,
|
||||||
|
- CTA réservation,
|
||||||
|
- CTA lancement lavage.
|
||||||
|
|
||||||
|
### Statuts V1 affichés
|
||||||
|
- disponible,
|
||||||
|
- réservée,
|
||||||
|
- en cours,
|
||||||
|
- maintenance,
|
||||||
|
- hors ligne,
|
||||||
|
- erreur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.3 Wallet
|
||||||
|
|
||||||
|
### Écran wallet
|
||||||
|
- solde actuel,
|
||||||
|
- bouton recharger,
|
||||||
|
- dernières transactions,
|
||||||
|
- message si données en cache.
|
||||||
|
|
||||||
|
### Historique
|
||||||
|
- liste simple paginée,
|
||||||
|
- type,
|
||||||
|
- montant,
|
||||||
|
- date,
|
||||||
|
- libellé métier.
|
||||||
|
|
||||||
|
### Rechargement V1
|
||||||
|
Parcours recommandé :
|
||||||
|
1. saisie montant,
|
||||||
|
2. lancement du paiement,
|
||||||
|
3. retour app,
|
||||||
|
4. confirmation backend,
|
||||||
|
5. mise à jour solde.
|
||||||
|
|
||||||
|
### Contraintes V1
|
||||||
|
- montant min et max configurables,
|
||||||
|
- aucune confiance dans le seul retour client,
|
||||||
|
- affichage clair des états : en cours / confirmé / échoué.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.4 Réservation
|
||||||
|
|
||||||
|
### Écran sélection de créneau
|
||||||
|
- choix date,
|
||||||
|
- créneaux disponibles,
|
||||||
|
- prix total,
|
||||||
|
- supplément réservation si applicable,
|
||||||
|
- indication pénalité no-show.
|
||||||
|
|
||||||
|
### Écran confirmation
|
||||||
|
- récapitulatif machine,
|
||||||
|
- créneau,
|
||||||
|
- prix,
|
||||||
|
- solde avant / après,
|
||||||
|
- bouton de confirmation.
|
||||||
|
|
||||||
|
### Écran mes réservations
|
||||||
|
- onglets à venir / passées,
|
||||||
|
- statut,
|
||||||
|
- actions : annuler, déplacer si autorisé.
|
||||||
|
|
||||||
|
### Règles UI
|
||||||
|
- si solde insuffisant, proposer rechargement,
|
||||||
|
- si réservation non déplaçable, expliquer pourquoi,
|
||||||
|
- afficher clairement les règles d'annulation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.5 Lavage
|
||||||
|
|
||||||
|
### Démarrage
|
||||||
|
Deux modes possibles selon intégration :
|
||||||
|
- scan QR,
|
||||||
|
- démarrage depuis une réservation active.
|
||||||
|
|
||||||
|
### Flux V1
|
||||||
|
1. identification machine,
|
||||||
|
2. vérification disponibilité,
|
||||||
|
3. affichage prix / programme si nécessaire,
|
||||||
|
4. confirmation utilisateur,
|
||||||
|
5. demande de démarrage,
|
||||||
|
6. affichage de l'état `en cours`.
|
||||||
|
|
||||||
|
### Écran lavage actif
|
||||||
|
- machine,
|
||||||
|
- laverie,
|
||||||
|
- heure de début,
|
||||||
|
- temps estimé restant si disponible,
|
||||||
|
- statut actualisé.
|
||||||
|
|
||||||
|
### Mode démo
|
||||||
|
Si aucune vraie intégration machine n'est disponible, un mode simulation doit permettre d'afficher un cycle complet crédible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.6 Notifications
|
||||||
|
|
||||||
|
### Notifications V1
|
||||||
|
- rechargement confirmé,
|
||||||
|
- réservation confirmée,
|
||||||
|
- rappel de créneau,
|
||||||
|
- lavage terminé,
|
||||||
|
- no-show détecté si applicable.
|
||||||
|
|
||||||
|
### Deep links
|
||||||
|
Les notifications doivent pouvoir ouvrir l'écran concerné :
|
||||||
|
- wallet,
|
||||||
|
- réservation,
|
||||||
|
- lavage,
|
||||||
|
- établissement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.7 Profil
|
||||||
|
|
||||||
|
### Écran profil
|
||||||
|
- informations personnelles,
|
||||||
|
- préférences de notification,
|
||||||
|
- consentements,
|
||||||
|
- déconnexion,
|
||||||
|
- suppression de compte si disponible en V1, sinon message préparant la V2.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Gestion d'état
|
||||||
|
|
||||||
|
### Providers principaux
|
||||||
|
```dart
|
||||||
|
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>(...);
|
||||||
|
final establishmentsProvider = FutureProvider<List<Establishment>>(...);
|
||||||
|
final establishmentDetailProvider = FutureProvider.family<EstablishmentDetail, String>(...);
|
||||||
|
final walletProvider = FutureProvider<WalletView>(...);
|
||||||
|
final bookingsProvider = StateNotifierProvider<BookingsNotifier, BookingsState>(...);
|
||||||
|
final washProvider = StateNotifierProvider<WashNotifier, WashState>(...);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Stratégie V1
|
||||||
|
- refresh manuel sur les écrans critiques,
|
||||||
|
- polling simple si nécessaire pour le lavage actif,
|
||||||
|
- éviter une architecture temps réel trop complexe pour la V1 si elle met en risque le planning.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Offline-first
|
||||||
|
|
||||||
|
### Ce qui est caché localement en V1
|
||||||
|
| Donnée | Cache |
|
||||||
|
|---|---|
|
||||||
|
| Solde wallet | Oui |
|
||||||
|
| Dernières transactions | Oui |
|
||||||
|
| Liste établissements | Oui |
|
||||||
|
| Réservations récentes | Oui |
|
||||||
|
| Disponibilité machine temps réel | Non |
|
||||||
|
|
||||||
|
### Règle
|
||||||
|
Le hors-ligne V1 est **consultatif**, pas transactionnel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Sécurité
|
||||||
|
|
||||||
|
### 9.1 Stockage
|
||||||
|
- tokens en stockage sécurisé,
|
||||||
|
- aucune donnée sensible en clair,
|
||||||
|
- purge des tokens en déconnexion.
|
||||||
|
|
||||||
|
### 9.2 Réseau
|
||||||
|
- HTTPS obligatoire,
|
||||||
|
- timeouts définis,
|
||||||
|
- retry mesuré,
|
||||||
|
- certificate pinning seulement si tu es sûr de pouvoir l'opérer correctement, sinon à repousser plutôt que mal implémenter.
|
||||||
|
|
||||||
|
### 9.3 QR code
|
||||||
|
- le QR seul ne déclenche jamais directement un lavage,
|
||||||
|
- validation serveur obligatoire,
|
||||||
|
- contrôle de cohérence utilisateur / machine / statut.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. UX / performance
|
||||||
|
|
||||||
|
### Priorités V1
|
||||||
|
- écrans rapides,
|
||||||
|
- états de chargement propres,
|
||||||
|
- erreurs compréhensibles,
|
||||||
|
- navigation simple,
|
||||||
|
- pas d'animations complexes non essentielles.
|
||||||
|
|
||||||
|
### À éviter en V1 si délai serré
|
||||||
|
- sur-optimisation visuelle,
|
||||||
|
- offline avancé,
|
||||||
|
- temps réel sophistiqué,
|
||||||
|
- effets UI coûteux sans valeur métier.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Mode démonstration
|
||||||
|
|
||||||
|
L'application doit pouvoir être connectée à un environnement de démonstration permettant :
|
||||||
|
- données multi-laveries fictives,
|
||||||
|
- wallet de test,
|
||||||
|
- réservations simulées,
|
||||||
|
- cycles machine simulés,
|
||||||
|
- notifications de test.
|
||||||
|
|
||||||
|
Ce mode doit être suffisamment crédible pour une démonstration client de fin de mois.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Tests
|
||||||
|
|
||||||
|
| Type | Outil | Portée |
|
||||||
|
|------|-------|--------|
|
||||||
|
| Unitaires | flutter_test | Providers, validateurs, formatters |
|
||||||
|
| Widgets | flutter_test | Écrans clés |
|
||||||
|
| Intégration | integration_test | Connexion, wallet, réservation, lavage |
|
||||||
|
|
||||||
|
### Parcours critiques à couvrir
|
||||||
|
1. connexion utilisateur,
|
||||||
|
2. affichage des laveries,
|
||||||
|
3. rechargement wallet,
|
||||||
|
4. réservation d'un créneau,
|
||||||
|
5. démarrage d'un lavage en mode simulation,
|
||||||
|
6. réception d'une notification.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Livrables attendus
|
||||||
|
|
||||||
|
- code source Flutter,
|
||||||
|
- configuration dev / staging / prod,
|
||||||
|
- README d'installation,
|
||||||
|
- configuration push,
|
||||||
|
- build de démonstration,
|
||||||
|
- dataset ou compte de démo,
|
||||||
|
- couverture de tests sur les flux critiques.
|
||||||
Reference in New Issue
Block a user