Aller au contenu

Session 14 — Chaos Métier Niveau Master (A12–A16) + Chaos Sécurité revue complète

Durée : ~5 heures (1 conversation Claude)
Objectif initial : Ajouter le niveau 4 Master au Chaos Métier — anomalies fonctionnelles avancées
Objectif final : 5 anomalies Master implémentées (A12–A16), UI pédagogique frontend, revue sécurité complète + 8 bugs corrigés


🎯 Réalisations

1. Chaos Métier — Niveau 4 Master (A12–A16)

Temps : ~2h30
Difficulté : ⭐⭐⭐⭐

Extension du système de chaos métier avec 5 anomalies fonctionnelles ciblant la validation de données et la cohérence métier — toutes silencieuses (aucune erreur HTTP), détectables uniquement par assertions sur les données.

Anomalies implémentées

Code Nom Mécanisme Détection recommandée
A12 Remise fidélité silencieuse orderCount > 5 → condition != -999 toujours vraie → remise -5% jamais accordée Comparer total payé vs calcul attendu sur compte avec historique
A13 Devise affichage USD getCurrency() retourne "USD" au lieu d"EUR" dans /api/products Parser réponse API, valider champ currency
A14 Frais de port doublés shippingCost × 2 dans le total commande Comparer total vs (prix × TVA) + frais port attendu
A15 Corruption historique ×1.1 GET /api/orders retourne totaux × 1.1 Croiser total création commande vs total historique
A16 Annulation sans remboursement stock cancelOrder ne recrédite pas le stock Vérifier stock avant/après commande/après annulation

Fil rouge pédagogique

Toutes les anomalies Master sont silencieuses — aucune erreur HTTP, aucune exception visible. Elles nécessitent des assertions de données (validation métier) pour être détectées. C'est l'enjeu du niveau Master : passer de la détection d'erreurs techniques à la validation fonctionnelle.

Interaction A14 × A1 (cumul niveaux)

En niveau 4, A1 (TVA 19,6%) est aussi active. Formule effective cumulative :

total = (shippingCost × 2 + Σarticles_HT) × 1.196

Cette interaction est documentée par un commentaire pédagogique dans OrderService.java.

Architecture backend

BusinessChaosService.java — 5 nouvelles méthodes : - applyLoyaltyDiscount(total, orderCount, orderNumber, email) → A12 - getCurrency() → A13 — retourne "USD" en niveau 4, "EUR" sinon - applyShippingCost(cost, orderNumber, email) → A14 - applyHistoryCorruption(amount, orderNumber) → A15 - shouldRestockOnCancel(orderNumber, email) → A16

OrderController.java — hooks A15 + A16 : - getUserOrders() : applyHistoryCorruption() sur chaque totalAmount avant retour - cancelOrder() : shouldRestockOnCancel() conditionne le recrédit stock - Requête changée : findByIdWithUserfindByIdWithItemsAndUser (nouvelle méthode repository)

OrderService.java — hooks A14 + A12 dans createOrderFromItems() : - A14 : effectiveShipping = applyShippingCost(shippingCost) avant accumulation articles - A12 : applyLoyaltyDiscount(total, orderCount) après TVA (A1)

ProductController.java — hook A13 : - getAllProducts() : si getCurrency() retourne "USD" → wrapper Map avec currency: "USD" - N0-3 : retour ResponseEntity.ok(products) strictement identique

OrderRepository.java — nouvelle requête JPQL :

@Query("SELECT o FROM Order o JOIN FETCH o.user LEFT JOIN FETCH o.orderItems i LEFT JOIN FETCH i.product WHERE o.id = :id")
Optional<Order> findByIdWithItemsAndUser(@Param("id") Long id);

