refactor(docs): réorganiser la documentation selon principes DDD
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.
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
# language: fr
|
||||
Fonctionnalité: API - Pas de dégradation temporelle
|
||||
En tant qu'API backend
|
||||
Je veux que les jauges n'évoluent que par les actions utilisateur
|
||||
Afin d'avoir un comportement prévisible sans automatisme caché
|
||||
|
||||
Contexte:
|
||||
Étant donné que l'API RoadWave est disponible
|
||||
Et que la base de données PostgreSQL est accessible
|
||||
|
||||
Scénario: API ne dégrade jamais les jauges automatiquement
|
||||
Étant donné qu'un utilisateur "user123" a une jauge "Économie" à 80% en base
|
||||
Et que la colonne updated_at = "2026-01-01T10:00:00Z"
|
||||
Quand 30 jours s'écoulent sans activité
|
||||
Et je GET /api/v1/users/user123/interest-gauges le "2026-02-01T10:00:00Z"
|
||||
Alors le statut de réponse est 200
|
||||
Et la jauge "Économie" est toujours à 80%
|
||||
Et aucune dégradation temporelle n'a été appliquée
|
||||
Et la colonne updated_at n'a pas changé
|
||||
|
||||
Scénario: Aucun cron job de dégradation n'existe
|
||||
Étant donné que le système vérifie les tâches cron planifiées
|
||||
Quand je liste tous les cron jobs du backend
|
||||
Alors aucun job nommé "degrade_interest_gauges" n'existe
|
||||
Et aucun job périodique ne modifie la table interest_gauges
|
||||
Et aucune ressource CPU n'est consommée pour la dégradation
|
||||
|
||||
Scénario: API GET jauges après 6 mois d'inactivité
|
||||
Étant donné qu'un utilisateur "user123" a les jauges suivantes:
|
||||
| catégorie | niveau | updated_at |
|
||||
| Automobile | 75% | 2025-08-01T10:00:00 |
|
||||
| Voyage | 60% | 2025-08-01T10:00:00 |
|
||||
| Musique | 45% | 2025-08-01T10:00:00 |
|
||||
Et qu'il ne se connecte pas pendant 6 mois
|
||||
Quand je GET /api/v1/users/user123/interest-gauges le "2026-02-01T10:00:00Z"
|
||||
Alors le statut de réponse est 200
|
||||
Et les jauges sont exactement les mêmes:
|
||||
| catégorie | niveau |
|
||||
| Automobile | 75% |
|
||||
| Voyage | 60% |
|
||||
| Musique | 45% |
|
||||
Et aucune modification n'a été appliquée
|
||||
|
||||
Scénario: Évolution par actions utilisateur uniquement
|
||||
Étant donné qu'un utilisateur "user123" a une jauge "Économie" à 80%
|
||||
Et qu'il skip 50 contenus "Économie" en 1 an
|
||||
Quand je calcule l'évolution via les events
|
||||
Alors la jauge "Économie" descend via les skips:
|
||||
| action | impact | nouveau_niveau |
|
||||
| 50 skips × -0.5%| -25% | 55% |
|
||||
Et la dégradation vient des actions, pas du temps
|
||||
Et la colonne updated_at reflète la date du dernier skip
|
||||
|
||||
Scénario: API POST réinitialiser centres d'intérêt
|
||||
Étant donné qu'un utilisateur "user123" a des jauges personnalisées:
|
||||
| catégorie | niveau |
|
||||
| Automobile | 75% |
|
||||
| Voyage | 60% |
|
||||
| Économie | 34% |
|
||||
| Sport | 88% |
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
"""json
|
||||
{
|
||||
"confirmation": true
|
||||
}
|
||||
"""
|
||||
Alors le statut de réponse est 200
|
||||
Et la réponse contient:
|
||||
"""json
|
||||
{
|
||||
"message": "Vos centres d'intérêt ont été réinitialisés",
|
||||
"previous_gauges_saved": true,
|
||||
"new_gauges": {
|
||||
"all_categories": 50
|
||||
}
|
||||
}
|
||||
"""
|
||||
Et en base de données, toutes les jauges de "user123" sont à 50%:
|
||||
| catégorie | niveau |
|
||||
| Automobile | 50 |
|
||||
| Voyage | 50 |
|
||||
| Économie | 50 |
|
||||
| Sport | 50 |
|
||||
| Musique | 50 |
|
||||
| Technologie | 50 |
|
||||
| Santé | 50 |
|
||||
| Politique | 50 |
|
||||
| Cryptomonnaie | 50 |
|
||||
| Culture générale | 50 |
|
||||
| Famille | 50 |
|
||||
| Amour | 50 |
|
||||
|
||||
Scénario: API sauvegarde jauges précédentes avant réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" a des jauges personnalisées
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
"""json
|
||||
{
|
||||
"confirmation": true
|
||||
}
|
||||
"""
|
||||
Alors le statut de réponse est 200
|
||||
Et une ligne est insérée dans interest_gauges_snapshots:
|
||||
| user_id | snapshot_type | snapshot_date | gauges_json |
|
||||
| user123 | manual_reset | 2026-02-02T14:00:00 | {"Automobile": 75, "Voyage": 60, ...} |
|
||||
Et l'historique permet de restaurer si besoin
|
||||
|
||||
Scénario: API rejette réinitialisation sans confirmation
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
"""json
|
||||
{
|
||||
"confirmation": false
|
||||
}
|
||||
"""
|
||||
Alors le statut de réponse est 400
|
||||
Et la réponse contient:
|
||||
"""json
|
||||
{
|
||||
"error": "CONFIRMATION_REQUIRED",
|
||||
"message": "Vous devez confirmer la réinitialisation"
|
||||
}
|
||||
"""
|
||||
Et les jauges ne sont pas modifiées
|
||||
|
||||
Scénario: API recommandations après réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" avait "Économie" à 85%
|
||||
Et qu'il réinitialise ses jauges (toutes à 50%)
|
||||
Quand je POST /api/v1/recommendations
|
||||
"""json
|
||||
{
|
||||
"user_id": "user123",
|
||||
"latitude": 48.8566,
|
||||
"longitude": 2.3522,
|
||||
"limit": 10
|
||||
}
|
||||
"""
|
||||
Alors le statut de réponse est 200
|
||||
Et les recommandations utilisent 50% pour toutes les catégories
|
||||
Et plus aucun biais "Économie" n'est appliqué
|
||||
Et la géolocalisation redevient le critère principal
|
||||
|
||||
Scénario: Historique d'écoute conservé après réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" a écouté 500 contenus
|
||||
Et que la table listening_history contient 500 lignes pour "user123"
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
Alors le statut de réponse est 200
|
||||
Et la table listening_history conserve toujours les 500 lignes
|
||||
Et aucune donnée d'historique n'est supprimée
|
||||
Et l'utilisateur peut toujours consulter ses anciens contenus écoutés
|
||||
|
||||
Scénario: API GET historique après réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" a réinitialisé ses jauges
|
||||
Quand je GET /api/v1/users/user123/listening-history
|
||||
Alors le statut de réponse est 200
|
||||
Et la réponse contient tous les anciens contenus écoutés
|
||||
Et l'historique est intact
|
||||
|
||||
Scénario: API enregistre timestamp réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" réinitialise ses jauges
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
Alors en base de données, la table users est mise à jour:
|
||||
| user_id | interest_gauges_reset_at | reset_count |
|
||||
| user123 | 2026-02-02T14:00:00Z | 1 |
|
||||
Et un compteur permet de tracker les réinitialisations multiples
|
||||
|
||||
Scénario: API permet réinitialisations multiples
|
||||
Étant donné qu'un utilisateur "user123" a déjà réinitialisé une fois
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset une 2ème fois
|
||||
Alors le statut de réponse est 200
|
||||
Et le reset_count passe à 2
|
||||
Et toutes les jauges reviennent à 50%
|
||||
|
||||
Scénario: API n'envoie jamais de suggestion de réinitialisation
|
||||
Étant donné qu'un utilisateur "user123" n'a pas utilisé l'app depuis 1 an
|
||||
Quand je GET /api/v1/users/user123/notifications
|
||||
Alors le statut de réponse est 200
|
||||
Et aucune notification "Réinitialiser vos centres d'intérêt" n'est présente
|
||||
Et le système ne suggère jamais de réinitialisation automatique
|
||||
|
||||
Scénario: API GET statistiques respect historique utilisateur
|
||||
Étant donné qu'un utilisateur "user123" aime "Cryptomonnaie" depuis 2 ans
|
||||
Et que sa jauge est à 90%
|
||||
Et qu'il n'a pas écouté de contenu "Cryptomonnaie" depuis 6 mois
|
||||
Quand je GET /api/v1/users/user123/interest-gauges
|
||||
Alors le statut de réponse est 200
|
||||
Et la jauge "Cryptomonnaie" est toujours à 90%
|
||||
Et la réponse contient:
|
||||
"""json
|
||||
{
|
||||
"gauges": [
|
||||
{
|
||||
"category": "Cryptomonnaie",
|
||||
"level": 90,
|
||||
"last_updated": "2025-08-02T10:00:00Z",
|
||||
"days_since_update": 183,
|
||||
"preserved": true
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
Et le système respecte l'historique des goûts
|
||||
|
||||
Scénario: API métrique temps écoulé sans modifier la jauge
|
||||
Étant donné qu'un utilisateur "user123" a une jauge "Sport" à 65%
|
||||
Et que la dernière modification date de 90 jours
|
||||
Quand je GET /api/v1/users/user123/interest-gauges/sport
|
||||
Alors le statut de réponse est 200
|
||||
Et la réponse contient:
|
||||
"""json
|
||||
{
|
||||
"category": "Sport",
|
||||
"level": 65,
|
||||
"last_updated": "2025-11-03T12:00:00Z",
|
||||
"days_since_update": 90
|
||||
}
|
||||
"""
|
||||
Et la métrique days_since_update est informative uniquement
|
||||
Et elle ne modifie jamais la jauge
|
||||
|
||||
Scénario: Requête SQL n'utilise jamais de calcul temporel
|
||||
Étant donné que je trace les requêtes SQL du backend
|
||||
Quand je GET /api/v1/users/user123/interest-gauges
|
||||
Alors la requête SQL exécutée est:
|
||||
"""sql
|
||||
SELECT category, level, updated_at
|
||||
FROM interest_gauges
|
||||
WHERE user_id = $1
|
||||
"""
|
||||
Et aucune clause WHERE avec date/timestamp n'est présente
|
||||
Et aucune fonction NOW(), CURRENT_TIMESTAMP, ou DATEDIFF n'est utilisée
|
||||
Et le calcul est minimal (simple SELECT)
|
||||
|
||||
Scénario: API coût CPU minimal - pas de calcul de dates
|
||||
Étant donné que 10000 utilisateurs consultent leurs jauges simultanément
|
||||
Quand les requêtes /api/v1/users/{id}/interest-gauges sont exécutées
|
||||
Alors aucun calcul de date n'est nécessaire
|
||||
Et aucun appel à time.Now() ou time.Since() n'est fait
|
||||
Et le coût CPU par requête est < 1ms
|
||||
Et aucune dégradation de performance liée aux dates
|
||||
|
||||
Scénario: API pas de risque de bug fuseau horaire
|
||||
Étant donné qu'aucune logique temporelle n'existe
|
||||
Quand un utilisateur change de fuseau horaire (Paris → Tokyo)
|
||||
Alors ses jauges ne sont pas affectées
|
||||
Et aucun bug de conversion UTC/local ne peut survenir
|
||||
Et le comportement reste déterministe
|
||||
|
||||
Scénario: Audit log réinitialisation manuelle
|
||||
Étant donné qu'un utilisateur "user123" réinitialise ses jauges
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
Alors une ligne est insérée dans audit_log:
|
||||
| user_id | action | timestamp | details |
|
||||
| user123 | interest_gauges_reset | 2026-02-02T14:00:00 | {"previous_snapshot_id": 42} |
|
||||
Et l'audit permet de tracer toutes les réinitialisations
|
||||
|
||||
Scénario: API empêche réinitialisation trop fréquente
|
||||
Étant donné qu'un utilisateur "user123" a réinitialisé il y a 10 minutes
|
||||
Quand je POST /api/v1/users/user123/interest-gauges/reset
|
||||
Alors le statut de réponse est 429
|
||||
Et la réponse contient:
|
||||
"""json
|
||||
{
|
||||
"error": "RATE_LIMIT_EXCEEDED",
|
||||
"message": "Vous ne pouvez réinitialiser qu'une fois par heure",
|
||||
"retry_after_seconds": 3000
|
||||
}
|
||||
"""
|
||||
|
||||
Scénario: API documentation endpoints réinitialisation
|
||||
Quand je GET /api/v1/openapi.json
|
||||
Alors le endpoint POST /api/v1/users/{id}/interest-gauges/reset est documenté:
|
||||
"""yaml
|
||||
/users/{id}/interest-gauges/reset:
|
||||
post:
|
||||
summary: Réinitialise toutes les jauges à 50%
|
||||
description: |
|
||||
Remet toutes les jauges d'intérêt à leur valeur par défaut (50%).
|
||||
Cette action est manuelle et requiert une confirmation.
|
||||
Les jauges précédentes sont sauvegardées.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
confirmation:
|
||||
type: boolean
|
||||
description: Doit être true
|
||||
responses:
|
||||
200:
|
||||
description: Réinitialisation réussie
|
||||
400:
|
||||
description: Confirmation manquante
|
||||
429:
|
||||
description: Trop de réinitialisations
|
||||
"""
|
||||
Reference in New Issue
Block a user