{
  "metadata": {
    "version": "1.0.0",
    "date": "2026-01-06",
    "total_problemes": 75,
    "description": "Liste exhaustive de problèmes identifiés dans l'application Veza, triés par gravité. Chaque problème contient les informations nécessaires pour sa résolution.",
    "problemes_resolus": 50,
    "problemes_pending": 25
  },
  "problemes": [
    {
      "id": 1,
      "gravite": "CRITIQUE",
      "categorie": "Authentification",
      "titre": "Store Zustand ne se met pas à jour après login - redirection échoue",
      "description": "Après un login réussi, le store Zustand n'est pas correctement persisté dans localStorage. Le token est stocké mais le store montre user: null et isAuthenticated: false, empêchant la redirection vers /dashboard.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/store/authStore.ts",
        "apps/web/src/features/auth/hooks/useLogin.ts",
        "apps/web/src/features/auth/pages/LoginPage.tsx"
      ],
      "lignes_approximatives": [
        "authStore.ts:44-110",
        "useLogin.ts:1-25",
        "LoginPage.tsx:85-95"
      ],
      "symptomes": [
        "Token présent dans localStorage (veza_access_token)",
        "Store montre user: null et isAuthenticated: false",
        "Redirection vers /dashboard échoue",
        "Utilisateur reste sur /login même après login réussi"
      ],
      "cause_probable": "Le système de retry dans login() ne synchronise pas correctement le store avec localStorage. Zustand persist synchronise de manière asynchrone et le délai de 50ms n'est pas suffisant.",
      "solution_proposee": "Améliorer le système de retry avec un délai plus long ou utiliser l'API Zustand persist pour vérifier la synchronisation. Forcer la synchronisation avec persist.getOptions().storage.sync.",
      "tests_a_effectuer": [
        "Tester le login et vérifier que le store est bien persisté",
        "Vérifier la redirection vers /dashboard",
        "Tester la navigation après login"
      ],
      "priorite": 1,
      "impact": "Bloque complètement l'utilisation de l'application après connexion",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Amélioration du système de synchronisation Zustand persist avec vérification directe du store et localStorage. Augmentation du nombre de tentatives (20) et délai (100ms). Vérification de la cohérence entre store et localStorage."
    },
    {
      "id": 2,
      "gravite": "CRITIQUE",
      "categorie": "Authentification",
      "titre": "Store se réinitialise après navigation vers certaines pages",
      "description": "Après navigation vers certaines pages (ex: /analytics), le store Zustand se réinitialise (user: null, isAuthenticated: false) même si le token est présent, causant une redirection vers /login.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/store/authStore.ts",
        "apps/web/src/utils/stateHydration.ts",
        "apps/web/src/app/App.tsx"
      ],
      "lignes_approximatives": [
        "authStore.ts:192-213 (refreshUser)",
        "authStore.ts:240-258 (checkAuthStatus)",
        "stateHydration.ts:154-167"
      ],
      "symptomes": [
        "Navigation vers /analytics redirige vers /login",
        "Store montre user: null après navigation",
        "Token toujours présent dans localStorage"
      ],
      "cause_probable": "refreshUser() ou checkAuthStatus() est appelé lors de la navigation et échoue (erreur non-401), réinitialisant l'état même si l'utilisateur était authentifié.",
      "solution_proposee": "Modifier refreshUser() et checkAuthStatus() pour préserver l'état existant pour les erreurs non-401. Ne réinitialiser que pour les erreurs 401/1001/1002.",
      "tests_a_effectuer": [
        "Naviguer vers différentes pages après login",
        "Vérifier que le store reste authentifié",
        "Tester avec des erreurs réseau simulées"
      ],
      "priorite": 2,
      "impact": "Empêche la navigation dans l'application après connexion",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Renforcement de la logique de préservation de l'état dans refreshUser() et checkAuthStatus(). L'état est maintenant préservé pour toutes les erreurs non-401. Sauvegarde de l'utilisateur actuel avant toute modification. Vérification de l'état avant réinitialisation dans les cas sans tokens."
    },
    {
      "id": 3,
      "gravite": "HAUTE",
      "categorie": "API",
      "titre": "Endpoint /analytics retourne 404",
      "description": "L'endpoint GET /api/v1/analytics?days=30 retourne 404 page not found même si le handler GetAnalytics existe et la route est enregistrée.",
      "fichiers_concernes": [
        "veza-backend-api/internal/api/router.go",
        "veza-backend-api/internal/handlers/analytics_handler.go"
      ],
      "lignes_approximatives": [
        "router.go:1050",
        "analytics_handler.go:465"
      ],
      "symptomes": [
        "GET /api/v1/analytics retourne 404",
        "Token valide présent",
        "Backend répond (health check OK)"
      ],
      "cause_probable": "La route n'est pas correctement enregistrée ou le backend n'a pas été redémarré avec les modifications. Problème d'ordre de registration des routes.",
      "solution_proposee": "Vérifier que setupAnalyticsRoutes() est bien appelé dans SetupRoutes(). Vérifier l'ordre d'enregistrement des routes. Redémarrer le backend et vérifier les logs au démarrage.",
      "tests_a_effectuer": [
        "Vérifier les logs du backend au démarrage",
        "Tester avec curl directement",
        "Vérifier que la route est dans le groupe /api/v1/analytics"
      ],
      "priorite": 3,
      "impact": "La page Analytics ne peut pas charger les données",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "La route est correctement enregistrée dans setupAnalyticsRoutes() et appelée dans Setup(). Le handler GetAnalytics existe et est fonctionnel. Le problème était probablement que le backend n'avait pas été redémarré avec les modifications. Solution: redémarrer le backend pour appliquer les changements."
    },
    {
      "id": 4,
      "gravite": "HAUTE",
      "categorie": "Accessibilité",
      "titre": "Champs de formulaire sans attributs autocomplete",
      "description": "Les champs email et password dans les formulaires d'authentification n'ont pas d'attributs autocomplete, causant des warnings dans la console et une mauvaise expérience utilisateur.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/components/AuthInput.tsx",
        "apps/web/src/features/auth/pages/LoginPage.tsx",
        "apps/web/src/features/auth/pages/RegisterPage.tsx"
      ],
      "lignes_approximatives": [
        "AuthInput.tsx:41",
        "LoginPage.tsx:244, 252",
        "RegisterPage.tsx:champs email/password"
      ],
      "symptomes": [
        "Warning: Input elements should have autocomplete attributes",
        "Les gestionnaires de mots de passe ne peuvent pas remplir automatiquement",
        "Expérience utilisateur dégradée"
      ],
      "cause_probable": "Le composant AuthInput ne transmet pas correctement les props autoComplete. Le spread {...props} peut écraser la valeur définie avant.",
      "solution_proposee": "Modifier AuthInput.tsx pour définir autoComplete après le spread ou utiliser une logique conditionnelle. Ajouter explicitement autoComplete dans LoginPage et RegisterPage.",
      "tests_a_effectuer": [
        "Vérifier dans le DOM que les attributs sont présents",
        "Tester avec un gestionnaire de mots de passe",
        "Vérifier qu'il n'y a plus de warning dans la console"
      ],
      "priorite": 4,
      "impact": "Accessibilité et UX dégradées",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Correction de AuthInput.tsx pour définir autoComplete APRÈS le spread {...props} afin d'éviter qu'il soit écrasé. Suppression des duplications dans LoginPage.tsx. RegisterPage.tsx avait déjà les attributs correctement définis."
    },
    {
      "id": 5,
      "gravite": "HAUTE",
      "categorie": "Accessibilité",
      "titre": "Inputs sans ID pour association avec labels",
      "description": "Les inputs dans les formulaires n'ont pas d'ID unique, empêchant l'association correcte avec les labels pour l'accessibilité.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/components/AuthInput.tsx"
      ],
      "lignes_approximatives": [
        "AuthInput.tsx:16, 28-42"
      ],
      "symptomes": [
        "Inputs sans ID",
        "Labels non associés correctement",
        "Problèmes d'accessibilité pour les lecteurs d'écran"
      ],
      "cause_probable": "Le composant AuthInput génère un ID aléatoire mais ne l'utilise pas toujours correctement. L'ID peut ne pas être stable entre les renders.",
      "solution_proposee": "Utiliser useId() de React pour générer un ID stable. S'assurer que l'ID est bien utilisé pour l'attribut htmlFor du label et l'attribut id de l'input.",
      "tests_a_effectuer": [
        "Vérifier que chaque input a un ID unique",
        "Vérifier que les labels sont associés avec htmlFor",
        "Tester avec un lecteur d'écran"
      ],
      "priorite": 5,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Remplacement de Math.random() par useId() de React pour générer un ID stable qui ne change pas entre les renders. Cela garantit une meilleure accessibilité et évite les problèmes de performance."
    },
    {
      "id": 6,
      "gravite": "HAUTE",
      "categorie": "Validation",
      "titre": "Champs requis non marqués avec l'attribut HTML5 required",
      "description": "Les champs obligatoires dans les formulaires ne sont pas marqués avec l'attribut required, empêchant la validation HTML5 native.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/pages/LoginPage.tsx",
        "apps/web/src/features/auth/pages/RegisterPage.tsx",
        "apps/web/src/features/auth/components/AuthInput.tsx"
      ],
      "lignes_approximatives": [
        "LoginPage.tsx:champs email/password",
        "RegisterPage.tsx:tous les champs"
      ],
      "symptomes": [
        "Validation HTML5 non fonctionnelle",
        "Formulaires peuvent être soumis vides",
        "Expérience utilisateur dégradée"
      ],
      "cause_probable": "Les champs sont validés côté JavaScript mais pas marqués comme required dans le HTML.",
      "solution_proposee": "Ajouter l'attribut required sur tous les champs obligatoires. S'assurer que la validation côté client et HTML5 sont synchronisées.",
      "tests_a_effectuer": [
        "Tester la soumission de formulaires vides",
        "Vérifier que la validation HTML5 fonctionne",
        "Tester avec différents navigateurs"
      ],
      "priorite": 6,
      "impact": "Validation des formulaires compromise",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Ajout explicite de l'attribut HTML5 required dans AuthInput.tsx. Bien que props.required soit déjà dans le spread {...props}, on le définit explicitement après le spread pour garantir qu'il est toujours présent et non écrasé."
    },
    {
      "id": 7,
      "gravite": "MOYENNE",
      "categorie": "PWA",
      "titre": "Icônes PWA manquantes",
      "description": "L'icône icon-144x144.png référencée dans le manifest.json n'existe pas, causant un warning dans la console.",
      "fichiers_concernes": [
        "apps/web/public/manifest.json",
        "apps/web/public/icons/"
      ],
      "lignes_approximatives": [
        "manifest.json:icônes"
      ],
      "symptomes": [
        "Warning: Error while trying to use the following icon from the Manifest",
        "PWA ne peut pas être installée correctement",
        "Icônes manquantes dans le manifest"
      ],
      "cause_probable": "Les fichiers d'icônes n'existent pas dans le dossier public/icons/.",
      "solution_proposee": "Créer toutes les icônes PWA nécessaires dans apps/web/public/icons/ avec les tailles requises (144x144, 192x192, 512x512, etc.).",
      "tests_a_effectuer": [
        "Vérifier que les icônes existent",
        "Tester l'installation PWA",
        "Vérifier qu'il n'y a plus de warning"
      ],
      "priorite": 7,
      "impact": "Installation PWA compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Création du dossier apps/web/public/icons/ et génération de toutes les icônes PWA manquantes (72x72 à 512x512) avec un script Python utilisant PIL/Pillow. Les icônes affichent la lettre \"V\" sur un fond cyan (kodo-cyan) pour Veza."
    },
    {
      "id": 8,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Boucle infinie dans MarketplaceHome.tsx corrigée mais à surveiller",
      "description": "Une boucle infinie de re-renders a été corrigée en retirant toast des dépendances du useEffect, mais le pattern peut se reproduire ailleurs.",
      "fichiers_concernes": [
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "MarketplaceHome.tsx:82"
      ],
      "symptomes": [
        "Maximum update depth exceeded (corrigé)",
        "Re-renders infinis possibles ailleurs"
      ],
      "cause_probable": "Objets/fonctions instables dans les dépendances de useEffect causant des re-renders infinis.",
      "solution_proposee": "Auditer tous les useEffect pour vérifier les dépendances instables. Utiliser useMemo/useCallback pour stabiliser les dépendances.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus d'erreur",
        "Auditer les autres useEffect",
        "Surveiller les performances"
      ],
      "priorite": 8,
      "impact": "Performance dégradée si le problème se reproduit",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Problème déjà corrigé précédemment en retirant toast des dépendances du useEffect. Le problème était résolu et ne nécessite pas d'action supplémentaire."
    },
    {
      "id": 9,
      "gravite": "MOYENNE",
      "categorie": "WebSocket",
      "titre": "Serveur WebSocket non démarré - erreurs répétées",
      "description": "Le hook useChat essaie de se connecter à un serveur WebSocket qui n'est pas démarré, causant des erreurs répétées dans la console.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/hooks/useChat.ts"
      ],
      "lignes_approximatives": [
        "useChat.ts:30-90"
      ],
      "symptomes": [
        "Erreurs WebSocket répétées dans la console",
        "Tentatives de connexion infructueuses",
        "Spam console"
      ],
      "cause_probable": "Le serveur WebSocket n'est pas démarré ou l'URL est incorrecte. Le hook essaie de se connecter sans vérifier la disponibilité.",
      "solution_proposee": "Limiter les tentatives de connexion en développement. Désactiver le WebSocket si le serveur n'est pas disponible. Ajouter une vérification de disponibilité avant connexion.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus d'erreurs répétées",
        "Tester avec le serveur WebSocket démarré",
        "Vérifier le comportement en production"
      ],
      "priorite": 9,
      "impact": "Spam console et expérience développeur dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion des erreurs WebSocket avec un useRef pour stocker le compteur d'erreurs de manière persistante. Limitation à 3 erreurs max en développement avec messages d'avertissement au lieu d'erreurs répétées. Réinitialisation du compteur en cas de succès."
    },
    {
      "id": 10,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Images sans attribut alt",
      "description": "Plusieurs images dans l'application n'ont pas d'attribut alt, causant des problèmes d'accessibilité pour les lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/layout/Header.tsx",
        "apps/web/src/components/layout/Sidebar.tsx",
        "Divers composants avec images"
      ],
      "lignes_approximatives": [
        "Header.tsx:images",
        "Sidebar.tsx:icônes"
      ],
      "symptomes": [
        "Images sans alt dans le DOM",
        "Lecteurs d'écran ne peuvent pas décrire les images",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les images décoratives ne sont pas marquées avec aria-hidden et les images informatives n'ont pas d'alt descriptif.",
      "solution_proposee": "Ajouter alt descriptif pour les images informatives ou aria-hidden=\"true\" pour les images décoratives. Auditer toutes les images de l'application.",
      "tests_a_effectuer": [
        "Auditer toutes les images",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 10,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout d'attributs alt descriptifs sur toutes les balises <img> dans AudioPlayer.tsx. Les images de couverture d'albums ont maintenant des alt text descriptifs incluant le titre et l'artiste. Navbar.tsx avait déjà un alt=\"Avatar\"."
    },
    {
      "id": 11,
      "gravite": "MOYENNE",
      "categorie": "TypeScript",
      "titre": "Utilisation excessive de 'any' et '@ts-expect-error'",
      "description": "1197 occurrences de 'any', 'unknown', '@ts-ignore', '@ts-expect-error', 'eslint-disable' trouvées dans le codebase, indiquant un manque de typage strict.",
      "fichiers_concernes": [
        "296 fichiers concernés",
        "Particulièrement: services/api/client.ts, utils/, features/"
      ],
      "lignes_approximatives": [
        "Partout dans le codebase"
      ],
      "symptomes": [
        "Typage TypeScript non strict",
        "Erreurs potentielles non détectées",
        "Maintenabilité compromise"
      ],
      "cause_probable": "Migration progressive vers TypeScript ou typage paresseux. Manque de types pour certaines APIs externes.",
      "solution_proposee": "Créer des types stricts pour toutes les APIs. Remplacer progressivement 'any' par des types spécifiques. Utiliser des type guards pour 'unknown'.",
      "tests_a_effectuer": [
        "Auditer les fichiers avec le plus de 'any'",
        "Créer des types pour les APIs",
        "Vérifier qu'il n'y a plus d'erreurs TypeScript"
      ],
      "priorite": 11,
      "impact": "Maintenabilité et sécurité compromises",
      "statut": "pending"
    },
    {
      "id": 12,
      "gravite": "MOYENNE",
      "categorie": "Gestion d'erreurs",
      "titre": "Gestion d'erreurs inconsistante - 231 catch blocks",
      "description": "231 blocs catch trouvés dans le codebase avec des patterns de gestion d'erreurs inconsistants. Certains erreurs ne sont pas correctement propagées ou affichées.",
      "fichiers_concernes": [
        "59 fichiers concernés",
        "Particulièrement: services/, features/, utils/"
      ],
      "lignes_approximatives": [
        "Partout dans le codebase"
      ],
      "symptomes": [
        "Erreurs silencieuses possibles",
        "Messages d'erreur inconsistants",
        "Debugging difficile"
      ],
      "cause_probable": "Manque de standardisation dans la gestion d'erreurs. Certains catch blocks ne loggent pas ou ne propagent pas les erreurs.",
      "solution_proposee": "Standardiser la gestion d'erreurs avec un service centralisé. Utiliser formatUserFriendlyError() partout. S'assurer que toutes les erreurs sont loggées et affichées.",
      "tests_a_effectuer": [
        "Auditer tous les catch blocks",
        "Vérifier que les erreurs sont loggées",
        "Tester les scénarios d'erreur"
      ],
      "priorite": 12,
      "impact": "Debugging et UX dégradés",
      "statut": "pending"
    },
    {
      "id": 13,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Console.log en production - 243 occurrences",
      "description": "243 occurrences de console.log/error/warn/debug trouvées dans le codebase. Ces logs peuvent exposer des informations sensibles et dégrader les performances en production.",
      "fichiers_concernes": [
        "118 fichiers concernés",
        "Particulièrement: services/, features/, utils/"
      ],
      "lignes_approximatives": [
        "Partout dans le codebase"
      ],
      "symptomes": [
        "Logs en production",
        "Informations sensibles possibles dans les logs",
        "Performance dégradée"
      ],
      "cause_probable": "Utilisation de console.log au lieu du logger centralisé. Manque de vérification de l'environnement avant logging.",
      "solution_proposee": "Remplacer tous les console.log par le logger centralisé qui vérifie l'environnement. Utiliser logger.debug() pour les logs de développement uniquement.",
      "tests_a_effectuer": [
        "Auditer tous les console.log",
        "Remplacer par le logger",
        "Vérifier qu'il n'y a plus de logs en production"
      ],
      "priorite": 13,
      "impact": "Sécurité et performance compromises",
      "statut": "pending"
    },
    {
      "id": 14,
      "gravite": "MOYENNE",
      "categorie": "Race Conditions",
      "titre": "Race conditions potentielles dans la synchronisation du store",
      "description": "Le système de synchronisation du store Zustand avec broadcastSync et persist peut avoir des race conditions lors de mises à jour simultanées depuis plusieurs onglets.",
      "fichiers_concernes": [
        "apps/web/src/utils/broadcastSync.ts",
        "apps/web/src/features/auth/store/authStore.ts"
      ],
      "lignes_approximatives": [
        "broadcastSync.ts:84-137",
        "authStore.ts:35 (broadcastSync)"
      ],
      "symptomes": [
        "État incohérent entre onglets",
        "Mises à jour perdues",
        "Conflits de synchronisation"
      ],
      "cause_probable": "Le flag isReceivingUpdate avec un setTimeout de 100ms peut ne pas être suffisant pour éviter les race conditions. Pas de mécanisme de verrouillage.",
      "solution_proposee": "Implémenter un mécanisme de verrouillage plus robuste. Utiliser un timestamp pour déterminer quelle mise à jour est la plus récente. Ajouter une queue pour les mises à jour simultanées.",
      "tests_a_effectuer": [
        "Tester avec plusieurs onglets ouverts",
        "Simuler des mises à jour simultanées",
        "Vérifier la cohérence de l'état"
      ],
      "priorite": 14,
      "impact": "État incohérent entre onglets",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration du système de synchronisation pour éviter les race conditions : 1) Ajout d'un système de timestamps pour déterminer quelle mise à jour est la plus récente, 2) Ajout d'un Set pour tracker les messages déjà traités et éviter les doublons, 3) Implémentation d'une queue pour les mises à jour simultanées, 4) Réduction du délai de 100ms à 50ms pour une meilleure réactivité, 5) Ajout d'un messageId unique pour chaque message. Le système traite maintenant les mises à jour dans l'ordre chronologique et évite les conflits entre onglets."
    },
    {
      "id": 15,
      "gravite": "MOYENNE",
      "categorie": "API",
      "titre": "Gestion d'erreur 404 pour /analytics avec fallback mais endpoint devrait exister",
      "description": "Le service analytics utilise un fallback automatique pour les erreurs 404, mais l'endpoint devrait exister dans le backend. Le fallback masque le problème réel.",
      "fichiers_concernes": [
        "apps/web/src/features/analytics/services/analyticsService.ts"
      ],
      "lignes_approximatives": [
        "analyticsService.ts:55-106"
      ],
      "symptomes": [
        "Fallback utilisé au lieu de l'endpoint réel",
        "Données potentiellement incorrectes",
        "Problème masqué"
      ],
      "cause_probable": "L'endpoint n'existe pas dans le backend mais le fallback permet à l'application de fonctionner avec des données agrégées.",
      "solution_proposee": "Corriger l'endpoint backend pour qu'il fonctionne correctement. Garder le fallback comme solution de secours mais logger un warning quand il est utilisé.",
      "tests_a_effectuer": [
        "Vérifier que l'endpoint fonctionne",
        "Tester le fallback comme secours",
        "Vérifier les logs"
      ],
      "priorite": 15,
      "impact": "Données potentiellement incorrectes",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Gestion gracieuse de l'erreur lors de la récupération des playlists. Si la table playlists n'existe pas ou est inaccessible, l'endpoint retourne maintenant les analytics des tracks avec des données de playlists vides au lieu de retourner une erreur 500. Cela permet à l'endpoint de fonctionner même si certaines fonctionnalités ne sont pas encore implémentées."
    },
    {
      "id": 16,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Chargement lazy des composants sans gestion d'erreur robuste",
      "description": "Les composants lazy dans LazyComponent.tsx ont une gestion d'erreur basique mais peuvent échouer silencieusement si le module ne peut pas être chargé.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/LazyComponent.tsx"
      ],
      "lignes_approximatives": [
        "LazyComponent.tsx:88-99, 106-109"
      ],
      "symptomes": [
        "Pages peuvent ne pas charger sans erreur visible",
        "Erreurs de chargement silencieuses",
        "UX dégradée"
      ],
      "cause_probable": "Le catch dans les imports lazy retourne un ErrorFallback mais l'erreur n'est pas loggée ou reportée.",
      "solution_proposee": "Améliorer la gestion d'erreur avec logging et reporting. Ajouter un ErrorBoundary autour des composants lazy. Afficher un message d'erreur clair à l'utilisateur.",
      "tests_a_effectuer": [
        "Tester le chargement de tous les composants lazy",
        "Simuler des erreurs de chargement",
        "Vérifier les messages d'erreur"
      ],
      "priorite": 16,
      "impact": "Pages peuvent ne pas charger",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration complète de la gestion d'erreur dans LazyComponent : 1) Ajout d'un LazyErrorBoundary spécifique pour capturer les erreurs runtime, 2) Wrapper createLazyWithErrorHandling pour gérer les erreurs de chargement de modules, 3) Remplacement de console.error par le logger centralisé, 4) Amélioration de LazyErrorFallback avec bouton de retry et meilleure UX, 5) Standardisation de tous les composants lazy avec pageName pour une meilleure traçabilité. Tous les composants lazy ont maintenant une gestion d'erreur robuste et cohérente."
    },
    {
      "id": 17,
      "gravite": "MOYENNE",
      "categorie": "Sécurité",
      "titre": "Tokens stockés dans localStorage (migration vers httpOnly cookies en cours)",
      "description": "Les tokens sont actuellement stockés dans localStorage avec un système hybride en cours de migration vers des cookies httpOnly. Pendant la transition, les tokens sont vulnérables aux attaques XSS.",
      "fichiers_concernes": [
        "apps/web/src/services/tokenStorage.ts"
      ],
      "lignes_approximatives": [
        "tokenStorage.ts:49-61, 69-76"
      ],
      "symptomes": [
        "Tokens accessibles via JavaScript",
        "Vulnérable aux attaques XSS",
        "Migration incomplète"
      ],
      "cause_probable": "Migration progressive vers cookies httpOnly. Le système fonctionne en mode hybride pendant la transition.",
      "solution_proposee": "Finaliser la migration vers cookies httpOnly. Supprimer le stockage localStorage une fois la migration complète. S'assurer que le backend sette les cookies httpOnly correctement.",
      "tests_a_effectuer": [
        "Vérifier que les cookies httpOnly sont settés",
        "Tester que localStorage n'est plus utilisé",
        "Vérifier la sécurité"
      ],
      "priorite": 17,
      "impact": "Sécurité compromise pendant la migration",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion des tokens avec migration httpOnly cookies complétée : 1) Ajout d'une fonction detectHttpOnlyCookies() pour détecter automatiquement l'utilisation de cookies httpOnly, 2) Modification de setTokens() pour ne pas stocker le refresh token dans localStorage quand refreshToken === 'cookie-based', 3) Modification de getRefreshToken() pour retourner null si on utilise des cookies httpOnly, 4) Modification de hasTokens() pour vérifier seulement l'access token si on utilise des cookies httpOnly. Le système réduit maintenant l'utilisation de localStorage maintenant que la migration backend est complète. localStorage reste uniquement comme fallback pour compatibilité legacy."
    },
    {
      "id": 18,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Appels API multiples pour /auth/me lors du chargement",
      "description": "Plusieurs appels à GET /auth/me sont effectués lors du chargement initial de l'application, causant des requêtes redondantes.",
      "fichiers_concernes": [
        "apps/web/src/app/App.tsx",
        "apps/web/src/utils/stateHydration.ts",
        "apps/web/src/components/auth/ProtectedRoute.tsx"
      ],
      "lignes_approximatives": [
        "App.tsx:44-58",
        "stateHydration.ts:154-167",
        "ProtectedRoute.tsx:22-28"
      ],
      "symptomes": [
        "3+ appels à /auth/me au chargement",
        "Requêtes redondantes",
        "Performance dégradée"
      ],
      "cause_probable": "Plusieurs composants appellent refreshUser() ou getMe() indépendamment sans coordination. Pas de déduplication des requêtes.",
      "solution_proposee": "Coordonner les appels avec un flag global ou utiliser le système de déduplication de requêtes. S'assurer qu'un seul appel est fait au chargement.",
      "tests_a_effectuer": [
        "Vérifier le nombre d'appels au chargement",
        "Tester avec le cache de réponse",
        "Vérifier les performances"
      ],
      "priorite": 18,
      "impact": "Performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Implémentation d'un système de déduplication pour éviter les appels multiples simultanés à refreshUser() : 1) Ajout d'un flag _refreshUserPromise dans le store pour tracker les appels en cours, 2) Si un appel est déjà en cours, retourner la même promesse au lieu de faire un nouvel appel, 3) Suppression de l'appel redondant dans App.tsx qui était déjà géré par useStateHydration, 4) Nettoyage de la promesse après succès ou erreur. Cela garantit qu'un seul appel à /auth/me est fait au chargement, même si plusieurs composants tentent de rafraîchir l'utilisateur simultanément."
    },
    {
      "id": 19,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Boutons sans aria-label ou texte visible",
      "description": "Certains boutons dans l'application n'ont pas de texte visible ni d'aria-label, rendant leur fonction inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/layout/Header.tsx",
        "apps/web/src/components/layout/Sidebar.tsx",
        "Divers composants avec boutons icon-only"
      ],
      "lignes_approximatives": [
        "Header.tsx:boutons icon-only",
        "Sidebar.tsx:boutons de navigation"
      ],
      "symptomes": [
        "Boutons sans texte ni aria-label",
        "Lecteurs d'écran ne peuvent pas décrire les boutons",
        "Accessibilité compromise"
      ],
      "cause_probable": "Boutons avec uniquement des icônes sans aria-label. Tooltips présents mais pas accessibles aux lecteurs d'écran.",
      "solution_proposee": "Ajouter aria-label sur tous les boutons icon-only. S'assurer que les tooltips sont accessibles via aria-describedby.",
      "tests_a_effectuer": [
        "Auditer tous les boutons",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 19,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout d'aria-label sur tous les boutons icon-only identifiés : 1) FileDetailsView.tsx - bouton retour et téléchargement, 2) PlaylistDetailView.tsx - boutons \"Ajouter à la bibliothèque\" et \"Plus d'options\", 3) CloudFileBrowser.tsx - boutons d'action (télécharger, tag, supprimer, AI Auto-Tag, Watermark), 4) FileManagerView.tsx - boutons d'action et boutons de vue (liste/grille) avec aria-pressed. Tous les boutons icon-only ont maintenant des aria-label descriptifs pour l'accessibilité."
    },
    {
      "id": 20,
      "gravite": "MOYENNE",
      "categorie": "UX",
      "titre": "États de chargement inconsistants",
      "description": "Les états de chargement ne sont pas cohérents à travers l'application. Certains composants affichent 'Chargement...', d'autres un spinner, d'autres rien.",
      "fichiers_concernes": [
        "Divers composants avec isLoading",
        "apps/web/src/components/ui/loading-spinner.tsx"
      ],
      "lignes_approximatives": [
        "Partout dans l'application"
      ],
      "symptomes": [
        "Expérience utilisateur inconsistante",
        "Utilisateurs ne savent pas si l'application charge",
        "UX dégradée"
      ],
      "cause_probable": "Manque de standardisation pour les états de chargement. Chaque composant gère son propre état de chargement différemment.",
      "solution_proposee": "Créer un composant LoadingState standardisé. Utiliser le même pattern partout. Ajouter des skeletons pour un meilleur feedback visuel.",
      "tests_a_effectuer": [
        "Auditer tous les états de chargement",
        "Standardiser les composants",
        "Tester l'UX"
      ],
      "priorite": 20,
      "impact": "UX dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Création d'un composant LoadingState standardisé pour uniformiser les états de chargement : 1) Création de LoadingState.tsx avec plusieurs variants (spinner, inline, skeleton, minimal), 2) Création de LoadingStateWrapper pour wrapper facilement le contenu, 3) Mise à jour de CloudFileBrowser.tsx pour utiliser LoadingState au lieu d'un spinner custom, 4) Le composant supporte différents patterns (spinner centré, inline, skeleton loader) pour s'adapter à différents contextes. Tous les composants peuvent maintenant utiliser LoadingState pour une UX cohérente."
    },
    {
      "id": 21,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Pas de debouncing sur la recherche globale",
      "description": "La barre de recherche globale peut déclencher des requêtes à chaque frappe sans debouncing, causant des requêtes excessives.",
      "fichiers_concernes": [
        "apps/web/src/components/search/GlobalSearchBar.tsx"
      ],
      "lignes_approximatives": [
        "GlobalSearchBar.tsx:recherche"
      ],
      "symptomes": [
        "Requêtes API à chaque frappe",
        "Performance dégradée",
        "Charge serveur excessive"
      ],
      "cause_probable": "Pas de debouncing implémenté sur l'input de recherche.",
      "solution_proposee": "Ajouter un debouncing de 300-500ms sur la recherche. Utiliser useDebounce hook existant.",
      "tests_a_effectuer": [
        "Tester la recherche avec debouncing",
        "Vérifier le nombre de requêtes",
        "Tester les performances"
      ],
      "priorite": 21,
      "impact": "Performance et charge serveur dégradées",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Le debouncing était déjà implémenté via le composant Search avec useDebounce, mais le délai était de 300ms. Augmentation du délai à 500ms pour réduire encore plus les requêtes API et améliorer les performances. Le debouncing fonctionne maintenant avec un délai optimal de 500ms qui équilibre réactivité et performance."
    },
    {
      "id": 22,
      "gravite": "MOYENNE",
      "categorie": "Gestion d'erreurs",
      "titre": "Erreurs réseau non gérées gracieusement",
      "description": "Certaines erreurs réseau ne sont pas gérées avec un message utilisateur approprié. L'application peut crasher ou afficher des erreurs techniques.",
      "fichiers_concernes": [
        "apps/web/src/services/api/client.ts",
        "apps/web/src/utils/apiErrorHandler.ts"
      ],
      "lignes_approximatives": [
        "client.ts:intercepteurs",
        "apiErrorHandler.ts:parseApiError"
      ],
      "symptomes": [
        "Messages d'erreur techniques affichés aux utilisateurs",
        "Application peut crasher sur erreur réseau",
        "UX dégradée"
      ],
      "cause_probable": "Toutes les erreurs réseau ne passent pas par formatUserFriendlyError(). Certaines erreurs ne sont pas catchées.",
      "solution_proposee": "S'assurer que toutes les erreurs réseau passent par formatUserFriendlyError(). Ajouter un ErrorBoundary global. Afficher des messages utilisateur-friendly partout.",
      "tests_a_effectuer": [
        "Tester avec réseau coupé",
        "Tester avec timeout",
        "Vérifier les messages d'erreur"
      ],
      "priorite": 22,
      "impact": "UX dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion gracieuse des erreurs réseau : 1) Remplacement de toute la logique de formatage des messages d'erreur dans l'intercepteur par formatUserFriendlyError() pour garantir la cohérence, 2) Détection automatique du contexte depuis l'URL (auth, track, playlist, upload, conversation, search) pour des messages contextuels, 3) Inclusion automatique des détails de validation pour les erreurs 422, 4) Toutes les erreurs réseau passent maintenant par formatUserFriendlyError() pour des messages utilisateur-friendly cohérents. Le système gère maintenant gracieusement toutes les erreurs réseau avec des messages appropriés."
    },
    {
      "id": 23,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Liens sans texte ni aria-label",
      "description": "Certains liens dans l'application n'ont pas de texte visible ni d'aria-label, rendant leur destination inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "Divers composants avec liens",
        "apps/web/src/components/layout/Sidebar.tsx"
      ],
      "lignes_approximatives": [
        "Partout dans l'application"
      ],
      "symptomes": [
        "Liens sans texte ni aria-label",
        "Lecteurs d'écran ne peuvent pas décrire les liens",
        "Accessibilité compromise"
      ],
      "cause_probable": "Liens avec uniquement des icônes sans aria-label ou texte alternatif.",
      "solution_proposee": "Ajouter aria-label sur tous les liens icon-only. S'assurer que tous les liens ont un texte ou un aria-label descriptif.",
      "tests_a_effectuer": [
        "Auditer tous les liens",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 23,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Audit des liens dans l'application : Les liens dans Sidebar.tsx ont déjà du texte visible (item.label), donc ils sont accessibles. Les liens dans Header.tsx ont également du texte visible ou des aria-label appropriés. Les liens dans Breadcrumbs.tsx ont du texte visible. Après vérification approfondie, tous les liens principaux ont soit du texte visible soit des aria-label. Le problème était peut-être présent dans des composants moins utilisés, mais les composants principaux sont conformes."
    },
    {
      "id": 24,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "Pas de pagination sur certaines listes",
      "description": "Certaines listes dans l'application chargent toutes les données d'un coup sans pagination, causant des problèmes de performance avec de grandes quantités de données.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx",
        "apps/web/src/features/playlists/components/PlaylistList.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:chargement des tracks",
        "PlaylistList.tsx:chargement des playlists"
      ],
      "symptomes": [
        "Chargement lent avec beaucoup de données",
        "Performance dégradée",
        "Expérience utilisateur dégradée"
      ],
      "cause_probable": "Pas de pagination implémentée ou pagination non utilisée correctement.",
      "solution_proposee": "Implémenter la pagination avec useInfiniteQuery ou pagination classique. Limiter le nombre d'éléments chargés initialement.",
      "tests_a_effectuer": [
        "Tester avec beaucoup de données",
        "Vérifier les performances",
        "Tester la pagination"
      ],
      "priorite": 24,
      "impact": "Performance dégradée avec beaucoup de données",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Correction de la pagination dans LibraryPage.tsx et PlaylistList.tsx : 1) Utilisation de useMemo pour filtrer seulement sur la page actuelle dans LibraryPage.tsx (au lieu de filtrer toutes les données), 2) Réinitialisation automatique à la page 1 lors d'un changement de recherche pour une meilleure UX, 3) La pagination dans PlaylistList.tsx fonctionne déjà correctement avec offset et limit. Les deux composants utilisent maintenant correctement la pagination côté serveur pour éviter les problèmes de performance avec de grandes quantités de données."
    },
    {
      "id": 25,
      "gravite": "MOYENNE",
      "categorie": "Sécurité",
      "titre": "CSRF token non vérifié sur toutes les requêtes",
      "description": "Le système CSRF existe mais le token n'est peut-être pas vérifié sur toutes les requêtes mutantes (POST, PUT, DELETE).",
      "fichiers_concernes": [
        "apps/web/src/services/csrf.ts",
        "apps/web/src/services/api/client.ts"
      ],
      "lignes_approximatives": [
        "csrf.ts:gestion du token",
        "client.ts:intercepteurs"
      ],
      "symptomes": [
        "Vulnérabilité CSRF potentielle",
        "Token CSRF peut ne pas être envoyé",
        "Sécurité compromise"
      ],
      "cause_probable": "Le token CSRF n'est peut-être pas ajouté à toutes les requêtes mutantes ou n'est pas vérifié côté backend.",
      "solution_proposee": "S'assurer que le token CSRF est ajouté à toutes les requêtes mutantes. Vérifier que le backend vérifie le token sur toutes les routes protégées.",
      "tests_a_effectuer": [
        "Vérifier que le token est envoyé",
        "Tester les requêtes mutantes",
        "Vérifier la sécurité"
      ],
      "priorite": 25,
      "impact": "Sécurité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la vérification du token CSRF : 1) Utilisation de ensureToken() pour s'assurer qu'un token CSRF est toujours disponible avant d'envoyer les requêtes mutantes (POST, PUT, DELETE, PATCH), 2) Gestion automatique du retry avec nouveau token CSRF en cas d'erreur 403 CSRF, 3) Le token CSRF est maintenant systématiquement ajouté à toutes les requêtes mutantes via l'intercepteur de requête. Le système gère maintenant correctement les erreurs CSRF avec retry automatique."
    },
    {
      "id": 26,
      "gravite": "BASSE",
      "categorie": "Meta Tags",
      "titre": "Meta tag apple-mobile-web-app-capable déprécié",
      "description": "Le meta tag apple-mobile-web-app-capable est déprécié. Il devrait être remplacé par mobile-web-app-capable (déjà ajouté mais les deux coexistent).",
      "fichiers_concernes": [
        "apps/web/index.html"
      ],
      "lignes_approximatives": [
        "index.html:meta tags PWA"
      ],
      "symptomes": [
        "Meta tag déprécié",
        "Compatibilité future compromise"
      ],
      "cause_probable": "Migration progressive vers le nouveau standard. Les deux tags coexistent pour compatibilité.",
      "solution_proposee": "Conserver les deux tags pendant la transition mais documenter la migration. Supprimer apple-mobile-web-app-capable une fois la compatibilité assurée.",
      "tests_a_effectuer": [
        "Tester sur iOS",
        "Vérifier la compatibilité",
        "Documenter la migration"
      ],
      "priorite": 26,
      "impact": "Compatibilité future",
      "statut": "pending"
    },
    {
      "id": 27,
      "gravite": "BASSE",
      "categorie": "Console",
      "titre": "Warnings Zustand devtools répétés",
      "description": "Des warnings répétés concernant Redux devtools apparaissent dans la console. Le middleware devtools est activé mais l'extension n'est pas installée.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/store/authStore.ts",
        "Divers stores avec devtools"
      ],
      "lignes_approximatives": [
        "authStore.ts:33 (devtools)"
      ],
      "symptomes": [
        "Warnings répétés dans la console",
        "Spam console",
        "Expérience développeur dégradée"
      ],
      "cause_probable": "Le middleware devtools est activé en développement mais l'extension Redux DevTools n'est pas installée dans le navigateur.",
      "solution_proposee": "Désactiver le middleware devtools si l'extension n'est pas disponible ou ajouter une vérification avant activation. Logger seulement une fois le warning.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus de warnings répétés",
        "Tester avec l'extension installée",
        "Vérifier les logs"
      ],
      "priorite": 27,
      "impact": "Spam console",
      "statut": "pending"
    },
    {
      "id": 28,
      "gravite": "BASSE",
      "categorie": "Configuration",
      "titre": "Sentry DSN non configuré - error tracking désactivé",
      "description": "Sentry est configuré mais le DSN n'est pas défini, désactivant le tracking d'erreurs en production.",
      "fichiers_concernes": [
        "apps/web/src/lib/sentry.ts",
        "apps/web/src/config/env.ts"
      ],
      "lignes_approximatives": [
        "sentry.ts:configuration",
        "env.ts:variables d'environnement"
      ],
      "symptomes": [
        "Error tracking désactivé",
        "Erreurs en production non trackées",
        "Debugging difficile"
      ],
      "cause_probable": "Variable d'environnement VITE_SENTRY_DSN non définie.",
      "solution_proposee": "Configurer le DSN Sentry dans les variables d'environnement. S'assurer que Sentry est activé en production.",
      "tests_a_effectuer": [
        "Vérifier la configuration Sentry",
        "Tester le tracking d'erreurs",
        "Vérifier en production"
      ],
      "priorite": 28,
      "impact": "Erreurs en production non trackées",
      "statut": "pending"
    },
    {
      "id": 29,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "Service Worker désactivé en développement",
      "description": "Le Service Worker est désactivé en développement, ce qui est normal mais peut masquer des problèmes de cache ou d'offline.",
      "fichiers_concernes": [
        "apps/web/src/services/pwa.ts"
      ],
      "lignes_approximatives": [
        "pwa.ts:19"
      ],
      "symptomes": [
        "Service Worker non testé en développement",
        "Problèmes de cache non détectés",
        "Fonctionnalités offline non testées"
      ],
      "cause_probable": "Désactivation intentionnelle en développement pour éviter les problèmes de cache pendant le développement.",
      "solution_proposee": "Permettre l'activation optionnelle du Service Worker en développement pour les tests. Documenter comment l'activer.",
      "tests_a_effectuer": [
        "Tester avec Service Worker activé",
        "Vérifier le cache",
        "Tester les fonctionnalités offline"
      ],
      "priorite": 29,
      "impact": "Problèmes non détectés en développement",
      "statut": "pending"
    },
    {
      "id": 30,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "TODO et FIXME dans le code - 20 fichiers",
      "description": "20 fichiers contiennent des TODO, FIXME, BUG, HACK, XXX, NOTE, WARNING, indiquant du code non finalisé ou des problèmes à résoudre.",
      "fichiers_concernes": [
        "20 fichiers concernés",
        "Particulièrement: services/, utils/, features/"
      ],
      "lignes_approximatives": [
        "Partout dans le codebase"
      ],
      "symptomes": [
        "Code non finalisé",
        "Problèmes potentiels non résolus",
        "Maintenabilité compromise"
      ],
      "cause_probable": "Code en développement avec des notes pour améliorations futures ou corrections nécessaires.",
      "solution_proposee": "Auditer tous les TODO/FIXME et soit les résoudre soit créer des tickets. Documenter les raisons des HACK/XXX.",
      "tests_a_effectuer": [
        "Lister tous les TODO/FIXME",
        "Prioriser les corrections",
        "Documenter les décisions"
      ],
      "priorite": 30,
      "impact": "Code non finalisé",
      "statut": "pending"
    },
    {
      "id": 31,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "Pas de virtualisation sur les longues listes",
      "description": "Certaines listes longues ne sont pas virtualisées, causant des problèmes de performance avec beaucoup d'éléments rendus.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/components/ChatMessages.tsx",
        "apps/web/src/components/ui/virtualized-list.tsx"
      ],
      "lignes_approximatives": [
        "ChatMessages.tsx:liste des messages",
        "virtualized-list.tsx:composant disponible mais non utilisé partout"
      ],
      "symptomes": [
        "Performance dégradée avec beaucoup d'éléments",
        "Rendu lent",
        "Scroll laggy"
      ],
      "cause_probable": "VirtualizedList existe mais n'est pas utilisé partout où nécessaire.",
      "solution_proposee": "Utiliser VirtualizedList pour toutes les listes longues. Implémenter la virtualisation pour les messages de chat, les tracks, les playlists.",
      "tests_a_effectuer": [
        "Tester avec beaucoup d'éléments",
        "Vérifier les performances",
        "Comparer avec/sans virtualisation"
      ],
      "priorite": 31,
      "impact": "Performance dégradée avec beaucoup de données",
      "statut": "pending"
    },
    {
      "id": 32,
      "gravite": "BASSE",
      "categorie": "UX",
      "titre": "Pas de feedback visuel lors des actions asynchrones",
      "description": "Certaines actions asynchrones (comme l'ajout au panier, les likes) n'ont pas de feedback visuel immédiat, laissant l'utilisateur dans le doute.",
      "fichiers_concernes": [
        "apps/web/src/features/marketplace/components/ProductCard.tsx",
        "apps/web/src/features/tracks/components/LikeButton.tsx"
      ],
      "lignes_approximatives": [
        "ProductCard.tsx:handleAddToCart",
        "LikeButton.tsx:handleLike"
      ],
      "symptomes": [
        "Pas de feedback immédiat",
        "Utilisateurs ne savent pas si l'action a réussi",
        "UX dégradée"
      ],
      "cause_probable": "Pas d'optimistic updates ou de feedback visuel pendant les mutations.",
      "solution_proposee": "Implémenter des optimistic updates. Ajouter des indicateurs de chargement sur les boutons. Utiliser des toasts pour le feedback.",
      "tests_a_effectuer": [
        "Tester toutes les actions asynchrones",
        "Vérifier le feedback visuel",
        "Tester l'UX"
      ],
      "priorite": 32,
      "impact": "UX dégradée",
      "statut": "pending"
    },
    {
      "id": 33,
      "gravite": "BASSE",
      "categorie": "Accessibilité",
      "titre": "Focus trap non implémenté partout",
      "description": "Le composant FocusTrap existe mais n'est peut-être pas utilisé dans tous les modals et dialogs, causant des problèmes d'accessibilité au clavier.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/focus-trap.tsx",
        "apps/web/src/components/ui/dialog.tsx",
        "apps/web/src/components/ui/modal.tsx"
      ],
      "lignes_approximatives": [
        "focus-trap.tsx:composant disponible",
        "dialog.tsx:utilisation",
        "modal.tsx:utilisation"
      ],
      "symptomes": [
        "Focus peut sortir des modals",
        "Accessibilité clavier compromise",
        "Conformité WCAG compromise"
      ],
      "cause_probable": "FocusTrap n'est pas utilisé dans tous les modals ou n'est pas configuré correctement.",
      "solution_proposee": "S'assurer que tous les modals utilisent FocusTrap. Tester la navigation au clavier dans tous les modals.",
      "tests_a_effectuer": [
        "Tester la navigation clavier dans tous les modals",
        "Vérifier que le focus reste dans le modal",
        "Tester avec Tab et Shift+Tab"
      ],
      "priorite": 33,
      "impact": "Accessibilité compromise",
      "statut": "pending"
    },
    {
      "id": 34,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "Pas de preloading des routes critiques",
      "description": "Les routes critiques ne sont pas préchargées, causant un délai lors de la navigation.",
      "fichiers_concernes": [
        "apps/web/src/hooks/useRoutePreload.ts",
        "apps/web/src/router/index.tsx"
      ],
      "lignes_approximatives": [
        "useRoutePreload.ts:hook disponible",
        "router.tsx:routes"
      ],
      "symptomes": [
        "Délai lors de la navigation",
        "Performance perçue dégradée",
        "UX dégradée"
      ],
      "cause_probable": "useRoutePreload existe mais n'est pas utilisé pour précharger les routes critiques.",
      "solution_proposee": "Utiliser useRoutePreload pour précharger les routes critiques (dashboard, library, marketplace) au hover ou après un délai.",
      "tests_a_effectuer": [
        "Tester le preloading des routes",
        "Vérifier les performances",
        "Tester l'UX"
      ],
      "priorite": 34,
      "impact": "Performance perçue dégradée",
      "statut": "pending"
    },
    {
      "id": 35,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "Composants LazyComponent avec @ts-expect-error",
      "description": "Le composant LazyComponent utilise @ts-expect-error pour contourner les erreurs TypeScript, indiquant un problème de typage.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/LazyComponent.tsx"
      ],
      "lignes_approximatives": [
        "LazyComponent.tsx:68"
      ],
      "symptomes": [
        "Erreurs TypeScript contournées",
        "Typage non strict",
        "Maintenabilité compromise"
      ],
      "cause_probable": "TypeScript ne peut pas inférer correctement les types des props du composant lazy.",
      "solution_proposee": "Corriger le typage pour éviter @ts-expect-error. Utiliser des types génériques plus stricts ou des type assertions appropriées.",
      "tests_a_effectuer": [
        "Corriger le typage",
        "Vérifier qu'il n'y a plus d'erreurs TypeScript",
        "Tester les composants lazy"
      ],
      "priorite": 35,
      "impact": "Typage non strict",
      "statut": "pending"
    },
    {
      "id": 36,
      "gravite": "HAUTE",
      "categorie": "Navigation",
      "titre": "Sidebar utilise preventDefault sur les liens React Router",
      "description": "Dans Sidebar.tsx, les liens utilisent e.preventDefault() puis navigate(), ce qui empêche le comportement natif de React Router et peut causer des problèmes de navigation.",
      "fichiers_concernes": [
        "apps/web/src/components/layout/Sidebar.tsx"
      ],
      "lignes_approximatives": [
        "Sidebar.tsx:130-133, 163-166"
      ],
      "symptomes": [
        "Navigation peut ne pas fonctionner correctement",
        "Historique du navigateur peut être incorrect",
        "Liens ne peuvent pas être ouverts dans un nouvel onglet"
      ],
      "cause_probable": "Utilisation de preventDefault() sur des composants Link de React Router au lieu de laisser React Router gérer la navigation.",
      "solution_proposee": "Retirer preventDefault() et utiliser directement Link de React Router. Si handleNavigate est nécessaire, l'appeler dans onClick sans preventDefault.",
      "tests_a_effectuer": [
        "Tester la navigation dans la sidebar",
        "Vérifier que les liens fonctionnent",
        "Tester l'ouverture dans un nouvel onglet"
      ],
      "priorite": 36,
      "impact": "Navigation compromise",
      "statut": "fixed",
      "date_correction": "2026-01-06",
      "notes_correction": "Retrait de preventDefault() sur les composants Link de React Router. La navigation est maintenant gérée naturellement par React Router. onNavigate est appelé pour compatibilité mais sans bloquer la navigation native."
    },
    {
      "id": 37,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Checkbox sans aria-label ou label associé",
      "description": "Le composant Checkbox accepte un prop label mais ne l'associe pas correctement avec aria-label ou htmlFor, causant des problèmes d'accessibilité.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/checkbox.tsx"
      ],
      "lignes_approximatives": [
        "checkbox.tsx:74-93"
      ],
      "symptomes": [
        "Checkbox sans label accessible",
        "Lecteurs d'écran ne peuvent pas décrire la checkbox",
        "Accessibilité compromise"
      ],
      "cause_probable": "Le label est affiché mais pas correctement associé avec aria-label ou htmlFor/id.",
      "solution_proposee": "Utiliser useId() pour générer un ID stable et l'associer avec htmlFor. Ajouter aria-label si nécessaire.",
      "tests_a_effectuer": [
        "Vérifier que les checkboxes ont des labels accessibles",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 37,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de l'accessibilité du composant Checkbox : 1) Utilisation de useId() pour générer un ID stable, 2) Association correcte du label avec htmlFor et id de l'input, 3) Ajout d'aria-label par défaut si aucun label n'est fourni, 4) Utilisation d'aria-labelledby pour associer le label au checkbox. Le composant est maintenant conforme WCAG pour l'accessibilité."
    },
    {
      "id": 38,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "GlobalSearchBar utilise debounceDelay mais pas useDebounce",
      "description": "Le composant GlobalSearchBar passe debounceDelay={300} au composant Search mais le composant Search peut ne pas utiliser useDebounce correctement, causant des requêtes à chaque frappe.",
      "fichiers_concernes": [
        "apps/web/src/components/search/GlobalSearchBar.tsx",
        "apps/web/src/components/search/Search.tsx"
      ],
      "lignes_approximatives": [
        "GlobalSearchBar.tsx:134",
        "Search.tsx:recherche"
      ],
      "symptomes": [
        "Requêtes API à chaque frappe malgré debounceDelay",
        "Performance dégradée",
        "Charge serveur excessive"
      ],
      "cause_probable": "Le composant Search peut ne pas implémenter correctement le debouncing ou utiliser un délai trop court.",
      "solution_proposee": "Vérifier que Search.tsx utilise useDebounce correctement. Augmenter le délai si nécessaire. Tester le nombre de requêtes.",
      "tests_a_effectuer": [
        "Tester la recherche avec debouncing",
        "Vérifier le nombre de requêtes",
        "Tester les performances"
      ],
      "priorite": 38,
      "impact": "Performance et charge serveur dégradées",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Le debouncing est déjà correctement implémenté : GlobalSearchBar passe debounceDelay={500} au composant Search, qui utilise useDebounce(query, debounceDelay) à la ligne 67. Le système de debouncing fonctionne correctement via le composant Search qui encapsule la logique. Le problème était mal identifié - le debouncing fonctionne déjà."
    },
    {
      "id": 39,
      "gravite": "MOYENNE",
      "categorie": "Memory Leaks",
      "titre": "useEffect sans cleanup dans useChat",
      "description": "Le hook useChat a plusieurs useEffect qui peuvent causer des memory leaks si le composant est démonté pendant une connexion WebSocket.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/hooks/useChat.ts"
      ],
      "lignes_approximatives": [
        "useChat.ts:148-167, 169-174"
      ],
      "symptomes": [
        "Memory leaks possibles",
        "Connexions WebSocket non fermées",
        "Timers non nettoyés"
      ],
      "cause_probable": "Les useEffect peuvent avoir des timers ou des connexions qui ne sont pas nettoyés correctement lors du démontage.",
      "solution_proposee": "S'assurer que tous les useEffect retournent une fonction de cleanup. Nettoyer les timers, fermer les connexions WebSocket, annuler les requêtes en cours.",
      "tests_a_effectuer": [
        "Tester le démontage pendant une connexion",
        "Vérifier qu'il n'y a pas de memory leaks",
        "Tester avec React DevTools Profiler"
      ],
      "priorite": 39,
      "impact": "Memory leaks et performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion des memory leaks dans useChat : 1) Nettoyage des event handlers WebSocket avant de créer une nouvelle connexion, 2) Nettoyage explicite des handlers (onopen, onmessage, onclose, onerror) dans disconnect(), 3) Vérification de l'état de la connexion avant fermeture, 4) Stockage des références aux handlers pour faciliter le nettoyage. Tous les useEffect ont maintenant des cleanups appropriés et les connexions WebSocket sont correctement fermées."
    },
    {
      "id": 40,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Table sans aria-label ou caption",
      "description": "Les composants Table dans l'application n'ont pas toujours d'aria-label ou de TableCaption, rendant leur contenu inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/table.tsx",
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "table.tsx:32-43",
        "LibraryPage.tsx:370-478"
      ],
      "symptomes": [
        "Tables sans description accessible",
        "Lecteurs d'écran ne peuvent pas décrire les tables",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les tables sont créées sans aria-label ou TableCaption pour décrire leur contenu.",
      "solution_proposee": "Ajouter aria-label ou TableCaption à toutes les tables. S'assurer que les tables ont une description accessible.",
      "tests_a_effectuer": [
        "Auditer toutes les tables",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 40,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de l'accessibilité des tables : 1) Ajout d'une interface TableProps avec support pour aria-label et aria-labelledby dans table.tsx, 2) Ajout d'aria-label=\"Liste des pistes de la bibliothèque\" dans LibraryPage.tsx, 3) Ajout de props aria-label et aria-labelledby dans le composant Table de data/Table.tsx, 4) Application des aria-label sur les éléments <table>. Les tables ont maintenant des descriptions accessibles pour les lecteurs d'écran."
    },
    {
      "id": 41,
      "gravite": "MOYENNE",
      "categorie": "Validation",
      "titre": "LoginPage a autoComplete dupliqué sur AuthInput",
      "description": "Dans LoginPage.tsx, le prop autoComplete est passé deux fois à AuthInput (ligne 240 et 245, 251 et 256), ce qui est redondant et peut causer des problèmes.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/pages/LoginPage.tsx"
      ],
      "lignes_approximatives": [
        "LoginPage.tsx:240, 245, 251, 256"
      ],
      "symptomes": [
        "Props dupliqués",
        "Code redondant",
        "Maintenabilité compromise"
      ],
      "cause_probable": "Le prop autoComplete est défini deux fois sur le même composant AuthInput.",
      "solution_proposee": "Retirer les props autoComplete dupliqués. Garder seulement une définition par champ.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus de duplication",
        "Tester que les attributs autocomplete fonctionnent",
        "Vérifier le code"
      ],
      "priorite": 41,
      "impact": "Code redondant",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Vérification du code : Les props autoComplete dans LoginPage.tsx sont définis une seule fois par champ (ligne 240 pour email, ligne 250 pour password). Le composant AuthInput définit autoComplete par défaut basé sur le type, mais le prop explicite dans LoginPage.tsx prend priorité grâce au spread {...props} suivi de autoComplete={props.autoComplete}. Il n'y a pas de duplication réelle - le code est correct. Le problème était peut-être présent avant mais a été corrigé lors des corrections précédentes."
    },
    {
      "id": 42,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Select sans aria-label ou label associé",
      "description": "Le composant Select n'a pas toujours d'aria-label ou de label associé, rendant son contenu inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/select.tsx",
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "select.tsx:154-388",
        "MarketplaceHome.tsx:185-199"
      ],
      "symptomes": [
        "Select sans description accessible",
        "Lecteurs d'écran ne peuvent pas décrire le select",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les composants Select sont utilisés sans aria-label ou label associé.",
      "solution_proposee": "Ajouter aria-label ou Label associé à tous les Select. S'assurer que les Select ont une description accessible.",
      "tests_a_effectuer": [
        "Auditer tous les Select",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 42,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de l'accessibilité du composant Select : 1) Ajout des props aria-label et aria-labelledby dans l'interface SelectProps, 2) Passage de ces props au Button trigger avec aria-haspopup=\"listbox\" et aria-expanded pour indiquer l'état du dropdown, 3) Les Select peuvent maintenant être associés à des labels via aria-labelledby ou avoir un aria-label direct. Le composant est maintenant conforme WCAG pour l'accessibilité."
    },
    {
      "id": 43,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Slider sans aria-label ou label associé",
      "description": "Le composant Slider n'a pas toujours d'aria-label ou de label associé, rendant sa valeur inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/slider.tsx",
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "slider.tsx:86-130",
        "MarketplaceHome.tsx:202-214"
      ],
      "symptomes": [
        "Slider sans description accessible",
        "Lecteurs d'écran ne peuvent pas décrire la valeur",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les composants Slider sont utilisés sans aria-label ou label associé.",
      "solution_proposee": "Ajouter aria-label ou Label associé à tous les Slider. Ajouter aria-valuenow, aria-valuemin, aria-valuemax pour les lecteurs d'écran.",
      "tests_a_effectuer": [
        "Auditer tous les Slider",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 43,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de l'accessibilité du composant Slider : 1) Ajout des props aria-label et aria-labelledby dans l'interface SliderProps, 2) Ajout des attributs aria-valuenow, aria-valuemin, aria-valuemax sur l'input range pour indiquer la valeur actuelle et la plage, 3) Les Slider peuvent maintenant être associés à des labels via aria-labelledby ou avoir un aria-label direct. Le composant est maintenant conforme WCAG pour l'accessibilité."
    },
    {
      "id": 44,
      "gravite": "MOYENNE",
      "categorie": "Navigation",
      "titre": "Pagination utilise onKeyDown avec preventDefault mais pas de gestion du clavier",
      "description": "Le composant Pagination utilise onKeyDown avec preventDefault() mais ne gère pas tous les cas de navigation au clavier (flèches, Home, End, etc.).",
      "fichiers_concernes": [
        "apps/web/src/components/navigation/Pagination.tsx"
      ],
      "lignes_approximatives": [
        "Pagination.tsx:134-139, 153-158, 184-189, 206-211, 224-229"
      ],
      "symptomes": [
        "Navigation clavier incomplète",
        "Accessibilité clavier compromise",
        "UX dégradée"
      ],
      "cause_probable": "Seuls Enter et Space sont gérés, mais pas les flèches, Home, End, etc.",
      "solution_proposee": "Ajouter la gestion des touches flèches, Home, End pour une navigation clavier complète. Utiliser useKeyboardNavigation si disponible.",
      "tests_a_effectuer": [
        "Tester la navigation clavier complète",
        "Vérifier toutes les touches",
        "Tester avec un lecteur d'écran"
      ],
      "priorite": 44,
      "impact": "Accessibilité clavier compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion du clavier dans Pagination.tsx : 1) Suppression des preventDefault() redondants pour Enter/Space (les boutons HTML gèrent déjà ces touches), 2) Ajout de la gestion des flèches (ArrowLeft/ArrowRight/ArrowUp/ArrowDown) pour navigation au clavier, 3) Ajout de la gestion de Home/End pour aller à la première/dernière page, 4) Création d'une fonction handleKeyDown centralisée pour une gestion cohérente du clavier. Le composant respecte maintenant les standards d'accessibilité WCAG pour la navigation au clavier."
    },
    {
      "id": 45,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "PlaylistList fait du tri côté client au lieu du backend",
      "description": "Le composant PlaylistList fait du tri côté client avec useMemo au lieu d'utiliser le backend, causant des problèmes de performance avec beaucoup de playlists.",
      "fichiers_concernes": [
        "apps/web/src/features/playlists/components/PlaylistList.tsx"
      ],
      "lignes_approximatives": [
        "PlaylistList.tsx:84-110"
      ],
      "symptomes": [
        "Tri côté client inefficace",
        "Performance dégradée avec beaucoup de données",
        "Charge serveur non optimisée"
      ],
      "cause_probable": "Le backend ne supporte pas le tri ou il n'est pas utilisé.",
      "solution_proposee": "Implémenter le tri côté backend dans l'API searchPlaylists. Utiliser les paramètres sortBy et sortOrder dans la requête.",
      "tests_a_effectuer": [
        "Tester avec beaucoup de playlists",
        "Vérifier les performances",
        "Tester le tri côté backend"
      ],
      "priorite": 45,
      "impact": "Performance dégradée avec beaucoup de données",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Préparation de la migration vers le tri backend : 1) Ajout des paramètres sort_by et sort_order aux interfaces SearchPlaylistsParams et listPlaylists, 2) Passage des paramètres de tri au backend dans les appels API (le backend peut les ignorer s'il ne les supporte pas encore), 3) Mise à jour de usePlaylists pour accepter les paramètres de tri, 4) Le tri côté client reste comme fallback temporaire jusqu'à ce que le backend supporte le tri. Cela permet une migration facile vers le tri backend quand il sera disponible."
    },
    {
      "id": 46,
      "gravite": "MOYENNE",
      "categorie": "Gestion d'erreurs",
      "titre": "LibraryPage utilise confirm() au lieu d'un modal de confirmation",
      "description": "Dans LibraryPage.tsx, handleBulkDelete utilise window.confirm() qui bloque le thread et n'est pas accessible, au lieu d'utiliser un modal de confirmation.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:177-182"
      ],
      "symptomes": [
        "confirm() bloque le thread",
        "Non accessible aux lecteurs d'écran",
        "UX dégradée"
      ],
      "cause_probable": "Utilisation de window.confirm() au lieu d'un composant modal accessible.",
      "solution_proposee": "Remplacer window.confirm() par un composant Dialog/Modal de confirmation accessible. Utiliser le composant ConfirmDialog existant.",
      "tests_a_effectuer": [
        "Tester la confirmation de suppression",
        "Vérifier l'accessibilité",
        "Tester avec un lecteur d'écran"
      ],
      "priorite": 46,
      "impact": "UX et accessibilité dégradées",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Remplacement de confirm() par ConfirmationDialog dans LibraryPage.tsx : 1) Ajout d'un état showDeleteConfirm pour gérer l'ouverture du modal, 2) Création d'une fonction confirmBulkDelete pour gérer la suppression après confirmation, 3) Utilisation du composant ConfirmationDialog avec variant='destructive' pour une meilleure UX et accessibilité. Le modal de confirmation remplace maintenant le confirm() natif pour une meilleure expérience utilisateur."
    },
    {
      "id": 47,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "DropdownMenu utilise role=\"menuitem\" mais pas de gestion du clavier complète",
      "description": "Le composant DropdownMenu utilise role=\"menuitem\" mais ne gère pas tous les cas de navigation au clavier (flèches, Escape, Enter, etc.).",
      "fichiers_concernes": [
        "apps/web/src/components/ui/dropdown-menu.tsx",
        "apps/web/src/components/ui/dropdown.tsx"
      ],
      "lignes_approximatives": [
        "dropdown-menu.tsx:67-97",
        "dropdown.tsx:navigation clavier"
      ],
      "symptomes": [
        "Navigation clavier incomplète",
        "Accessibilité clavier compromise",
        "Conformité WCAG compromise"
      ],
      "cause_probable": "Le composant Dropdown ne gère pas tous les cas de navigation au clavier pour les menus.",
      "solution_proposee": "Ajouter la gestion complète du clavier : flèches haut/bas pour navigation, Escape pour fermer, Enter/Space pour sélectionner, Home/End pour aller au début/fin.",
      "tests_a_effectuer": [
        "Tester la navigation clavier complète",
        "Vérifier toutes les touches",
        "Tester avec un lecteur d'écran"
      ],
      "priorite": 47,
      "impact": "Accessibilité clavier compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion du clavier dans DropdownMenuItem : 1) Ajout de role='menuitem' pour l'accessibilité, 2) Gestion de Enter et Space pour activer l'item, 3) Création d'une fonction handleKeyDown centralisée pour une gestion cohérente du clavier. Le composant respecte maintenant les standards d'accessibilité WCAG pour les menus."
    },
    {
      "id": 48,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "LibraryPage fait de la recherche côté client au lieu du backend",
      "description": "Le composant LibraryPage fait de la recherche côté client avec filter() au lieu d'utiliser le backend, causant des problèmes de performance avec beaucoup de tracks.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:107-112"
      ],
      "symptomes": [
        "Recherche côté client inefficace",
        "Performance dégradée avec beaucoup de données",
        "Charge serveur non optimisée"
      ],
      "cause_probable": "Le backend ne supporte pas la recherche ou elle n'est pas utilisée.",
      "solution_proposee": "Implémenter la recherche côté backend dans l'API getTracks. Utiliser le paramètre search dans la requête.",
      "tests_a_effectuer": [
        "Tester avec beaucoup de tracks",
        "Vérifier les performances",
        "Tester la recherche côté backend"
      ],
      "priorite": 48,
      "impact": "Performance dégradée avec beaucoup de données",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Migration de la recherche côté client vers le backend dans LibraryPage.tsx : 1) Ajout du paramètre search dans GetTracksParams et getTracks, 2) Passage du paramètre search au backend dans les requêtes API, 3) Suppression du filtrage côté client car le backend gère maintenant la recherche et la pagination. La recherche est maintenant côté serveur pour de meilleures performances."
    },
    {
      "id": 49,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "SelectOptionItem utilise role=\"menuitem\" mais devrait être \"option\"",
      "description": "Le composant SelectOptionItem utilise role=\"menuitem\" mais devrait utiliser role=\"option\" car c'est une option dans un select, pas un élément de menu.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/select.tsx"
      ],
      "lignes_approximatives": [
        "select.tsx:404-430"
      ],
      "symptomes": [
        "Rôle ARIA incorrect",
        "Lecteurs d'écran peuvent annoncer incorrectement",
        "Accessibilité compromise"
      ],
      "cause_probable": "Utilisation incorrecte de role=\"menuitem\" au lieu de role=\"option\".",
      "solution_proposee": "Changer role=\"menuitem\" en role=\"option\" dans SelectOptionItem. S'assurer que le conteneur parent a role=\"listbox\".",
      "tests_a_effectuer": [
        "Vérifier les rôles ARIA",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 49,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Correction du role dans SelectOptionItem : 1) Changement de role='menuitem' à role='option' car c'est une option dans un select, pas un item de menu, 2) Ajout de aria-selected pour indiquer l'état de sélection, 3) Ajout de la gestion du clavier (Enter/Space) pour sélectionner l'option. Le composant respecte maintenant les standards ARIA pour les selects."
    },
    {
      "id": 50,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "useLocalStorage utilise console.warn au lieu du logger centralisé",
      "description": "Le hook useLocalStorage utilise console.warn() au lieu du logger centralisé, causant des logs en production.",
      "fichiers_concernes": [
        "apps/web/src/hooks/useLocalStorage.ts"
      ],
      "lignes_approximatives": [
        "useLocalStorage.ts:23, 43, 54"
      ],
      "symptomes": [
        "Logs en production",
        "Inconsistance dans le logging",
        "Code quality compromise"
      ],
      "cause_probable": "Utilisation de console.warn() au lieu du logger centralisé.",
      "solution_proposee": "Remplacer console.warn() par le logger centralisé. Utiliser logger.warn() ou logger.error() selon le cas.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus de console.warn",
        "Tester le logging",
        "Vérifier en production"
      ],
      "priorite": 50,
      "impact": "Logs en production",
      "statut": "pending"
    },
    {
      "id": 51,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Inputs dans LoginPage et RegisterPage sans aria-describedby pour les erreurs",
      "description": "Les champs de formulaire dans LoginPage et RegisterPage affichent des erreurs mais ne les associent pas avec aria-describedby, rendant les erreurs inaccessibles aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/pages/LoginPage.tsx",
        "apps/web/src/features/auth/pages/RegisterPage.tsx",
        "apps/web/src/features/auth/components/AuthInput.tsx"
      ],
      "lignes_approximatives": [
        "LoginPage.tsx:236-257",
        "RegisterPage.tsx:champs avec erreurs",
        "AuthInput.tsx:gestion des erreurs"
      ],
      "symptomes": [
        "Erreurs non annoncées par les lecteurs d'écran",
        "Accessibilité compromise",
        "Conformité WCAG compromise"
      ],
      "cause_probable": "Les erreurs sont affichées mais pas associées avec aria-describedby sur les inputs.",
      "solution_proposee": "Ajouter aria-describedby sur les inputs pointant vers l'élément d'erreur. Utiliser un ID unique pour chaque message d'erreur.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que les erreurs sont annoncées",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 51,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout de aria-describedby pour les erreurs dans LoginForm et Input du design-system : 1) Ajout de aria-describedby et aria-invalid dans LoginForm pour les inputs email et password, 2) Ajout d'IDs uniques pour les messages d'erreur (email-error, password-error), 3) Mise à jour du composant Input du design-system pour supporter aria-describedby et aria-invalid. Les lecteurs d'écran peuvent maintenant annoncer les erreurs correctement."
    },
    {
      "id": 52,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "ChatPage fait plusieurs requêtes pour le token WebSocket",
      "description": "Le composant ChatPage utilise useQuery pour récupérer le token WebSocket mais peut faire plusieurs requêtes si le composant se re-rend.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/pages/ChatPage.tsx"
      ],
      "lignes_approximatives": [
        "ChatPage.tsx:25-35"
      ],
      "symptomes": [
        "Requêtes redondantes pour le token",
        "Performance dégradée",
        "Charge serveur excessive"
      ],
      "cause_probable": "useQuery peut se déclencher plusieurs fois si les dépendances changent ou si le composant se re-rend.",
      "solution_proposee": "Utiliser staleTime et cacheTime pour éviter les requêtes redondantes. S'assurer que enabled est correctement configuré.",
      "tests_a_effectuer": [
        "Vérifier le nombre de requêtes",
        "Tester avec React DevTools",
        "Vérifier les performances"
      ],
      "priorite": 52,
      "impact": "Performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout de staleTime et gcTime dans useQuery pour le token WebSocket dans ChatPage.tsx : 1) staleTime de 5 minutes pour éviter les requêtes multiples pendant la période de validité du token, 2) gcTime de 10 minutes pour garder le token en cache, 3) Le token est maintenant mis en cache pour éviter les requêtes redondantes lors de la reconnexion ou du remontage du composant."
    },
    {
      "id": 53,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Boutons dans Pagination sans type explicite",
      "description": "Les boutons dans le composant Pagination n'ont pas toujours de type explicite, ce qui peut causer des problèmes si le composant est utilisé dans un formulaire.",
      "fichiers_concernes": [
        "apps/web/src/components/navigation/Pagination.tsx"
      ],
      "lignes_approximatives": [
        "Pagination.tsx:128-234"
      ],
      "symptomes": [
        "Boutons peuvent soumettre des formulaires par accident",
        "Comportement inattendu",
        "UX dégradée"
      ],
      "cause_probable": "Les boutons n'ont pas type=\"button\" explicite.",
      "solution_proposee": "Ajouter type=\"button\" sur tous les boutons de pagination pour éviter la soumission accidentelle de formulaires.",
      "tests_a_effectuer": [
        "Tester dans un formulaire",
        "Vérifier que les boutons ne soumettent pas",
        "Tester le comportement"
      ],
      "priorite": 53,
      "impact": "Comportement inattendu",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout de type='button' explicite sur tous les boutons de Pagination.tsx : 1) Ajout de type='button' sur les boutons First, Previous, Next, Last et les boutons de numéro de page, 2) Cela évite que les boutons déclenchent une soumission de formulaire si le composant Pagination est utilisé dans un formulaire, 3) Comportement plus prévisible et conforme aux standards HTML."
    },
    {
      "id": 54,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Select utilise role=\"menuitem\" au lieu de role=\"option\"",
      "description": "Le composant SelectOptionItem utilise role=\"menuitem\" mais devrait utiliser role=\"option\" car c'est une option dans un select, pas un élément de menu.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/select.tsx"
      ],
      "lignes_approximatives": [
        "select.tsx:404-430"
      ],
      "symptomes": [
        "Rôle ARIA incorrect",
        "Lecteurs d'écran peuvent annoncer incorrectement",
        "Accessibilité compromise"
      ],
      "cause_probable": "Utilisation incorrecte de role=\"menuitem\" au lieu de role=\"option\".",
      "solution_proposee": "Changer role=\"menuitem\" en role=\"option\" dans SelectOptionItem. S'assurer que le conteneur parent a role=\"listbox\".",
      "tests_a_effectuer": [
        "Vérifier les rôles ARIA",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 54,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Le problème #54 était déjà corrigé dans #49. SelectOptionItem utilise maintenant role='option' et le conteneur parent a role='listbox'. Le composant respecte maintenant les standards ARIA pour les selects."
    },
    {
      "id": 55,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "DashboardPage utilise formatDistanceToNow sans memoization",
      "description": "Le composant DashboardPage utilise formatDistanceToNow dans formatTimestamp qui est appelé à chaque render, causant des calculs redondants.",
      "fichiers_concernes": [
        "apps/web/src/pages/DashboardPage.tsx"
      ],
      "lignes_approximatives": [
        "DashboardPage.tsx:91-100"
      ],
      "symptomes": [
        "Calculs redondants à chaque render",
        "Performance dégradée",
        "Re-renders inutiles"
      ],
      "cause_probable": "formatTimestamp est appelé à chaque render sans memoization.",
      "solution_proposee": "Utiliser useMemo pour memoizer les timestamps formatés. Ne recalculer que si les données changent.",
      "tests_a_effectuer": [
        "Vérifier les performances",
        "Tester avec React DevTools Profiler",
        "Vérifier les re-renders"
      ],
      "priorite": 55,
      "impact": "Performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Memoization des timestamps formatés dans DashboardPage.tsx : 1) Utilisation de useMemo pour créer un cache des timestamps formatés basé sur recentActivity, 2) La fonction formatTimestamp utilise maintenant ce cache au lieu de recalculer formatDistanceToNow à chaque render, 3) Performance améliorée en évitant les recalculs inutiles lors des re-renders."
    },
    {
      "id": 56,
      "gravite": "MOYENNE",
      "categorie": "Gestion d'erreurs",
      "titre": "LibraryPage n'a pas de gestion d'erreur pour batchDeleteTracks et batchUpdateTracks",
      "description": "Les fonctions handleBulkDelete et handleBulkUpdate dans LibraryPage catch les erreurs mais ne les affichent pas toujours correctement à l'utilisateur.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:173-210"
      ],
      "symptomes": [
        "Erreurs peuvent être silencieuses",
        "UX dégradée",
        "Debugging difficile"
      ],
      "cause_probable": "Les erreurs sont catchées mais pas toujours affichées avec un message utilisateur approprié.",
      "solution_proposee": "S'assurer que toutes les erreurs sont affichées avec toast.error() ou un message utilisateur approprié. Logger les erreurs pour le debugging.",
      "tests_a_effectuer": [
        "Tester les scénarios d'erreur",
        "Vérifier que les erreurs sont affichées",
        "Tester l'UX"
      ],
      "priorite": 56,
      "impact": "UX dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion d'erreur pour batchUpdateTracks dans LibraryPage.tsx : 1) Extraction des messages d'erreur détaillés depuis error.response.data, 2) Fallback vers error.message ou message par défaut si les détails ne sont pas disponibles, 3) Log de l'erreur complète dans la console pour le debugging, 4) Message d'erreur plus informatif pour l'utilisateur."
    },
    {
      "id": 57,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "TableRow dans LibraryPage n'a pas de aria-selected pour les lignes sélectionnées",
      "description": "Les lignes de table dans LibraryPage changent de style quand elles sont sélectionnées mais n'ont pas aria-selected, rendant l'état de sélection inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:392-462"
      ],
      "symptomes": [
        "État de sélection non annoncé",
        "Lecteurs d'écran ne peuvent pas décrire la sélection",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les lignes changent de style mais n'ont pas aria-selected=\"true\" quand elles sont sélectionnées.",
      "solution_proposee": "Ajouter aria-selected=\"true\" sur les TableRow sélectionnées. S'assurer que l'état est correctement annoncé.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que la sélection est annoncée",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 57,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout de aria-selected sur TableRow dans LibraryPage.tsx : 1) Ajout de aria-selected={selectedTracks.has(track.id)} sur chaque TableRow pour indiquer l'état de sélection, 2) Les lecteurs d'écran peuvent maintenant annoncer quelles lignes sont sélectionnées, 3) Accessibilité améliorée pour les utilisateurs de lecteurs d'écran."
    },
    {
      "id": 58,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "MarketplaceHome charge tous les produits même avec pagination",
      "description": "Le composant MarketplaceHome utilise la pagination mais peut charger tous les produits si la pagination n'est pas correctement implémentée côté backend.",
      "fichiers_concernes": [
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "MarketplaceHome.tsx:41-83"
      ],
      "symptomes": [
        "Chargement de tous les produits",
        "Performance dégradée",
        "Charge serveur excessive"
      ],
      "cause_probable": "La pagination peut ne pas être correctement implémentée ou les paramètres page/limit ne sont pas utilisés.",
      "solution_proposee": "Vérifier que la pagination est correctement implémentée côté backend. S'assurer que les paramètres page et limit sont utilisés.",
      "tests_a_effectuer": [
        "Vérifier le nombre de produits chargés",
        "Tester la pagination",
        "Vérifier les performances"
      ],
      "priorite": 58,
      "impact": "Performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "MarketplaceHome charge déjà les produits avec pagination : 1) Les paramètres page et limit sont passés à marketplaceService.fetchProducts, 2) Le backend retourne seulement les produits de la page demandée, 3) La pagination est correctement implémentée avec setTotalPages et setTotal. Le problème était mal identifié."
    },
    {
      "id": 59,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Slider n'a pas aria-valuenow, aria-valuemin, aria-valuemax",
      "description": "Le composant Slider n'a pas les attributs ARIA nécessaires pour rendre sa valeur accessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/ui/slider.tsx"
      ],
      "lignes_approximatives": [
        "slider.tsx:105-116"
      ],
      "symptomes": [
        "Valeur du slider non annoncée",
        "Lecteurs d'écran ne peuvent pas décrire la valeur",
        "Accessibilité compromise"
      ],
      "cause_probable": "L'input range n'a pas les attributs ARIA nécessaires.",
      "solution_proposee": "Ajouter aria-valuenow, aria-valuemin, aria-valuemax sur l'input range. Ajouter aria-label ou aria-labelledby.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que la valeur est annoncée",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 59,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Le problème #59 était déjà corrigé dans #43. Le Slider a maintenant aria-valuenow, aria-valuemin, et aria-valuemax sur l'input range. Le composant respecte maintenant les standards ARIA pour les sliders."
    },
    {
      "id": 60,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "useChat utilise _errorCount avec any pour limiter les logs",
      "description": "Le hook useChat utilise (ws.current as any)?._errorCount pour limiter les logs d'erreur, ce qui est une solution de contournement non typée.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/hooks/useChat.ts"
      ],
      "lignes_approximatives": [
        "useChat.ts:126-130"
      ],
      "symptomes": [
        "Utilisation de any",
        "Solution de contournement",
        "Maintenabilité compromise"
      ],
      "cause_probable": "Besoin de stocker un compteur d'erreurs sur l'objet WebSocket mais pas de type approprié.",
      "solution_proposee": "Créer un type étendu pour WebSocket ou utiliser un ref séparé pour le compteur d'erreurs. Éviter l'utilisation de any.",
      "tests_a_effectuer": [
        "Corriger le typage",
        "Vérifier qu'il n'y a plus de any",
        "Tester le comportement"
      ],
      "priorite": 60,
      "impact": "Typage non strict",
      "statut": "pending"
    },
    {
      "id": 61,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "PlaylistList fait du tri côté client même avec pagination",
      "description": "Le composant PlaylistList fait du tri côté client avec useMemo même si les données sont paginées, ce qui peut causer des problèmes si le tri devrait être fait côté backend.",
      "fichiers_concernes": [
        "apps/web/src/features/playlists/components/PlaylistList.tsx"
      ],
      "lignes_approximatives": [
        "PlaylistList.tsx:84-110"
      ],
      "symptomes": [
        "Tri côté client inefficace",
        "Performance dégradée",
        "Logique métier côté client"
      ],
      "cause_probable": "Le tri est fait côté client au lieu d'être fait côté backend avec les paramètres de requête.",
      "solution_proposee": "Implémenter le tri côté backend. Utiliser les paramètres sortBy et sortOrder dans la requête API.",
      "tests_a_effectuer": [
        "Tester le tri côté backend",
        "Vérifier les performances",
        "Tester avec beaucoup de données"
      ],
      "priorite": 61,
      "impact": "Performance dégradée",
      "statut": "pending"
    },
    {
      "id": 62,
      "gravite": "BASSE",
      "categorie": "Accessibilité",
      "titre": "Checkbox dans LibraryPage n'a pas de label associé pour 'Select All'",
      "description": "La checkbox 'Select All' dans LibraryPage n'a pas de label associé, rendant sa fonction inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:375-382"
      ],
      "symptomes": [
        "Checkbox sans label",
        "Lecteurs d'écran ne peuvent pas décrire la fonction",
        "Accessibilité compromise"
      ],
      "cause_probable": "La checkbox n'a pas de label ou aria-label.",
      "solution_proposee": "Ajouter aria-label=\"Sélectionner tout\" ou un label associé sur la checkbox 'Select All'.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que la fonction est annoncée",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 62,
      "impact": "Accessibilité compromise",
      "statut": "pending"
    },
    {
      "id": 63,
      "gravite": "BASSE",
      "categorie": "UX",
      "titre": "Pas de message d'état vide cohérent dans les listes",
      "description": "Les composants de liste (LibraryPage, PlaylistList, etc.) affichent des messages d'état vide différents, causant une expérience utilisateur inconsistante.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx",
        "apps/web/src/features/playlists/components/PlaylistList.tsx",
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:464-475",
        "PlaylistList.tsx:état vide",
        "MarketplaceHome.tsx:229-238"
      ],
      "symptomes": [
        "Messages d'état vide inconsistants",
        "UX dégradée",
        "Expérience utilisateur confuse"
      ],
      "cause_probable": "Chaque composant gère son propre message d'état vide différemment.",
      "solution_proposee": "Créer un composant EmptyState standardisé. Utiliser le même pattern partout. Ajouter des icônes et messages cohérents.",
      "tests_a_effectuer": [
        "Auditer tous les messages d'état vide",
        "Standardiser les composants",
        "Tester l'UX"
      ],
      "priorite": 63,
      "impact": "UX dégradée",
      "statut": "pending"
    },
    {
      "id": 64,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "DashboardPage utilise formatNumber sans memoization",
      "description": "Le composant DashboardPage utilise formatNumber dans le render qui est appelé à chaque render, causant des calculs redondants.",
      "fichiers_concernes": [
        "apps/web/src/pages/DashboardPage.tsx"
      ],
      "lignes_approximatives": [
        "DashboardPage.tsx:31-39, 44-69"
      ],
      "symptomes": [
        "Calculs redondants à chaque render",
        "Performance dégradée",
        "Re-renders inutiles"
      ],
      "cause_probable": "formatNumber est appelé à chaque render sans memoization.",
      "solution_proposee": "Utiliser useMemo pour memoizer les valeurs formatées. Ne recalculer que si les stats changent.",
      "tests_a_effectuer": [
        "Vérifier les performances",
        "Tester avec React DevTools Profiler",
        "Vérifier les re-renders"
      ],
      "priorite": 64,
      "impact": "Performance dégradée",
      "statut": "pending"
    },
    {
      "id": 65,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "ChatPage utilise _disconnect avec underscore pour variable non utilisée",
      "description": "Le composant ChatPage utilise const { disconnect: _disconnect } = useChat() pour indiquer qu'une variable n'est pas utilisée, ce qui est une mauvaise pratique.",
      "fichiers_concernes": [
        "apps/web/src/features/chat/pages/ChatPage.tsx"
      ],
      "lignes_approximatives": [
        "ChatPage.tsx:18"
      ],
      "symptomes": [
        "Code non propre",
        "Variable non utilisée",
        "Maintenabilité compromise"
      ],
      "cause_probable": "disconnect est disponible mais non utilisé, donc préfixé avec underscore.",
      "solution_proposee": "Soit utiliser disconnect dans un useEffect cleanup, soit ne pas le destructurer du hook. Nettoyer le code.",
      "tests_a_effectuer": [
        "Vérifier l'utilisation de disconnect",
        "Nettoyer le code",
        "Vérifier qu'il n'y a plus de variables non utilisées"
      ],
      "priorite": 65,
      "impact": "Code non propre",
      "statut": "pending"
    },
    {
      "id": 66,
      "gravite": "MOYENNE",
      "categorie": "Navigation",
      "titre": "Header utilise Link pour le logo mais devrait être un bouton si c'est juste pour navigation",
      "description": "Le Header utilise Link pour le logo qui pointe vers /dashboard, mais si c'est juste pour la navigation, cela devrait être cohérent avec le reste de l'application.",
      "fichiers_concernes": [
        "apps/web/src/components/layout/Header.tsx"
      ],
      "lignes_approximatives": [
        "Header.tsx:95-105"
      ],
      "symptomes": [
        "Navigation peut être inconsistante",
        "Comportement peut être inattendu"
      ],
      "cause_probable": "Utilisation de Link au lieu de navigate() ou vice versa.",
      "solution_proposee": "Standardiser la navigation. Utiliser Link pour les liens et navigate() pour les actions programmatiques.",
      "tests_a_effectuer": [
        "Tester la navigation du logo",
        "Vérifier la cohérence",
        "Tester le comportement"
      ],
      "priorite": 66,
      "impact": "Navigation inconsistante",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "L'utilisation de Link pour le logo dans Header.tsx est correcte et appropriée : 1) Link de React Router est le composant approprié pour la navigation vers le dashboard, 2) Il permet l'ouverture dans un nouvel onglet avec Ctrl+Click, 3) Il gère correctement l'historique du navigateur. Le problème était mal identifié."
    },
    {
      "id": 67,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "Header menu utilisateur n'a pas aria-controls pour associer le menu",
      "description": "Le bouton du menu utilisateur dans Header n'a pas aria-controls pour associer le menu déroulant, rendant la relation inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/components/layout/Header.tsx"
      ],
      "lignes_approximatives": [
        "Header.tsx:147-159"
      ],
      "symptomes": [
        "Relation bouton-menu non annoncée",
        "Lecteurs d'écran ne peuvent pas décrire la relation",
        "Accessibilité compromise"
      ],
      "cause_probable": "Le bouton n'a pas aria-controls pointant vers le menu.",
      "solution_proposee": "Ajouter aria-controls sur le bouton pointant vers l'ID du menu. S'assurer que le menu a un ID unique.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que la relation est annoncée",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 67,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Ajout de aria-controls sur le bouton du menu utilisateur dans Header.tsx : 1) Ajout de aria-controls='user-menu' sur le bouton pour associer le bouton au menu, 2) Ajout de id='user-menu' sur le div du menu pour créer la relation, 3) Les lecteurs d'écran peuvent maintenant associer le bouton au menu qu'il contrôle, améliorant l'accessibilité."
    },
    {
      "id": 68,
      "gravite": "MOYENNE",
      "categorie": "Performance",
      "titre": "DashboardPage utilise useDashboard qui peut faire plusieurs requêtes",
      "description": "Le hook useDashboard dans DashboardPage peut faire plusieurs requêtes pour récupérer les stats et l'activité récente, causant des requêtes redondantes.",
      "fichiers_concernes": [
        "apps/web/src/pages/DashboardPage.tsx",
        "apps/web/src/features/dashboard/hooks/useDashboard.ts"
      ],
      "lignes_approximatives": [
        "DashboardPage.tsx:23",
        "useDashboard.ts:requêtes"
      ],
      "symptomes": [
        "Requêtes redondantes",
        "Performance dégradée",
        "Charge serveur excessive"
      ],
      "cause_probable": "Le hook peut faire plusieurs requêtes indépendantes au lieu d'une seule requête agrégée.",
      "solution_proposee": "Optimiser le hook pour faire une seule requête ou utiliser Promise.all pour paralléliser les requêtes. Utiliser le cache de réponse.",
      "tests_a_effectuer": [
        "Vérifier le nombre de requêtes",
        "Tester avec React DevTools",
        "Vérifier les performances"
      ],
      "priorite": 68,
      "impact": "Performance dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "useDashboard fait déjà une seule requête : 1) useEffect avec dépendances vides garantit un seul appel au montage, 2) fetchData est appelé une seule fois, 3) Le hook retourne refetch pour permettre un rafraîchissement manuel si nécessaire. Ajout d'un commentaire pour clarifier l'intention."
    },
    {
      "id": 69,
      "gravite": "MOYENNE",
      "categorie": "Accessibilité",
      "titre": "DropdownMenu utilise role=\"menu\" mais les items utilisent role=\"menuitem\" au lieu de role=\"option\" pour Select",
      "description": "Le composant DropdownMenu utilise role=\"menu\" mais quand il est utilisé pour un Select, les items devraient utiliser role=\"option\" au lieu de role=\"menuitem\".",
      "fichiers_concernes": [
        "apps/web/src/components/ui/dropdown-menu.tsx",
        "apps/web/src/components/ui/select.tsx"
      ],
      "lignes_approximatives": [
        "dropdown-menu.tsx:168",
        "select.tsx:404-430"
      ],
      "symptomes": [
        "Rôles ARIA incorrects",
        "Lecteurs d'écran peuvent annoncer incorrectement",
        "Accessibilité compromise"
      ],
      "cause_probable": "Confusion entre menu et listbox pour les composants Select.",
      "solution_proposee": "Utiliser role=\"listbox\" pour le conteneur Select et role=\"option\" pour les items. Réserver role=\"menu\" pour les vrais menus.",
      "tests_a_effectuer": [
        "Vérifier les rôles ARIA",
        "Tester avec un lecteur d'écran",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 69,
      "impact": "Accessibilité compromise",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Le problème #69 était déjà corrigé dans #49. DropdownMenu utilise role='menu' pour les menus, et Select utilise role='listbox' avec role='option' pour les options. Les rôles ARIA sont maintenant corrects selon le contexte."
    },
    {
      "id": 70,
      "gravite": "MOYENNE",
      "categorie": "Gestion d'erreurs",
      "titre": "MarketplaceHome n'a pas de gestion d'erreur pour purchaseProduct",
      "description": "La fonction handlePurchase dans MarketplaceHome catch les erreurs mais peut ne pas afficher un message utilisateur approprié dans tous les cas.",
      "fichiers_concernes": [
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx"
      ],
      "lignes_approximatives": [
        "MarketplaceHome.tsx:90-102"
      ],
      "symptomes": [
        "Erreurs peuvent être silencieuses",
        "UX dégradée",
        "Debugging difficile"
      ],
      "cause_probable": "Les erreurs sont catchées mais le message peut ne pas être utilisateur-friendly.",
      "solution_proposee": "S'assurer que toutes les erreurs sont affichées avec toast.error() et un message utilisateur approprié. Utiliser formatUserFriendlyError().",
      "tests_a_effectuer": [
        "Tester les scénarios d'erreur",
        "Vérifier que les erreurs sont affichées",
        "Tester l'UX"
      ],
      "priorite": 70,
      "impact": "UX dégradée",
      "statut": "fixed",
      "date_correction": "2026-01-07",
      "notes_correction": "Amélioration de la gestion d'erreur pour purchaseProduct dans MarketplaceHome.tsx : 1) Extraction des messages d'erreur détaillés depuis error.response.data, 2) Fallback vers error.message ou message par défaut si les détails ne sont pas disponibles, 3) Log de l'erreur complète dans la console pour le debugging, 4) Message d'erreur plus informatif pour l'utilisateur."
    },
    {
      "id": 71,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "LoginPage utilise console.error dans onError",
      "description": "Le composant LoginPage utilise console.error() dans le callback onError au lieu du logger centralisé.",
      "fichiers_concernes": [
        "apps/web/src/features/auth/pages/LoginPage.tsx"
      ],
      "lignes_approximatives": [
        "LoginPage.tsx:110"
      ],
      "symptomes": [
        "Logs en production",
        "Inconsistance dans le logging",
        "Code quality compromise"
      ],
      "cause_probable": "Utilisation de console.error() au lieu du logger centralisé.",
      "solution_proposee": "Remplacer console.error() par le logger centralisé. Utiliser logger.error() avec les informations appropriées.",
      "tests_a_effectuer": [
        "Vérifier qu'il n'y a plus de console.error",
        "Tester le logging",
        "Vérifier en production"
      ],
      "priorite": 71,
      "impact": "Logs en production",
      "statut": "pending"
    },
    {
      "id": 72,
      "gravite": "BASSE",
      "categorie": "Performance",
      "titre": "LibraryPage utilise filteredTracks qui recalcule à chaque render",
      "description": "Le composant LibraryPage calcule filteredTracks à chaque render au lieu d'utiliser useMemo, causant des calculs redondants.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:107-112"
      ],
      "symptomes": [
        "Calculs redondants à chaque render",
        "Performance dégradée",
        "Re-renders inutiles"
      ],
      "cause_probable": "filteredTracks est calculé à chaque render sans memoization.",
      "solution_proposee": "Utiliser useMemo pour memoizer filteredTracks. Ne recalculer que si tracksData ou searchTerm changent.",
      "tests_a_effectuer": [
        "Vérifier les performances",
        "Tester avec React DevTools Profiler",
        "Vérifier les re-renders"
      ],
      "priorite": 72,
      "impact": "Performance dégradée",
      "statut": "pending"
    },
    {
      "id": 73,
      "gravite": "BASSE",
      "categorie": "Accessibilité",
      "titre": "ProductCard dans MarketplaceHome n'a pas d'aria-label pour les boutons d'action",
      "description": "Les boutons d'action dans ProductCard (ajouter au panier, acheter) n'ont pas d'aria-label, rendant leurs fonctions inaccessible aux lecteurs d'écran.",
      "fichiers_concernes": [
        "apps/web/src/features/marketplace/components/ProductCard.tsx"
      ],
      "lignes_approximatives": [
        "ProductCard.tsx:boutons d'action"
      ],
      "symptomes": [
        "Boutons sans aria-label",
        "Lecteurs d'écran ne peuvent pas décrire les boutons",
        "Accessibilité compromise"
      ],
      "cause_probable": "Les boutons n'ont pas d'aria-label ou de texte visible.",
      "solution_proposee": "Ajouter aria-label sur tous les boutons d'action. S'assurer que les boutons ont une description accessible.",
      "tests_a_effectuer": [
        "Tester avec un lecteur d'écran",
        "Vérifier que les boutons sont décrits",
        "Vérifier la conformité WCAG"
      ],
      "priorite": 73,
      "impact": "Accessibilité compromise",
      "statut": "pending"
    },
    {
      "id": 74,
      "gravite": "BASSE",
      "categorie": "UX",
      "titre": "Pas de loading state sur les boutons d'action dans MarketplaceHome",
      "description": "Les boutons 'Add to Cart' et 'Purchase' dans MarketplaceHome n'ont pas d'état de chargement pendant les actions asynchrones, laissant l'utilisateur dans le doute.",
      "fichiers_concernes": [
        "apps/web/src/pages/marketplace/MarketplaceHome.tsx",
        "apps/web/src/features/marketplace/components/ProductCard.tsx"
      ],
      "lignes_approximatives": [
        "MarketplaceHome.tsx:85-102",
        "ProductCard.tsx:boutons"
      ],
      "symptomes": [
        "Pas de feedback visuel pendant les actions",
        "Utilisateurs ne savent pas si l'action est en cours",
        "UX dégradée"
      ],
      "cause_probable": "Les boutons n'ont pas d'état disabled ou loading pendant les actions.",
      "solution_proposee": "Ajouter un état loading sur les boutons. Désactiver les boutons pendant les actions. Afficher un spinner ou un indicateur de chargement.",
      "tests_a_effectuer": [
        "Tester les actions asynchrones",
        "Vérifier le feedback visuel",
        "Tester l'UX"
      ],
      "priorite": 74,
      "impact": "UX dégradée",
      "statut": "pending"
    },
    {
      "id": 75,
      "gravite": "BASSE",
      "categorie": "Code Quality",
      "titre": "LibraryPage utilise genres et formats calculés à chaque render",
      "description": "Le composant LibraryPage calcule genres et formats à chaque render au lieu d'utiliser useMemo, causant des calculs redondants.",
      "fichiers_concernes": [
        "apps/web/src/features/library/pages/LibraryPage.tsx"
      ],
      "lignes_approximatives": [
        "LibraryPage.tsx:114-128"
      ],
      "symptomes": [
        "Calculs redondants à chaque render",
        "Performance dégradée",
        "Re-renders inutiles"
      ],
      "cause_probable": "genres et formats sont calculés à chaque render sans memoization.",
      "solution_proposee": "Utiliser useMemo pour memoizer genres et formats. Ne recalculer que si tracksData change.",
      "tests_a_effectuer": [
        "Vérifier les performances",
        "Tester avec React DevTools Profiler",
        "Vérifier les re-renders"
      ],
      "priorite": 75,
      "impact": "Performance dégradée",
      "statut": "pending"
    }
  ],
  "statistiques": {
    "par_gravite": {
      "CRITIQUE": 2,
      "HAUTE": 5,
      "MOYENNE": 46,
      "BASSE": 22
    },
    "par_categorie": {
      "Authentification": 2,
      "API": 2,
      "Accessibilité": 21,
      "Validation": 2,
      "PWA": 1,
      "Performance": 19,
      "WebSocket": 1,
      "TypeScript": 1,
      "Gestion d'erreurs": 5,
      "Race Conditions": 1,
      "Sécurité": 2,
      "UX": 4,
      "Meta Tags": 1,
      "Console": 1,
      "Configuration": 1,
      "Code Quality": 7,
      "Navigation": 3,
      "Memory Leaks": 1
    }
  }
}