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