--- name: test-logique-metier description: À lancer systématiquement à la fin de l'implémentation de toute fonctionnalité touchant à la logique métier (stock, commandes, paiements, points, parrainage, pénalités). Démarre l'API en local, exécute une série de scénarios réels via curl contre l'API, et vérifie en base que les invariants métier tiennent (stock décrémenté puis remboursé exactement, idempotence, autorisations par rôle). Ne se contente pas de lire le code — observe le comportement réel. --- # Test de logique métier — vérification comportementale locale Ce skill exécute des tests **de bout en bout contre une instance locale de l'API**, pas une relecture de code. Objectif : détecter les bugs de la classe "le code compile et semble correct, mais le comportement observé diverge" — exactement le type de bugs trouvés et corrigés dans ce projet (stock jamais décrémenté, double remboursement, commande fantôme). S'appuie sur les règles métier du skill `comprehension-metier` : le lire d'abord si ce n'est pas déjà fait. **Ne jamais exécuter ces tests contre la base pre-prod ou prod.** Uniquement contre un environnement local jetable. ## Quand l'utiliser - À la fin de l'implémentation de toute fonctionnalité qui touche : stock, cycle de vie d'une commande, paiement (cash/crypto), points/récompenses, parrainage, pénalités, permissions par rôle. - Après toute correction de bug dans ces domaines (pour confirmer la correction ET l'absence de régression sur les cas adjacents). - Complément du skill `plan-fonctionnalite` (étape "plan de test" de ce skill) — celui-ci l'exécute réellement au lieu de rester une liste sur papier. - Ne pas l'utiliser pour un changement purement cosmétique ou un fix qui ne touche aucune règle métier. ## Étape 0 — Préparer l'environnement local ```bash # 1. Postgres + Redis locaux (depuis backend/gestion/) cd backend/gestion docker compose up -d docker compose ps # attendre "healthy" sur les deux services # 2. Variables d'environnement minimales (adapter aux valeurs du .env local) export DB_HOST=localhost DB_PORT=5432 DB_USER=postgres DB_PASSWORD=postgres DB_NAME= export REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD= export USER_JWT_SECRET=$(openssl rand -hex 32) export ADMIN_JWT_SECRET=$(openssl rand -hex 32) # 3. Lancer l'API (dans un terminal séparé ou en arrière-plan) go run main.go # écoute sur :8080, crée les tables au démarrage (createTables) ``` Vérifier que l'API répond avant de continuer : ```bash curl -sf http://localhost:8080/api/v1/app-settings > /dev/null && echo "API up" ``` ## Étape 1 — Obtenir un compte admin de test **La création d'un compte admin est volontairement bloquée via l'API** (voir `comprehension-metier`) — impossible d'obtenir un token admin par un simple appel HTTP. Il faut l'insérer directement en base locale (jetable, jamais en pre-prod/prod) : ```bash # Générer un hash bcrypt pour le mot de passe de test HASH=$(go run -exec "" - <<'EOF' 2>/dev/null || python3 -c "import bcrypt; print(bcrypt.hashpw(b'TestPass123!', bcrypt.gensalt()).decode())" package main import ("fmt"; "golang.org/x/crypto/bcrypt") func main() { h, _ := bcrypt.GenerateFromPassword([]byte("TestPass123!"), bcrypt.DefaultCost) fmt.Println(string(h)) } EOF ) docker exec -i gestion_postgres psql -U postgres -d -c \ "INSERT INTO users (username, password, role) VALUES ('test_admin', '$HASH', 'admin') ON CONFLICT (username) DO NOTHING;" ``` Puis se connecter normalement : ```bash ADMIN_TOKEN=$(curl -s -X POST http://localhost:8080/api/v2/admin/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"test_admin","password":"TestPass123!"}' | jq -r .access_token) ``` À partir de ce token admin, créer les comptes de test nécessaires **via l'API** (c'est le chemin normal) : client de test, livreur de test, cabine de test — jamais par insertion SQL directe pour ceux-là, afin de tester le vrai chemin de création. ## Étape 2 — Méthode générale Pour chaque scénario : **agir via l'API (curl)**, puis **vérifier l'état réel en base** (`docker exec gestion_postgres psql ...`) plutôt que de se fier uniquement à la réponse HTTP — une réponse 200 ne prouve pas que l'effet de bord a eu lieu correctement. Gabarit de vérification stock : ```bash docker exec -i gestion_postgres psql -U postgres -d -t -c \ "SELECT stock FROM products WHERE id = $PRODUCT_ID;" ``` Toujours noter le stock **avant** l'action, exécuter l'action, relire le stock **après**, et comparer à la valeur attendue calculée manuellement (pas juste "différent de avant"). ## Étape 3 — Scénarios à exécuter ### Stock — commande normale 1. Créer un produit avec stock connu (ex. 10). 2. Client ajoute 3 unités au panier, checkout. 3. Vérifier : stock produit = 7 exactement. 4. Client annule la commande. 5. Vérifier : stock produit = 10 exactement (retour à la valeur initiale). ### Stock — articles récompense 1. Configurer un pool de points avec un seuil bas et un `RewardItem` pointant vers un produit à stock connu. 2. Faire gagner assez de points au client de test (achats successifs), puis réclamer la récompense (`ClaimMyReward`). 3. Checkout incluant l'article récompense. 4. Vérifier : stock décrémenté de la quantité offerte, **comme un article payant**. 5. Annuler la commande → vérifier stock restauré exactement. ### Stock — idempotence de l'annulation 1. Créer une commande, la faire annuler une première fois (client, livreur, ou admin — tester les trois chemins séparément). 2. Rejouer le même appel d'annulation une seconde fois sur la même commande. 3. Vérifier : le second appel ne modifie **pas** le stock une seconde fois (comparer stock après 1er appel et après 2e appel — doivent être identiques), et renvoie une réponse cohérente (pas une erreur qui laisserait croire à un échec silencieux). ### Stock — commande fantôme / double-submit 1. Vider le panier d'un client, y ajouter un article dont le stock est juste suffisant pour une seule commande (ex. stock = 2, quantité demandée = 2). 2. Envoyer **deux requêtes de checkout quasi simultanées** pour ce même client (deux processus curl en parallèle, `&` en shell). 3. Vérifier : une seule commande a réellement décrémenté le stock, l'autre échoue proprement (panier vide ou stock insuffisant) — **aucune commande "pending" orpheline** ne doit rester en base avec des `command_items` mais un stock jamais décrémenté pour elle. ### Paiement crypto 1. Checkout avec `payment_method: crypto` → vérifier statut `pending_payment` et stock déjà décrémenté à ce stade. 2. Simuler le webhook IPN avec statut `failed` (signature HMAC valide requise — générer avec le secret de test) → vérifier commande `cancelled` et stock restauré. 3. Répéter avec statut `finished` sur une nouvelle commande → vérifier commande repasse en `pending` (cycle normal), stock reste décrémenté. 4. Renvoyer deux fois le même webhook `failed` → vérifier pas de double remboursement. ### Parrainage 1. Lier un parrain à un client, vérifier `referral_balance` du parrain crédité du montant configuré (`ReferralAmount`). 2. Checkout du filleul avec crédit parrainage utilisé, panier tout juste au-dessus du minimum de zone + crédit → vérifier acceptation ; en dessous → vérifier rejet avec message explicite. 3. Faire échouer le checkout après débit du crédit (ex. stock insuffisant découvert tardivement) → vérifier que `referral_balance` est recrédité, pas perdu. ### Points et récompenses 1. Vérifier que les points s'accumulent dans le bon pool selon la catégorie du produit acheté (pas dans tous les pools). 2. Réclamer une récompense au-delà du nombre disponible → vérifier rejet. 3. Reset admin des récompenses réclamées d'un client → vérifier que le compteur repart à zéro et que de nouvelles réclamations redeviennent possibles. ### Pénalités 1. Simuler 4 annulations successives du même client (avec livreur assigné + statut `en_route`/`arrived` pour déclencher la pénalité) → vérifier progression exacte du barème (20€, 50€, 100€, 150€ ou barème configuré). 2. Avec `amende > 0`, tenter un checkout → vérifier blocage 403 avec message contact. 3. Simuler le flux "client absent" (livreur annule depuis `arrived`) → vérifier pénalité appliquée au **client**, jamais au livreur. 4. Annulation sans livreur assigné → vérifier absence de pénalité. ### Permissions par rôle 1. Token livreur A tente d'agir sur une commande assignée à livreur B → vérifier 403 (pas seulement vérification du rôle, vérification de la propriété). 2. Token client tente d'accéder à une route admin → 403. 3. Vérifier qu'aucun endpoint ne permet de créer un compte `admin` via l'API (tenter et confirmer le rejet/l'absence de route). 4. Vérifier que le livreur ne reçoit jamais le téléphone du client dans `GET /livreur/deliveries`. ## Étape 4 — Rapport et suite Pour chaque scénario : **PASS** ou **FAIL** avec la preuve chiffrée (valeurs avant/après). En cas de FAIL, ce n'est pas la fin du skill — revenir au code, corriger, puis **relancer uniquement les scénarios concernés** (pas besoin de tout rejouer) jusqu'à ce que tout passe. Ne jamais considérer une fonctionnalité "terminée" avec un scénario en FAIL non expliqué. ## Nettoyage ```bash docker compose down -v # supprime aussi les volumes (base de test jetable) ```