Plan d'amélioration

Accueil
# UtilityLogs — Plan d'amélioration (issu de l'audit de recette) ## Contexte du projet UtilityLogs est un site d'analyse de logs World of Warcraft (extension actuelle : Midnight, WoW 12.x). Les données proviennent de l'API GraphQL v2 de Warcraft Logs, récupérées en tâche de fond (fair-use) puis stockées en base locale. Aucune requête WCL n'est faite au moment de la visite. **Proposition de valeur** : mettre en évidence les actions *utiles* des joueurs qui font réussir les donjons et raids — tout ce que les damage meters ne mesurent pas : interruptions, dispels, cooldowns défensifs externes, battle rez, CC, soaks. **Règle générale pour toutes les tâches** : ne pas casser le pipeline d'ingestion WCL existant. Toute modification de la taxonomie doit être rétrocompatible avec les données déjà en base (prévoir une migration si le schéma change). --- ## TÂCHE 0 — [URGENT — BUG] Gestion d'erreur sur les IDs inexistants **Problème** : `GET /player/100` (ID inexistant) provoque une erreur 500 qui rend le serveur indisponible pendant plusieurs minutes. **À faire** : - Auditer toutes les routes paramétrées (`/player/{id}`, `/fight/{id}`, `/report/{code}`) : toute ressource introuvable doit renvoyer un 404 propre avec une page d'erreur utilisateur. - Identifier pourquoi le serveur reste indisponible plusieurs minutes (crash du process ? pool de connexions DB épuisé ? requête sans timeout ?) et corriger la cause racine. - Ajouter un handler d'erreur global : aucune exception non gérée ne doit faire tomber le serveur. - Ajouter des tests : ID inexistant, ID non numérique, ID négatif, injection dans le paramètre. **Critères d'acceptation** : `/player/100`, `/fight/0`, `/report/zzz` renvoient un 404 en < 1 s ; le serveur continue de répondre normalement aux autres requêtes. --- ## TÂCHE 1 — [FOND — CRITIQUE] Refonte de la taxonomie des catégories **Problème actuel** : incohérences et chevauchements. - « Rals./Roots » mélange deux mécaniques distinctes (slow = déplacement réduit ; root = immobilisation). - « Stuns/CCs » est un fourre-tout : « CC » est une méta-catégorie qui englobe stuns, roots, slows, peurs, polymorphes. Un Polymorph n'a pas de catégorie claire aujourd'hui. - La page d'accueil dit « Stuns, slows, externes et dispels » alors que la page /utility sépare différemment : harmoniser les libellés partout. **Nouvelle taxonomie cible** (chaque sort appartient à UNE seule catégorie) : 1. **Interruptions** (kicks au sens strict : sort dédié, sur le school lock) 2. **Crowd Control** — avec sous-types : Stun, Root, Slow, Incapacitate (Polymorph, Imprison, Freezing Trap…), Disorient (Blind, Dragon's Breath…), Knockback/Déplacement (Typhoon, Ring of Peace, Death Grip) 3. **Dispels** — sous-types : dispel allié (magie/maladie/poison/malédiction), purge ennemi (offensive) 4. **Défensifs externes** — sous-types : réduction de dégâts ciblée (Pain Suppression, Ironbark, Blessing of Sacrifice), réduction de raid (Rallying Cry, Darkness, Anti-Magic Zone), heal d'urgence/transfert (Spirit Link Totem, Life Cocoon) 5. **Résurrections de combat** (battle rez : Rebirth, Raise Ally, Soulstone, Intercession) 6. **Soutien de ressource** (Innervate, Power Infusion — optionnel, phase 2) **Cas particuliers à traiter explicitement** : - **Cécité (Blind, Rogue)** : actuellement classée en « Interruptions ». La déplacer en CC > Disorient. Elle interrompt une incantation mais n'est pas un kick (cassable par les dégâts, pas de school lock fiable). - **Sigil of Silence (DH Vengeance)** : interrupt de zone, à classer en Interruptions. - **Interrupts de pet** (Spell Lock de la Felhunter du Démoniste, kicks de pets Chasseur) : doivent être attribués au propriétaire du pet dans les Interruptions. Vérifier que l'ingestion WCL remonte bien les events des pets avec résolution du owner. - **Shadow Word: Death (Prêtre)** : ne pas le compter comme interrupt générique ; le Prêtre n'a pas de kick natif — ajouter une note explicative sur sa fiche/classe. **À faire techniquement** : - Externaliser la taxonomie dans un fichier de données (JSON/YAML ou table DB) : `{ spell_id, classe, spécialisation(s), catégorie, sous_type, actif_depuis_patch, retiré_depuis_patch }`. Ne PAS coder les sorts en dur dans la logique. - Écrire une migration qui reclasse les données existantes selon la nouvelle taxonomie. - Harmoniser tous les libellés UI (accueil, /utility, /fight, tooltips) sur cette taxonomie. **Critères d'acceptation** : chaque sort n'apparaît que dans une catégorie ; les libellés sont identiques sur toutes les pages ; Cécité n'est plus dans Interruptions ; un test vérifie qu'aucun spell_id n'est présent dans deux catégories. --- ## TÂCHE 2 — [FOND — CRITIQUE] Catégories manquantes : battle rez, externals détaillés, soaks **À faire** : - Implémenter l'ingestion des **résurrections de combat** (event type `resurrect` dans WCL, filtré sur les sorts de battle rez) : qui a rez, qui a été rez, à quel timestamp du combat. - Détailler les **défensifs externes** selon les sous-types de la Tâche 1 : l'ingestion doit capter le lanceur, la cible, et le timestamp. - Vérifier la liste des externes : exclure les effets passifs ou auto (Atonement, Beacon of Light ne sont pas des « externes » actifs). - **Phase 2 (ne pas bloquer)** : soaks de mécaniques et immunités défensives (Ice Block, Divine Shield utilisés pour absorber une mécanique). Nécessite une table de correspondance boss → mécaniques soakables : créer la structure de données, remplir pour 2-3 boss pilotes. **Couverture par classe à compléter** (sous-représentations relevées en audit) : - Voleur : Kick, Blind, Gouge, Sap, Smoke Bomb (défensif de groupe majeur en M+) - Mage : Polymorph, Dragon's Breath, Frost Nova, Ring of Frost - Chasseur : Freezing Trap, Tar Trap, Concussive Shot, Binding Shot, interrupts de pet - Demon Hunter : Imprison, Chaos Nova, Sigil of Silence/Misery/Chains - Chaman et Moine : vérifier que leurs kicks (Wind Shear, Spear Hand Strike) sont bien ingérés - Démoniste : interrupt de Felhunter attribué au joueur **Critères d'acceptation** : sur un rapport de test contenant un battle rez, celui-ci apparaît dans la vue du combat ; chaque classe a au moins ses sorts emblématiques listés dans la taxonomie ; un script de contrôle liste les spécialisations sans aucun sort par catégorie (pour détecter les trous de couverture). --- ## TÂCHE 3 — [FOND — IMPORTANT] Pondération : criticité du sort interrompu **Problème** : un interrupt sur un sort qui wipe le raid vaut autant qu'un interrupt anecdotique. Le site compte les actions mais ne les qualifie pas. **À faire** : - Créer une table `enemy_spell_criticality` : `{ spell_id_ennemi, rencontre/donjon, niveau ∈ {critique, important, mineur}, commentaire }`. - Remplir manuellement pour les donjons de la saison M+ en cours et le raid actuel (sources : guides Wowhead/Archon des priorités d'interrupt). Prévoir un niveau par défaut « non classé ». - Dans le tableau des interruptions de `/fight/{id}` : badge visuel sur les sorts critiques (icône « ! » rouge pour critique, orange pour important) + tooltip expliquant pourquoi. - Préparer (sans l'afficher encore) un « score d'utilité » par joueur : somme pondérée interruptions (×criticité) + dispels + CC + externals + battle rez. Les coefficients doivent être dans un fichier de configuration, pas en dur. **Critères d'acceptation** : sur un combat de test, les interrupts de sorts critiques sont visuellement distincts ; la table de criticité est éditable sans redéploiement. --- ## TÂCHE 4 — [FORME — IMPORTANT] Vue par combat : afficher TOUS les utilitaires **Problème** : `/fight/{id}` ne montre que les interruptions, alors que c'est la page centrale du site. Les dispels, CC, externals, battle rez n'y figurent pas. **À faire** : - Ajouter dans `/fight/{id}` des sections sur le modèle du tableau d'interruptions existant : « Dispels », « Crowd Control », « Défensifs externes », « Résurrections de combat » (avec lanceur, sort, cible, icône, compteur ; timestamp pour les battle rez). - Masquer les sections vides plutôt que d'afficher des tableaux vides. - **Remplacer le graphique « Activité par joueur »** : supprimer la métrique « Lancers » (nombre total de sorts lancés — sans valeur analytique). À la place : barres empilées par joueur montrant interruptions / dispels / CC / externals / battle rez, avec légende et couleurs distinctes. Quand le score d'utilité (Tâche 3) sera activé, trier par ce score. - Ajouter un tooltip pédagogique sur chaque titre de section (une phrase : pourquoi cette métrique compte). Centraliser ces textes pour la future i18n. **Critères d'acceptation** : un combat contenant dispels + stuns + un battle rez les affiche tous ; le graphique ne montre plus « Lancers ». --- ## TÂCHE 5 — [FORME — IMPORTANT] Navigation joueurs + fiche joueur + classement corrigé **Problèmes** : - Les noms de joueurs dans `/fight/{id}` sont des liens qui ne naviguent nulle part. - Le bouton « Analyse » de `/player` est inactif (routing client-side SPA non opérationnel). - Le classement d'accueil trie par total brut d'interruptions toutes sessions confondues : il favorise le volume de logs uploadés, pas la qualité. **À faire** : - Réparer le routing client-side ; chaque nom de joueur (combat, classements) doit mener à `/player/{id}`. - Construire la fiche joueur : classe/spé, top sorts utilisés par catégorie, ratio interruptions par combat ET par minute de combat, nombre de combats analysés, derniers combats (liens). - Sur l'accueil : remplacer le tri « total brut » par « interruptions par combat » (ou par minute) avec un seuil minimal de combats (ex. ≥ 5) pour éviter le bruit statistique. Garder le total brut en colonne secondaire. **Critères d'acceptation** : navigation fonctionnelle depuis toutes les pages vers la fiche joueur ; le classement affiche un ratio et un nombre de combats ; un joueur avec 2 combats n'apparaît pas en tête du classement. --- ## Ordre d'exécution recommandé 1. Tâche 0 (bug 500) — immédiat, isolé, sans dépendance. 2. Tâche 1 (taxonomie) — fondation de tout le reste, inclut la migration de données. 3. Tâche 2 (catégories manquantes) — dépend de la taxonomie. 4. Tâche 4 (vue par combat) — dépend des données des tâches 1 et 2. 5. Tâche 5 (navigation/fiche joueur) — indépendante, peut être parallélisée. 6. Tâche 3 (pondération) — en dernier : nécessite la table de criticité et bénéficie de tout le reste. ## Consignes transverses - Tests : chaque tâche livre ses tests (unitaires sur la classification des sorts ; intégration sur les routes). - i18n : tous les nouveaux libellés passent par le système de traduction existant (ou, s'il n'existe pas encore, créer des fichiers de traduction JSON dès maintenant — le site sera multilingue). - Performance : les nouvelles sections de `/fight/{id}` doivent lire la base locale uniquement, jamais l'API WCL en direct. - Données : si l'ingestion doit être enrichie (battle rez, events de pets), prévoir un script de ré-ingestion des rapports déjà en base, en respectant le quota de points de l'API WCL (étaler dans le temps).