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
- Module Overview + Runbook
- Health/Build/Test Status
- Security Findings
- Observability & Prod Readiness Gaps
- Performance Notes
- Issue List Priorisée (P0→P3)
- 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/stores/auth.ts,src/stores/chat.ts,src/stores/library.ts,src/stores/ui.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 RESTVITE_WS_BASE_URL: URL WebSocketVITE_STREAM_URL: URL streamingVITE_UPLOAD_URL: URL uploadVITE_APP_NAME: Nom de l'appVITE_DEBUG: Mode debug (boolean)VITE_USE_MSW: Activer MSW mocksVITE_FCM_VAPID_KEY: Push notifications (optionnel)
Fichiers de config :
vite.config.ts: Configuration Vite (aliases, plugins, CSP)tsconfig.json: TypeScript configvitest.config.ts: Tests configeslint.config.js: ESLint confignginx.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 attendstring(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.tsetnginx.conf)
Schéma DB / UUID
- IDs : Backend retourne
int64, frontend utilisestring(conversion danssrc/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 :
-
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
-
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étracksmanquanteChatPage: export par défaut manquant (lazy loading)
-
React Query v5 incompatibilité (P1) :
onSuccessdéprécié (remplacé paruseEffect+data)keepPreviousDatadéprécié (remplacé parplaceholderData: keepPreviousData)
-
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 :
src/features/playlists/hooks/usePlaylistTrack.test.tsx:useAddTrackToPlaylist— argument manquantsrc/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 :
useAuthStorevsuseAuth(deux hooks différents)apiServicevsapiClient(deux clients API différents)websocketServicevswsService(aliases, confusion)
Structure dossiers
- ✅ Feature-based :
src/features/* - ✅ Séparation claire : components, hooks, services, stores
- ⚠️ Duplication :
src/services/api.tsetsrc/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-121src/services/api/auth.ts: lignes 64-68, 124-126src/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
httpOnlycookies (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-evalen 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 102src/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à danspackage.json:dompurify@^3.3.0) au lieu de la sanitisation custom - Vérifier que
DOMPurifyest 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-Tokendans 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 380src/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
Authorizationsi 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-78src/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
expavant 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éthodessrc/services/websocket.ts: méthodesend()
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 18vite.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_KEYdoit ê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
.envest bien publique (commence parBKou 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.tsxsrc/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.tsest 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: SAMEORIGINau lieu deDENYdansnginx.conf - Pas de HSTS : Header
Strict-Transport-Securitymanquant dansnginx.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/warnpartout (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 occurrencessrc/features/streaming/services/playbackAnalyticsService.ts: 11 occurrencessrc/app/App.tsx: 1 occurrence- Et 50+ autres fichiers
Fix recommandé
- Implémenter un logger structuré (ex:
pinoouwinstoncôté client) - Ajouter
request_idpour 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 attendstring - 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 buildpuis ouvrirdist/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 —useCallbackavec dépendance manquante- Pas de
React.memosur les composants lourds (liste de tracks, messages chat)
Fix recommandé :
- Ajouter
React.memosur 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
staleTimepour 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 :
- Créer les modules manquants ou corriger les imports
- 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
TracketUserdanssrc/types/api.tsne correspondent pas à l'usage réel - Backend retourne plus de champs que définis dans les types
Fix minimal :
- Mettre à jour
src/types/api.tsavec tous les champs utilisés - 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 existsrc/features/library/hooks/useMyTracks.ts:17:'keepPreviousData' does not exist
Cause racine : Migration React Query v4 → v5 incomplète
Fix minimal :
- Remplacer
onSuccessparuseEffectavec dépendance surdata - Remplacer
keepPreviousDataparplaceholderData: 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 échouentuseAddTrackToPlaylist: argument manquantuseRemoveTrackFromPlaylist: fonction non exportée
Cause racine :
- Signature de fonction changée sans mise à jour des tests
- Export manquant
Fix minimal :
- Corriger les signatures de fonction
- Ajouter les exports manquants
- 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: classeApiService(singletonapiService)src/services/api/client.ts:apiClient(Axios instance)src/lib/apiClient.ts: autreapiClient(Axios instance)
Cause racine : Refactoring incomplet, plusieurs implémentations coexistent
Fix minimal :
- Unifier en un seul client API
- Migrer tous les usages vers le client unifié
- 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 manuelleString(conv.id)src/services/api.ts:361-374: conversion manuelleString(data.id)
Cause racine : Backend retourne int64, frontend attend string
Fix minimal :
- Créer un utilitaire
convertBackendId(id: number | string): string - Utiliser partout où nécessaire
- 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 :
- Créer un logger wrapper (
src/utils/logger.ts) - Remplacer tous les
console.*par le logger - 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:useCallbackavec dépendance manquante- Pas de
React.memosurTrackList,ChatMessages, etc.
Cause racine : Optimisation non faite
Fix minimal :
- Ajouter
React.memosur les composants de liste - 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/stores/auth.ts: exporteuseAuthStoresrc/features/auth/hooks/useAuth.ts: exporteuseAuth(utiliseuseAuthStoreen interne)src/services/api.ts:apiServicesrc/services/api/client.ts:apiClient
Cause racine : Refactoring incomplet, conventions non suivies
Fix minimal :
- Documenter les conventions de naming
- 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 :
- Remplacer progressivement les
anypar des types stricts - Utiliser
unknownsi 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 headerStrict-Transport-Security
Fix minimal :
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Plan de validation :
- Vérifier avec
curl -Ique 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 functionsrc/features/library/components/LibraryManager.tsx:247:isLiked={() => false} // Todo
Fix minimal :
- Créer des issues GitHub pour chaque TODO
- Supprimer les TODOs résolus
- 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)
-
✅ 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 typecheckpasse
- Créer
-
✅ WEB-P1-001 : Corriger les types Track/User
- Mettre à jour
src/types/api.tsavec tous les champs - Valider :
npm run typecheckpasse
- Mettre à jour
Phase 2 : Sécurité Critique (4-6h)
-
✅ WEB-P0-004 : Utiliser DOMPurify pour sanitisation
- Remplacer
sanitizeChatMessageparDOMPurify.sanitize() - Valider : Test XSS avec
<img src=x onerror=alert(1)>
- Remplacer
-
✅ WEB-P0-003 : Renforcer CSP (supprimer
unsafe-eval)- Modifier
vite.config.tspour production - Utiliser nonces pour scripts inline
- Valider : Build prod, vérifier CSP header
- Modifier
-
✅ 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
- Option alternative : Utiliser
-
✅ WEB-P0-005 : Implémenter CSRF token (nécessite backend)
- Implémenter
refreshCsrfToken()danssrc/services/csrf.ts - Ajouter header dans intercepteurs Axios
- Valider : Test CSRF échoue sans token
- Implémenter
Phase 3 : Tests (1h)
- ✅ WEB-P1-003 : Corriger tests usePlaylistTrack
- Corriger signatures et exports
- Valider :
npm test -- usePlaylistTrackpasse
Checklist P1 (par lots cohérents)
Lot 1 : React Query v5 Migration (1-2h)
- ✅ WEB-P1-002 : Migrer
onSuccess→useEffect- Remplacer dans
src/features/chat/pages/ChatPage.tsx - Remplacer
keepPreviousData→placeholderData - Valider :
npm run typecheck+npm test
- Remplacer dans
Lot 2 : Unification Clients API (3-4h)
- ✅ WEB-P1-005 : Unifier
apiServiceetapiClient- Choisir un client (recommandé :
apiClientdesrc/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
- Choisir un client (recommandé :
Lot 3 : JWT & WebSocket (3-4h)
-
✅ 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é
- Décoder JWT et vérifier
-
✅ 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)
- ✅ 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
- Créer
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
- Test XSS : Injecter
<script>alert(1)</script>dans chat, vérifier qu'il ne s'exécute pas - Test CSRF : Requête POST depuis site externe, vérifier rejet
- Test token expiration : Vérifier refresh automatique
P1 — Importants
- Test rate limiting : Envoyer 100 requêtes, vérifier limitation
- Test upload taille max : Tenter upload > 100MB, vérifier rejet
- 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.tsTests :npm run typecheckpasse
PR 2 : Security - XSS & CSP (P0-003, P0-004)
Titre : security: improve XSS protection (DOMPurify, strict CSP)
Fichiers :
src/features/chat/components/ChatMessages.tsxsrc/features/chat/components/VirtualizedChatMessages.tsxvite.config.tsTests : 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.tssrc/services/csrf.tssrc/services/api/client.tsTests : 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.tsxsrc/features/library/hooks/useMyTracks.tsTests :npm testpasse
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
apiServiceTests : 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.tssrc/services/websocket.tssrc/utils/token-manager.tsTests : 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.tssrc/services/api.ts(utiliser converter)src/features/playlists/hooks/usePlaylistTrack.test.tsxTests : 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
- Centraliser la gestion d'erreurs : Créer un service d'erreurs global
- Logger structuré : Implémenter un logger avec niveaux et corrélation
- Métriques : Ajouter des métriques custom (erreurs, latence, etc.)
- Documentation : Documenter les conventions de code et les patterns
- CI/CD : Ajouter des checks automatiques (typecheck, lint, tests) dans CI
Fin du rapport d'audit