veza/apps/web/AUDIT_TECHNIQUE_EXHAUSTIF.md

43 KiB

Audit Technique Exhaustif — Module Frontend Veza (apps/web)

Date: 2025-12-12
Auditeur: Auto (Cursor AI)
Module: Frontend React (Vite + TypeScript)
Version: 1.0.0


Table des matières

  1. Module Overview + Runbook
  2. Health/Build/Test Status
  3. Security Findings
  4. Observability & Prod Readiness Gaps
  5. Performance Notes
  6. Issue List Priorisée (P0→P3)
  7. Execution Plan

Module Overview + Runbook

But du module

Le module apps/web est l'application frontend React de la plateforme Veza, une plateforme audio collaborative avec streaming, chat en temps réel, bibliothèque musicale, playlists collaboratives, et marketplace.

Rôle exact : Interface utilisateur web (SPA) pour :

  • Authentification (JWT, 2FA, OAuth)
  • Streaming audio (HLS.js, WebRTC)
  • Chat en temps réel (WebSocket)
  • Gestion de bibliothèque et playlists
  • Marketplace de tracks
  • Profils utilisateurs et collaboration

Entrées / Sorties

APIs exposées (consommées)

HTTP REST :

  • Base URL : VITE_API_BASE_URL (défaut: http://localhost:8080/api/v1)
  • Client : Axios (src/services/api.ts, src/services/api/client.ts)
  • Endpoints principaux :
    • /auth/* : login, register, refresh, logout, me
    • /users/* : CRUD utilisateurs
    • /tracks/* : CRUD tracks, upload, download
    • /library/* : bibliothèque utilisateur
    • /conversations/*, /messages/* : chat
    • /playlists/* : playlists

WebSocket :

  • URL : VITE_WS_BASE_URL (défaut: ws://localhost:8081/ws)
  • Service : src/services/websocket.ts
  • Protocole : JSON messages avec types (join_conversation, send_message, typing, etc.)

Streaming :

  • URL : VITE_STREAM_URL (défaut: http://localhost:8082)
  • Protocole : HLS.js pour audio streaming

Formats

  • JSON : Toutes les APIs REST et WebSocket
  • FormData : Upload de fichiers (tracks, avatars)
  • Schémas Zod : Validation côté client (src/services/api.ts)

Dépendances internes

  • Stores Zustand : src/features/auth/store/authStore.ts (moved from stores/auth.ts), src/features/chat/store/chatStore.ts (moved from stores/chat.ts), src/stores/library.ts, src/stores/ui.ts, src/stores/cartStore.ts
  • Types partagés : src/types/api.ts, src/types/index.ts
  • Utils : src/utils/* (sanitize, token-manager, validation, etc.)
  • Hooks : src/hooks/* (useAuth, useDebounce, usePWA, etc.)

Dépendances externes

  • Base de données : Aucune (consomme API backend Go)
  • Redis : Aucune (consomme via backend)
  • Storage : localStorage (tokens), sessionStorage (refresh tokens), IndexedDB (PWA cache)
  • Services externes : Pas de dépendances directes (tout via backend)

Exécution

Commandes de build/run/dev

# Dev
npm run dev                    # Vite dev server (port 3000)
npm run dev:lab                # Dev avec vraie BDD (via scripts/start_lab.sh)
npm run dev:mocks              # Dev avec MSW mocks

# Build
npm run build                  # Production build → dist/

# Tests
npm test                       # Vitest (unit)
npm run test:e2e               # Playwright E2E
npm run test:e2e:mocks         # E2E avec MSW

# Qualité
npm run typecheck              # TypeScript check
npm run lint                   # ESLint
npm run format                 # Prettier

Configuration

Variables d'environnement (validées via Zod dans src/config/env.ts) :

  • VITE_API_BASE_URL : URL API REST
  • VITE_WS_BASE_URL : URL WebSocket
  • VITE_STREAM_URL : URL streaming
  • VITE_UPLOAD_URL : URL upload
  • VITE_APP_NAME : Nom de l'app
  • VITE_DEBUG : Mode debug (boolean)
  • VITE_USE_MSW : Activer MSW mocks
  • VITE_FCM_VAPID_KEY : Push notifications (optionnel)

Fichiers de config :

  • vite.config.ts : Configuration Vite (aliases, plugins, CSP)
  • tsconfig.json : TypeScript config
  • vitest.config.ts : Tests config
  • eslint.config.js : ESLint config
  • nginx.conf : Config production (Docker)
  • Dockerfile : Build production

Docker

docker build -t veza-frontend .
docker run -p 80:80 veza-frontend

Points d'intégration

Contrats d'API

Backend Go (veza-backend-api) :

  • Format réponse : { success: true, data: {...} } ou { error: "...", message: "..." }
  • Auth : JWT dans header Authorization: Bearer <token>
  • IDs : Backend retourne int64, frontend attend string (conversion nécessaire)

Chat Server Rust (veza-chat-server) :

  • WebSocket sur /ws
  • Token JWT en query param : ?token=<access_token>
  • Messages JSON : { type: string, data: any }

Stream Server Rust (veza-stream-server) :

  • HLS streaming via HTTP
  • WebSocket pour synchronisation playback

Auth

  • JWT : Access token (15min) + Refresh token (30/90 jours selon remember_me)
  • Storage : localStorage (access), sessionStorage/cookie (refresh)
  • Refresh automatique : Intercepteur Axios (src/services/api/client.ts)
  • 2FA : Supporté via src/services/2fa-service.ts
  • OAuth : Supporté via src/features/auth/hooks/useOAuthCallback.ts

Headers / CORS

  • CORS géré par backend
  • Headers de sécurité : CSP, X-Frame-Options, etc. (via vite.config.ts et nginx.conf)

Schéma DB / UUID

  • IDs : Backend retourne int64, frontend utilise string (conversion dans src/services/api.ts)
  • UUID : Pas utilisé (IDs numériques)

Health/Build/Test Status

Build Status

TypeScript Errors

Total : ~100+ erreurs TypeScript (voir ts_real_errors.log)

Catégories principales :

  1. Modules manquants (P0) :

    • @/hooks/use-toast : utilisé mais non exporté/existant
    • @/stores/player : utilisé mais non existant
    • @/components/ui/progress : utilisé mais non existant
    • @/hooks/useIntersectionObserver : utilisé mais non existant
    • @/features/settings/pages/SettingsPage : importé mais chemin incorrect
    • @/features/profile/pages/UserProfilePage : importé mais chemin incorrect
    • @/features/roles/pages/RolesPage : importé mais chemin incorrect
    • @/features/tracks/pages/TrackDetailPage : importé mais chemin incorrect
    • @/features/playlists/routes : importé mais chemin incorrect
    • @/pages/marketplace/MarketplaceHome : importé mais chemin incorrect
  2. Types incorrects (P1) :

    • Track : propriétés manquantes (url, cover_url, album, file_size, is_playing, progress)
    • User : propriétés manquantes (userId, username)
    • PaginatedResponse<Track> : propriété tracks manquante
    • ChatPage : export par défaut manquant (lazy loading)
  3. React Query v5 incompatibilité (P1) :

    • onSuccess déprécié (remplacé par useEffect + data)
    • keepPreviousData déprécié (remplacé par placeholderData: keepPreviousData)
  4. Types implicites any (P2) : ~20 occurrences

ESLint Warnings

Total : ~50+ warnings

Principaux :

  • no-console : 121 occurrences (devrait être supprimé en prod)
  • @typescript-eslint/no-explicit-any : ~30 occurrences
  • @typescript-eslint/no-unused-vars : 2 erreurs (variables non utilisées)
  • react-hooks/exhaustive-deps : 1 warning

Test Status

Coverage

Configuré : 80% threshold (branches, functions, lines, statements)
État actuel : Non mesuré (pas de rapport de coverage visible)

Tests unitaires (Vitest)

Total : 189 fichiers de test (.test.ts, .test.tsx)

Résultats :

  • La plupart des tests passent
  • 2 tests échouent :
    1. src/features/playlists/hooks/usePlaylistTrack.test.tsx : useAddTrackToPlaylist — argument manquant
    2. src/features/playlists/hooks/usePlaylistTrack.test.tsx : useRemoveTrackFromPlaylist — fonction non exportée

Problèmes identifiés :

  • MSW handlers manquants pour certains endpoints WebSocket
  • Mocks incomplets pour certains services

Tests E2E (Playwright)

Config : playwright.config.ts
Tests : e2e/qa-audit.spec.ts
État : Non exécuté dans cet audit

Gestion des erreurs

Points positifs

  • ErrorBoundary React (src/components/ErrorBoundary.tsx)
  • Intercepteurs Axios pour refresh token automatique
  • Validation Zod pour les réponses API

Points à améliorer

  • Pas de centralisation des erreurs (chaque composant gère ses erreurs)
  • Pas de logging structuré (console.log partout)
  • Pas de retry automatique pour les requêtes échouées (sauf refresh token)

Cohérence des conventions

Naming

  • Cohérent : PascalCase pour composants, camelCase pour fonctions
  • ⚠️ Incohérences :
    • useAuthStore vs useAuth (deux hooks différents)
    • apiService vs apiClient (deux clients API différents)
    • websocketService vs wsService (aliases, confusion)

Structure dossiers

  • Feature-based : src/features/*
  • Séparation claire : components, hooks, services, stores
  • ⚠️ Duplication : src/services/api.ts et src/services/api/client.ts (deux implémentations)

Séparation couches

  • Services séparés des composants
  • Stores Zustand pour state management
  • ⚠️ Logique métier parfois dans les composants (ex: src/features/library/components/LibraryManager.tsx)

Security Findings

Top 10 Risques Sécurité

P0 — Critiques (Exploitables immédiatement)

1. Tokens JWT stockés en localStorage (XSS vulnérable)

Fichiers :

  • src/services/api.ts : lignes 105-121
  • src/services/api/auth.ts : lignes 64-68, 124-126
  • src/utils/token-manager.ts : lignes 15-34, 40-54

Problème :

// src/services/api.ts:105-106
private getAccessToken(): string | null {
  return localStorage.getItem('access_token');
}

Les tokens JWT sont stockés dans localStorage, vulnérables aux attaques XSS. Un script malveillant injecté peut voler les tokens.

Impact : Vol de session, accès non autorisé aux comptes utilisateurs

Fix minimal :

  • Option 1 : Utiliser httpOnly cookies (nécessite backend)
  • Option 2 : Utiliser sessionStorage + rotation fréquente des tokens
  • Option 3 : Implémenter un service worker pour isoler les tokens

Plan de validation :

  • Test XSS : Injecter <script>alert(localStorage.getItem('access_token'))</script>
  • Vérifier que les tokens ne sont pas accessibles via XSS

Effet de bord : Nécessite modification backend pour cookies httpOnly

Effort : M (2-4h)


2. CSP non-strict en production (unsafe-inline, unsafe-eval)

Fichiers :

  • vite.config.ts : lignes 62-75

Problème :

'script-src': [
  "'self'",
  "'unsafe-inline' 'unsafe-eval' blob:",  // ⚠️ Dangereux
],
'style-src': [
  "'self'",
  "'unsafe-inline'",  // ⚠️ Nécessaire pour Tailwind mais risqué
],

La CSP en dev contient unsafe-inline et unsafe-eval, permettant l'exécution de scripts inline (XSS).

Impact : Attaques XSS facilitées

Fix minimal :

  • Utiliser des nonces CSP pour les scripts inline (déjà partiellement implémenté dans src/utils/csp.ts)
  • Supprimer unsafe-eval en production
  • Utiliser nonce- pour les styles inline si possible

Plan de validation :

  • Tester avec CSP strict en production
  • Vérifier que tous les scripts ont des nonces

Effet de bord : Peut casser certains composants si nonces mal gérés

Effort : S (1-2h)


3. Utilisation de dangerouslySetInnerHTML sans sanitisation complète

Fichiers :

  • src/features/chat/components/ChatMessages.tsx : ligne 102
  • src/features/chat/components/VirtualizedChatMessages.tsx : ligne 75

Problème :

// src/features/chat/components/ChatMessages.tsx:102
dangerouslySetInnerHTML={{ 
  __html: sanitizeChatMessage(message.content) 
}}

Bien que sanitizeChatMessage soit utilisé, la fonction sanitizeHTML dans src/utils/sanitize.ts peut avoir des failles (regex-based, pas de parser HTML complet).

Impact : XSS via messages de chat

Fix minimal :

  • Utiliser DOMPurify (déjà dans package.json : dompurify@^3.3.0) au lieu de la sanitisation custom
  • Vérifier que DOMPurify est bien utilisé partout

Plan de validation :

  • Test XSS : Envoyer <img src=x onerror=alert(1)> dans un message
  • Vérifier que le script ne s'exécute pas

Effet de bord : Aucun (DOMPurify est déjà une dépendance)

Effort : S (1h)


4. CSRF Token non implémenté

Fichiers :

  • src/services/csrf.ts : lignes 1-34

Problème :

// src/services/csrf.ts:14-17
public async refreshCsrfToken(): Promise<void> {
  // Placeholder: fetch from backend if needed
  // this.csrfToken = ...
}

Le service CSRF existe mais n'est pas implémenté. Aucune protection CSRF pour les requêtes POST/PUT/DELETE.

Impact : Attaques CSRF possibles (actions non autorisées)

Fix minimal :

  • Implémenter refreshCsrfToken() pour récupérer le token depuis le backend
  • Ajouter le header X-CSRF-Token dans tous les intercepteurs Axios
  • Backend doit générer et valider les tokens CSRF

Plan de validation :

  • Test CSRF : Créer une requête POST depuis un site externe
  • Vérifier que la requête est rejetée sans token CSRF valide

Effet de bord : Nécessite modification backend

Effort : M (2-3h)


5. WebSocket token en query param (exposé dans logs/URLs)

Fichiers :

  • src/services/api.ts : ligne 380
  • src/services/websocket.ts : ligne 45

Problème :

// src/services/api.ts:378-381
getWebSocketUrl(): string {
  const token = this.getAccessToken();
  return `${WS_BASE_URL}?token=${token}`;
}

Le token JWT est passé en query param, exposé dans :

  • Logs serveur
  • Historique navigateur
  • URLs partagées

Impact : Fuite de token via logs/historique

Fix minimal :

  • Utiliser le header Authorization si le serveur WebSocket le supporte
  • Sinon, utiliser un token temporaire (one-time token) généré par le backend

Plan de validation :

  • Vérifier que le token n'apparaît pas dans les logs serveur
  • Vérifier que l'historique navigateur ne contient pas le token

Effet de bord : Nécessite modification serveur WebSocket Rust

Effort : M (2-3h)


P1 — Haute priorité (Bugs fréquents / Dette bloquante)

6. Validation JWT côté client absente (expiration non vérifiée)

Fichiers :

  • src/services/api/client.ts : lignes 11-78
  • src/utils/token-manager.ts : lignes 40-54

Problème : Aucune vérification de l'expiration du token JWT côté client. Le token peut être expiré mais toujours utilisé jusqu'à ce que le backend renvoie 401.

Impact : Requêtes inutiles avec token expiré, UX dégradée

Fix minimal :

  • Décoder le JWT (base64) et vérifier exp avant chaque requête
  • Refresh automatique si expiration < 5min

Plan de validation :

  • Test : Créer un token expiré, vérifier qu'il est refresh automatiquement

Effet de bord : Aucun

Effort : S (1h)


7. Pas de rate limiting côté client

Fichiers :

  • src/services/api.ts : toutes les méthodes
  • src/services/websocket.ts : méthode send()

Problème : Aucune protection contre le spam de requêtes (rate limiting). Un utilisateur malveillant peut spammer l'API.

Impact : DoS côté client, surcharge serveur

Fix minimal :

  • Implémenter un rate limiter simple (ex: max 10 requêtes/seconde)
  • Utiliser un debounce pour les requêtes répétées

Plan de validation :

  • Test : Envoyer 100 requêtes simultanées, vérifier que seules 10 passent

Effet de bord : Peut ralentir certaines opérations légitimes

Effort : S (1-2h)


8. Secrets potentiels dans le code (VITE_FCM_VAPID_KEY)

Fichiers :

  • src/config/env.ts : ligne 18
  • vite.config.ts : pas de validation

Problème : VITE_FCM_VAPID_KEY est une clé publique (VAPID), mais elle est chargée côté client. Si elle est mal configurée, elle pourrait exposer une clé privée.

Impact : Fuite de clé si erreur de configuration

Fix minimal :

  • Documenter que VITE_FCM_VAPID_KEY doit être la clé publique uniquement
  • Ajouter une validation pour s'assurer que ce n'est pas une clé privée

Plan de validation :

  • Vérifier que la clé dans .env est bien publique (commence par BK ou similaire)

Effet de bord : Aucun

Effort : S (30min)


9. Pas de validation de taille de fichier upload côté client

Fichiers :

  • src/features/library/components/UploadModal.tsx
  • src/features/tracks/components/TrackUpload.tsx

Problème : Aucune validation de la taille de fichier avant upload. Un utilisateur peut tenter d'uploader un fichier de 10GB.

Impact : Surcharge serveur, DoS

Fix minimal :

  • Valider la taille max (ex: 100MB) avant upload
  • Afficher une erreur claire si dépassement

Plan de validation :

  • Test : Tenter d'uploader un fichier > 100MB, vérifier que c'est rejeté

Effet de bord : Aucun

Effort : S (1h)


10. CSP middleware non utilisé (créé mais jamais appelé)

Fichiers :

  • src/utils/csp.ts : lignes 185-202

Problème :

// src/utils/csp.ts:185-202
export function createCSPMiddleware() {
  return (_req: any, res: any, next: any) => {
    // ... génère CSP header
  }
}

Le middleware CSP est créé mais jamais utilisé (c'est du code Node.js dans un frontend React). La CSP est gérée via vite.config.ts uniquement.

Impact : CSP peut être inconsistante entre dev et prod

Fix minimal :

  • Supprimer le middleware inutile (code mort)
  • S'assurer que la CSP dans vite.config.ts est correcte pour prod

Plan de validation :

  • Vérifier que la CSP en prod est stricte (pas d'unsafe-inline)

Effet de bord : Aucun (code mort)

Effort : S (30min)


Autres problèmes sécurité (P2/P3)

P2 — Moyenne priorité

  • Pas de validation de format de fichier upload : Seule la validation backend existe
  • Pas de protection contre clickjacking : X-Frame-Options: SAMEORIGIN au lieu de DENY dans nginx.conf
  • Pas de HSTS : Header Strict-Transport-Security manquant dans nginx.conf
  • Logs console en production : 121 occurrences de console.log/error/warn (peuvent exposer des infos sensibles)

P3 — Basse priorité

  • Pas de validation de rate limiting pour WebSocket : Spam de messages possible
  • Pas de chiffrement des données sensibles en localStorage : Tokens non chiffrés (mais localStorage est déjà vulnérable)

Observability & Prod Readiness Gaps

Logs structurés

État actuel

Aucun logging structuré :

  • Utilisation de console.log/error/warn partout (121 occurrences)
  • Pas de corrélation (pas de request_id / trace_id)
  • Pas de niveaux de log cohérents
  • Logs en production (devrait être désactivé)

Fichiers concernés :

  • src/services/websocket.ts : 6 occurrences
  • src/features/streaming/services/playbackAnalyticsService.ts : 11 occurrences
  • src/app/App.tsx : 1 occurrence
  • Et 50+ autres fichiers

Fix recommandé

  • Implémenter un logger structuré (ex: pino ou winston côté client)
  • Ajouter request_id pour chaque requête API
  • Désactiver les logs en production (if (import.meta.env.DEV))

Effort : M (2-3h)


Metrics

État actuel

Aucune métrique :

  • Pas de Prometheus / StatsD
  • Pas de métriques custom (erreurs, latence, etc.)
  • Pas de healthcheck détaillé

Healthcheck

Basique : /health endpoint dans nginx.conf (ligne 26-30)

  • Retourne simplement 200 "healthy\n"
  • Pas de vérification de dépendances (API, WebSocket, etc.)

Fix recommandé

  • Ajouter un healthcheck frontend qui vérifie :
    • Connectivité API
    • Connectivité WebSocket
    • État du storage (localStorage disponible)
  • Exposer des métriques custom (optionnel, via API backend)

Effort : S (1-2h)


Timeouts / Retries

État actuel

⚠️ Partiel :

  • Timeout Axios : 10s (src/services/api.ts:58)
  • Retry : Seulement pour refresh token (intercepteur)
  • Pas de retry pour autres erreurs réseau
  • Pas de circuit breaker

Fix recommandé

  • Implémenter un retry avec backoff exponentiel pour les erreurs réseau (5xx, timeout)
  • Ajouter un circuit breaker pour éviter de spammer un serveur down
  • Configurer des timeouts différents selon le type de requête (upload: 60s, API: 10s)

Effort : M (2-3h)


Gestion de charge

État actuel

⚠️ Basique :

  • Pas de pool de connexions (Axios gère automatiquement)
  • Pas de limite de connexions WebSocket simultanées
  • Pas de chunking pour les uploads volumineux

Uploads

Chunked upload : Implémenté dans src/features/tracks/services/chunkedUploadService.ts

  • Upload par chunks pour fichiers volumineux
  • Retry automatique en cas d'échec

WebSocket

⚠️ Pas de backpressure :

  • Pas de limite de messages en queue
  • Pas de gestion de reconnexion intelligente (backoff exponentiel partiel)

Fix recommandé :

  • Limiter la queue de messages WebSocket (max 100 messages)
  • Implémenter un backpressure (pause si queue > 50)

Effort : S (1-2h)


Migrations / Compatibilité

État actuel

⚠️ Conversion IDs :

  • Backend retourne int64, frontend attend string
  • Conversion manuelle dans src/services/api.ts (lignes 339-344, 361-374)

Problème : Risque d'erreur si conversion oubliée

Fix recommandé :

  • Créer un utilitaire centralisé pour la conversion
  • Utiliser des types TypeScript stricts pour forcer la conversion

Effort : S (1h)


Performance Notes

Hotspots évidents

1. Bundle size

État : Non mesuré (bundle analyzer présent mais non exécuté)

Fichiers :

  • vite.config.ts : lignes 34-39 (bundle analyzer configuré)
  • dist/bundle-analysis.html : présent mais non analysé

Recommandations :

  • Analyser le bundle (npm run build puis ouvrir dist/bundle-analysis.html)
  • Identifier les dépendances lourdes
  • Code splitting par route (déjà fait via lazy loading)

Effort : S (30min pour analyse)


2. Re-renders inutiles

Problèmes identifiés :

  • src/components/data/Table.tsx : ligne 102 — useCallback avec dépendance manquante
  • Pas de React.memo sur les composants lourds (liste de tracks, messages chat)

Fix recommandé :

  • Ajouter React.memo sur les composants de liste
  • Corriger les dépendances de useCallback/useMemo

Effort : M (2-3h)


3. JSON parsing répétitif

Fichiers :

  • src/services/websocket.ts : ligne 59 — JSON.parse à chaque message

Impact : Faible (WebSocket messages sont petits)

Fix recommandé : Aucun (optimisation prématurée)


4. N+1 queries potentielles

Fichiers :

  • src/features/library/components/LibraryManager.tsx : chargement de tracks un par un possible

Impact : Moyen (si beaucoup de tracks)

Fix recommandé :

  • Utiliser la pagination côté API
  • Charger les tracks par batch

Effort : S (1h)


Streaming

HLS.js

Bien configuré : Utilisation de hls.js@^1.6.14

  • Buffering automatique
  • Adaptation de bitrate (si backend supporte)

Pas de problème identifié


React Query

Cache

Bien configuré : React Query v5 avec cache automatique

  • staleTime : défaut (0, toujours stale)
  • cacheTime : défaut (5min)

Recommandation :

  • Augmenter staleTime pour les données peu changeantes (profils, tracks)
  • Configurer staleTime: 5 * 60 * 1000 (5min) pour les tracks

Effort : S (30min)


WebSocket

Reconnexion

Bien implémenté : Backoff exponentiel dans src/services/websocket.ts (lignes 76-98)

  • Max 5 tentatives
  • Délai exponentiel : 3000 * 2^(attempt-1)

Pas de problème identifié


Issue List Priorisée (P0→P3)

Format des issues

Chaque issue suit le format :

  • ID : WEB-<P0|P1|P2|P3>-###
  • Titre
  • Impact (concret, scénarios)
  • Preuve : fichiers + symboles + extrait court
  • Cause racine
  • Fix minimal (patch-level, pas de refonte totale)
  • Plan de validation (tests + commande + cas limites)
  • Effet de bord / risque de régression
  • Effort estimé (S/M/L) + dépendances

P0 — Build Breakers / Sécurité Critique

WEB-P0-001 : Modules manquants (build cassé)

Impact : Build TypeScript échoue, application ne compile pas

Preuve :

  • src/components/player/AudioPlayer.tsx:6 : Cannot find module '@/hooks/use-toast'
  • src/components/player/AudioPlayer.tsx:2 : Cannot find module '@/stores/player'
  • src/components/ui/optimized-image.tsx:2 : Cannot find module '@/hooks/useIntersectionObserver'
  • src/components/ui/LazyComponent.tsx:39 : Cannot find module '@/features/settings/pages/SettingsPage'
  • Et 5+ autres modules manquants

Cause racine :

  • Fichiers supprimés/déplacés sans mise à jour des imports
  • Exports manquants dans les modules

Fix minimal :

  1. Créer les modules manquants ou corriger les imports
  2. Vérifier que tous les exports sont corrects

Plan de validation :

npm run typecheck  # Doit passer sans erreur
npm run build      # Doit compiler

Effet de bord : Aucun (fix nécessaire pour build)

Effort : M (2-3h)


WEB-P0-002 : Tokens JWT en localStorage (XSS vulnérable)

Voir Security Finding #1

Effort : M (2-4h)


WEB-P0-003 : CSP non-strict (unsafe-inline, unsafe-eval)

Voir Security Finding #2

Effort : S (1-2h)


WEB-P0-004 : dangerouslySetInnerHTML sans sanitisation complète

Voir Security Finding #3

Effort : S (1h)


WEB-P0-005 : CSRF Token non implémenté

Voir Security Finding #4

Effort : M (2-3h)


P1 — Bugs fréquents / Dette bloquante

WEB-P1-001 : Types Track/User incomplets (100+ erreurs TypeScript)

Impact : Erreurs TypeScript partout, développement ralenti, bugs runtime possibles

Preuve :

  • src/components/player/AudioPlayer.tsx:90 : Property 'url' does not exist on type 'Track'
  • src/components/player/AudioPlayer.tsx:179 : Property 'cover_url' does not exist on type 'Track'
  • src/features/library/components/VirtualizedTrackList.tsx:56 : Property 'album' does not exist on type 'Track'
  • src/features/chat/hooks/useChat.ts:9 : Property 'userId' does not exist on type 'AuthState'

Cause racine :

  • Types Track et User dans src/types/api.ts ne correspondent pas à l'usage réel
  • Backend retourne plus de champs que définis dans les types

Fix minimal :

  1. Mettre à jour src/types/api.ts avec tous les champs utilisés
  2. Vérifier la cohérence avec le backend Go

Plan de validation :

npm run typecheck  # Doit passer sans erreur

Effet de bord : Aucun (correction de types)

Effort : M (2-3h)


WEB-P1-002 : React Query v5 incompatibilité (onSuccess, keepPreviousData)

Impact : Warnings React Query, comportement incorrect possible

Preuve :

  • src/features/chat/pages/ChatPage.tsx:28 : 'onSuccess' does not exist
  • src/features/library/hooks/useMyTracks.ts:17 : 'keepPreviousData' does not exist

Cause racine : Migration React Query v4 → v5 incomplète

Fix minimal :

  1. Remplacer onSuccess par useEffect avec dépendance sur data
  2. Remplacer keepPreviousData par placeholderData: keepPreviousData

Plan de validation :

npm run typecheck  # Doit passer sans erreur
npm test           # Tests doivent passer

Effet de bord : Aucun (migration standard)

Effort : S (1-2h)


WEB-P1-003 : Tests échouent (usePlaylistTrack)

Impact : CI/CD peut échouer, confiance réduite dans les tests

Preuve :

  • src/features/playlists/hooks/usePlaylistTrack.test.tsx : 2 tests échouent
    • useAddTrackToPlaylist : argument manquant
    • useRemoveTrackFromPlaylist : fonction non exportée

Cause racine :

  • Signature de fonction changée sans mise à jour des tests
  • Export manquant

Fix minimal :

  1. Corriger les signatures de fonction
  2. Ajouter les exports manquants
  3. Mettre à jour les tests

Plan de validation :

npm test -- usePlaylistTrack  # Doit passer

Effet de bord : Aucun

Effort : S (1h)


WEB-P1-004 : Validation JWT côté client absente

Voir Security Finding #6

Effort : S (1h)


WEB-P1-005 : Duplication de clients API (apiService vs apiClient)

Impact : Confusion, maintenance difficile, bugs possibles

Preuve :

  • src/services/api.ts : classe ApiService (singleton apiService)
  • src/services/api/client.ts : apiClient (Axios instance)
  • src/lib/apiClient.ts : autre apiClient (Axios instance)

Cause racine : Refactoring incomplet, plusieurs implémentations coexistent

Fix minimal :

  1. Unifier en un seul client API
  2. Migrer tous les usages vers le client unifié
  3. Supprimer les clients dupliqués

Plan de validation :

grep -r "apiService\|apiClient" src/  # Vérifier qu'un seul client est utilisé
npm run typecheck                      # Doit passer
npm test                              # Tests doivent passer

Effet de bord : Risque de régression si migration incomplète

Effort : M (3-4h)


WEB-P1-006 : WebSocket token en query param

Voir Security Finding #5

Effort : M (2-3h)


WEB-P1-007 : Conversion IDs int64 → string manuelle (risque d'erreur)

Impact : Bugs possibles si conversion oubliée, maintenance difficile

Preuve :

  • src/services/api.ts:339-344 : conversion manuelle String(conv.id)
  • src/services/api.ts:361-374 : conversion manuelle String(data.id)

Cause racine : Backend retourne int64, frontend attend string

Fix minimal :

  1. Créer un utilitaire convertBackendId(id: number | string): string
  2. Utiliser partout où nécessaire
  3. Ajouter des types stricts pour forcer la conversion

Plan de validation :

grep -r "String(.*\.id)" src/  # Vérifier que toutes les conversions utilisent l'utilitaire
npm run typecheck              # Doit passer

Effet de bord : Aucun

Effort : S (1h)


P2 — Qualité, maintenabilité, perf non critique

WEB-P2-001 : 121 occurrences de console.log/error/warn (logs en production)

Impact : Performance légère, exposition d'infos sensibles possible, pollution console

Preuve :

grep -r "console\." src/ | wc -l  # 121 occurrences

Cause racine : Pas de logger structuré, logs de debug laissés

Fix minimal :

  1. Créer un logger wrapper (src/utils/logger.ts)
  2. Remplacer tous les console.* par le logger
  3. Désactiver les logs en production

Plan de validation :

grep -r "console\." src/ | wc -l  # Doit être 0
npm run build && npm run preview    # Vérifier que pas de logs en prod

Effet de bord : Aucun

Effort : M (2-3h)


WEB-P2-002 : Pas de rate limiting côté client

Voir Security Finding #7

Effort : S (1-2h)


WEB-P2-003 : Re-renders inutiles (pas de React.memo)

Impact : Performance dégradée sur les listes longues

Preuve :

  • src/components/data/Table.tsx:102 : useCallback avec dépendance manquante
  • Pas de React.memo sur TrackList, ChatMessages, etc.

Cause racine : Optimisation non faite

Fix minimal :

  1. Ajouter React.memo sur les composants de liste
  2. Corriger les dépendances de useCallback

Plan de validation :

  • Profiler avec React DevTools
  • Vérifier que les re-renders sont réduits

Effet de bord : Aucun

Effort : M (2-3h)


WEB-P2-004 : Pas de validation de taille de fichier upload

Voir Security Finding #9

Effort : S (1h)


WEB-P2-005 : Pas de logging structuré

Voir Observability - Logs structurés

Effort : M (2-3h)


WEB-P2-006 : Healthcheck basique (pas de vérification dépendances)

Voir Observability - Healthcheck

Effort : S (1-2h)


WEB-P2-007 : Pas de retry automatique (sauf refresh token)

Voir Observability - Timeouts / Retries

Effort : M (2-3h)


WEB-P2-008 : Bundle size non analysé

Voir Performance - Bundle size

Effort : S (30min)


WEB-P2-009 : CSP middleware inutile (code mort)

Voir Security Finding #10

Effort : S (30min)


WEB-P2-010 : Naming incohérent (useAuthStore vs useAuth, apiService vs apiClient)

Impact : Confusion, maintenance difficile

Preuve :

  • src/features/auth/store/authStore.ts : exporte useAuthStore (moved from stores/auth.ts)
  • src/features/auth/hooks/useAuth.ts : exporte useAuth (utilise useAuthStore en interne)
  • src/services/api.ts : apiService
  • src/services/api/client.ts : apiClient

Cause racine : Refactoring incomplet, conventions non suivies

Fix minimal :

  1. Documenter les conventions de naming
  2. Unifier progressivement (dans le cadre de P1-005)

Plan de validation :

  • Revue de code pour vérifier cohérence

Effet de bord : Aucun

Effort : S (1h pour documentation)


P3 — Cosmétique, refactors non urgents

WEB-P3-001 : 30+ occurrences de any (types implicites)

Impact : Perte de type safety, bugs possibles

Preuve :

grep -r ": any\|as any" src/ | wc -l  # ~30 occurrences

Cause racine : Types non définis, migration TypeScript incomplète

Fix minimal :

  1. Remplacer progressivement les any par des types stricts
  2. Utiliser unknown si type vraiment inconnu

Plan de validation :

npm run lint  # Doit passer sans warnings @typescript-eslint/no-explicit-any

Effet de bord : Aucun

Effort : L (4-6h, peut être fait progressivement)


WEB-P3-002 : Pas de HSTS header

Impact : Sécurité légèrement réduite (manque protection HTTPS forcé)

Preuve :

  • nginx.conf : pas de header Strict-Transport-Security

Fix minimal :

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

Plan de validation :

  • Vérifier avec curl -I que le header est présent

Effet de bord : Aucun

Effort : S (5min)


WEB-P3-003 : X-Frame-Options: SAMEORIGIN au lieu de DENY

Impact : Protection clickjacking partielle

Preuve :

  • nginx.conf:14 : X-Frame-Options "SAMEORIGIN"

Fix minimal :

add_header X-Frame-Options "DENY" always;

Plan de validation :

  • Vérifier avec curl -I

Effet de bord : Aucun (pas d'iframe dans l'app)

Effort : S (5min)


WEB-P3-004 : Pas de validation de format de fichier upload

Voir Security - Autres problèmes P2

Effort : S (1h)


WEB-P3-005 : TODO/FIXME dans le code (38 occurrences)

Impact : Dette technique, fonctionnalités incomplètes

Preuve :

grep -ri "TODO\|FIXME\|XXX\|HACK" src/ | wc -l  # 38 occurrences

Exemples :

  • src/features/chat/hooks/useChat.ts:114 : // TODO: Add fetchHistory function
  • src/features/library/components/LibraryManager.tsx:247 : isLiked={() => false} // Todo

Fix minimal :

  1. Créer des issues GitHub pour chaque TODO
  2. Supprimer les TODOs résolus
  3. Documenter les TODOs non urgents

Plan de validation :

  • Revue manuelle des TODOs

Effet de bord : Aucun

Effort : S (1h pour trier et documenter)


Execution Plan

Checklist P0 (ordre strict)

Phase 1 : Build Fixes (Critique — 2-3h)

  1. WEB-P0-001 : Créer/corriger les modules manquants

    • Créer src/hooks/use-toast.ts (ou corriger import)
    • Créer src/stores/player.ts (ou corriger import)
    • Créer src/hooks/useIntersectionObserver.ts (ou corriger import)
    • Corriger les imports dans src/components/ui/LazyComponent.tsx
    • Valider : npm run typecheck passe
  2. WEB-P1-001 : Corriger les types Track/User

    • Mettre à jour src/types/api.ts avec tous les champs
    • Valider : npm run typecheck passe

Phase 2 : Sécurité Critique (4-6h)

  1. WEB-P0-004 : Utiliser DOMPurify pour sanitisation

    • Remplacer sanitizeChatMessage par DOMPurify.sanitize()
    • Valider : Test XSS avec <img src=x onerror=alert(1)>
  2. WEB-P0-003 : Renforcer CSP (supprimer unsafe-eval)

    • Modifier vite.config.ts pour production
    • Utiliser nonces pour scripts inline
    • Valider : Build prod, vérifier CSP header
  3. WEB-P0-002 : Migrer tokens vers httpOnly cookies (nécessite backend)

    • Option alternative : Utiliser sessionStorage + rotation fréquente
    • Valider : Test XSS ne peut plus voler tokens
  4. WEB-P0-005 : Implémenter CSRF token (nécessite backend)

    • Implémenter refreshCsrfToken() dans src/services/csrf.ts
    • Ajouter header dans intercepteurs Axios
    • Valider : Test CSRF échoue sans token

Phase 3 : Tests (1h)

  1. WEB-P1-003 : Corriger tests usePlaylistTrack
    • Corriger signatures et exports
    • Valider : npm test -- usePlaylistTrack passe

Checklist P1 (par lots cohérents)

Lot 1 : React Query v5 Migration (1-2h)

  1. WEB-P1-002 : Migrer onSuccessuseEffect
    • Remplacer dans src/features/chat/pages/ChatPage.tsx
    • Remplacer keepPreviousDataplaceholderData
    • Valider : npm run typecheck + npm test

Lot 2 : Unification Clients API (3-4h)

  1. WEB-P1-005 : Unifier apiService et apiClient
    • Choisir un client (recommandé : apiClient de src/services/api/client.ts)
    • Migrer tous les usages
    • Supprimer src/services/api.ts (ou le garder comme wrapper)
    • Valider : npm run typecheck + npm test + tests manuels

Lot 3 : JWT & WebSocket (3-4h)

  1. WEB-P1-004 : Validation JWT expiration côté client

    • Décoder JWT et vérifier exp
    • Refresh automatique si < 5min
    • Valider : Test avec token expiré
  2. WEB-P1-006 : WebSocket token en header (nécessite backend)

    • Option alternative : Utiliser token temporaire (one-time)
    • Valider : Token n'apparaît pas dans logs

Lot 4 : Utilitaires (1h)

  1. WEB-P1-007 : Créer utilitaire conversion IDs
    • Créer src/utils/id-converter.ts
    • Remplacer toutes les conversions manuelles
    • Valider : grep -r "String(.*\.id)" src/ retourne 0

Quick Wins (≤ 1h chacun)

Sécurité

  • WEB-P2-009 : Supprimer CSP middleware inutile (30min)
  • WEB-P3-002 : Ajouter HSTS header (5min)
  • WEB-P3-003 : Changer X-Frame-Options à DENY (5min)
  • WEB-P2-004 : Validation taille fichier upload (1h)

Qualité

  • WEB-P2-008 : Analyser bundle size (30min)
  • WEB-P3-005 : Trier et documenter TODOs (1h)

Tests à ajouter en priorité

P0 — Critiques

  1. Test XSS : Injecter <script>alert(1)</script> dans chat, vérifier qu'il ne s'exécute pas
  2. Test CSRF : Requête POST depuis site externe, vérifier rejet
  3. Test token expiration : Vérifier refresh automatique

P1 — Importants

  1. Test rate limiting : Envoyer 100 requêtes, vérifier limitation
  2. Test upload taille max : Tenter upload > 100MB, vérifier rejet
  3. Test WebSocket reconnexion : Simuler déconnexion, vérifier reconnexion

PR Plan

PR 1 : Build Fixes (P0-001, P1-001)

Titre : fix: resolve TypeScript build errors (missing modules, incomplete types) Fichiers :

  • Créer modules manquants
  • Mettre à jour src/types/api.ts Tests : npm run typecheck passe

PR 2 : Security - XSS & CSP (P0-003, P0-004)

Titre : security: improve XSS protection (DOMPurify, strict CSP) Fichiers :

  • src/features/chat/components/ChatMessages.tsx
  • src/features/chat/components/VirtualizedChatMessages.tsx
  • vite.config.ts Tests : Test XSS manuel

PR 3 : Security - Tokens & CSRF (P0-002, P0-005)

Titre : security: migrate tokens to httpOnly cookies, implement CSRF protection Fichiers :

  • src/services/api/auth.ts
  • src/services/csrf.ts
  • src/services/api/client.ts Tests : Tests CSRF, test XSS token theft Note : Nécessite coordination backend

PR 4 : React Query v5 Migration (P1-002)

Titre : chore: migrate to React Query v5 API (remove onSuccess, keepPreviousData) Fichiers :

  • src/features/chat/pages/ChatPage.tsx
  • src/features/library/hooks/useMyTracks.ts Tests : npm test passe

PR 5 : Unify API Clients (P1-005)

Titre : refactor: unify API clients (remove duplication) Fichiers :

  • src/services/api.ts (supprimer ou wrapper)
  • src/services/api/client.ts (garder)
  • Tous les fichiers utilisant apiService Tests : Tests complets + tests manuels

PR 6 : JWT & WebSocket Security (P1-004, P1-006)

Titre : security: add JWT expiration validation, move WebSocket token to header Fichiers :

  • src/services/api/client.ts
  • src/services/websocket.ts
  • src/utils/token-manager.ts Tests : Tests expiration, tests WebSocket Note : WebSocket nécessite backend

PR 7 : Utilities & Tests (P1-007, P1-003)

Titre : fix: add ID converter utility, fix usePlaylistTrack tests Fichiers :

  • src/utils/id-converter.ts
  • src/services/api.ts (utiliser converter)
  • src/features/playlists/hooks/usePlaylistTrack.test.tsx Tests : Tests unitaires

PR 8 : Quick Wins (P2-009, P3-002, P3-003, P2-004, P2-008, P3-005)

Titre : chore: quick wins (remove dead code, add security headers, validate uploads, analyze bundle, document TODOs) Fichiers :

  • src/utils/csp.ts (supprimer middleware)
  • nginx.conf (ajouter headers)
  • src/features/library/components/UploadModal.tsx (validation taille)
  • package.json (script bundle analysis)
  • Documentation TODOs Tests : Tests manuels

Estimation totale

  • P0 : 8-12h (build fixes + sécurité critique)
  • P1 : 8-12h (bugs fréquents, dette bloquante)
  • P2 : 6-10h (qualité, maintenabilité)
  • P3 : 2-4h (cosmétique)

Total : 24-38h de travail (3-5 jours développeur)


Dépendances externes

Backend Go (veza-backend-api)

  • Support httpOnly cookies pour tokens (P0-002)
  • Endpoint CSRF token (P0-005)
  • Validation CSRF sur toutes les requêtes POST/PUT/DELETE (P0-005)

Chat Server Rust (veza-chat-server)

  • Support token JWT en header au lieu de query param (P1-006)

Stream Server Rust (veza-stream-server)

  • Aucune dépendance identifiée

Notes finales

Points positifs

Architecture feature-based claire
Tests unitaires nombreux (189 fichiers)
Utilisation de Zod pour validation
ErrorBoundary React
Upload par chunks pour gros fichiers
WebSocket avec reconnexion intelligente
PWA support (service worker)
i18n (français/anglais)

Points à surveiller

⚠️ Duplication de code (clients API)
⚠️ Logs console partout (121 occurrences)
⚠️ Types incomplets (Track/User)
⚠️ Sécurité tokens (localStorage)

Recommandations long terme

  1. Centraliser la gestion d'erreurs : Créer un service d'erreurs global
  2. Logger structuré : Implémenter un logger avec niveaux et corrélation
  3. Métriques : Ajouter des métriques custom (erreurs, latence, etc.)
  4. Documentation : Documenter les conventions de code et les patterns
  5. CI/CD : Ajouter des checks automatiques (typecheck, lint, tests) dans CI

Fin du rapport d'audit