Modifications BusinessChaosService.java

  • setLevel() : validation étendue à 0-4
  • labelOf() : case 4 → "Master"
  • levelName() : case 4 → "Niveau 4 — Master"
  • anomalyCount() : case 4 → 16
  • anomalyList() : case 4 → liste A1–A16
  • anomalyDescriptions() : bloc if (l >= 4) avec descriptions A12–A16
  • getCounters() : entrées A12_loyalty, A13_currency, A14_shipping, A15_history, A16_cancel
  • reset() : cntA12.set(0) à cntA16.set(0)

2. Frontend React — UI pédagogique

Temps : ~45 min
Difficulté : ⭐⭐

Deux indicateurs pédagogiques visibles dans l'interface — permettent aux étudiants de valider leur compréhension des anomalies.

Bannière Fidélité — MyOrders.jsx

Bannière violette en haut de la page "Mes commandes" indiquant le statut du programme fidélité :

  • Badge "✓ Éligible" si orders.length >= 6 → la remise devrait s'appliquer
  • Badge "N/6" sinon (ex : 3/6)
  • Compteur basé sur TOUTES les commandes (y compris CANCELLED) pour correspondre exactement à countByUserId() côté backend
// Alignement intentionnel avec le backend
const loyaltyCount = orders.length; // TOUTES commandes, pas seulement ACTIVE
const isLoyaltyEligible = loyaltyCount >= 6;

Piège pédagogique

En niveau 4, la bannière affiche "✓ Éligible" et la remise "s'applique automatiquement" — mais A12 la supprime silencieusement. L'étudiant voit le message, paie le prix plein, et doit détecter l'écart par assertion sur le total.

Bandeau devise — Products.jsx

Bandeau jaune d'avertissement ⚠️ Les prix sont affichés en USD visible uniquement quand currency !== 'EUR' (i.e. en niveau 4 uniquement).

  • State currency initialisé à 'EUR'
  • fetchProducts() : setCurrency(data.currency || 'EUR') — fallback 'EUR' si champ absent
  • Bandeau conditionnel {currency !== 'EUR'} — invisible en N0-3

3. Revue chaos sécurité — non-régression complète

Temps : ~45 min

Audit complet de tous les fichiers consommateurs de SecurityChaosService après les modifications de la session.

Faille Controller Modifié session 14 ?
S1 SQLi ProductController ✅ Non (seul getAllProducts modifié — searchProducts inchangé)
S2 IDOR OrderController ✅ Non
S3 Hash exposé UserController ✅ Non
S4 XSS stocké OrderController ✅ Non
S5 Prix falsifié OrderController ✅ Non
S6 Timing attack AuthController ✅ Non
S7 Token faible AuthController ✅ Non
S8 Path traversal OrderController ✅ Non
S9 Mass assignment UserController ✅ Non
S10–S12 Portail admin AdminPortalController ✅ Non

Conclusion : aucune régression sécurité — les deux corrections dans OrderController (getUserOrders et createOrderFromItems) sont dans des méthodes entièrement séparées des hooks sécurité.


🐛 Bugs corrigés

# Fichier Bug Correction Sévérité
1 Products.jsx if (data.currency) ne réinitialisait pas à 'EUR' au retour en N0-3 setCurrency(data.currency \|\| 'EUR') ⭐⭐
2 MyOrders.jsx orders.filter(o => o.status !== 'CANCELLED').length divergeait de countByUserId() backend orders.length (toutes commandes) ⭐⭐⭐
3 MyOrders.jsx "devrait s'appliquer" suggérait une incertitude côté UI "s'applique automatiquement"
4 monitoring.html Texte Sortie parasite en ligne 1 avant <!DOCTYPE html> Suppression ⭐⭐
5 BusinessChaosController.java Javadoc { "level": 0-3 } incorrect Corrigé en 0-4
6 OrderService.java Interaction A14×A1 non documentée Commentaire pédagogique ajouté
7 OrderController.java Cast row[2] silencieux si type inattendu (BigDecimal vs autre) Cast défensif 3 niveaux : null / BigDecimal / toString() ⭐⭐⭐
8 OrderService.java orderNumber dans log A14 = "pending-email" au lieu de ORD-xxx order.getOrderNumber() (appelé après buildOrderWithCard) ⭐⭐

