Réorganise la documentation du projet selon les principes du Domain-Driven Design (DDD) pour améliorer la cohésion, la maintenabilité et l'alignement avec l'architecture modulaire du backend. **Structure cible:** ``` docs/domains/ ├── README.md (Context Map) ├── _shared/ (Core Domain) ├── recommendation/ (Supporting Subdomain) ├── content/ (Supporting Subdomain) ├── moderation/ (Supporting Subdomain) ├── advertising/ (Generic Subdomain) ├── premium/ (Generic Subdomain) └── monetization/ (Generic Subdomain) ``` **Changements effectués:** Phase 1: Création de l'arborescence des 7 bounded contexts Phase 2: Déplacement des règles métier (01-19) vers domains/*/rules/ Phase 3: Déplacement des diagrammes d'entités vers domains/*/entities/ Phase 4: Déplacement des diagrammes flux/états/séquences vers domains/*/ Phase 5: Création des README.md pour chaque domaine Phase 6: Déplacement des features Gherkin vers domains/*/features/ Phase 7: Création du Context Map (domains/README.md) Phase 8: Mise à jour de mkdocs.yml pour la nouvelle navigation Phase 9: Correction automatique des liens internes (script fix-markdown-links.sh) Phase 10: Nettoyage de l'ancienne structure (regles-metier/, diagrammes/, features/) **Configuration des tests:** - Makefile: godog run docs/domains/*/features/ - scripts/generate-bdd-docs.py: features_dir → docs/domains **Avantages:** ✅ Cohésion forte: toute la doc d'un domaine au même endroit ✅ Couplage faible: domaines indépendants, dépendances explicites ✅ Navigabilité améliorée: README par domaine = entrée claire ✅ Alignement code/docs: miroir de backend/internal/ ✅ Onboarding facilité: exploration domaine par domaine ✅ Tests BDD intégrés: features au plus près des règles métier Voir docs/REFACTOR-DDD.md pour le plan complet.
188 lines
11 KiB
Gherkin
188 lines
11 KiB
Gherkin
# language: fr
|
|
|
|
@api @authentication @security @mvp
|
|
Fonctionnalité: Récupération et réinitialisation avancée du mot de passe
|
|
|
|
En tant qu'utilisateur ayant oublié son mot de passe
|
|
Je veux pouvoir récupérer l'accès à mon compte de manière sécurisée
|
|
Afin de reprendre l'utilisation de l'application
|
|
|
|
Contexte:
|
|
Étant donné que le système de récupération est configuré avec:
|
|
| Paramètre | Valeur |
|
|
| Durée de validité du lien de reset | 1 heure |
|
|
| Nombre max de demandes par heure | 3 |
|
|
| Nombre max de demandes par jour | 10 |
|
|
| Longueur du token de reset | 64 chars |
|
|
| Délai de cooldown entre demandes | 5 minutes |
|
|
|
|
Scénario: Demande de réinitialisation de mot de passe
|
|
Étant donné un utilisateur "alice@roadwave.fr" qui a oublié son mot de passe
|
|
Quand l'utilisateur clique sur "Mot de passe oublié ?" sur l'écran de connexion
|
|
Et saisit son adresse email "alice@roadwave.fr"
|
|
Alors un email de réinitialisation est envoyé avec:
|
|
| Élément | Contenu |
|
|
| Sujet | Réinitialisation de votre mot de passe RoadWave |
|
|
| Lien sécurisé | https://roadwave.fr/reset?token=abc123... |
|
|
| Durée de validité | Ce lien expire dans 1 heure |
|
|
| Warning sécurité | Si vous n'êtes pas à l'origine de cette demande... |
|
|
Et un événement "PASSWORD_RESET_REQUESTED" est enregistré
|
|
Et la métrique "auth.password_reset.requested" est incrémentée
|
|
Et un message s'affiche: "Si cette adresse est enregistrée, vous recevrez un email de réinitialisation"
|
|
|
|
Scénario: Protection contre l'énumération d'adresses email
|
|
Étant donné une adresse email "inexistant@roadwave.fr" non enregistrée
|
|
Quand un utilisateur demande la réinitialisation pour cette adresse
|
|
Alors le même message de confirmation s'affiche: "Si cette adresse est enregistrée, vous recevrez un email"
|
|
Et aucun email n'est envoyé
|
|
Et le temps de réponse est identique à une demande valide (800-1200ms)
|
|
Et un événement "PASSWORD_RESET_UNKNOWN_EMAIL" est enregistré
|
|
Et la métrique "auth.password_reset.unknown_email" est incrémentée
|
|
Et les logs n'exposent pas l'information de l'existence ou non de l'email
|
|
|
|
Scénario: Limitation du nombre de demandes de réinitialisation
|
|
Étant donné un utilisateur "bob@roadwave.fr"
|
|
Et il a déjà effectué 3 demandes de réinitialisation dans la dernière heure
|
|
Quand l'utilisateur effectue une 4ème demande
|
|
Alors la demande est refusée avec le message: "Trop de demandes de réinitialisation. Veuillez attendre 1 heure."
|
|
Et aucun email n'est envoyé
|
|
Et un événement "PASSWORD_RESET_RATE_LIMITED" est enregistré
|
|
Et la métrique "auth.password_reset.rate_limited" est incrémentée
|
|
|
|
Scénario: Utilisation du lien de réinitialisation valide
|
|
Étant donné un utilisateur "charlie@roadwave.fr" ayant demandé la réinitialisation
|
|
Et il a reçu un email avec un token valide il y a 30 minutes
|
|
Quand l'utilisateur clique sur le lien dans l'email
|
|
Alors il est redirigé vers la page de réinitialisation
|
|
Et le formulaire de nouveau mot de passe s'affiche
|
|
Et le token est validé côté serveur
|
|
Et un événement "PASSWORD_RESET_TOKEN_ACCESSED" est enregistré
|
|
Et la session est sécurisée avec CSRF protection
|
|
|
|
Scénario: Définition du nouveau mot de passe avec validation
|
|
Étant donné un utilisateur "david@roadwave.fr" sur la page de réinitialisation
|
|
Et il a un token valide
|
|
Quand l'utilisateur saisit un nouveau mot de passe "SecurePass2026!"
|
|
Et confirme le mot de passe
|
|
Alors le mot de passe est validé selon les règles de sécurité
|
|
Et le mot de passe est hashé avec bcrypt (cost: 12)
|
|
Et le mot de passe est enregistré dans la base de données
|
|
Et toutes les sessions actives sont révoquées
|
|
Et tous les tokens d'accès sont invalidés
|
|
Et un événement "PASSWORD_RESET_COMPLETED" est enregistré
|
|
Et un email de confirmation est envoyé: "Votre mot de passe a été modifié avec succès"
|
|
Et la métrique "auth.password_reset.completed" est incrémentée
|
|
Et l'utilisateur est redirigé vers la page de connexion
|
|
|
|
Scénario: Tentative d'utilisation d'un token expiré
|
|
Étant donné un utilisateur "eve@roadwave.fr" ayant demandé la réinitialisation
|
|
Et il a reçu un email avec un token valide il y a 2 heures
|
|
Quand l'utilisateur clique sur le lien expiré
|
|
Alors un message d'erreur s'affiche: "Ce lien de réinitialisation a expiré. Veuillez faire une nouvelle demande."
|
|
Et un bouton "Demander un nouveau lien" est affiché
|
|
Et un événement "PASSWORD_RESET_TOKEN_EXPIRED" est enregistré
|
|
Et la métrique "auth.password_reset.token_expired" est incrémentée
|
|
|
|
Scénario: Tentative d'utilisation d'un token déjà utilisé
|
|
Étant donné un utilisateur "frank@roadwave.fr" ayant réinitialisé son mot de passe
|
|
Et le token a déjà été utilisé il y a 10 minutes
|
|
Quand l'utilisateur tente de réutiliser le même lien
|
|
Alors un message d'erreur s'affiche: "Ce lien a déjà été utilisé. Si vous avez besoin de réinitialiser à nouveau, faites une nouvelle demande."
|
|
Et un événement "PASSWORD_RESET_TOKEN_REUSED" est enregistré avec niveau "MEDIUM"
|
|
Et un email d'alerte est envoyé: "Tentative de réutilisation d'un ancien lien de réinitialisation"
|
|
Et la métrique "auth.password_reset.token_reused" est incrémentée
|
|
|
|
Scénario: Détection de tentative d'attaque par force brute sur les tokens
|
|
Étant donné un attaquant qui tente de deviner des tokens de réinitialisation
|
|
Quand 10 tokens invalides sont testés depuis la même IP en 5 minutes
|
|
Alors l'IP est bloquée temporairement pour 1 heure
|
|
Et tous les tokens valides pour cette IP sont invalidés
|
|
Et un événement "PASSWORD_RESET_BRUTE_FORCE_DETECTED" est enregistré avec niveau "CRITICAL"
|
|
Et l'équipe de sécurité est alertée via webhook
|
|
Et la métrique "security.password_reset.brute_force" est incrémentée
|
|
|
|
Scénario: Réinitialisation avec validation 2FA pour comptes sensibles
|
|
Étant donné un utilisateur "grace@roadwave.fr" avec 2FA activé
|
|
Et il a demandé la réinitialisation de son mot de passe
|
|
Quand l'utilisateur clique sur le lien de réinitialisation
|
|
Alors une étape supplémentaire de vérification 2FA s'affiche
|
|
Et l'utilisateur doit saisir un code TOTP ou un code de récupération
|
|
Et après validation 2FA, le formulaire de nouveau mot de passe s'affiche
|
|
Et un événement "PASSWORD_RESET_2FA_VALIDATED" est enregistré
|
|
Et la métrique "auth.password_reset.with_2fa" est incrémentée
|
|
|
|
Scénario: Notification de sécurité sur tous les appareils
|
|
Étant donné un utilisateur "henry@roadwave.fr" connecté sur 3 appareils
|
|
Quand l'utilisateur réinitialise son mot de passe
|
|
Alors une notification push est envoyée sur tous les appareils:
|
|
| Message |
|
|
| Votre mot de passe a été modifié |
|
|
| Si ce n'est pas vous, contactez immédiatement le support |
|
|
Et un email est envoyé avec détails:
|
|
| Détail | Valeur |
|
|
| Date et heure | 2026-02-03 14:32:18 |
|
|
| Adresse IP | 1.2.3.4 |
|
|
| Localisation | Paris, France |
|
|
| Appareil | iPhone 14 Pro |
|
|
| Navigateur | Safari 17.2 |
|
|
Et un lien "Ce n'était pas moi" permet de bloquer le compte immédiatement
|
|
|
|
Scénario: Historique des modifications de mot de passe
|
|
Étant donné un utilisateur "iris@roadwave.fr"
|
|
Quand l'utilisateur accède à "Mon compte > Sécurité > Historique"
|
|
Alors l'utilisateur voit l'historique des modifications:
|
|
| Date | Action | IP | Appareil | Localisation |
|
|
| 2026-02-03 14:32 | Réinitialisation mot de passe | 1.2.3.4 | iPhone 14 | Paris, FR |
|
|
| 2026-01-15 10:20 | Changement mot de passe | 5.6.7.8 | MacBook Pro | Lyon, FR |
|
|
| 2025-12-01 08:15 | Création du compte | 9.10.11.12| iPad Air | Marseille, FR |
|
|
Et les événements sont conservés pendant 90 jours minimum
|
|
Et les logs sont conformes RGPD
|
|
|
|
Scénario: Réinitialisation impossible pour compte bloqué ou suspendu
|
|
Étant donné un utilisateur "jack@roadwave.fr" dont le compte est suspendu
|
|
Quand l'utilisateur demande la réinitialisation de son mot de passe
|
|
Alors un message s'affiche: "Votre compte est actuellement suspendu. Veuillez contacter le support."
|
|
Et aucun email de réinitialisation n'est envoyé
|
|
Et un événement "PASSWORD_RESET_ACCOUNT_SUSPENDED" est enregistré
|
|
Et un lien vers le support est fourni
|
|
Et la métrique "auth.password_reset.blocked_account" est incrémentée
|
|
|
|
Scénario: Vérification de l'unicité du nouveau mot de passe
|
|
Étant donné un utilisateur "kate@roadwave.fr" sur la page de réinitialisation
|
|
Quand l'utilisateur tente de définir le même mot de passe que l'ancien
|
|
Alors une erreur s'affiche: "Veuillez choisir un mot de passe différent de l'ancien"
|
|
Et le mot de passe n'est pas enregistré
|
|
Et un événement "PASSWORD_RESET_SAME_PASSWORD" est enregistré
|
|
Et la métrique "auth.password_reset.same_password" est incrémentée
|
|
|
|
Scénario: Vérification contre les mots de passe compromis
|
|
Étant donné un utilisateur "luke@roadwave.fr" sur la page de réinitialisation
|
|
Quand l'utilisateur tente de définir un mot de passe "Password123!"
|
|
Et ce mot de passe figure dans la base de données Have I Been Pwned
|
|
Alors une erreur s'affiche: "Ce mot de passe est connu et a été compromis. Veuillez en choisir un autre."
|
|
Et le mot de passe n'est pas enregistré
|
|
Et un événement "PASSWORD_RESET_COMPROMISED_PASSWORD" est enregistré
|
|
Et la métrique "auth.password_reset.compromised_blocked" est incrémentée
|
|
|
|
Scénario: Cooldown entre demandes successives de réinitialisation
|
|
Étant donné un utilisateur "mary@roadwave.fr"
|
|
Et il a fait une demande de réinitialisation il y a 2 minutes
|
|
Quand l'utilisateur fait une nouvelle demande de réinitialisation
|
|
Alors la demande est refusée avec le message: "Veuillez attendre 5 minutes entre chaque demande"
|
|
Et un compteur affiche "Vous pourrez faire une nouvelle demande dans 3 minutes"
|
|
Et un événement "PASSWORD_RESET_COOLDOWN" est enregistré
|
|
Et la métrique "auth.password_reset.cooldown_hit" est incrémentée
|
|
|
|
Scénario: Métriques de sécurité pour la réinitialisation de mot de passe
|
|
Étant donné que le système traite 1000 demandes de réinitialisation par jour
|
|
Quand les métriques de sécurité sont collectées
|
|
Alors les indicateurs suivants sont disponibles:
|
|
| Métrique | Valeur cible |
|
|
| Taux de complétion des réinitialisations | > 75% |
|
|
| Taux de tokens expirés avant utilisation | < 20% |
|
|
| Temps moyen de complétion | < 5 min |
|
|
| Taux de détection de mots de passe compromis | > 5% |
|
|
| Nombre de tentatives de brute force bloquées | Visible |
|
|
Et les métriques sont exportées vers le système de monitoring
|
|
Et des alertes sont déclenchées si anomalies détectées
|