# language: fr Fonctionnalité: API - Évolution des jauges d'intérêt En tant qu'API backend Je veux calculer et persister les évolutions de jauges d'intérêt Afin d'alimenter l'algorithme de recommandation Contexte: Étant donné que l'API RoadWave est disponible Et que la base de données PostgreSQL est accessible Et qu'un utilisateur "user123" existe avec token JWT valide Scénario: API calcule like automatique renforcé (≥80% écoute) Étant donné que l'utilisateur "user123" a une jauge "Automobile" à 45% en base Et qu'un contenu "content456" de 5 minutes est tagué "Automobile" Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content456", "listened_duration_seconds": 270, "total_duration_seconds": 300, "completion_percentage": 90 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "like_type": "automatic_reinforced", "gauge_updates": [ { "category": "Automobile", "previous_value": 45, "delta": 2, "new_value": 47 } ] } """ Et en base de données, la jauge "Automobile" de "user123" est à 47% Scénario: API calcule like automatique standard (30-79% écoute) Étant donné que l'utilisateur "user123" a une jauge "Voyage" à 60% en base Et qu'un contenu "content789" de 10 minutes est tagué "Voyage" Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content789", "listened_duration_seconds": 300, "total_duration_seconds": 600, "completion_percentage": 50 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "like_type": "automatic_standard", "gauge_updates": [ { "category": "Voyage", "previous_value": 60, "delta": 1, "new_value": 61 } ] } """ Et en base de données, la jauge "Voyage" de "user123" est à 61% Scénario: API applique like manuel explicite (+2%) Étant donné que l'utilisateur "user123" a une jauge "Musique" à 55% en base Et qu'un contenu "content999" est tagué "Musique" Quand je POST /api/v1/likes """json { "user_id": "user123", "content_id": "content999", "like_type": "manual" } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "like_id": "", "gauge_updates": [ { "category": "Musique", "previous_value": 55, "delta": 2, "new_value": 57 } ] } """ Et en base de données, la jauge "Musique" de "user123" est à 57% Scénario: API applique unlike (retire like manuel) Étant donné que l'utilisateur "user123" a une jauge "Sport" à 57% en base Et qu'il a liké manuellement le contenu "content888" tagué "Sport" Et que le like a l'ID "like_abc123" Quand je DELETE /api/v1/likes/like_abc123 Alors le statut de réponse est 204 Et en base de données, la jauge "Sport" de "user123" est à 55% Et le like "like_abc123" est supprimé de la table likes Scénario: API refuse unlike d'un like automatique Étant donné que l'utilisateur "user123" a écouté un contenu à 90% Et qu'il a reçu un like automatique "like_auto456" Quand je DELETE /api/v1/likes/like_auto456 Alors le statut de réponse est 403 Et la réponse contient: """json { "error": "CANNOT_UNLIKE_AUTOMATIC", "message": "Les likes automatiques ne peuvent pas être retirés" } """ Et en base de données, le like "like_auto456" existe toujours Scénario: API cumule like automatique + like manuel Étant donné que l'utilisateur "user123" a une jauge "Technologie" à 50% en base Et qu'un contenu "content777" de 10 minutes est tagué "Technologie" Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content777", "completion_percentage": 50 } """ Alors la jauge "Technologie" passe à 51% (+1% auto) Quand je POST ensuite /api/v1/likes """json { "user_id": "user123", "content_id": "content777", "like_type": "manual" } """ Alors la jauge "Technologie" passe à 53% (+2% manuel) Et le delta total est de 3% Scénario: API applique bonus abonnement créateur (+5% tous tags) Étant donné que l'utilisateur "user123" a les jauges suivantes: | catégorie | niveau | | Automobile | 50% | | Technologie | 45% | Et qu'un créateur "creator456" publie des contenus tagués "Automobile" et "Technologie" Quand je POST /api/v1/subscriptions """json { "user_id": "user123", "creator_id": "creator456" } """ Alors le statut de réponse est 201 Et en base de données: | catégorie | niveau | | Automobile | 55% | | Technologie | 50% | Et l'abonnement est créé avec bonus appliqué Scénario: API retire bonus désabonnement créateur (-5% tous tags) Étant donné que l'utilisateur "user123" a les jauges suivantes: | catégorie | niveau | | Voyage | 65% | | Culture | 58% | Et qu'il est abonné au créateur "creator789" qui publie "Voyage" et "Culture" Quand je DELETE /api/v1/subscriptions/creator789 Alors le statut de réponse est 204 Et en base de données: | catégorie | niveau | | Voyage | 60% | | Culture | 53% | Scénario: API applique pénalité skip rapide (<10s) Étant donné que l'utilisateur "user123" a une jauge "Politique" à 50% en base Et qu'un contenu "content555" de 300 secondes est tagué "Politique" Quand je POST /api/v1/skip-events """json { "user_id": "user123", "content_id": "content555", "listened_duration_seconds": 5, "total_duration_seconds": 300 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "skip_type": "early", "gauge_updates": [ { "category": "Politique", "previous_value": 50, "delta": -0.5, "new_value": 49.5 } ] } """ Et en base de données, la jauge "Politique" de "user123" est à 49.5% Scénario: API n'applique pas de pénalité pour skip ≥10s et <30% Étant donné que l'utilisateur "user123" a une jauge "Économie" à 60% en base Et qu'un contenu "content333" de 600 secondes est tagué "Économie" Quand je POST /api/v1/skip-events """json { "user_id": "user123", "content_id": "content333", "listened_duration_seconds": 120, "total_duration_seconds": 600, "completion_percentage": 20 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "skip_type": "neutral", "gauge_updates": [] } """ Et en base de données, la jauge "Économie" de "user123" reste à 60% Scénario: API n'applique pas de pénalité pour skip ≥30% Étant donné que l'utilisateur "user123" a une jauge "Sport" à 55% en base Et qu'un contenu "content222" de 600 secondes est tagué "Sport" Quand je POST /api/v1/skip-events """json { "user_id": "user123", "content_id": "content222", "listened_duration_seconds": 300, "total_duration_seconds": 600, "completion_percentage": 50 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "skip_type": "late", "gauge_updates": [] } """ Et en base de données, la jauge "Sport" de "user123" reste à 55% Scénario: API applique évolution sur plusieurs tags simultanément Étant donné que l'utilisateur "user123" a les jauges suivantes: | catégorie | niveau | | Automobile | 45% | | Voyage | 60% | Et qu'un contenu "content111" est tagué "Automobile" et "Voyage" Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content111", "completion_percentage": 90 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "like_type": "automatic_reinforced", "gauge_updates": [ { "category": "Automobile", "previous_value": 45, "delta": 2, "new_value": 47 }, { "category": "Voyage", "previous_value": 60, "delta": 2, "new_value": 62 } ] } """ Et en base de données: | catégorie | niveau | | Automobile | 47% | | Voyage | 62% | Scénario: API respecte la borne maximum 100% Étant donné que l'utilisateur "user123" a une jauge "Cryptomonnaie" à 99% en base Et qu'un contenu "content_crypto" est tagué "Cryptomonnaie" Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content_crypto", "completion_percentage": 95 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "like_type": "automatic_reinforced", "gauge_updates": [ { "category": "Cryptomonnaie", "previous_value": 99, "delta": 2, "new_value": 100, "capped": true } ] } """ Et en base de données, la jauge "Cryptomonnaie" de "user123" est à 100% Et la jauge n'a pas dépassé 100% Scénario: API respecte la borne minimum 0% Étant donné que l'utilisateur "user123" a une jauge "Politique" à 0.3% en base Et qu'un contenu "content_pol" est tagué "Politique" Quand je POST /api/v1/skip-events """json { "user_id": "user123", "content_id": "content_pol", "listened_duration_seconds": 3, "total_duration_seconds": 300 } """ Alors le statut de réponse est 201 Et la réponse contient: """json { "skip_type": "early", "gauge_updates": [ { "category": "Politique", "previous_value": 0.3, "delta": -0.5, "new_value": 0, "capped": true } ] } """ Et en base de données, la jauge "Politique" de "user123" est à 0% Et la jauge n'est pas devenue négative Scénario: API respecte borne minimum lors désabonnement Étant donné que l'utilisateur "user123" a une jauge "Économie" à 3% en base Et qu'il est abonné au créateur "creator_eco" qui publie "Économie" Quand je DELETE /api/v1/subscriptions/creator_eco Alors le statut de réponse est 204 Et en base de données, la jauge "Économie" de "user123" est à 0% (et non -2%) Scénario: API GET retourne toutes les jauges utilisateur Étant donné que l'utilisateur "user123" a les jauges suivantes en base: | catégorie | niveau | | Automobile | 67% | | Voyage | 82% | | Économie | 34% | | Sport | 50% | | Musique | 45% | | Technologie | 71% | Quand je GET /api/v1/users/user123/interest-gauges Alors le statut de réponse est 200 Et la réponse contient les 12 catégories avec leurs niveaux: """json { "user_id": "user123", "gauges": [ {"category": "Automobile", "level": 67}, {"category": "Voyage", "level": 82}, {"category": "Économie", "level": 34}, {"category": "Sport", "level": 50}, {"category": "Musique", "level": 45}, {"category": "Technologie", "level": 71} ] } """ Scénario: API calcule évolution immédiate (pas de batch différé) Étant donné que l'utilisateur "user123" a une jauge "Voyage" à 50% en base Quand je POST /api/v1/listening-events à 12:00:00 """json { "user_id": "user123", "content_id": "content_travel", "completion_percentage": 85 } """ Alors le statut de réponse est 201 Quand je GET /api/v1/users/user123/interest-gauges à 12:00:01 (1 seconde après) Alors la jauge "Voyage" est à 52% Et la mise à jour est visible immédiatement Scénario: API rejette token JWT invalide Quand je POST /api/v1/listening-events sans token JWT Alors le statut de réponse est 401 Et la réponse contient: """json { "error": "UNAUTHORIZED", "message": "Token JWT manquant ou invalide" } """ Scénario: API valide format des données d'entrée Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content456", "completion_percentage": 150 } """ Alors le statut de réponse est 400 Et la réponse contient: """json { "error": "VALIDATION_ERROR", "message": "completion_percentage doit être entre 0 et 100" } """ Scénario: API gère contenu avec tags inexistants en base Étant donné qu'un contenu "content_new" est tagué "NouvelleCategorie" (non encore en base) Quand je POST /api/v1/listening-events """json { "user_id": "user123", "content_id": "content_new", "completion_percentage": 90 } """ Alors le statut de réponse est 201 Et une nouvelle ligne est créée dans la table interest_gauges: | user_id | category | level | | user123 | NouvelleCategorie | 52 | Et l'initialisation démarre à 50% + 2% de like auto = 52% Scénario: API persiste historique des modifications de jauges Étant donné que l'utilisateur "user123" a une jauge "Sport" à 50% Quand je POST /api/v1/listening-events qui applique +2% Alors une ligne est insérée dans interest_gauge_history: | user_id | category | previous_value | delta | new_value | event_type | event_id | timestamp | | user123 | Sport | 50 | 2 | 52 | listening_event| | 2026-02-02T12:00:00 | Et cet historique permet d'auditer les évolutions Scénario: API retourne métriques d'évolution utilisateur Étant donné que l'utilisateur "user123" a un historique d'évolution en base Quand je GET /api/v1/users/user123/interest-gauges/evolution?since=7d Alors le statut de réponse est 200 Et la réponse contient: """json { "period": "7d", "evolution": [ { "category": "Automobile", "start_value": 60, "end_value": 67, "delta": 7, "events_count": 15 }, { "category": "Voyage", "start_value": 80, "end_value": 82, "delta": 2, "events_count": 3 } ] } """