🤖 Erreurs imputables à Claude AI — Session 14

❌ Erreur S14-1 — if (data.currency) sans fallback

Ce que j'ai proposé : dans Products.jsx, if (data.currency) setCurrency(data.currency) — ce qui laisse currency à "USD" même après retour en niveau 0-3 (car l'API retourne alors products[] sans champ currency).

Ce qui s'est passé : le bandeau "USD" restait visible après désactivation du chaos — régression UX détectée lors de la revue.

Pourquoi c'était une erreur : ne pas avoir anticipé le cas "champ absent = retour à la valeur par défaut" — pattern courant en React avec des réponses API variables.

Temps perdu : ~5 min | Sévérité : ⭐⭐


❌ Erreur S14-2 — Compteur fidélité excluant les commandes annulées

Ce que j'ai proposé : orders.filter(o => o.status !== 'CANCELLED').length pour le compteur fidélité dans MyOrders.jsx.

Ce qui s'est passé : le backend utilise countByUserId() qui compte toutes les commandes sans filtre — l'UI divergeait donc du comportement backend, rendant l'anomalie A12 non reproductible proprement.

Pourquoi c'était une erreur : ne pas avoir audité l'implémentation backend countByUserId() avant de coder la logique frontend.

Temps perdu : ~10 min | Sévérité : ⭐⭐⭐


📊 Récapitulatif Session 14

# Erreur Temps perdu Sévérité
S14-1 Fallback currency manquant dans Products.jsx ~5 min ⭐⭐
S14-2 Compteur fidélité frontend/backend désaligné ~10 min ⭐⭐⭐
TOTAL ~15 min

Pattern : ne pas auditer l'implémentation backend avant de coder la logique frontend miroir — les deux côtés doivent utiliser exactement les mêmes règles de comptage/calcul.


📁 Fichiers modifiés

Backend Java

  • chaos/BusinessChaosService.java — compteurs A12–A16, 5 méthodes, reset, labels, descripteurs
  • controller/BusinessChaosController.java — validation level > 4, javadoc corrigée
  • controller/OrderController.java — hooks A15 (history corruption) + A16 (restock cancel), cast défensif row[2], requête findByIdWithItemsAndUser
  • controller/ProductController.java — hook A13 (currency USD), injection BusinessChaosService
  • service/OrderService.java — hooks A14 (shipping ×2) + A12 (loyalty discount), commentaire A14×A1
  • repository/OrderRepository.java — méthode findByIdWithItemsAndUser

Frontend React

  • pages/MyOrders.jsx — bannière programme fidélité, compteur toutes commandes
  • pages/Products.jsx — state currency, bandeau USD conditionnel, fallback 'EUR'

Monitoring

  • monitoring/public/admin/monitoring.html — suppression texte parasite Sortie, tableau anomalies A1–A16, LEVEL_THRESHOLDS.master = 4

🎓 Conclusion Session 14

Chaos Métier niveau 4 Master — 5 anomalies A12–A16, toutes silencieuses, nécessitant assertion de données
Interaction A14×A1 documentée — formule cumulative commentée dans OrderService.java
UI pédagogique — bannière fidélité MyOrders.jsx + bandeau devise Products.jsx
8 bugs corrigés — dont 2 divergences frontend/backend sur des règles de calcul
Revue sécurité complète — 12 failles S1–S12 auditées, zéro régression
Non-régression chaos — A1–A11, Scripting, Fonctionnel, Sécurité inchangés

Ratio temps productif / temps total : ~95%
Total cumulé projet : ~87h de vibe coding sur 14 sessions
Prochaine étape : Build Docker perfshop-backend:v34 + perfshop-frontend:v34, déploiement NAS — puis mise à jour mkdocs/docs/chaos/business.md et roadmap