feat(bdd): réorganiser features en catégories api/ui/e2e et créer ADR-024
Résolution des incohérences #10, #11, et #12 de l'analyse d'architecture. ## Phase 1 : Réorganisation Features BDD (Point #10 - RÉSOLU) - Créer structure features/{api,ui,e2e} - Déplacer 83 features en 3 catégories via git mv (historique préservé) - features/api/ : 53 features (tests API backend) - features/ui/ : 22 features (tests UI mobile) - features/e2e/ : 8 features (tests end-to-end) Domaines déplacés : - API : authentication, recommendation, rgpd-compliance, content-creation, moderation, monetisation, premium, radio-live, publicites - UI : audio-guides, navigation, interest-gauges, mode-offline, partage, profil, recherche - E2E : abonnements, error-handling ## Phase 2 : Mise à jour Documentation ### ADR-007 - Tests BDD - Ajouter section "Convention de Catégorisation des Features" - Documenter règles api/ui/e2e avec exemples concrets - Spécifier step definitions (backend Go, mobile Dart) ### ADR-024 - Stratégie CI/CD Monorepo (NOUVEAU) - Créer ADR dédié pour stratégie CI/CD avec path filters - Architecture workflows séparés (backend.yml, mobile.yml, shared.yml) - Configuration path filters détaillée avec exemples YAML - Matrice de déclenchement et optimisations (~70% gain temps CI) - Plan d'implémentation (~2h, reporté jusqu'au développement) ### ADR-016 - Organisation Monorepo - Simplifier en retirant section CI/CD détaillée - Ajouter référence vers ADR-024 pour stratégie CI/CD ### INCONSISTENCIES-ANALYSIS.md - Point #10 (Tests BDD synchronisés) : ✅ RÉSOLU - Catégorisation features implémentée - ADR-007 mis à jour avec convention complète - Point #11 (70/30 Split paiements) : ✅ ANNULÉ (faux problème) - ADR-009 et Règle 18 parfaitement cohérents - Documentation exhaustive existante (formule, SQL, comparaisons) - Point #12 (Monorepo path filters) : ⏸️ DOCUMENTÉ - Architecture CI/CD complète dans ADR-024 - Implémentation reportée (projet en phase documentation) - Métriques mises à jour : - MODERATE : 6/9 traités (4 résolus + 1 annulé + 1 documenté) - ADR à jour : 100% (19/19 avec ADR-024) ## Phase 3 : Validation - Structure features validée (api/ui/e2e, aucun répertoire restant) - Historique Git préservé (git mv, renommages détectés) - 83 features total (API: 53, UI: 22, E2E: 8) Closes: Point #10 (résolu), Point #11 (annulé), Point #12 (documenté) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
288
features/api/publicites/caracteristiques-pub.feature
Normal file
288
features/api/publicites/caracteristiques-pub.feature
Normal file
@@ -0,0 +1,288 @@
|
||||
# language: fr
|
||||
Fonctionnalité: Caractéristiques et facturation des publicités
|
||||
En tant que système RoadWave
|
||||
Je veux appliquer des règles précises de durée, skippabilité et facturation
|
||||
Afin d'équilibrer expérience utilisateur et rentabilité publicitaire
|
||||
|
||||
Contexte:
|
||||
Étant donné que l'API RoadWave est disponible
|
||||
Et qu'un utilisateur gratuit écoute du contenu
|
||||
|
||||
Scénario: Durée minimale 10 secondes
|
||||
Étant donné qu'un publicitaire uploade une publicité de 8 secondes
|
||||
Quand le système valide la durée
|
||||
Alors une erreur s'affiche: "Durée minimale: 10 secondes"
|
||||
Et l'upload est rejeté
|
||||
|
||||
Scénario: Durée maximale 60 secondes
|
||||
Étant donné qu'un publicitaire uploade une publicité de 65 secondes
|
||||
Quand le système valide la durée
|
||||
Alors une erreur s'affiche: "Durée maximale: 60 secondes"
|
||||
Et l'upload est rejeté
|
||||
|
||||
Scénario: Durée recommandée 15-30 secondes
|
||||
Étant donné qu'un publicitaire crée une campagne
|
||||
Quand il voit les recommandations
|
||||
Alors un message s'affiche:
|
||||
"""
|
||||
💡 Durée recommandée: 15-30 secondes
|
||||
|
||||
Les publicités de cette durée ont:
|
||||
- Taux d'écoute complète: 45% (vs 35% pour 60s)
|
||||
- Meilleur engagement utilisateur
|
||||
- Coût par écoute optimisé
|
||||
"""
|
||||
|
||||
Scénario: Publicité de 10 secondes acceptée
|
||||
Étant donné qu'un publicitaire uploade une publicité de 10 secondes
|
||||
Quand le système valide la durée
|
||||
Alors le fichier est accepté
|
||||
Et aucune erreur n'est affichée
|
||||
|
||||
Scénario: Publicité de 60 secondes acceptée
|
||||
Étant donné qu'un publicitaire uploade une publicité de 60 secondes
|
||||
Quand le système valide la durée
|
||||
Alors le fichier est accepté
|
||||
Et un avertissement s'affiche: "⚠️ Durée longue: taux de skip potentiellement élevé"
|
||||
|
||||
Scénario: Délai minimum skippable 5 secondes par défaut
|
||||
Étant donné qu'une publicité de 30 secondes démarre
|
||||
Et que le délai minimal est configuré à 5 secondes
|
||||
Quand j'écoute pendant 3 secondes
|
||||
Alors le bouton "Passer" n'est pas visible
|
||||
Et je dois attendre 2 secondes supplémentaires
|
||||
Quand j'atteins 5 secondes d'écoute
|
||||
Alors le bouton "Passer" apparaît
|
||||
Et je peux cliquer pour passer au contenu suivant
|
||||
|
||||
Scénario: Délai minimum paramétrable admin (3 secondes)
|
||||
Étant donné que l'admin configure le délai à 3 secondes
|
||||
Et qu'une publicité démarre
|
||||
Quand j'écoute pendant 3 secondes
|
||||
Alors le bouton "Passer" apparaît immédiatement
|
||||
Et je peux skipper
|
||||
|
||||
Scénario: Délai minimum paramétrable admin (10 secondes)
|
||||
Étant donné que l'admin configure le délai à 10 secondes
|
||||
Et qu'une publicité démarre
|
||||
Quand j'écoute pendant 9 secondes
|
||||
Alors le bouton "Passer" n'est toujours pas visible
|
||||
Quand j'atteins 10 secondes
|
||||
Alors le bouton "Passer" apparaît
|
||||
|
||||
Scénario: Facturation écoute complète (>80%) - 0.05€
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Quand j'écoute pendant 25 secondes (83%)
|
||||
Alors l'écoute est considérée comme "complète"
|
||||
Et le publicitaire est facturé 0.05€
|
||||
Et le compteur "écoutes complètes" s'incrémente
|
||||
|
||||
Scénario: Facturation écoute complète exactement 80%
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Quand j'écoute pendant exactement 24 secondes (80%)
|
||||
Alors l'écoute est considérée comme "complète"
|
||||
Et le publicitaire est facturé 0.05€
|
||||
|
||||
Scénario: Facturation skip après délai minimal - 0.02€
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Et que le délai minimal est 5 secondes
|
||||
Quand j'écoute pendant 10 secondes (33%)
|
||||
Et que je clique sur "Passer"
|
||||
Alors l'écoute est considérée comme "partielle"
|
||||
Et le publicitaire est facturé 0.02€
|
||||
Car il y a eu une exposition partielle
|
||||
|
||||
Scénario: Facturation skip immédiat (<5s) - 0€
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Et que le délai minimal est 5 secondes
|
||||
Quand j'écoute pendant 3 secondes
|
||||
Et que je clique sur "Suivant" (pas de bouton skip encore)
|
||||
Alors l'écoute est considérée comme "non engagée"
|
||||
Et le publicitaire n'est PAS facturé (0€)
|
||||
Car l'exposition est trop courte
|
||||
|
||||
Scénario: Comptabilisation écoute complète à 79%
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Quand j'écoute pendant 23 secondes (77%)
|
||||
Alors l'écoute est considérée comme "partielle" (pas complète)
|
||||
Et le publicitaire est facturé 0.02€
|
||||
Car le seuil 80% n'est pas atteint
|
||||
|
||||
Scénario: Comptabilisation écoute complète à 100%
|
||||
Étant donné qu'une publicité de 30 secondes est diffusée
|
||||
Quand j'écoute les 30 secondes complètes (100%)
|
||||
Alors l'écoute est considérée comme "complète"
|
||||
Et le publicitaire est facturé 0.05€
|
||||
|
||||
Scénario: Budget consommé selon mix écoutes
|
||||
Étant donné qu'une campagne à 300€ a généré:
|
||||
| Type écoute | Nombre | Coût unitaire | Total |
|
||||
| Complète (>80%) | 4000 | 0.05€ | 200€ |
|
||||
| Partielle (5-80%) | 2000 | 0.02€ | 40€ |
|
||||
| Skip immédiat | 1000 | 0€ | 0€ |
|
||||
Quand je calcule le budget consommé
|
||||
Alors le total est 240€
|
||||
Et il reste 60€ de budget disponible
|
||||
|
||||
Scénario: Affichage compteur secondes restantes
|
||||
Étant donné qu'une publicité de 30s démarre
|
||||
Et que le délai minimal est 5s
|
||||
Quand j'écoute pendant 2 secondes
|
||||
Alors un compteur s'affiche: "Passer dans 3s..."
|
||||
Quand j'atteins 5 secondes
|
||||
Alors le compteur disparaît
|
||||
Et le bouton "Passer la publicité" s'affiche
|
||||
|
||||
Scénario: Progress bar publicité visible
|
||||
Étant donné qu'une publicité de 30s est en lecture
|
||||
Quand 10 secondes se sont écoulées
|
||||
Alors la progress bar affiche 33% (10/30)
|
||||
Et l'indicateur temporel affiche "0:10 / 0:30"
|
||||
Et l'utilisateur visualise la progression
|
||||
|
||||
Scénario: Message "Publicité" clairement affiché
|
||||
Étant donné qu'une publicité démarre
|
||||
Quand l'audio commence
|
||||
Alors un badge "Publicité" est affiché en haut de l'écran
|
||||
Et la durée totale est indiquée: "Publicité (30s)"
|
||||
Et la transparence est maximale (utilisateur sait que c'est une pub)
|
||||
|
||||
Scénario: Transition fluide après publicité
|
||||
Étant donné qu'une publicité de 30s se termine
|
||||
Quand la lecture atteint 30 secondes
|
||||
Alors le délai de transition de 2s démarre
|
||||
Et le contenu normal suivant est annoncé
|
||||
Et l'enchaînement est naturel (même UX que entre contenus)
|
||||
|
||||
Scénario: Like autorisé sur publicité
|
||||
Étant donné qu'une publicité est en lecture
|
||||
Et que le véhicule est à l'arrêt
|
||||
Quand je clique sur le bouton cœur
|
||||
Alors un like explicite (+2%) est enregistré
|
||||
Et mes jauges d'intérêt sont mises à jour selon les tags de la pub
|
||||
Et le publicitaire voit un compteur "Likes" incrémenté
|
||||
|
||||
Scénario: Abonnement autorisé sur publicité
|
||||
Étant donné qu'une publicité est diffusée par un créateur
|
||||
Et que le véhicule est à l'arrêt
|
||||
Quand je clique sur "S'abonner"
|
||||
Alors l'abonnement est enregistré (+5% jauges)
|
||||
Et le publicitaire bénéficie de l'engagement fort
|
||||
Et cela compte comme une conversion majeure
|
||||
|
||||
Scénario: Bouton skip visible et accessible
|
||||
Étant donné qu'une publicité a dépassé le délai minimal
|
||||
Quand le bouton "Passer" s'affiche
|
||||
Alors il est positionné en bas à droite de l'écran
|
||||
Et il a une taille de clic confortable (44×44px minimum iOS)
|
||||
Et il est clairement visible (contraste élevé)
|
||||
|
||||
Scénario: Analytics tracking précis par type
|
||||
Étant donné qu'une publicité est diffusée
|
||||
Quand un événement se produit
|
||||
Alors il est tracké en temps réel:
|
||||
| Événement | Données enregistrées |
|
||||
| Impression | timestamp, user_id, pub_id, zone_geo |
|
||||
| Écoute complète | durée_ecoutee, pourcentage, coût (0.05€) |
|
||||
| Skip après délai | durée_ecoutee, pourcentage, coût (0.02€) |
|
||||
| Skip immédiat | durée_ecoutee, pourcentage, coût (0€) |
|
||||
| Like | timestamp, tags impactés |
|
||||
| Abonnement | timestamp, creator_id |
|
||||
|
||||
Scénario: Recommandation sweet spot 15-30s
|
||||
Étant donné les statistiques RoadWave globales:
|
||||
| Durée pub | Taux complétion moyen |
|
||||
| 10s | 65% |
|
||||
| 15s | 55% |
|
||||
| 30s | 45% |
|
||||
| 45s | 30% |
|
||||
| 60s | 20% |
|
||||
Quand un publicitaire consulte les recommandations
|
||||
Alors le sweet spot affiché est "15-30 secondes"
|
||||
Et l'explication est "Meilleur compromis engagement/message"
|
||||
|
||||
Scénario: Optimisation durée selon taux de skip campagne
|
||||
Étant donné qu'une campagne de 60s a un taux de skip de 85%
|
||||
Quand le publicitaire consulte les recommandations
|
||||
Alors le système suggère:
|
||||
"""
|
||||
⚠️ Taux de skip élevé (85%)
|
||||
|
||||
Recommandation: Réduire la durée à 30s maximum
|
||||
Impact estimé: Taux de skip attendu 55% (-30%)
|
||||
"""
|
||||
|
||||
Scénario: Coût effectif moyen (CEM) calculé
|
||||
Étant donné une campagne avec:
|
||||
| Type écoute | Nombre | Coût unitaire | Total |
|
||||
| Complète | 2000 | 0.05€ | 100€ |
|
||||
| Partielle | 3000 | 0.02€ | 60€ |
|
||||
| Skip immédiat | 1000 | 0€ | 0€ |
|
||||
Quand je calcule le coût effectif moyen
|
||||
Alors CEM = 160€ / 6000 impressions = 0.027€/impression
|
||||
Et cette métrique aide à comparer avec CPM industrie
|
||||
|
||||
Scénario: Publicité non skippable interdite
|
||||
Étant donné qu'un publicitaire demande "Publicité non skippable"
|
||||
Quand il configure sa campagne
|
||||
Alors cette option n'existe pas
|
||||
Et toutes les publicités sont obligatoirement skippables après 5s minimum
|
||||
Car l'expérience utilisateur est prioritaire
|
||||
|
||||
Scénario: Délai minimal jamais <3 secondes
|
||||
Étant donné qu'un admin essaie de configurer le délai à 2 secondes
|
||||
Quand il valide le paramètre
|
||||
Alors une erreur s'affiche: "Délai minimal: 3 secondes minimum"
|
||||
Car un délai trop court dégrade trop l'expérience
|
||||
|
||||
Scénario: Délai minimal jamais >10 secondes
|
||||
Étant donné qu'un admin essaie de configurer le délai à 15 secondes
|
||||
Quand il valide le paramètre
|
||||
Alors une erreur s'affiche: "Délai maximal: 10 secondes maximum"
|
||||
Car un délai trop long réduit les revenus publicitaires
|
||||
|
||||
Plan du Scénario: Facturation selon durée écoutée
|
||||
Étant donné qu'une publicité de 30s est diffusée
|
||||
Quand j'écoute pendant <duree>s (<pourcentage>%)
|
||||
Alors le type d'écoute est <type>
|
||||
Et le coût facturé est <cout>€
|
||||
|
||||
Exemples:
|
||||
| duree | pourcentage | type | cout |
|
||||
| 3 | 10 | skip immédiat| 0 |
|
||||
| 5 | 17 | partielle | 0.02 |
|
||||
| 10 | 33 | partielle | 0.02 |
|
||||
| 20 | 67 | partielle | 0.02 |
|
||||
| 24 | 80 | complète | 0.05 |
|
||||
| 27 | 90 | complète | 0.05 |
|
||||
| 30 | 100 | complète | 0.05 |
|
||||
|
||||
Plan du Scénario: Budget consommé selon distribution écoutes
|
||||
Étant donné <completes> écoutes complètes à 0.05€
|
||||
Et <partielles> écoutes partielles à 0.02€
|
||||
Et <skips> skips immédiats à 0€
|
||||
Quand je calcule le budget total consommé
|
||||
Alors le résultat est <budget_total>€
|
||||
|
||||
Exemples:
|
||||
| completes | partielles | skips | budget_total |
|
||||
| 1000 | 500 | 100 | 60 |
|
||||
| 2000 | 1000 | 500 | 120 |
|
||||
| 5000 | 2000 | 1000 | 290 |
|
||||
| 0 | 1000 | 0 | 20 |
|
||||
| 1000 | 0 | 0 | 50 |
|
||||
|
||||
Plan du Scénario: Apparition bouton skip selon délai configuré
|
||||
Étant donné que le délai minimal est configuré à <delai>s
|
||||
Quand j'écoute pendant <temps_ecoute>s
|
||||
Alors le bouton "Passer" est <visible>
|
||||
|
||||
Exemples:
|
||||
| delai | temps_ecoute | visible |
|
||||
| 5 | 3 | non visible |
|
||||
| 5 | 5 | visible |
|
||||
| 5 | 10 | visible |
|
||||
| 10 | 8 | non visible |
|
||||
| 10 | 10 | visible |
|
||||
| 3 | 2 | non visible |
|
||||
| 3 | 3 | visible |
|
||||
Reference in New Issue
Block a user