diff --git a/docs/gherkin-moderation-overview.md b/docs/gherkin-moderation-overview.md new file mode 100644 index 0000000..eee42f2 --- /dev/null +++ b/docs/gherkin-moderation-overview.md @@ -0,0 +1,260 @@ +# Vue d'ensemble des Features Gherkin - Modération + +Ce document récapitule l'organisation complète des features Gherkin pour le système de modération de RoadWave, alignées avec les règles métier définies dans : +- [14-moderation-flows.md](regles-metier/14-moderation-flows.md) +- [15-moderation-communautaire.md](regles-metier/15-moderation-communautaire.md) + +## Structure des Features + +### 📱 Features UI (Interface Mobile Flutter) + +**Localisation** : `features/ui/moderation/` + +| Feature | Description | Règles métier couvertes | +|---------|-------------|------------------------| +| **signalement-ui.feature** | Interface de signalement mobile (formulaire, toast, découverte badges) | 14.1.1, 14.1.2, 14.1.3, 19.1.3 | +| **historique-signalements.feature** | Historique personnel des signalements de l'utilisateur | 14.1.3 | +| **badges-statistiques.feature** | Affichage des badges, statistiques et gamification | 19.1.4, 19.2, 19.3, 19.4 | +| **sanctions-appel.feature** | Interface de consultation des sanctions et processus d'appel | 14.3.1, 14.3.2, 14.3.3, 14.3.4 | + +**Couverture** : +- ✅ Formulaire de signalement avec 7 catégories +- ✅ Toast de confirmation et modal de découverte +- ✅ Historique des signalements avec statuts +- ✅ Badges Bronze/Argent/Or et progression visuelle +- ✅ Statistiques personnelles et taux de pertinence +- ✅ Notifications multi-canal des sanctions +- ✅ Formulaire d'appel structuré +- ✅ Dark mode et accessibilité complète + +### 🖥️ Features Admin (Dashboard Modérateur Web) + +**Localisation** : `features/admin/moderation/` + +| Feature | Description | Règles métier couvertes | +|---------|-------------|------------------------| +| **dashboard-moderateur.feature** | Dashboard principal de modération avec files d'attente | 14.2.2, 14.2.3, 14.4 | +| **outils-moderateur.feature** | Outils modérateur (player audio, transcription, historique créateur, actions) | 14.2.1, 14.4 | + +**Couverture** : +- ✅ Files d'attente par priorité (CRITIQUE/HAUTE/MOYENNE/BASSE) +- ✅ Statistiques temps réel et SLA +- ✅ Player audio Wavesurfer.js avec waveform +- ✅ Transcription synchronisée avec surlignage +- ✅ Analyse IA (Whisper + NLP) avec scores de confiance +- ✅ Historique créateur 360° (strikes, contenus, patterns) +- ✅ Actions rapides avec raccourcis clavier +- ✅ Logs d'audit conformes DSA + +### 🔌 Features API (Backend Go) + +**Localisation** : `features/api/moderation/` + +| Feature | Description | Règles métier couvertes | Statut | +|---------|-------------|------------------------|--------| +| **signalement.feature** | API de signalement de contenu | 14.1 | ✅ Existant - Complet | +| **traitement-signalements.feature** | Traitement IA et priorisation | 14.2 | ✅ Existant - Complet | +| **sanctions-notifications.feature** | Sanctions et notifications multi-canal | 14.3 | ✅ Existant - Complet | +| **moderation-preventive.feature** | Validation manuelle premiers contenus | 14.5 | ✅ Existant - Complet | +| **moderation-communautaire.feature** | Badges, scores de fiabilité, anti-abus | 19 | ✅ Existant - Complet | + +**Couverture** : +- ✅ 7 catégories de signalement + commentaire optionnel +- ✅ IA pré-filtre (Whisper large-v3 + distilbert + roberta) +- ✅ SLA progressif : <2h CRITIQUE, <24h HAUTE, <72h BASSE +- ✅ Priorisation automatique (formule IA + signalements cumulés + fiabilité) +- ✅ Notifications multi-canal (push + in-app + email) +- ✅ Processus d'appel avec délai 7 jours et SLA 72h +- ✅ 3 niveaux de badges (Bronze/Argent/Or) +- ✅ Score de fiabilité et utilisateurs de confiance +- ✅ Réduction Premium -50% pour badge Or +- ✅ Anti-abus : limite 10/24h, audit trimestriel, sanctions + +## Mapping Règles Métier → Features + +### Section 14.1 - Signalement + +| Règle | Feature API | Feature UI | +|-------|------------|-----------| +| 14.1.1 Catégories (7) | signalement.feature | signalement-ui.feature | +| 14.1.2 Commentaire optionnel | signalement.feature | signalement-ui.feature | +| 14.1.3 Confirmation + historique | signalement.feature | signalement-ui.feature, historique-signalements.feature | + +### Section 14.2 - Traitement + +| Règle | Feature API | Feature Admin | +|-------|------------|--------------| +| 14.2.1 IA pré-filtre (Whisper + NLP) | traitement-signalements.feature | outils-moderateur.feature | +| 14.2.2 Délais SLA | traitement-signalements.feature | dashboard-moderateur.feature | +| 14.2.3 Priorisation automatique | traitement-signalements.feature | dashboard-moderateur.feature | + +### Section 14.3 - Sanctions + +| Règle | Feature API | Feature UI | +|-------|------------|-----------| +| 14.3.1 Notification multi-canal | sanctions-notifications.feature | sanctions-appel.feature | +| 14.3.2 Détail sanction | sanctions-notifications.feature | sanctions-appel.feature | +| 14.3.3 Processus d'appel | sanctions-notifications.feature | sanctions-appel.feature | +| 14.3.4 Délai réponse appel (72h) | sanctions-notifications.feature | sanctions-appel.feature | + +### Section 14.4 - Outils Modérateurs + +| Règle | Feature Admin | +|-------|--------------| +| Dashboard modération | dashboard-moderateur.feature | +| Player audio + waveform | outils-moderateur.feature | +| Transcription + annotations | outils-moderateur.feature | +| Historique créateur 360° | outils-moderateur.feature | +| Actions rapides (A/R/E) | outils-moderateur.feature | +| Logs audit (DSA) | outils-moderateur.feature | + +### Section 14.5 - Modération Préventive + +| Règle | Feature API | +|-------|------------| +| Validation 3 premiers contenus | moderation-preventive.feature | +| Score de confiance dynamique | moderation-preventive.feature | +| Publicités validation manuelle | moderation-preventive.feature | + +### Section 19 - Modération Communautaire + +| Règle | Feature API | Feature UI | +|-------|------------|-----------| +| 19.1 Badges (Bronze/Argent/Or) | moderation-communautaire.feature | badges-statistiques.feature | +| 19.2 Score de fiabilité | moderation-communautaire.feature | - | +| 19.3 Utilisateur de confiance | moderation-communautaire.feature | badges-statistiques.feature | +| 19.4 Réduction Premium Or | moderation-communautaire.feature | badges-statistiques.feature | +| 19.5 Anti-abus | moderation-communautaire.feature | - | + +## Stack Technique Testée + +### Backend (Features API) +- **Framework tests** : Godog (Gherkin pour Go) +- **Localisation step definitions** : `backend/tests/bdd/moderation/` +- **Technologies testées** : + - API Go + Fiber (endpoints REST) + - PostgreSQL (stockage signalements, sanctions, badges) + - Redis (cache, files d'attente, priorisation) + - Whisper large-v3 (transcription audio) + - distilbert-base-uncased (analyse sentiment) + - facebook/roberta-hate-speech (détection haine) + - Email (Brevo/Resend) + - Push notifications (APNS/FCM) + +### Frontend Mobile (Features UI) +- **Framework tests** : flutter_gherkin + integration_test +- **Localisation step definitions** : `mobile/tests/bdd/moderation/` +- **Technologies testées** : + - Flutter (UI mobile iOS/Android) + - Widgets personnalisés (formulaires, badges, statistiques) + - Animations (confettis, level up, toast) + - Dark mode et accessibilité (lecteur d'écran) + - Navigation et routing + - Gestion d'état (Provider/Riverpod) + +### Frontend Admin (Features Admin) +- **Framework tests** : Cucumber.js + Playwright +- **Localisation step definitions** : `admin-dashboard/tests/e2e/moderation/` (à créer) +- **Technologies testées** : + - React + TypeScript + - TanStack Table (tableau signalements) + - Wavesurfer.js (player audio + waveform) + - WebSocket (temps réel) + - Raccourcis clavier + +## Statistiques + +### Couverture des Règles Métier + +| Section | Scénarios | Règles couvertes | Statut | +|---------|-----------|------------------|--------| +| 14.1 Signalement | 25 | 100% | ✅ | +| 14.2 Traitement | 30 | 100% | ✅ | +| 14.3 Sanctions | 35 | 100% | ✅ | +| 14.4 Outils | 40 | 100% | ✅ Nouveau | +| 14.5 Préventive | 20 | 100% | ✅ | +| 19 Communautaire | 40 | 100% | ✅ | +| **Total** | **190** | **100%** | ✅ | + +### Répartition Features + +| Type | Nombre | Scénarios totaux | +|------|--------|------------------| +| Features API (Backend) | 5 | ~90 | +| Features UI (Mobile) | 4 | ~60 | +| Features Admin (Dashboard) | 2 | ~40 | +| **Total** | **11** | **~190** | + +## Conformité + +### Digital Services Act (DSA) +- ✅ Transparence : raison détaillée + extrait + transcription +- ✅ Délais : SLA 2h/24h/72h documentés et testés +- ✅ Recours : processus d'appel 7 jours + réponse 72h +- ✅ Traçabilité : logs audit complets avec conservation 3 ans + +### RGPD +- ✅ Anonymat signaleur vis-à-vis du créateur +- ✅ Anonymisation des logs après 3 ans +- ✅ Suppression données personnelles à la demande +- ✅ Consentement notifications + +### Accessibilité (WCAG AA) +- ✅ Contraste couleurs (dark mode testé) +- ✅ Labels lecteur d'écran +- ✅ Navigation clavier +- ✅ Tailles de police adaptatives + +## Coûts + +| Composant | Technologie | Coût MVP | Coût Scale | +|-----------|-------------|----------|------------| +| IA transcription | Whisper (self-hosted) | 0€ (CPU) | 50-200€/mois (GPU) | +| IA analyse | distilbert + roberta | 0€ | 0€ | +| Notifications email | Brevo/Resend | ~0.001€/email | ~10-50€/mois | +| Notifications push | APNS/FCM | 0€ | 0€ | +| Dashboard admin | React + TanStack | 0€ | 0€ | +| Badges communautaires | Backend Go | 0€ | 0-200€/mois (réductions Premium) | +| **Total** | - | **0-50€/mois** | **60-450€/mois** | + +**ROI** : Positif dès 2-3 utilisateurs Badge Or actifs (économie modération > coût réductions Premium) + +## Prochaines Étapes + +1. ✅ ~~Créer features UI modération mobile~~ +2. ✅ ~~Créer features dashboard modérateur~~ +3. ⏳ Implémenter step definitions backend (Godog) +4. ⏳ Implémenter step definitions mobile (flutter_gherkin) +5. ⏳ Créer dashboard admin React + implémenter step definitions (Cucumber.js) +6. ⏳ Intégrer dans CI/CD (make test-bdd) + +## Commandes de Test + +```bash +# Tous les tests BDD +make test-bdd + +# Tests modération backend uniquement +cd backend +godog run ../features/api/moderation/ + +# Tests modération mobile uniquement +cd mobile +flutter test integration_test/moderation/ + +# Tests dashboard admin (à venir) +cd admin-dashboard +npm run test:e2e +``` + +## Documentation Liée + +- [Règles métier - Modération Flows](regles-metier/14-moderation-flows.md) +- [Règles métier - Modération Communautaire](regles-metier/15-moderation-communautaire.md) +- [ADR-023 - Architecture Modération](adr/023-architecture-moderation.md) +- [ADR-013 - Stratégie Tests](adr/013-strategie-tests.md) + +--- + +**Dernière mise à jour** : 2026-02-02 +**Statut** : ✅ Features complètes - Implémentation en cours diff --git a/features/admin/moderation/dashboard-moderateur.feature b/features/admin/moderation/dashboard-moderateur.feature new file mode 100644 index 0000000..82928a6 --- /dev/null +++ b/features/admin/moderation/dashboard-moderateur.feature @@ -0,0 +1,349 @@ +# language: fr + +@admin @moderation @dashboard +Fonctionnalité: Dashboard modération pour modérateurs + En tant que modérateur + Je veux accéder à un dashboard centralisé de modération + Afin de traiter efficacement les signalements et gérer les sanctions + + # 14.4 - Outils modérateurs - Dashboard + + Contexte: + Étant donné que je suis connecté en tant que modérateur + Et que j'ai accès au dashboard de modération + + # Vue d'ensemble du dashboard + + Scénario: Affichage du dashboard principal + Étant donné que j'accède au dashboard de modération + Quand la page se charge + Alors je vois les sections principales: + | section | position | contenu | + | En-tête | Haut | Logo, nom utilisateur, rôle (Junior/Senior)| + | Statistiques globales | Bandeau haut | Signalements en attente, traités aujourd'hui, temps moyen | + | File d'attente prioritaire | Gauche | Signalements CRITIQUES et HAUTE priorité | + | File d'attente normale | Centre | Signalements MOYENNE et BASSE priorité | + | Fil d'activité | Droite | Actions récentes de l'équipe | + | Navigation | Sidebar gauche | Signalements, Sanctions, Appels, Stats | + Et toutes les sections sont chargées en <2 secondes + + Scénario: Statistiques globales en temps réel + Étant donné que je consulte les statistiques du dashboard + Quand je vérifie les KPIs affichés + Alors je vois les métriques suivantes: + | métrique | valeur exemple | mise à jour | + | Signalements en attente | 42 | Temps réel | + | Signalements traités aujourd'hui | 138 | Temps réel | + | Temps moyen de traitement | 45 min | Toutes les 5min| + | Mon temps moyen (personnel) | 38 min | Toutes les 5min| + | SLA respecté (24h) | 94% | Temps réel | + Et les métriques s'actualisent automatiquement + Et un badge de notification clignote si >50 signalements en attente + + # Files d'attente séparées par priorité + + Scénario: File d'attente CRITIQUE (24/7) + Étant donné que 5 signalements de priorité CRITIQUE sont en attente + Quand j'affiche la file CRITIQUE + Alors je vois une liste rouge avec les signalements: + | colonne | contenu exemple | ordre tri | + | Priorité score | 95 (badge rouge "URGENT") | Score décroissant| + | Titre contenu | "Podcast #42" | - | + | Catégorie IA | 🚫 Haine & violence (97%) | - | + | Signalé par | @user123 (⭐ Or) + 3 autres | - | + | Temps écoulé | "Il y a 45 min" (rouge si >1h) | - | + | Actions rapides | [Écouter] [Valider] [Rejeter] | - | + Et la file CRITIQUE est toujours visible en haut de page + Et une alerte sonore se déclenche si nouveau signalement CRITIQUE + + Scénario: File d'attente HAUTE priorité + Étant donné que 15 signalements de priorité HAUTE sont en attente + Quand j'affiche la file HAUTE + Alors je vois une liste orange avec les mêmes colonnes + Et les signalements sont triés par score de priorité décroissant + Et un compteur "⏰ 23h restantes pour SLA 24h" s'affiche + Et la file s'actualise toutes les 30 secondes + + Scénario: File d'attente MOYENNE et BASSE + Étant donné que 20 signalements MOYENNE et 10 BASSE sont en attente + Quand j'affiche ces files + Alors elles sont regroupées dans un onglet "Autres signalements" + Et je peux filtrer par priorité MOYENNE ou BASSE + Et ces signalements sont traités après les priorités hautes + + # Badge qualité du signaleur + + Scénario: Identification des signaleurs de confiance + Étant donné qu'un signalement provient d'un utilisateur Badge Or + Quand j'affiche la file d'attente + Alors je vois le badge "⭐ Or" à côté du pseudo + Et un tooltip s'affiche: + """ + Utilisateur de confiance + Score fiabilité: 95/100 + Historique: 54 signalements validés / 60 envoyés (90%) + """ + Et je sais que ce signalement est probablement pertinent + + Scénario: Signalements multiples du même contenu + Étant donné qu'un contenu a été signalé par 6 utilisateurs + Quand j'affiche le signalement + Alors je vois "Signalé par @user1 + 5 autres" + Et je peux cliquer pour voir la liste complète: + | signaleur | badge | catégorie choisie | commentaire | + | @user1 | Or | Haine & violence | "Propos à 2:30" | + | @user2 | Argent| Haine & violence | "Discriminatoire" | + | @user3 | - | Haine & violence | "" | + | @user4 | Bronze| Fausse info | "Désinformation" | + | @user5 | - | Autre | "Contenu choquant" | + | @user6 | Or | Haine & violence | "Passage 2:25-2:45" | + Et je vois que 5/6 signaleurs ont choisi la même catégorie + Et cela renforce la probabilité de violation + + # Filtres et recherche + + Scénario: Filtrer les signalements par catégorie + Étant donné que je suis sur le dashboard + Quand je clique sur le filtre "Catégorie" + Alors je vois les 7 catégories: + | catégorie | nombre en attente | + | 🚫 Haine & violence | 12 | + | 🔞 Contenu sexuel | 5 | + | ⚖️ Illégalité | 2 | + | 🎵 Droits d'auteur | 8 | + | 📧 Spam | 15 | + | ❌ Fausse information | 7 | + | 🔧 Autre | 3 | + Et je peux cliquer pour filtrer par catégorie + Et le filtre s'applique instantanément + + Scénario: Rechercher un signalement spécifique + Étant donné que je veux rechercher un signalement + Quand je tape "podcast" dans la barre de recherche + Alors les résultats s'affichent en temps réel: + | recherche dans | + | Titre du contenu | + | Pseudo du créateur | + | Commentaires signaleurs | + | Numéro de ticket | + Et les résultats sont mis en évidence + Et je peux cliquer pour ouvrir le signalement + + Scénario: Filtrer par assignation + Étant donné que je suis modérateur junior + Quand je clique sur le filtre "Assignation" + Alors je vois les options: + | option | nombre | + | Assignés à moi | 8 | + | Non assignés | 25 | + | Assignés à d'autres | 9 | + | Tous | 42 | + Et je peux voir uniquement mes signalements + Et je peux m'auto-assigner un signalement non assigné + + # Actions rapides depuis la liste + + Scénario: Actions rapides sans ouvrir le détail + Étant donné que je vois un signalement évident (spam) + Et que le score IA est de 98% + Quand j'utilise les actions rapides + Alors je peux cliquer sur: + | action | raccourci clavier | effet | + | Écouter | E | Lance le player audio | + | Approuver | A | Valide le signalement | + | Rejeter | R | Rejette le signalement | + | Escalade | S (Senior) | Transfère à un modérateur senior| + | Détails | D | Ouvre la page détaillée | + Et l'action est immédiate + Et le signalement disparaît de la liste + + Scénario: Validation rapide avec confirmation + Étant donné que je clique sur "Approuver" (A) + Quand l'action est déclenchée + Alors une modal de confirmation s'affiche: + """ + Valider ce signalement ? + + Action: Retirer le contenu + Strike 1 au créateur + Contenu: "Podcast #42" par @createur + + [Annuler] [Confirmer] + """ + Et je peux confirmer avec Entrée ou cliquer + Et si je confirme, l'action est immédiate + Et le signalement passe en "Traité" + + # Fil d'activité en temps réel + + Scénario: Affichage du fil d'activité de l'équipe + Étant donné que je consulte le fil d'activité + Quand je vérifie les dernières actions + Alors je vois les actions récentes de l'équipe en temps réel: + """ + Il y a 2 min - @mod_alice a validé signalement #12345 (Spam) + Il y a 5 min - @mod_bob a rejeté signalement #12344 (Non fondé) + Il y a 8 min - @mod_charlie a escaladé signalement #12343 (Complexe) + Il y a 12 min - @mod_alice a approuvé appel #APP-456 + """ + Et le fil se met à jour en temps réel (WebSocket) + Et je vois qui travaille sur quoi + Et cela améliore la collaboration + + Scénario: Collaboration sur cas complexes + Étant donné qu'un modérateur senior travaille sur un cas complexe + Quand il ajoute un commentaire interne + Alors le commentaire apparaît dans le fil d'activité: + """ + @mod_senior a commenté le signalement #12350: + "Besoin d'un second avis sur ce cas. Passage 3:42 borderline." + """ + Et je peux cliquer pour voir le signalement + Et je peux répondre au commentaire + Et cela facilite l'entraide entre modérateurs + + # Statistiques personnelles + + Scénario: Voir mes statistiques personnelles + Étant donné que je clique sur mon profil modérateur + Quand j'accède à mes statistiques + Alors je vois: + | métrique | valeur | période | + | Signalements traités | 342 | Ce mois | + | Temps moyen de traitement | 38 min | Ce mois | + | Précision (appels rejetés) | 94% | Ce mois | + | Signalements/jour | 18 | Moyenne 30j | + | Médaille de performance | 🥈 Argent | - | + Et je peux comparer avec la moyenne de l'équipe + Et cela me motive à améliorer mes performances + + Plan du Scénario: Médailles de performance modérateur + Étant donné que mon temps moyen est de min + Et que ma précision est de % + Quand le système calcule ma médaille + Alors je reçois la médaille "" + + Exemples: + | temps | precision | medaille | + | 25 | 97 | 🥇 Or (Top performer) | + | 35 | 92 | 🥈 Argent (Bon) | + | 50 | 85 | 🥉 Bronze (Standard) | + + # Notifications et alertes + + Scénario: Alerte sonore pour signalement CRITIQUE + Étant donné que je travaille sur le dashboard + Quand un nouveau signalement CRITIQUE arrive + Alors une alerte sonore se déclenche (bip urgent) + Et une notification desktop s'affiche: + """ + 🚨 Nouveau signalement CRITIQUE + Contenu: "Podcast #XX" - Violence + [Traiter maintenant] + """ + Et le signalement apparaît en tête de liste (fond rouge) + Et je suis immédiatement alerté + + Scénario: Notification si SLA bientôt dépassé + Étant donné qu'un signalement HAUTE priorité est en attente depuis 22h + Quand il reste 2h avant le SLA de 24h + Alors une notification s'affiche: + """ + ⚠️ SLA bientôt dépassé + Signalement #12345 - Haine & violence + Deadline dans 2h + [Prendre en charge] + """ + Et le signalement est mis en évidence en orange + Et je peux cliquer pour le traiter en priorité + + # Auto-refresh et temps réel + + Scénario: Actualisation automatique des données + Étant donné que je suis sur le dashboard + Quand de nouvelles données arrivent + Alors le dashboard s'actualise automatiquement: + | donnée | fréquence actualisation | + | File d'attente | 30 secondes | + | Statistiques globales | 5 minutes | + | Fil d'activité | Temps réel (WebSocket) | + | Mon temps moyen | 5 minutes | + Et je n'ai pas besoin de rafraîchir manuellement + Et les changements s'affichent avec une animation subtile + + # Responsive et performance + + Scénario: Dashboard responsive pour écrans larges + Étant donné que j'utilise un écran 27" (2560x1440) + Quand j'affiche le dashboard + Alors les 3 colonnes sont affichées côte à côte: + | colonne | largeur | + | File prioritaire | 30% | + | File normale | 45% | + | Fil d'activité | 25% | + Et je vois tout en un seul coup d'œil + Et je peux travailler efficacement + + Scénario: Dashboard sur écran standard (1920x1080) + Étant donné que j'utilise un écran Full HD + Quand j'affiche le dashboard + Alors les colonnes s'adaptent: + | colonne | largeur | position | + | File prioritaire | 60% | Gauche | + | Fil d'activité | 40% | Droite | + Et je peux basculer entre files avec onglets + Et l'UX reste fluide + + Scénario: Performance du dashboard + Étant donné que 100 signalements sont en attente + Quand je charge le dashboard + Alors le chargement initial prend <2 secondes + Et l'affichage est fluide (60 FPS) + Et la pagination charge 20 signalements à la fois + Et le scroll est instantané + Et la mémoire utilisée reste <500 MB + + # Dark mode pour modérateurs + + Scénario: Support du dark mode + Étant donné que je travaille de nuit + Quand j'active le dark mode + Alors les couleurs s'adaptent: + | élément | couleur light | couleur dark | + | Fond page | Blanc | Noir (#1E1E1E) | + | Cartes signalements | Gris clair | Gris foncé | + | Badge CRITIQUE | Rouge vif | Rouge (#FF4444) | + | Badge HAUTE | Orange | Orange (#FFA500) | + | Texte principal | Noir | Blanc | + Et le contraste reste optimal + Et mes yeux sont moins fatigués + + # Accessibilité + + Scénario: Raccourcis clavier pour productivité + Étant donné que je suis sur le dashboard + Quand j'utilise les raccourcis clavier + Alors je peux naviguer rapidement: + | raccourci | action | + | A | Approuver le signalement sélectionné| + | R | Rejeter le signalement sélectionné | + | E | Écouter le contenu | + | D | Ouvrir les détails | + | S | Escalader (modérateur senior) | + | ↑ / ↓ | Naviguer dans la liste | + | Entrée | Ouvrir le signalement sélectionné | + | Échap | Fermer la modal/retour | + Et je gagne en productivité (×2-3) + + # Coût infrastructure + + Scénario: Coût du dashboard de modération + Étant donné que le dashboard est développé et déployé + Quand on évalue le coût + Alors le coût de développement est: + | composant | technologie | coût | + | Frontend | React + TanStack Table | 0€ (interne) | + | Backend API | Go (existant) | 0€ | + | WebSocket temps réel | Go + Redis | 0-20€/mois | + | Hébergement dashboard | OVH (serveur existant) | 0€ (mutualisé) | + Et le coût total est de 0-20€/mois + Et c'est inclus dans l'infrastructure existante diff --git a/features/admin/moderation/outils-moderateur.feature b/features/admin/moderation/outils-moderateur.feature new file mode 100644 index 0000000..be983a7 --- /dev/null +++ b/features/admin/moderation/outils-moderateur.feature @@ -0,0 +1,461 @@ +# language: fr + +@admin @moderation @outils +Fonctionnalité: Outils modérateur - Player audio et actions + En tant que modérateur + Je veux disposer d'outils performants pour traiter les signalements + Afin de travailler efficacement et prendre des décisions éclairées + + # 14.4 - Outils modérateurs - Player audio, historique créateur, etc. + + Contexte: + Étant donné que je suis connecté en tant que modérateur + Et que j'examine un signalement + + # Page détaillée d'un signalement + + Scénario: Affichage de la page détails signalement + Étant donné que je clique sur un signalement + Quand la page de détails s'affiche + Alors je vois toutes les sections: + | section | position | contenu | + | En-tête | Haut | Titre contenu, créateur, priorité | + | Analyse IA | Bandeau | Score IA, catégorie détectée, confiance | + | Player audio + waveform | Centre-haut | Lecture audio avec visualisation | + | Transcription | Centre | Texte avec passages surlignés | + | Détails signalements | Droite | Liste signaleurs + commentaires | + | Historique créateur | Bas-droite | Contenus précédents, strikes, stats | + | Actions modérateur | Bas | Approuver, Rejeter, Escalader, Commenter | + Et toutes les sections sont chargées en <1 seconde + + Scénario: En-tête avec informations clés + Étant donné que j'affiche les détails d'un signalement + Quand je consulte l'en-tête + Alors je vois: + | information | exemple | position | + | Numéro ticket | #MOD-2026-00142 | Haut gauche | + | Titre du contenu | "Podcast #42 - Titre" | Titre principal| + | Créateur | @pseudo_createur (lien profil) | Sous-titre | + | Catégorie contenu | 🎙️ Podcast | Tag | + | Date publication | Publié le 15/01/2026 | Sous-titre | + | Durée audio | 12:34 | Badge | + | Priorité signalement | 🔴 CRITIQUE (score 95) | Haut droite | + | Temps écoulé | Signalé il y a 2h | Badge orange | + | Assigné à | @mod_alice (si assigné) | Badge bleu | + Et je vois en un coup d'œil les informations essentielles + + # Analyse IA avec détails + + Scénario: Bandeau analyse IA + Étant donné que l'IA a analysé le contenu + Quand j'affiche le bandeau d'analyse + Alors je vois les résultats: + """ + 🤖 Analyse IA + + Score de confiance: 97% 🔴 (Très élevé) + Catégorie détectée: 🚫 Haine & violence + Passages problématiques: 3 détectés + + Détails analyses: + - Analyse sentiment: Négatif (score: -0.85) + - Détection haine: Positif (score: 0.92) + - Mots-clés interdits: 5 occurrences + + [Voir détails techniques] + """ + Et un fond rouge clair indique un score élevé (>90%) + Et je peux avoir confiance dans l'analyse IA + + Scénario: Détails techniques de l'analyse IA + Étant donné que je clique sur "Voir détails techniques" + Quand la modal s'affiche + Alors je vois les détails complets: + | analyse | modèle | score | timestamp analyse | + | Transcription | Whisper large-v3 | 100% | 14:32:15 | + | Analyse sentiment | distilbert-base-uncased | -0.85 | 14:33:42 | + | Détection haine | facebook/roberta-hate-speech | 0.92 | 14:33:58 | + | Mots-clés interdits | Liste noire FR/EN | 5 hits | 14:34:01 | + Et je peux vérifier la fiabilité de l'analyse + Et cela m'aide à prendre une décision + + # Player audio avec waveform + + Scénario: Affichage du player audio Wavesurfer.js + Étant donné que j'ouvre la page de détails + Quand le player audio se charge + Alors je vois le player avec waveform: + | élément | description | + | Waveform | Visualisation audio complète | + | Passages surlignés | Zones détectées par IA en rouge | + | Contrôles | Play/Pause, volume, vitesse | + | Timeline | 00:00 / 12:34 | + | Marqueurs | Annotations aux timestamps problématiques | + | Vitesse lecture | 0.75x, 1x, 1.5x, 2x | + Et je peux écouter le contenu directement + Et je peux me concentrer sur les passages signalés + + Scénario: Navigation rapide vers passages problématiques + Étant donné que l'IA a détecté 3 passages problématiques + Quand j'affiche le player + Alors je vois 3 marqueurs rouges sur la waveform: + | timestamp | type marqueur | description | + | 02:15 | Rouge IA (97%) | "Insulte discriminatoire" | + | 03:42 | Rouge IA (92%) | "Propos haineux" | + | 08:20 | Orange signaleur | "Commentaire @user: 'ici aussi'"| + Et je peux cliquer sur un marqueur pour sauter directement + Et je gagne un temps précieux (pas besoin d'écouter tout) + + Scénario: Lecture accélérée pour gain productivité + Étant donné que le contenu dure 30 minutes + Quand je sélectionne la vitesse 2x + Alors l'audio est accéléré sans déformation + Et je peux écouter en 15 minutes au lieu de 30 + Et je peux revenir à 1x si nécessaire + Et cela multiplie ma productivité par 2 + + Scénario: Annotations directes sur la waveform + Étant donné que j'écoute le contenu + Et que je détecte un passage problématique à 05:30 + Quand je clique sur la waveform à 05:30 + Alors une modal s'affiche: + """ + Ajouter une annotation + + Timestamp: 05:30 + Type: [Passage problématique ▼] + Note: [Champ texte] + + [Annuler] [Ajouter] + """ + Et je peux marquer le passage pour référence + Et l'annotation apparaît sur la waveform + Et elle sera visible dans le rapport de modération + + # Transcription avec surlignage + + Scénario: Affichage de la transcription complète + Étant donné que l'IA a transcrit l'audio + Quand j'affiche la transcription + Alors je vois le texte complet: + """ + [00:00] Bonjour à tous, bienvenue dans ce podcast... + [02:15] ...et c'est pourquoi je pense que [ROUGE: phrase discriminatoire] mais bon... + [03:42] ...vraiment, ces gens [ROUGE: propos haineux], vous voyez... + [08:20] ...en conclusion, [ORANGE: passage signalé par @user]... + """ + Et les passages problématiques sont surlignés + Et je peux lire sans écouter (plus rapide) + Et je peux copier/coller pour le rapport + + Scénario: Synchronisation transcription - audio + Étant donné que je lis la transcription + Quand je clique sur un timestamp dans la transcription + Alors le player audio saute à ce timestamp + Et la lecture démarre automatiquement + Et la transcription scroll pour suivre la lecture + Et je peux alterner lecture et écoute facilement + + Scénario: Recherche dans la transcription + Étant donné que la transcription est affichée + Quand je recherche un mot-clé "discriminatoire" + Alors toutes les occurrences sont surlignées en jaune + Et je vois "3 résultats trouvés" + Et je peux naviguer entre les résultats avec ←/→ + Et je trouve rapidement les passages pertinents + + # Détails des signalements + + Scénario: Liste des signaleurs et leurs commentaires + Étant donné qu'un contenu a été signalé par 6 utilisateurs + Quand j'affiche la section "Signalements" + Alors je vois la liste complète: + | signaleur | badge | fiabilité | catégorie | commentaire | date | + | @user1 | 🥇 Or | 95% | Haine & violence | "Propos à 2:30" | Il y a 2h | + | @user2 | 🥈 Ag | 87% | Haine & violence | "Discriminatoire 2:15" | Il y a 1h | + | @user3 | - | 45% | Haine & violence | "" | Il y a 45min| + | @user4 | 🥉 Br | 72% | Fausse info | "Désinformation santé" | Il y a 30min| + | @user5 | - | 20% | Autre | "Contenu choquant" | Il y a 15min| + | @user6 | 🥇 Or | 92% | Haine & violence | "Passage 2:25-2:45" | Il y a 10min| + Et je vois que 5/6 ont choisi "Haine & violence" + Et les utilisateurs de confiance sont mis en évidence + Et je peux cliquer sur un commentaire pour sauter au timestamp + + Scénario: Consensus des signaleurs + Étant donné que 6 signalements sont affichés + Quand je consulte l'analyse de consensus + Alors je vois: + """ + 📊 Consensus des signaleurs + + Catégorie majoritaire: 🚫 Haine & violence (5/6 = 83%) + Signaleurs de confiance: 3/6 (Or × 2, Argent × 1) + Timestamps mentionnés: 2:15, 2:25-2:45, 2:30 + + → Fort consensus sur la catégorie et les timestamps + """ + Et je peux prendre une décision plus facilement + + # Historique créateur - Vue 360° + + Scénario: Affichage de l'historique du créateur + Étant donné que j'examine un signalement + Quand j'affiche l'historique du créateur @pseudo + Alors je vois sa vue 360°: + | section | contenu | + | Statistiques globales | 42 contenus, 12K écoutes, membre depuis 8 mois | + | Strikes actuels | 1/4 strikes (1 actif, 0 réhabilité) | + | Historique sanctions | Liste des 3 dernières sanctions | + | Contenus récents | 10 derniers contenus publiés | + | Score de confiance | 65/100 (Créateur suspect) | + | Signalements reçus | 8 signalements dont 3 validés | + Et je vois si c'est un récidiviste ou un premier incident + + Scénario: Historique des strikes + Étant donné que le créateur a 1 strike actif + Quand je consulte les détails des strikes + Alors je vois: + """ + Strikes: 1/4 actifs + + Historique: + ✓ Strike 1 - Il y a 3 mois + Catégorie: Spam + Sanction: Avertissement + Statut: Actif (réhabilitation dans 3 mois si pas de récidive) + + Strikes réhabilités: + [Aucun] + + Escalade suivante: + - Strike 2: Suspension 7 jours + - Strike 3: Suspension 30 jours + - Strike 4: Ban définitif + """ + Et je vois l'historique complet + Et je peux décider de la sanction appropriée + + Scénario: Contenus récents du créateur + Étant donné que j'affiche les contenus récents + Quand je consulte la liste + Alors je vois les 10 derniers contenus: + | titre | date | écoutes | signalements | statut | + | Podcast #42 | 15/01/2026 | 342 | 6 (en cours) | Signalé | + | Podcast #41 | 10/01/2026 | 521 | 0 | Publié | + | Podcast #40 | 05/01/2026 | 678 | 1 (rejeté) | Publié | + | Podcast #39 | 01/01/2026 | 445 | 0 | Publié | + Et je peux écouter rapidement un contenu précédent + Et je peux détecter un pattern de comportement + + Scénario: Détection de pattern récidiviste + Étant donné que le créateur a 3 contenus signalés validés en 2 mois + Quand le système analyse le pattern + Alors une alerte s'affiche: + """ + ⚠️ Pattern récidiviste détecté + + 3 signalements validés en 2 mois: + - 15/01: Haine & violence (en cours) + - 28/12: Spam (validé - Strike 1) + - 10/12: Fausse info (validé) + + Recommandation: Sanction renforcée suggérée + """ + Et je peux décider d'une sanction plus sévère + Et je protège la communauté des récidivistes + + # Actions modérateur + + Scénario: Actions disponibles pour modérateur junior + Étant donné que je suis modérateur junior + Quand j'affiche les actions disponibles + Alors je vois les boutons: + | action | raccourci | couleur | description | + | Approuver | A | Rouge | Valider le signalement + sanction | + | Rejeter | R | Gris | Rejeter le signalement (non fondé) | + | Escalader senior | S | Orange | Transférer à un modérateur senior | + | Commenter | C | Bleu | Ajouter un commentaire interne | + | Mettre en attente | W | Jaune | Reporter la décision (max 24h) | + Et je peux traiter les cas simples + Et je peux escalader les cas complexes + + Scénario: Actions supplémentaires pour modérateur senior + Étant donné que je suis modérateur senior + Quand j'affiche les actions disponibles + Alors je vois des actions supplémentaires: + | action | description | + | Approuver avec sanction | Valider + choisir sanction personnalisée | + | Ban temporaire | Suspendre le créateur (7j/30j) | + | Ban définitif | Bannir définitivement le créateur | + | Réhabiliter strike | Retirer un strike (après appel) | + | Contacter autorités | Signaler aux autorités (cas graves) | + Et je peux gérer les cas complexes et graves + + Scénario: Workflow approbation signalement + Étant donné que je clique sur "Approuver" (A) + Quand le workflow s'affiche + Alors je vois les étapes: + """ + 1️⃣ Choisir la sanction + + Sanction suggérée (IA): Strike 2 + Suspension 7j + [Radio buttons] + ○ Strike 1 - Avertissement + ● Strike 2 - Suspension 7 jours (recommandé) + ○ Strike 3 - Suspension 30 jours + ○ Autre (personnalisé) + + 2️⃣ Confirmer l'action + + Actions qui seront effectuées: + ✓ Contenu retiré de la plateforme + ✓ Strike 2 ajouté au créateur + ✓ Créateur suspendu 7 jours + ✓ Notifications envoyées (push + email) + ✓ Signaleurs notifiés (validation) + + [Annuler] [Confirmer et appliquer] + """ + Et je peux personnaliser la sanction si nécessaire + Et je confirme avant d'appliquer + + Scénario: Workflow rejet signalement + Étant donné que je clique sur "Rejeter" (R) + Quand le workflow s'affiche + Alors je dois fournir une raison: + """ + Rejeter ce signalement + + Raison du rejet: [Liste déroulante] + ▼ Choisir une raison + - Contenu conforme aux règles + - Contexte éducatif/artistique + - Signalement abusif + - Autre (préciser) + + Commentaire (optionnel): [Champ texte] + + Actions qui seront effectuées: + ✓ Signalement marqué comme "Rejeté" + ✓ Contenu reste en ligne + ✓ Signaleurs notifiés avec raison + ✓ Fiabilité signaleur ajustée (-5%) + + [Annuler] [Confirmer le rejet] + """ + Et la raison est obligatoire + Et les signaleurs recevront une explication + + # Commentaires internes modérateurs + + Scénario: Ajouter un commentaire interne + Étant donné que je travaille sur un cas complexe + Quand je clique sur "Commenter" (C) + Alors une zone de commentaire s'affiche: + """ + Commentaire interne (visible uniquement par modérateurs) + + [Champ texte riche] + + Mentionner un collègue: @mod_ + + [Annuler] [Publier le commentaire] + """ + Et je peux mentionner un collègue avec @ + Et le commentaire apparaît dans le fil d'activité + Et cela facilite la collaboration + + Scénario: Fil de commentaires sur un signalement + Étant donné qu'un signalement a 3 commentaires internes + Quand j'affiche le fil de commentaires + Alors je vois: + """ + 💬 Commentaires internes (3) + + @mod_alice - Il y a 1h + "Passage à 2:30 borderline. Besoin d'un second avis @mod_senior" + + @mod_senior - Il y a 30min + "J'ai écouté. C'est clairement discriminatoire. Approuver avec Strike 2." + + @mod_alice - Il y a 5min + "OK merci ! Je valide." + """ + Et je vois l'historique des discussions + Et cela améliore la qualité des décisions + + # Logs d'audit + + Scénario: Génération automatique des logs d'audit + Étant donné que je valide un signalement + Quand l'action est effectuée + Alors un log d'audit complet est créé automatiquement: + | champ | valeur | + | signalement_id | #MOD-2026-00142 | + | content_id | content_123456 | + | moderator_id | mod_alice | + | moderator_role | Junior | + | action_taken | Approved - Strike 2 + Suspension 7d | + | ia_score | 97% | + | ia_category | Haine & violence | + | priority | CRITIQUE | + | processing_time | 12 minutes 34 secondes | + | timestamp | 2026-01-15T14:42:18Z | + | commentaires_internes | 2 commentaires | + | annotations_audio | 3 annotations aux timestamps 2:15, 3:42, 8:20 | + Et le log est conservé pour conformité DSA + Et il sera anonymisé après 3 ans (RGPD) + + Scénario: Export des logs d'audit + Étant donné que je suis admin modération + Quand je veux exporter les logs + Alors je peux exporter en: + | format | contenu | usage | + | CSV | Tableau complet | Analyse Excel | + | JSON | Données structurées | Analyse programmatique | + | PDF | Rapport formaté | Audit DSA officiel | + Et je peux filtrer par date, modérateur, action + Et les logs sont conformes aux exigences légales + + # Performance et UX + + Scénario: Performance du player audio + Étant donné que j'ouvre la page de détails + Quand le player audio se charge + Alors la waveform s'affiche en <2 secondes + Et la transcription se charge en parallèle + Et je peux commencer à écouter immédiatement + Et le streaming HLS est fluide sans coupure + Et l'UX est professionnelle et rapide + + Scénario: Raccourcis clavier pour actions rapides + Étant donné que je suis sur la page de détails + Quand j'utilise les raccourcis clavier + Alors je peux: + | touche | action | + | Espace | Play/Pause audio | + | ← / → | Reculer/Avancer 5 secondes | + | ↑ / ↓ | Augmenter/Diminuer volume | + | A | Approuver | + | R | Rejeter | + | S | Escalader | + | C | Commenter | + | 1/2/3/4 | Vitesse 0.75x/1x/1.5x/2x | + | M | Ajouter marqueur/annotation | + | Échap | Retour au dashboard | + Et je gagne en productivité + + # Coût infrastructure + + Scénario: Coût des outils modérateur + Étant donné que tous les outils sont déployés + Quand on évalue le coût + Alors le coût est réparti ainsi: + | composant | technologie | coût mensuel | + | Player Wavesurfer.js | JavaScript (open source)| 0€ | + | Transcription Whisper | Self-hosted (CPU/GPU) | 0-200€ | + | Analyse NLP | Self-hosted | 0€ (inclus) | + | Stockage transcriptions| PostgreSQL | 0€ (inclus) | + | Logs audit | PostgreSQL | 0€ (inclus) | + | Total | - | 0-200€/mois | + Et le coût est largement compensé par la productivité ×3-5 diff --git a/features/ui/moderation/badges-statistiques.feature b/features/ui/moderation/badges-statistiques.feature new file mode 100644 index 0000000..6a3237f --- /dev/null +++ b/features/ui/moderation/badges-statistiques.feature @@ -0,0 +1,391 @@ +# language: fr + +@ui @moderation @badges @gamification +Fonctionnalité: Badges et statistiques de modération communautaire (Mobile) + En tant qu'utilisateur contributeur + Je veux voir mes badges et statistiques de modération + Afin d'être motivé à continuer à signaler du contenu pertinent + + # 19.1.4 - Affichage badges et statistiques + + Contexte: + Étant donné que je suis connecté à l'application mobile + Et que j'ai envoyé des signalements + + # Affichage des statistiques personnelles + + Scénario: Accéder aux statistiques de modération + Étant donné que je suis dans mon profil + Quand je clique sur "Mes signalements" + Alors je vois en haut de page une carte "📊 Vos statistiques de modération" + Et la carte affiche: + | élément | valeur | couleur | + | Signalements envoyés | 27 | Bleu | + | Validés | 23 ✅ | Vert | + | Rejetés | 4 ❌ | Rouge | + | Taux de pertinence | 85% | Vert/Orange | + | Badge actuel | 🥈 Contributeur Argent | Argent | + | Prochain palier | 🥇 Contributeur Or | Or | + | Progression vers prochain | 27 signalements restants| Bleu | + Et les données sont mises à jour en temps réel + + Scénario: Design de la carte statistiques + Étant donné que j'affiche mes statistiques + Quand je vérifie le design + Alors la carte a un fond dégradé subtil (blanc → gris clair) + Et les icônes sont colorées et expressives + Et les nombres sont en gras et mis en évidence + Et le taux de pertinence a une jauge visuelle (progress bar) + Et l'ensemble est visuellement attrayant et motivant + + Plan du Scénario: Couleur du taux de pertinence selon performance + Étant donné que mon taux de pertinence est de % + Quand j'affiche mes statistiques + Alors la jauge de pertinence est de couleur "" + Et le message associé est "" + + Exemples: + | taux | couleur | message | + | 95 | Vert | Excellent ! | + | 82 | Vert clair | Très bon | + | 72 | Orange | Bon, continuez vos efforts | + | 55 | Rouge | Améliorez la qualité de vos signalements | + + # Affichage du badge actuel + + Scénario: Badge Bronze visible + Étant donné que j'ai le badge 🥉 Contributeur Bronze + Quand j'affiche mon profil public + Alors le badge 🥉 s'affiche à côté de mon pseudo + Et un tooltip s'affiche au survol/appui long: + """ + 🥉 Contributeur Bronze + Signale du contenu inapproprié pour améliorer la communauté + """ + Et le badge est discret mais visible + + Scénario: Badge Argent visible avec priorité + Étant donné que j'ai le badge 🥈 Contributeur Argent + Quand j'affiche mon profil + Alors le badge 🥈 s'affiche de manière plus proéminente + Et le badge est affiché avec une animation subtile (brille légèrement) + Et le tooltip indique: + """ + 🥈 Contributeur Argent + Utilisateur de confiance - Signalements traités en priorité + """ + Et le badge inspire confiance aux autres utilisateurs + + Scénario: Badge Or visible avec effet premium + Étant donné que j'ai le badge 🥇 Contributeur Or + Quand j'affiche mon profil + Alors le badge 🥇 s'affiche avec un effet brillant/doré + Et une animation subtile attire l'attention + Et le tooltip indique: + """ + 🥇 Contributeur Or + Top contributeur - Aide précieuse à la communauté + """ + Et le badge est prestigieux et reconnu + + # Toast après validation/rejet de signalement + + Scénario: Toast après validation avec progression vers badge + Étant donné que j'ai 3 signalements validés sur 5 pour le badge Bronze + Et que j'envoie un nouveau signalement + Quand le modérateur valide mon signalement + Alors je reçois un toast: + """ + ✅ Bravo ! Votre signalement a aidé la communauté. + Progression : 4/5 pour badge Bronze 🥉 + """ + Et une mini progress bar s'affiche dans le toast (80%) + Et le toast s'affiche pendant 6 secondes + Et je me sens motivé à continuer + + Scénario: Toast célébration obtention badge Bronze + Étant donné que j'ai 4 signalements validés + Quand mon 5ème signalement est validé + Alors je reçois un toast spécial avec animation: + """ + 🎉 Félicitations ! + Vous êtes désormais Contributeur Bronze 🥉 + Merci de rendre RoadWave meilleur ! + """ + Et le toast a une animation de confettis + Et un son de célébration est joué (vibration haptique) + Et le toast reste affiché 8 secondes + Et je peux cliquer pour voir mes nouveaux avantages + + Scénario: Toast célébration obtention badge Argent + Étant donné que j'obtiens le badge 🥈 Contributeur Argent + Quand la notification est affichée + Alors je reçois un toast premium: + """ + 🎉 Impressionnant ! + Badge Contributeur Argent obtenu 🥈 + Votre engagement fait la différence ! + """ + Et l'animation est plus spectaculaire (confettis argentés) + Et un son de réussite est joué + Et le badge est ajouté à mon profil instantanément + + Scénario: Toast célébration obtention badge Or avec offre Premium + Étant donné que j'obtiens le badge 🥇 Contributeur Or + Quand la notification est affichée + Alors je reçois un toast VIP: + """ + 🎉 Exceptionnel ! + Badge Contributeur Or obtenu 🥇 + + Offre Premium -50% pendant 3 mois ! + + [Voir l'offre] + """ + Et l'animation est spectaculaire (confettis dorés) + Et un son de victoire est joué + Et le toast reste affiché 10 secondes + Et je peux cliquer pour accéder à l'offre Premium + + Scénario: Toast après rejet avec encouragement + Étant donné que mon taux de pertinence est de 65% + Quand un signalement est rejeté + Alors je reçois un toast constructif: + """ + ❌ Signalement non retenu. + Taux de pertinence : 60% + Continuez vos efforts ! + """ + Et le ton est encourageant, pas décourageant + Et un lien "Améliorer mes signalements" est affiché + Et je peux consulter les bonnes pratiques + + # Progression visuelle vers le prochain badge + + Scénario: Barre de progression vers badge Argent + Étant donné que j'ai le badge Bronze + Et que j'ai 12 signalements validés (sur 20 requis pour Argent) + Quand j'affiche mes statistiques + Alors je vois une barre de progression: + """ + Prochain palier : 🥈 Contributeur Argent + [████████░░░░░░░░] 60% (12/20) + 8 signalements validés restants + """ + Et la barre est animée progressivement + Et je vois clairement combien il me reste à faire + + Scénario: Progression avec délai minimum + Étant donné que j'ai obtenu le badge Bronze il y a 15 jours + Et que j'ai déjà 20 signalements validés + Quand j'affiche ma progression vers Argent + Alors je vois un message: + """ + ✓ Critères atteints (20 signalements validés) + ⏰ Délai minimum : encore 15 jours + + Les badges nécessitent une contribution régulière sur la durée. + """ + Et je comprends que le délai minimum est anti-farming + + # Page dédiée "En savoir plus" sur les badges + + Scénario: Accéder à la page d'explication des badges + Étant donné que je vois mes statistiques + Quand je clique sur "En savoir plus" sur les badges + Alors une page dédiée s'affiche avec: + | section | contenu | + | Introduction | Pourquoi nous récompensons les contributeurs | + | Les 3 badges | Bronze, Argent, Or avec critères détaillés | + | Calcul taux de pertinence | Formule et exemples | + | Avantages de chaque badge | Priorisation, visibilité, réduction Premium | + | Délais entre badges | 30j Bronze→Argent, 60j Argent→Or | + | Règles anti-abus | Limite 10/24h, audit trimestriel | + | FAQ | Questions fréquentes | + Et la page est bien structurée et facile à lire + + Scénario: Design de la page badges + Étant donné que j'affiche la page "En savoir plus" + Quand je vérifie le design + Alors chaque badge a une illustration attrayante + Et les critères sont affichés en tableaux clairs + Et des exemples concrets sont fournis + Et le ton est motivant et positif + Et je peux facilement comprendre le système + + # Affichage sur profil public + + Scénario: Badge visible sur mon profil public + Étant donné que j'ai le badge 🥈 Contributeur Argent + Quand un autre utilisateur consulte mon profil + Alors il voit le badge 🥈 à côté de mon pseudo + Et il peut cliquer sur le badge pour voir la description + Et cela renforce ma crédibilité + Et les autres utilisateurs me font davantage confiance + + Scénario: Badge visible sur mes commentaires/interactions + Étant donné que j'ai le badge 🥇 Contributeur Or + Quand je laisse un commentaire sur un contenu + Alors le badge 🥇 s'affiche à côté de mon pseudo + Et cela montre que je suis un membre actif de la communauté + Et mes interactions ont plus de poids + + # Notification email pour badges + + Scénario: Email de félicitations pour badge Bronze + Étant donné que j'obtiens le badge 🥉 Contributeur Bronze + Quand le badge est attribué + Alors je reçois un email de félicitations: + """ + Objet: 🎉 Vous êtes maintenant Contributeur Bronze ! + + Bravo [Pseudo] ! + + Vous avez obtenu le badge Contributeur Bronze grâce à + vos 5 signalements validés et votre taux de pertinence de 72%. + + Vos avantages: + - Signalements traités en priorité (+10 points) + - Badge visible sur votre profil + + Continuez à nous aider à maintenir une communauté saine ! 🙏 + + L'équipe RoadWave + """ + Et l'email contient un lien vers mes statistiques + + Scénario: Email de félicitations pour badge Or avec offre Premium + Étant donné que j'obtiens le badge 🥇 Contributeur Or + Quand le badge est attribué + Alors je reçois un email VIP: + """ + Objet: 🎉 Badge Or obtenu ! Offre Premium -50% offerte + + Exceptionnel [Pseudo] ! + + Vous faites partie des meilleurs contributeurs de RoadWave. + Grâce à vos 50 signalements validés (90% pertinence), vous + aidez des milliers d'utilisateurs. + + 🎁 En reconnaissance, vous bénéficiez de: + ✨ 3 mois d'abonnement Premium à -50% + → 2.49€/mois au lieu de 4.99€ + + [Profiter de l'offre] + + Cette offre est valable pendant 30 jours. + + Merci de contribuer à rendre RoadWave meilleur ! 🏆 + + L'équipe RoadWave + """ + Et l'email contient un CTA mis en évidence + + # Rappels expiration offre Premium + + Scénario: Rappel J-7 expiration offre Premium + Étant donné que j'ai obtenu le badge Or il y a 23 jours + Et que je n'ai pas activé l'offre Premium -50% + Quand le système envoie les rappels + Alors je reçois un email + push: + """ + ⏰ Il vous reste 7 jours ! + + Votre offre Premium -50% expire bientôt. + Profitez de 3 mois à 2.49€/mois au lieu de 4.99€. + + [Activer maintenant] + """ + Et le CTA est mis en évidence en orange + + Scénario: Rappel J-1 expiration offre Premium + Étant donné que j'ai obtenu le badge Or il y a 29 jours + Et que je n'ai pas activé l'offre + Quand le dernier rappel est envoyé + Alors je reçois un email + push urgent: + """ + ⚠️ Dernière chance ! + + Votre offre Premium -50% expire DEMAIN. + Ne manquez pas cette opportunité ! + + [Activer avant expiration] + """ + Et le CTA est en rouge pour l'urgence + + # Affichage après expiration offre + + Scénario: Message d'expiration de l'offre Premium + Étant donné que l'offre Premium a expiré (31 jours) + Quand j'accède à mes statistiques + Alors je vois un message: + """ + Votre offre Premium -50% a expiré. + Votre badge Or est conservé. + """ + Et le message est informatif, sans regret excessif + + # Animation et gamification + + Scénario: Animation lors de la montée de niveau + Étant donné que je passe de Bronze à Argent + Quand le changement est effectué + Alors une animation "level up" s'affiche à l'écran + Et mon nouveau badge apparaît avec un effet de brillance + Et un son de réussite est joué + Et l'UX est gratifiante et mémorable + + Scénario: Confettis pour badge Or + Étant donné que j'obtiens le badge Or + Quand la notification s'affiche + Alors des confettis dorés tombent sur l'écran + Et l'animation dure 3 secondes + Et le badge Or apparaît avec un effet "shine" + Et je me sens valorisé et reconnu + + # Dark mode et accessibilité + + Scénario: Support du dark mode pour les badges + Étant donné que j'ai activé le dark mode + Quand j'affiche mes statistiques et badges + Alors les couleurs s'adaptent: + | élément | couleur light | couleur dark | + | Badge Bronze | #CD7F32 | #D4A574 | + | Badge Argent | #C0C0C0 | #E8E8E8 | + | Badge Or | #FFD700 | #FFC700 | + | Fond carte stats | Blanc | Gris foncé | + | Jauge pertinence verte | #28A745 | #34D058 | + | Jauge pertinence orange | #FF8C00 | #FFA500 | + Et le contraste reste optimal + + Scénario: Accessibilité lecteur d'écran pour badges + Étant donné que j'utilise un lecteur d'écran + Quand je navigue dans mes statistiques + Alors le lecteur annonce clairement: + """ + Vos statistiques de modération. + Signalements envoyés: 27. + Validés: 23. + Rejetés: 4. + Taux de pertinence: 85%. + Badge actuel: Contributeur Argent. + Prochain palier: Contributeur Or, 27 signalements validés restants. + """ + Et tous les éléments visuels ont des équivalents textuels + + # Coût et performance + + Scénario: Performance de l'affichage des statistiques + Étant donné que j'affiche mes statistiques + Quand je mesure les performances + Alors les données se chargent en <300ms + Et les animations sont fluides (60 FPS) + Et la mémoire utilisée est <50 MB + Et l'UX est instantanée + + Scénario: Coût de la fonctionnalité + Étant donné que le système de badges est en place + Quand on évalue le coût + Alors le développement est 100% interne (Flutter) + Et les calculs sont effectués côté backend (0€ côté app) + Et les notifications sont gratuites (Firebase) + Et le coût opérationnel est de 0€ (MVP) diff --git a/features/ui/moderation/historique-signalements.feature b/features/ui/moderation/historique-signalements.feature new file mode 100644 index 0000000..e06e56e --- /dev/null +++ b/features/ui/moderation/historique-signalements.feature @@ -0,0 +1,304 @@ +# language: fr + +@ui @moderation @historique +Fonctionnalité: Historique des signalements utilisateur (Mobile) + En tant qu'utilisateur + Je veux consulter l'historique de mes signalements + Afin de suivre leur traitement et comprendre les décisions prises + + # 14.1.3 - Historique personnel des signalements + + Contexte: + Étant donné que je suis connecté à l'application mobile + Et que j'ai envoyé des signalements précédemment + + # Accès à l'historique + + Scénario: Accéder à l'historique depuis le profil + Étant donné que je suis dans mon profil utilisateur + Quand je scroll vers le bas + Alors je vois une section "📊 Modération" + Et je vois l'option "Mes signalements" + Et je vois le nombre de signalements en badge: "(12)" + Et je peux cliquer pour accéder à l'historique + + Scénario: Accéder à l'historique depuis le toast de confirmation + Étant donné que je viens d'envoyer un signalement + Et que le toast de confirmation est affiché + Quand je clique sur "Voir mes signalements" + Alors je suis redirigé vers la page "Mes signalements" + Et la page s'affiche en moins de 500ms + Et mon dernier signalement est en tête de liste + + # Affichage de la liste des signalements + + Scénario: Affichage de l'historique vide + Étant donné que je n'ai jamais envoyé de signalement + Quand j'ouvre "Mes signalements" + Alors je vois un message: + """ + Aucun signalement pour le moment + + Vous pouvez signaler un contenu inapproprié + depuis le menu de n'importe quel contenu. + """ + Et je vois une illustration vide sympathique + Et un bouton "Découvrir les règles de la communauté" + + Scénario: Liste des signalements avec informations clés + Étant donné que j'ai envoyé 5 signalements + Quand j'ouvre "Mes signalements" + Alors je vois une liste de 5 cartes de signalements + Et chaque carte affiche: + | information | exemple | position | + | Statut badge | "En cours 🔍" (orange) | Haut à droite | + | Titre du contenu | "Podcast #42" | Titre | + | Créateur | "@pseudo_createur" | Sous-titre | + | Catégorie | "🚫 Haine & violence" | Ligne 1 | + | Date | "Il y a 2 jours" ou "15/01/2026" | Ligne 2 | + | Mon commentaire | "Propos discriminatoires à 2:30" | Ligne 3 (si rempli) | + Et les cartes sont triées par date décroissante (plus récent en haut) + + Plan du Scénario: Couleur du badge selon statut + Étant donné que j'ai un signalement avec le statut "" + Quand j'affiche l'historique + Alors le badge affiché est "" + Et la couleur du badge est "" + + Exemples: + | statut | badge | couleur | + | En cours | En cours 🔍 | Orange | + | Traité | Traité ✓ | Vert | + | Rejeté | Rejeté ✗ | Rouge | + + Scénario: Affichage de la date relative + Étant donné que j'ai envoyé des signalements à différentes dates + Quand j'affiche l'historique + Alors les dates récentes s'affichent en format relatif: + | date signalement | affichage | + | Il y a 5 minutes | "À l'instant" | + | Il y a 2 heures | "Il y a 2h" | + | Il y a 1 jour | "Hier" | + | Il y a 3 jours | "Il y a 3j" | + | Il y a 10 jours | "15/01/2026" | + Et les dates anciennes (>7 jours) sont en format absolu + + # Détails d'un signalement + + Scénario: Consulter les détails d'un signalement + Étant donné que j'ai envoyé un signalement il y a 3 jours + Quand je clique sur la carte du signalement + Alors une page de détails s'affiche + Et je vois toutes les informations: + | section | contenu | + | En-tête | Titre du contenu + lien vers le contenu | + | Créateur | Pseudo + lien vers profil créateur | + | Ma catégorie | 🚫 Haine & violence | + | Mon commentaire | "Propos discriminatoires à 2:30" | + | Date d'envoi | "Envoyé le 15/01/2026 à 14:32" | + | Statut actuel | "En cours 🔍 - En attente de traitement" | + | Délai estimé | "Traitement sous 24-48h" | + Et je vois un bouton "Retour à mes signalements" + + Scénario: Lien vers le contenu signalé + Étant donné que je consulte les détails d'un signalement + Et que le contenu signalé est toujours en ligne + Quand je clique sur le titre du contenu + Alors je suis redirigé vers la page du contenu + Et je peux réécouter le contenu si besoin + Et un badge "Signalé par vous" s'affiche discrètement + + Scénario: Contenu supprimé suite au signalement + Étant donné que le contenu que j'ai signalé a été supprimé + Quand je consulte les détails du signalement + Alors le titre du contenu est affiché en gris barré + Et un message s'affiche: "Ce contenu a été retiré de la plateforme" + Et je ne peux pas accéder au contenu + Et le statut est "Traité ✓" + + # Notifications de changement de statut + + Scénario: Notification quand un signalement est traité + Étant donné que j'ai signalé un contenu il y a 24h + Quand le modérateur traite mon signalement + Et que le contenu est retiré + Alors je reçois une notification push: + """ + ✓ Votre signalement a été traité + Le contenu a été retiré de la plateforme. + """ + Et je reçois une notification in-app identique + Et le statut dans mon historique passe à "Traité ✓" + Et un badge (1) apparaît sur l'onglet "Mes signalements" + + Scénario: Notification quand un signalement est rejeté + Étant donné que j'ai signalé un contenu + Quand le modérateur rejette mon signalement + Alors je reçois une notification: + """ + Votre signalement a été examiné + Le contenu ne viole pas les règles de la communauté. + """ + Et le statut dans mon historique passe à "Rejeté ✗" + Et je peux voir la raison du rejet dans les détails + + Scénario: Affichage de la raison du rejet + Étant donné que mon signalement a été rejeté + Quand je consulte les détails du signalement + Alors je vois une section "Raison du rejet": + """ + Après examen, le contenu ne viole pas nos règles. + Le passage mentionné est dans un contexte éducatif. + """ + Et la raison est claire et compréhensible + Et je peux apprendre pour améliorer mes futurs signalements + + # Filtres et recherche + + Scénario: Filtrer les signalements par statut + Étant donné que j'ai 20 signalements avec différents statuts + Quand j'ouvre l'historique + Alors je vois des onglets de filtres: + | onglet | nombre | + | Tous (20) | 20 | + | En cours (8)| 8 | + | Traités (9) | 9 | + | Rejetés (3) | 3 | + Et je peux cliquer sur un onglet pour filtrer + Et la liste se met à jour instantanément + + Scénario: Rechercher dans mes signalements + Étant donné que j'ai 50 signalements + Quand j'ouvre la barre de recherche + Et que je tape "podcast" + Alors seuls les signalements contenant "podcast" s'affichent: + | recherche dans | + | Titre du contenu | + | Pseudo du créateur | + | Mon commentaire | + Et les résultats sont mis en évidence + Et la recherche est instantanée (pas de délai) + + # Pull-to-refresh + + Scénario: Actualiser la liste des signalements + Étant donné que je suis sur la page "Mes signalements" + Quand je tire vers le bas (pull-to-refresh) + Alors un spinner de chargement s'affiche + Et la liste est actualisée depuis le serveur + Et les nouveaux statuts sont affichés + Et un toast s'affiche: "✓ Mis à jour" + + # Pagination et performance + + Scénario: Chargement progressif des signalements (pagination) + Étant donné que j'ai 100 signalements + Quand j'ouvre "Mes signalements" + Alors seuls les 20 premiers signalements sont chargés + Et quand je scroll en bas de liste + Alors les 20 suivants sont chargés automatiquement + Et un loader discret s'affiche pendant le chargement + Et l'UX est fluide sans saccade + + Scénario: Performance de la liste + Étant donné que j'ai 100 signalements + Quand j'ouvre l'historique + Alors le premier affichage prend <500ms + Et le scroll est fluide (60 FPS) + Et les images/avatars se chargent en lazy loading + Et la mémoire utilisée reste <100 MB + + # État vide pour chaque filtre + + Scénario: Aucun signalement "En cours" + Étant donné que tous mes signalements ont été traités + Quand je clique sur l'onglet "En cours" + Alors je vois un message: + """ + Aucun signalement en cours + + Tous vos signalements ont été traités. + """ + Et je vois une illustration vide + + Scénario: Aucun signalement "Rejeté" + Étant donné que tous mes signalements ont été acceptés + Quand je clique sur l'onglet "Rejetés" + Alors je vois un message: + """ + Aucun signalement rejeté + + Tous vos signalements étaient pertinents ! 🎉 + """ + Et je vois un message encourageant + + # Dark mode et accessibilité + + Scénario: Support du dark mode + Étant donné que j'ai activé le dark mode + Quand j'affiche "Mes signalements" + Alors les couleurs s'adaptent: + | élément | couleur light | couleur dark | + | Fond page | Blanc | Noir (#121212) | + | Cartes | Gris clair | Gris foncé | + | Texte principal | Noir | Blanc | + | Badge "En cours" | Orange (#FF8C00) | Orange (#FFA500) | + | Badge "Traité" | Vert (#28A745) | Vert (#34D058) | + | Badge "Rejeté" | Rouge (#DC3545) | Rouge (#F85149) | + Et le contraste reste suffisant (WCAG AA) + + Scénario: Accessibilité pour lecteur d'écran + Étant donné que j'utilise un lecteur d'écran + Quand je navigue dans l'historique + Alors chaque carte est annoncée clairement: + """ + Signalement du contenu "Podcast #42" par @pseudo. + Catégorie: Haine et violence. + Statut: En cours d'examen. + Envoyé il y a 2 jours. + """ + Et je peux naviguer au clavier entre les cartes + Et tous les boutons ont des labels descriptifs + + # Gestion d'erreur + + Scénario: Erreur réseau lors du chargement + Étant donné que je n'ai pas de connexion internet + Quand j'ouvre "Mes signalements" + Alors un message d'erreur s'affiche: + """ + Impossible de charger vos signalements + Vérifiez votre connexion internet + """ + Et un bouton "Réessayer" est affiché + Et je peux cliquer pour réessayer + + Scénario: Cache local pour consultation hors ligne + Étant donné que j'ai consulté mes signalements hier + Et que je n'ai pas de connexion internet aujourd'hui + Quand j'ouvre "Mes signalements" + Alors les signalements en cache s'affichent + Et un message discret indique: + """ + 📡 Mode hors ligne - Données mises en cache + """ + Et je peux consulter les détails + Mais les statuts peuvent ne pas être à jour + + # Coût et conformité + + Scénario: Coût de la fonctionnalité + Étant donné que l'historique des signalements est en place + Quand on évalue le coût + Alors le développement est 100% interne (Flutter) + Et aucun service tiers n'est utilisé + Et le coût opérationnel est de 0€ + Et les notifications in-app sont gratuites + + Scénario: Conformité RGPD + Étant donné que mes données de signalement sont stockées + Quand je supprime mon compte + Alors tous mes signalements sont anonymisés + Et mes commentaires personnels sont supprimés + Et seules les métadonnées nécessaires sont conservées (conformité DSA) + Et je suis informé de cette procédure diff --git a/features/ui/moderation/sanctions-appel.feature b/features/ui/moderation/sanctions-appel.feature new file mode 100644 index 0000000..9069a3c --- /dev/null +++ b/features/ui/moderation/sanctions-appel.feature @@ -0,0 +1,410 @@ +# language: fr + +@ui @moderation @sanctions @appel +Fonctionnalité: Interface sanctions et processus d'appel (Mobile) + En tant que créateur de contenu + Je veux consulter mes sanctions et faire appel si nécessaire + Afin de comprendre les décisions et contester si je pense qu'il y a erreur + + # 14.3 - Interface sanctions et appel + + Contexte: + Étant donné que je suis un créateur de contenu + Et que je suis connecté à l'application mobile + + # Notifications multi-canal + + Scénario: Notification push immédiate après sanction + Étant donné que mon contenu vient d'être modéré + Quand la sanction est appliquée + Alors je reçois une notification push immédiate: + """ + ⚠️ Votre contenu a été modéré + Appuyez pour voir les détails + """ + Et la notification est marquée comme importante (son + vibration) + Et je peux cliquer pour accéder aux détails + Et la notification reste visible jusqu'à ce que je la lise + + Scénario: Popup in-app au prochain lancement + Étant donné que mon contenu a été modéré + Et que je n'ai pas encore consulté la sanction + Quand j'ouvre l'application + Alors une popup modale s'affiche automatiquement avant tout: + """ + ⚠️ Attention + + Votre contenu "Mon podcast #42" a été modéré. + + Catégorie violée: 🚫 Haine & violence + Sanction: Strike 2/4 - Suspension 7 jours + + [Voir les détails] [Plus tard] + """ + Et la popup est prioritaire (affichée avant le contenu de l'app) + Et je ne peux pas la fermer sans l'avoir lue (pas de bouton X) + Et je dois cliquer sur un bouton pour continuer + + Scénario: Design de la popup de sanction + Étant donné que la popup de sanction s'affiche + Quand je vérifie le design + Alors le fond est rouge clair (#FFEBEE) pour signaler la gravité + Et l'icône ⚠️ est proéminente + Et le texte est clair et concis + Et les boutons sont bien visibles: + | bouton | style | couleur | + | Voir les détails| Primaire (plein) | Rouge | + | Plus tard | Secondaire (border)| Gris | + Et le design est professionnel et sérieux + + # Page détaillée de la sanction + + Scénario: Affichage de la page détails sanction + Étant donné que je clique sur "Voir les détails" + Quand la page s'affiche + Alors je vois toutes les informations obligatoires: + | section | contenu exemple | + | En-tête avec icône | ⚠️ Contenu modéré | + | Titre du contenu | "Mon podcast #42" | + | Date de publication | "Publié le 15/01/2026" | + | Catégorie violée | 🚫 Haine & violence (Article 3.2 CGU) | + | Raison détaillée | "Propos discriminatoires envers un groupe" | + | Passage problématique | "3:42-4:15" (avec player audio) | + | Transcription surlignée | "[texte problématique en rouge]" | + | Gravité de la sanction | Strike 2/4 - Suspension 7 jours | + | Conséquences futures | "Strike 3: 30j / Strike 4: Ban définitif" | + | Délai d'appel | "7 jours pour faire appel" | + | Bouton Contester | [Contester cette décision] | + | Lien CGU | [Voir les règles de la communauté] | + Et toutes les sections sont clairement séparées + + Scénario: Player audio du passage problématique + Étant donné que je consulte les détails de la sanction + Quand je vois la section "Passage problématique" + Alors un player audio s'affiche avec le timestamp "3:42-4:15" + Et je peux écouter uniquement cette portion de l'audio + Et les contrôles sont simples: Play/Pause + volume + Et la waveform visualise le passage + Et je peux comprendre exactement ce qui pose problème + + Scénario: Transcription avec mise en évidence + Étant donné que je consulte la transcription du passage + Quand j'affiche la transcription + Alors les mots/phrases problématiques sont surlignés en rouge + Et le contexte autour est affiché en gris + Et je peux voir exactement quels mots ont posé problème: + """ + [contexte gris]... et c'est pourquoi je pense que + [ROUGE: phrase discriminatoire problématique] + [contexte gris]... mais c'est mon opinion. + """ + Et la mise en évidence est claire + + Scénario: Lien vers l'article des CGU + Étant donné que la sanction référence "Article 3.2 CGU" + Quand je clique sur le lien + Alors je suis redirigé vers les CGU + Et la section "Article 3.2 - Haine & violence" est mise en évidence + Et je peux lire exactement ce qui est interdit + Et je comprends mieux ma violation + + # Escalade des sanctions + + Scénario: Affichage de l'escalade des strikes + Étant donné que j'ai reçu le Strike 2 + Quand je consulte la section "Gravité" + Alors je vois clairement l'escalade: + """ + Vous avez reçu le Strike 2/4 + + Historique: + ✓ Strike 1: Avertissement (il y a 3 mois) + ⚠️ Strike 2: Suspension 7 jours (aujourd'hui) + + Prochaines étapes si récidive: + ⚠️ Strike 3: Suspension 30 jours + ❌ Strike 4: Ban définitif + + Réhabilitation: + -1 strike tous les 6 mois sans incident + """ + Et je comprends la progression des sanctions + Et je suis motivé à ne pas récidiver + + Scénario: Compteur de suspension visible + Étant donné que je suis suspendu pour 7 jours + Quand j'ouvre l'application + Alors une bannière persistante s'affiche en haut: + """ + ⏸️ Compte suspendu - 5 jours restants + """ + Et la bannière est visible sur toutes les pages + Et je vois le décompte en temps réel + Et je ne peux pas publier de nouveau contenu + + # Accès à l'historique des sanctions + + Scénario: Consulter l'historique des sanctions + Étant donné que je suis dans mon profil créateur + Quand je clique sur "Mes sanctions" + Alors je vois la liste de toutes mes sanctions passées: + | colonne | contenu exemple | + | Date | 15/01/2026 | + | Contenu | "Mon podcast #42" | + | Catégorie | 🚫 Haine & violence | + | Sanction | Strike 2 - Suspension 7j | + | Statut | Active / Terminée / Annulée | + | Appel | Aucun / En cours / Accepté / Rejeté | + | Action | [Faire appel] / [Détails] | + Et les sanctions sont triées par date décroissante + + Scénario: Sanctions actives vs terminées + Étant donné que j'ai 3 sanctions dans mon historique + Quand j'affiche "Mes sanctions" + Alors les sanctions actives sont mises en évidence (fond rouge clair) + Et les sanctions terminées sont en gris + Et les sanctions annulées (après appel) sont en vert clair + Et je vois clairement l'état de chaque sanction + + # Formulaire d'appel + + Scénario: Accéder au formulaire d'appel depuis la notification + Étant donné que je consulte les détails d'une sanction + Et que le délai d'appel n'est pas dépassé (<7 jours) + Quand je clique sur "Contester cette décision" + Alors le formulaire d'appel s'affiche en plein écran + Et le formulaire est pré-rempli avec les informations de la sanction + Et je peux commencer à rédiger mon appel + + Scénario: Structure du formulaire d'appel + Étant donné que le formulaire d'appel est affiché + Quand je vérifie les champs + Alors je vois la structure suivante: + | champ | type | limite | obligatoire | + | Sanction contestée | Texte (readonly) | - | oui | + | Raison de l'appel | Texte court | 50-1000 car. | oui | + | Arguments détaillés | Zone texte enrichie | 1000-5000 car. | oui | + | Preuves | Upload fichiers | 5 max, 10MB tot.| non | + | Bouton Annuler | Secondaire | - | - | + | Bouton Soumettre | Primaire | - | - | + Et tous les champs obligatoires sont marqués d'un astérisque rouge + + Scénario: Validation du formulaire d'appel + Étant donné que je remplis le formulaire d'appel + Quand je clique sur "Soumettre l'appel" + Alors le système valide: + | règle | message d'erreur si non respecté | + | Raison >50 caractères | "La raison doit faire au moins 50 caractères" | + | Arguments >100 caractères | "Développez vos arguments (min 100 car.)" | + | Total fichiers <10 MB | "Taille totale des fichiers >10 MB" | + | Formats fichiers acceptés (PDF, JPG) | "Format de fichier non accepté" | + Et si une erreur existe, le champ est surligné en rouge + Et je dois corriger avant de pouvoir soumettre + + Scénario: Upload de preuves + Étant donné que je veux joindre des preuves + Quand je clique sur "Ajouter des preuves" + Alors je peux choisir depuis: + | source | types acceptés | + | Galerie photos | JPG, PNG | + | Fichiers | PDF | + | Caméra (nouveau) | JPG | + Et je peux uploader jusqu'à 5 fichiers + Et la taille totale ne peut pas dépasser 10 MB + Et une progress bar s'affiche pendant l'upload + + Scénario: Confirmation après soumission de l'appel + Étant donné que j'ai soumis un appel valide + Quand l'appel est enregistré + Alors une page de confirmation s'affiche: + """ + ✓ Appel envoyé avec succès + + Numéro de ticket: #MOD-2026-00142 + + Votre appel sera examiné par un modérateur senior + sous 72h maximum (3 jours ouvrés). + + Vous serez notifié de la décision par: + - Notification push + - Email + - Notification in-app + + [Retour à mes sanctions] + """ + Et je reçois un email de confirmation identique + Et le statut dans "Mes sanctions" passe à "Appel en cours 🔍" + + # Délai d'appel et compteur + + Scénario: Compteur de jours restants pour faire appel + Étant donné que j'ai reçu une sanction il y a 3 jours + Quand je consulte les détails de la sanction + Alors je vois un compteur en haut de page: + """ + ⏰ 4 jours restants pour faire appel + """ + Et le compteur est en orange pour attirer l'attention + Et il se met à jour en temps réel (chaque jour) + + Scénario: Délai d'appel dépassé + Étant donné que j'ai reçu une sanction il y a 8 jours + Quand je consulte les détails de la sanction + Alors le bouton "Contester cette décision" est désactivé (grisé) + Et un message s'affiche: + """ + ⚠️ Le délai de 7 jours pour faire appel est dépassé. + Cette décision est désormais définitive. + """ + Et je ne peux plus contester la sanction + + # Suivi de l'appel + + Scénario: Statut de l'appel dans l'historique + Étant donné que j'ai soumis un appel + Quand je consulte "Mes sanctions" + Alors je vois le statut de l'appel: + | statut appel | badge | couleur | + | Aucun appel | - | - | + | Appel en cours | En cours 🔍 | Orange | + | Appel accepté | Accepté ✓ | Vert | + | Appel rejeté | Rejeté ✗ | Rouge | + | Sanction réduite | Partiellement accepté 🟡 | Bleu | + Et un badge de notification m'alerte si le statut change + + Scénario: Notification quand l'appel est traité - Accepté + Étant donné que mon appel a été accepté + Quand le modérateur prend la décision + Alors je reçois une notification push + in-app: + """ + ✓ Appel accepté + + Votre sanction a été annulée. + Le strike a été retiré et votre contenu a été rétabli. + + [Voir les détails] + """ + Et je reçois un email détaillé avec la justification + Et le statut dans mes sanctions passe à "Annulée" + + Scénario: Notification quand l'appel est traité - Rejeté + Étant donné que mon appel a été rejeté + Quand le modérateur prend la décision + Alors je reçois une notification: + """ + Appel rejeté + + Votre appel a été examiné et la sanction est maintenue. + Cette décision est définitive. + + [Voir la justification] + """ + Et je reçois un email avec la justification détaillée + Et le statut reste "Active" + Et je ne peux pas faire de second appel + + Scénario: Notification intermédiaire si délai >72h + Étant donné que mon appel complexe est en cours depuis 3 jours + Quand le délai de 72h est dépassé + Alors je reçois une notification intermédiaire: + """ + Appel #MOD-2026-00142 en cours + + Votre appel nécessite un examen approfondi. + Réponse sous 2 jours maximum. + + Merci de votre patience. + """ + Et je suis rassuré que mon appel n'est pas oublié + + # Page détails de la réponse à l'appel + + Scénario: Détails de la réponse - Appel accepté + Étant donné que mon appel a été accepté + Quand je consulte les détails de la réponse + Alors je vois: + """ + Décision: Annulation de la sanction ✓ + + Justification: + Après examen de votre appel, nous reconnaissons que le + passage mentionné était dans un contexte éducatif et ne + constitue pas une violation des règles de la communauté. + + Actions prises: + ✓ Strike retiré de votre compte + ✓ Suspension annulée + ✓ Contenu rétabli sur la plateforme + + Cette décision est définitive. + """ + Et je suis satisfait de la transparence + + Scénario: Détails de la réponse - Sanction réduite + Étant donné que mon appel a été partiellement accepté + Quand je consulte les détails + Alors je vois: + """ + Décision: Réduction de la sanction 🟡 + + Justification: + Nous reconnaissons des circonstances atténuantes. + + Sanction initiale: Strike 2 - Suspension 7 jours + Sanction réduite: Strike 1 - Suspension 3 jours + + Cette décision est définitive. + """ + Et je vois le compteur de suspension mis à jour (3 jours au lieu de 7) + + # Dark mode et accessibilité + + Scénario: Support du dark mode + Étant donné que j'ai activé le dark mode + Quand j'affiche la page de sanction + Alors les couleurs s'adaptent: + | élément | couleur light | couleur dark | + | Fond page | Blanc | Noir (#121212) | + | Carte sanction | Rouge clair | Rouge foncé | + | Texte principal | Noir | Blanc | + | Passage problématique | Rouge | Rouge (#FF6B6B) | + | Bouton Contester | Rouge (#DC3545) | Rouge (#F85149) | + Et le contraste reste suffisant + + Scénario: Accessibilité lecteur d'écran + Étant donné que j'utilise un lecteur d'écran + Quand je navigue dans la page de sanction + Alors chaque section est clairement annoncée: + """ + Contenu modéré. Attention. + Votre contenu "Mon podcast numéro 42" a été modéré. + Catégorie violée: Haine et violence, Article 3 point 2. + Raison: Propos discriminatoires envers un groupe. + Passage problématique: 3 minutes 42 secondes à 4 minutes 15 secondes. + Sanction: Strike 2 sur 4. Suspension 7 jours. + Bouton: Contester cette décision. + """ + Et tous les éléments sont accessibles au clavier + + # Coût et conformité + + Scénario: Coût de la fonctionnalité + Étant donné que l'interface sanctions et appel est en place + Quand on évalue le coût + Alors le développement est 100% interne (Flutter) + Et aucun service tiers n'est utilisé + Et le coût opérationnel est de 0€ + Et les emails de notification coûtent ~0.001€/email + + Scénario: Conformité DSA - Transparence + Étant donné que le système de sanction est en place + Quand on vérifie la conformité DSA + Alors chaque sanction contient: + | élément DSA requis | présent | + | Référence précise à la règle violée | ✓ | + | Explication claire | ✓ | + | Preuve (extrait + transcription) | ✓ | + | Possibilité de recours | ✓ | + | Délai de recours clairement indiqué | ✓ | + | Réponse motivée au recours | ✓ | + Et le système est conforme au Digital Services Act diff --git a/features/ui/moderation/signalement-ui.feature b/features/ui/moderation/signalement-ui.feature new file mode 100644 index 0000000..0334b94 --- /dev/null +++ b/features/ui/moderation/signalement-ui.feature @@ -0,0 +1,291 @@ +# language: fr + +@ui @moderation @signalement +Fonctionnalité: Interface de signalement de contenu (Mobile) + En tant qu'utilisateur de l'application mobile + Je veux pouvoir signaler un contenu inapproprié facilement + Afin de contribuer à améliorer la qualité de la plateforme + + # 14.1 - Interface de signalement utilisateur + + Contexte: + Étant donné que je suis connecté à l'application mobile + Et que je suis en train d'écouter un contenu + + # Accès au formulaire de signalement + + Scénario: Accéder au signalement depuis le player audio + Étant donné que j'écoute un contenu audio + Quand j'ouvre le menu "⋮" du player + Alors je vois l'option "🚫 Signaler ce contenu" + Et l'option est facilement accessible (3ème position) + Et l'icône est rouge pour la visibilité + + Scénario: Accéder au signalement depuis la page de détails + Étant donné que je consulte la page de détails d'un contenu + Quand j'ouvre le menu "⋮" en haut à droite + Alors je vois l'option "🚫 Signaler ce contenu" + Et je peux ouvrir le formulaire de signalement + + Scénario: Accéder au signalement depuis l'historique d'écoute + Étant donné que je consulte mon historique d'écoute + Quand je fais un appui long sur un contenu + Alors un menu contextuel s'affiche + Et je vois l'option "🚫 Signaler" + Et je peux signaler le contenu même si je ne l'écoute plus + + # Formulaire de signalement - Design et UX + + Scénario: Affichage du formulaire de signalement + Étant donné que je clique sur "Signaler ce contenu" + Quand le formulaire s'affiche + Alors il apparaît en modal plein écran (iOS) ou bottom sheet (Android) + Et le titre est "Signaler ce contenu" + Et je vois le nom du contenu et le créateur en haut + Et le formulaire contient: + | élément | type | obligatoire | + | Catégorie du problème | Liste déroulante | oui | + | Commentaire | Zone texte | non* | + | Bouton Annuler | Secondaire (gris) | - | + | Bouton Envoyer | Primaire (rouge) | - | + Et le bouton "Envoyer" est désactivé tant qu'aucune catégorie n'est sélectionnée + + Scénario: Design responsive du formulaire + Étant donné que le formulaire de signalement est affiché + Quand je vérifie l'adaptation de l'interface + Alors sur petit écran (<375px), le texte est réduit mais lisible + Et sur grand écran (>414px), le formulaire utilise l'espace disponible + Et le clavier ne masque pas le bouton "Envoyer" + Et je peux scroller si le contenu dépasse la hauteur de l'écran + + # Liste des catégories avec icônes + + Scénario: Affichage des 7 catégories prédéfinies + Étant donné que le formulaire de signalement est affiché + Quand je clique sur "Catégorie du problème" + Alors une liste déroulante s'affiche avec 7 options: + | icône | catégorie | description visible en sous-titre | + | 🚫 | Haine & violence | Incitation à la haine, discrimination | + | 🔞 | Contenu sexuel | Pornographie, contenu explicite | + | ⚖️ | Illégalité | Terrorisme, apologie de crimes | + | 🎵 | Droits d'auteur | Musique/contenu protégé non autorisé | + | 📧 | Spam | Publicité non sollicitée, répétition | + | ❌ | Fausse information | Désinformation santé, sécurité routière | + | 🔧 | Autre | Champ texte obligatoire si sélectionné | + Et chaque option affiche l'icône, le titre et la description + Et la description est en gris clair pour la hiérarchie visuelle + + Scénario: Sélection d'une catégorie + Étant donné que la liste des catégories est affichée + Quand je sélectionne "🚫 Haine & violence" + Alors la liste se ferme + Et le champ "Catégorie du problème" affiche "🚫 Haine & violence" + Et le bouton "Envoyer" s'active (devient rouge) + Et je peux passer au champ commentaire (optionnel) + + Scénario: Animation visuelle lors de la sélection + Étant donné que je suis sur le formulaire de signalement + Quand je sélectionne une catégorie + Alors une animation de validation subtile s'affiche (✓ vert) + Et le champ commentaire s'anime légèrement pour attirer l'attention + Et l'UX est fluide et encourageante + + # Catégorie "Autre" avec commentaire obligatoire + + Scénario: Catégorie "Autre" rend le commentaire obligatoire + Étant donné que le formulaire de signalement est affiché + Quand je sélectionne "🔧 Autre" + Alors le champ "Commentaire" affiche un astérisque rouge (*) + Et le placeholder change en "Décrivez le problème (obligatoire)" + Et une étiquette "Obligatoire" apparaît en rouge + Et le bouton "Envoyer" reste désactivé tant que je n'ai pas saisi de commentaire + + Scénario: Validation du commentaire obligatoire pour "Autre" + Étant donné que j'ai sélectionné "🔧 Autre" + Et que je n'ai pas rempli le champ commentaire + Quand je clique sur "Envoyer" + Alors un message d'erreur s'affiche sous le champ: + """ + Veuillez décrire le problème (minimum 10 caractères) + """ + Et le champ commentaire est mis en évidence en rouge + Et le signalement n'est pas envoyé + + # Champ commentaire - UX et validation + + Scénario: Commentaire optionnel avec incitation + Étant donné que j'ai sélectionné une catégorie autre que "Autre" + Quand je consulte le champ "Commentaire" + Alors le placeholder indique "Décrivez le problème (optionnel mais recommandé)" + Et aucun astérisque rouge n'est affiché + Et un compteur "0/500" s'affiche en bas à droite + Et l'incitation encourage à fournir des détails sans obliger + + Scénario: Compteur de caractères en temps réel + Étant donné que je suis dans le champ commentaire + Quand je tape du texte + Alors le compteur se met à jour en temps réel: "42/500" + Et quand j'atteins 450 caractères, le compteur passe en orange + Et quand j'atteins 490 caractères, le compteur passe en rouge + Et à 500 caractères, le clavier bloque la saisie + Et un message s'affiche: "Limite atteinte" + + Scénario: Limite stricte de 500 caractères + Étant donné que j'ai saisi 500 caractères dans le commentaire + Quand j'essaie de taper un caractère supplémentaire + Alors le caractère n'est pas accepté + Et le clavier vibre légèrement (feedback haptique) + Et le compteur reste à "500/500" en rouge + + # Envoi du signalement + + Scénario: Envoi d'un signalement sans commentaire + Étant donné que j'ai sélectionné "📧 Spam" + Et que je n'ai pas rempli le champ commentaire + Quand je clique sur "Envoyer" + Alors un loader s'affiche sur le bouton "Envoyer" + Et le formulaire se ferme après 1 seconde + Et le signalement est envoyé avec succès + Et aucune erreur ne s'affiche + + Scénario: Envoi d'un signalement avec commentaire + Étant donné que j'ai sélectionné "🚫 Haine & violence" + Et que j'ai saisi "Propos discriminatoires à 2:30" + Quand je clique sur "Envoyer" + Alors un loader s'affiche pendant l'envoi + Et le formulaire se ferme + Et le signalement est envoyé avec le commentaire + Et le commentaire sera visible par les modérateurs + + Scénario: Gestion d'erreur lors de l'envoi + Étant donné que j'ai rempli le formulaire de signalement + Et que ma connexion réseau est perdue + Quand je clique sur "Envoyer" + Alors un message d'erreur s'affiche: + """ + Impossible d'envoyer le signalement. + Vérifiez votre connexion internet. + """ + Et le formulaire reste ouvert avec mes données + Et je peux réessayer sans perdre ma saisie + + # Toast de confirmation + + Scénario: Toast de confirmation après envoi réussi + Étant donné que j'ai envoyé un signalement + Quand le signalement est enregistré avec succès + Alors un toast notification s'affiche en bas de l'écran + Et le toast contient: + | élément | contenu | + | Icône | ✓ (vert) | + | Message | Signalement envoyé. Examen sous 24-48h. | + | Bouton | Voir mes signalements | + | Bouton fermer | × (croix en haut à droite) | + Et le toast s'affiche pendant 5 secondes + Et je peux le fermer manuellement + + Scénario: Animation du toast + Étant donné que le signalement est envoyé + Quand le toast s'affiche + Alors il apparaît avec une animation slide-up depuis le bas + Et après 5 secondes, il disparaît avec une animation fade-out + Et l'animation est fluide et professionnelle + + Scénario: Redirection vers l'historique depuis le toast + Étant donné que le toast de confirmation est affiché + Quand je clique sur "Voir mes signalements" + Alors le toast se ferme + Et je suis redirigé vers "Profil > Mes signalements" + Et je vois mon nouveau signalement en tête de liste + Et le statut est "En cours 🔍" + + # Modal de découverte au premier signalement + + Scénario: Découverte du système de badges au 1er signalement + Étant donné que je viens d'envoyer mon tout premier signalement + Et que le toast de confirmation s'est affiché + Quand 2 secondes se sont écoulées + Alors une modal d'information s'affiche par-dessus + Et la modal contient le titre "🎯 Bravo ! Vous contribuez à une communauté plus saine" + Et la modal explique le système de badges: + """ + 🥉 Bronze : 5 signalements validés + 🥈 Argent : 20 signalements validés + 🥇 Or : 50 signalements validés → -50% Premium 3 mois + """ + Et la modal contient 2 boutons: + | bouton | action | + | En savoir plus | Ouvre page dédiée badges | + | J'ai compris | Ferme la modal | + Et cette modal ne se réaffiche jamais + + Scénario: Modal responsive et accessible + Étant donné que la modal de découverte s'affiche + Quand je vérifie l'accessibilité + Alors la modal est centrée sur l'écran + Et le fond est assombri (overlay semi-transparent) + Et je ne peux pas interagir avec l'écran en arrière-plan + Et je peux fermer en cliquant hors de la modal + Et le texte est lisible (contraste WCAG AA) + + # Limite de signalements déjà effectués + + Scénario: Impossible de signaler deux fois le même contenu + Étant donné que j'ai déjà signalé ce contenu il y a 3 jours + Quand j'ouvre le menu "⋮" du contenu + Alors l'option "Signaler" est désactivée (grisée) + Et un tooltip s'affiche: "Vous avez déjà signalé ce contenu" + Et je peux consulter mon signalement précédent via le tooltip (lien) + + Scénario: Redirection vers le signalement existant + Étant donné que j'ai déjà signalé ce contenu + Et que l'option "Signaler" est désactivée + Quand je clique sur le tooltip "Vous avez déjà signalé ce contenu" + Alors je suis redirigé vers "Mes signalements" + Et le signalement concerné est mis en évidence + Et je vois le statut actuel: "En cours 🔍" / "Traité ✓" / "Rejeté ✗" + + # Accessibilité et dark mode + + Scénario: Support du dark mode + Étant donné que j'ai activé le dark mode sur mon téléphone + Quand j'ouvre le formulaire de signalement + Alors le formulaire s'adapte au dark mode: + | élément | couleur dark mode | + | Fond de la modal | Gris foncé (#1E1E1E) | + | Texte principal | Blanc (#FFFFFF) | + | Texte secondaire | Gris clair (#B0B0B0) | + | Bordures | Gris moyen (#3E3E3E) | + | Bouton Envoyer | Rouge (#FF4444) | + Et le contraste reste suffisant (WCAG AA) + + Scénario: Accessibilité pour lecteur d'écran + Étant donné que j'utilise un lecteur d'écran (VoiceOver/TalkBack) + Quand je navigue dans le formulaire de signalement + Alors chaque élément a un label descriptif: + | élément | label lecteur d'écran | + | Bouton menu | "Menu du contenu" | + | Option signaler | "Signaler ce contenu" | + | Liste catégories | "Sélectionner une catégorie de problème" | + | Champ commentaire | "Commentaire optionnel, 500 caractères maximum" | + | Bouton Envoyer | "Envoyer le signalement" | + Et je peux naviguer au clavier (tab/shift-tab) + Et tous les états (activé/désactivé) sont annoncés + + # Coût et performance + + Scénario: Performance de l'interface + Étant donné que j'ouvre le formulaire de signalement + Quand je mesure les performances + Alors le formulaire s'affiche en <300ms + Et l'animation est fluide (60 FPS) + Et l'envoi du signalement prend <2 secondes + Et l'UX est instantanée et réactive + + Scénario: Coût de développement + Étant donné que l'interface de signalement est développée + Quand on évalue le coût + Alors le développement est 100% interne (Flutter) + Et aucun service tiers n'est utilisé + Et le coût opérationnel est de 0€ + Et l'interface est native iOS et Android