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:
jpgiannetti
2026-02-07 17:15:02 +01:00
parent 78422bb2c0
commit 5e5fcf4714
227 changed files with 1413 additions and 1967 deletions

View File

@@ -0,0 +1,314 @@
# language: fr
Fonctionnalité: API - File d'attente et pré-calcul des contenus
En tant qu'API backend
Je veux pré-calculer et gérer la file d'attente de contenus
Afin d'assurer une navigation fluide sans latence
Contexte:
Étant donné que l'API RoadWave est disponible
Et que Redis est accessible
Et que PostgreSQL avec PostGIS est accessible
Et qu'un utilisateur "user123" existe avec token JWT valide
# Pré-calcul initial
Scénario: API pré-calcule 5 contenus au démarrage de session
Étant donné que l'utilisateur "user123" démarre une session
Et qu'il est situé à Paris (48.8566, 2.3522)
Et qu'il est en mode voiture (vitesse 5 km/h)
Quand je POST /api/v1/queue/initialize
"""json
{
"user_id": "user123",
"latitude": 48.8566,
"longitude": 2.3522,
"mode": "voiture"
}
"""
Alors le statut de réponse est 201
Et la réponse contient:
"""json
{
"queue_size": 5,
"contents": [
{"id": "content1", "title": "...", "position": 1},
{"id": "content2", "title": "...", "position": 2},
{"id": "content3", "title": "...", "position": 3},
{"id": "content4", "title": "...", "position": 4},
{"id": "content5", "title": "...", "position": 5}
]
}
"""
Et en Redis, la clé "user:user123:queue" contient 5 contenus
Et les métadonnées incluent:
| champ | valeur |
| last_lat | 48.8566 |
| last_lon | 2.3522 |
| mode | voiture |
| computed_at | (timestamp actuel) |
Et le TTL est de 900 secondes (15 minutes)
Scénario: API GET retourne la file d'attente en cache
Étant donné qu'une file de 5 contenus existe en cache Redis pour "user123"
Quand je GET /api/v1/queue
Alors le statut de réponse est 200
Et la réponse contient les 5 contenus pré-calculés
Et la latence de réponse est < 50ms (lecture Redis)
Scénario: API retire un contenu de la file après lecture
Étant donné qu'une file de 5 contenus [C1, C2, C3, C4, C5] existe pour "user123"
Quand je POST /api/v1/queue/consume
"""json
{
"user_id": "user123",
"content_id": "C1"
}
"""
Alors le statut de réponse est 200
Et la file d'attente devient [C2, C3, C4, C5]
Et la taille de la file est 4
# Recalcul automatique
Scénario: API recalcule après déplacement >10km
Étant donné qu'une file a été calculée à Paris (48.8566, 2.3522)
Et que l'utilisateur se déplace à Versailles (48.8049, 2.1204) soit 12km
Quand je POST /api/v1/queue/update-location
"""json
{
"user_id": "user123",
"latitude": 48.8049,
"longitude": 2.1204
}
"""
Alors le statut de réponse est 200
Et la réponse contient:
"""json
{
"queue_invalidated": true,
"reason": "distance_threshold_exceeded",
"distance_km": 12.1,
"new_queue_size": 5
}
"""
Et la nouvelle file est basée sur la position Versailles
Et l'ancienne file a été supprimée de Redis
Scénario: API ne recalcule pas si déplacement ≤10km
Étant donné qu'une file a été calculée à Paris (48.8566, 2.3522)
Et que l'utilisateur se déplace de 8 km
Quand je POST /api/v1/queue/update-location
"""json
{
"user_id": "user123",
"latitude": 48.8500,
"longitude": 2.3600
}
"""
Alors le statut de réponse est 200
Et la réponse contient:
"""json
{
"queue_invalidated": false,
"distance_km": 8.2,
"threshold": 10
}
"""
Et la file en cache reste inchangée
Scénario: API recalcule après 10 minutes
Étant donné qu'une file a été calculée à 10:00:00
Et que l'heure actuelle est 10:10:01
Quand je GET /api/v1/queue
Alors le statut de réponse est 200
Et la réponse contient:
"""json
{
"queue_invalidated": true,
"reason": "time_threshold_exceeded",
"elapsed_minutes": 10,
"new_queue_size": 5
}
"""
Et une nouvelle file de 5 contenus est recalculée
Et le timestamp "computed_at" est mis à jour
Scénario: API recalcule quand il reste <3 contenus
Étant donné qu'il reste 3 contenus [C3, C4, C5] dans la file
Quand je POST /api/v1/queue/consume (consomme C3)
Alors le statut de réponse est 200
Et la file devient [C4, C5]
Et un recalcul asynchrone est déclenché
Et 3 nouveaux contenus [C6, C7, C8] sont ajoutés
Et la file finale est [C4, C5, C6, C7, C8]
# Invalidation immédiate
Scénario: API invalide après modification préférences utilisateur
Étant donné qu'une file de 5 contenus existe pour "user123"
Et que l'utilisateur est en mode piéton (vitesse < 5 km/h)
Quand je PUT /api/v1/users/user123/preferences
"""json
{
"geo_radius": 20,
"discovery_factor": 0.7,
"political_content": false
}
"""
Alors le statut de réponse est 200
Et la file d'attente est invalidée immédiatement
Et une nouvelle file est recalculée avec les nouvelles préférences
Et en Redis, l'ancienne file a été supprimée
Scénario: API refuse modification préférences si vitesse >10 km/h
Étant donné que l'utilisateur roule à 50 km/h
Quand je PUT /api/v1/users/user123/preferences
"""json
{
"geo_radius": 30
}
"""
Alors le statut de réponse est 403
Et la réponse contient:
"""json
{
"error": "MODIFICATION_BLOCKED_WHILE_DRIVING",
"message": "Modification des préférences interdite en conduite (vitesse > 10 km/h)",
"current_speed_kmh": 50
}
"""
Et les préférences ne sont pas modifiées
Scénario: API invalide après démarrage live d'un créateur suivi
Étant donné que l'utilisateur "user123" suit le créateur "creator456"
Et qu'une file de 5 contenus existe
Et que l'utilisateur est dans la zone du créateur
Quand le créateur "creator456" démarre un live
Alors une notification push est envoyée à "user123"
Et la file d'attente est recalculée
Et le contenu live est inséré en tête de file
Et la nouvelle file commence par le live
# Métadonnées et persistence
Scénario: API stocke métadonnées complètes en Redis
Étant donné qu'une file est calculée à 10:30:00
Quand je consulte Redis avec la clé "user:user123:queue"
Alors la structure est:
"""json
{
"contents": [
{"id": "C1", "position": 1},
{"id": "C2", "position": 2},
{"id": "C3", "position": 3},
{"id": "C4", "position": 4},
{"id": "C5", "position": 5}
],
"metadata": {
"last_lat": 48.8566,
"last_lon": 2.3522,
"computed_at": "2026-02-02T10:30:00Z",
"mode": "voiture"
}
}
"""
Et le TTL est exactement 900 secondes
Scénario: API calcule distance avec PostGIS
Étant donné que l'ancienne position est Paris (48.8566, 2.3522)
Et que la nouvelle position est Versailles (48.8049, 2.1204)
Quand l'API calcule la distance
Alors la requête SQL utilise:
"""sql
SELECT ST_Distance(
ST_MakePoint(2.3522, 48.8566)::geography,
ST_MakePoint(2.1204, 48.8049)::geography
) / 1000 AS distance_km
"""
Et le résultat est 12.1 km
# Gestion erreurs
Scénario: API gère échec Redis gracieusement
Étant donné que Redis est indisponible
Quand je GET /api/v1/queue
Alors le statut de réponse est 503
Et la réponse contient:
"""json
{
"error": "CACHE_UNAVAILABLE",
"message": "Service de cache temporairement indisponible",
"fallback": "Calcul direct sans cache"
}
"""
Et une nouvelle file est calculée directement depuis PostgreSQL
Scénario: API gère aucun contenu disponible
Étant donné qu'aucun contenu n'existe dans la zone de l'utilisateur
Quand je POST /api/v1/queue/initialize
Alors le statut de réponse est 200
Et la réponse contient:
"""json
{
"queue_size": 0,
"contents": [],
"message": "Aucun contenu disponible dans cette zone",
"suggested_action": "expand_radius"
}
"""
Scénario: API élargit la zone de recherche si aucun contenu
Étant donné qu'aucun contenu n'existe dans un rayon de 20km
Quand je POST /api/v1/queue/expand-radius
"""json
{
"user_id": "user123",
"additional_radius_km": 50
}
"""
Alors le statut de réponse est 200
Et la recherche utilise un rayon de 70km (20 + 50)
Et une nouvelle file est calculée avec ce rayon
# Performance
Scénario: API répond en <100ms pour lecture cache
Étant donné qu'une file existe en Redis
Quand je GET /api/v1/queue à 10:30:00.000
Alors la réponse est reçue à 10:30:00.050 (50ms)
Et la latence est < 100ms
Scénario: API recalcule en arrière-plan sans bloquer
Étant donné qu'il reste 2 contenus dans la file
Quand je POST /api/v1/queue/consume
Alors le statut de réponse est 200 (immédiat)
Et la réponse est retournée en < 100ms
Et le recalcul asynchrone démarre en parallèle
Et le client ne perçoit aucune latence
Plan du Scénario: Conditions de recalcul selon distance
Étant donné qu'une file a été calculée à une position donnée
Quand l'utilisateur se déplace de <distance> km
Alors la file est <action>
Exemples:
| distance | action |
| 5 | conservée |
| 9.9 | conservée |
| 10.0 | conservée |
| 10.1 | invalidée et recalculée |
| 15 | invalidée et recalculée |
| 50 | invalidée et recalculée |
Plan du Scénario: Conditions de recalcul selon temps écoulé
Étant donné qu'une file a été calculée il y a <temps> minutes
Quand je consulte la file
Alors la file est <action>
Exemples:
| temps | action |
| 5 | conservée |
| 9 | conservée |
| 10 | invalidée et recalculée |
| 15 | invalidée et recalculée |
| 60 | invalidée et recalculée |