veza/docs/archive/root-md/AUDIT_FRONTEND_EXHAUSTIF_2025_02.md
senke 43af35fd93 chore(audit 2.2, 2.3): nettoyer .md et .json à la racine
- Archiver 131 .md dans docs/archive/root-md/
- Archiver 22 .json dans docs/archive/root-json/
- Conserver 7 .md utiles (README, CONTRIBUTING, CHANGELOG, etc.)
- Conserver package.json, package-lock.json, turbo.json
- Ajouter README d'index dans chaque archive
2026-02-15 14:35:08 +01:00

21 KiB
Raw Blame History

Audit Frontend Exhaustif — Veza

Date : 2025-02-10
Cellule d'audit : Lead Frontend Architect, Design Engineer, Staff Engineer (Architecture), Expert DX / Performance / Dette technique
Objectif : Audit exhaustif, critique et sans complaisance du frontend et de ses connexions avec le reste du système, en vue d'atteindre une qualité visuelle, structurelle et perceptive équivalente aux meilleures plateformes audio/sociales (Spotify, Discord, SoundCloud, Deezer, Splice).


A. Diagnostic Global

A.1 Maturité réelle du frontend

Verdict : Produit intermédiaire (56/10) — entre prototype avancé et produit MVP industrialisé.

L'application Veza dispose de fondations solides : structure feature-based, design system documenté (KŌDŌ v3), stack moderne (React 18, Vite 7, Tailwind 4, TanStack Query, Zustand), MSW pour le développement et les tests, Storybook, et une batterie de tests (unitaires, intégration, E2E, visuels). Cependant, l'exécution est inégale et plusieurs dettes structurelles empêchent d'atteindre le niveau des références du marché.

Critère État Commentaire
Architecture Correcte en intention Feature-based, services, stores, routing lazy. Mais double source d'auth, callbacks no-op dans la config de routes, client API monolithique (~2238 lignes).
Qualité du code Inégale Bonne sur auth, playlists, player. Environ 40 fichiers avec valeurs Tailwind arbitraires malgré une règle explicite d'interdiction.
Design system Solide sur le papier Tokens, layout primitives, dark mode. Mais primitives peu utilisées, règles violées massivement, pas de lint pour les arbitraires.
UX / polish Insuffisant pour premium Skeletons et LoadingState présents mais pas systématiquement. États empty/error variables. Correctifs CSS visibles (fix-input-focus.css, fix-login-form.css).
Performance Base correcte Lazy routes, React Query, code splitting. Vendor chunk = 2 Mo (warning Vite). Pas de Suspense/streaming.
Accessibilité En option aria/roles présents mais non systématiques. Storybook a11y en todo. Pas de politique WCAG.

A.2 Forces structurelles existantes

  1. Design system KŌDŌ v3index.css contient une palette sémantique complète (oklch), layout primitives (max-w-layout-content, min-h-layout-main, etc.), easings, keyframes, dark mode. La cible est claire, même si non respectée partout.

  2. Storybook-first et MSW — Environ 324 stories, décorateur global (Theme, QueryClient, Router, Toast, Audio, Auth, i18n), handlers MSW très complets (~1682 lignes). Handlers par endpoint. Pas d'import de providers dans les stories.

  3. Patterns de chargement et d'erreurLOADING_STATES_PATTERN.md, composant LoadingState, skeletons dédiés par page. Données via React Query avec états loading/error gérés au niveau page (mais pas partout).

  4. Optimistic UIOPTIMISTIC_UPDATES.md et optimisticUpdates.ts. Utilisation dans playlists, likes, commentaires. Rollback et invalidation documentés.

  5. API client robuste — Requêtes avec retry, exponential backoff, refresh token, CSRF, validation Zod, déduplication, cache, offline queue. Gestion des erreurs centralisée.

  6. Intégration backend — Types générés (OpenAPI), proxy Vite en dev, withCredentials pour cookies httpOnly, flux auth cohérent.

A.3 Faiblesses bloquantes ou insidieuses

  1. Double source de vérité pour l'authAuthContext + useAuth() (Storybook, ProtectedRoute, pages) vs authStore (Zustand) + useAuthStore() (App, Sidebar, Login). Risque de désync et confusion pour tout nouveau dev. Dette d'architecture prioritaire.

  2. Client API monolithiqueclient.ts = 2238 lignes. ValidationMetricsTracker, ValidationAlerting, NetworkFailureTracker, interceptors, retry, refresh, CSRF, offline queue, etc. Tout dans un seul fichier. Maintenance et testabilité difficiles.

  3. Correctifs applicatifs visiblesmain.tsx charge fix-input-focus.css, fix-login-form.css, fixDisplayIssues, fixInputFocus. Problèmes de conception résolus par patch plutôt qu'à la source. Coût de maintenance et risque de régression élevés.

  4. Route config et couplage produitrouteConfig.tsx injecte des callbacks vides : onCreateProduct={() => {}}, onNavigateTrack={() => {}}. La routing ne doit pas porter de callbacks métier.

  5. Bundle vendor énormevendor-Bo5_qjiz.js2 Mo (minifié). Lucide-react, Framer Motion, HLS.js, Swagger UI, etc. Pas de lazy-load des dépendances lourdes.

  6. Header search inactif — La barre de recherche du header affiche un placeholder mais ne déclenche aucune navigation. UX trompeuse.


B. Architecture Frontend

B.1 Organisation des dossiers

src/
├── app/           # Point d'entrée React
├── components/    # ~969 fichiers — UI, views, layout, feedback
├── config/        # Env, config
├── context/       # AuthContext, etc.
├── features/      # ~783 fichiers — auth, chat, player, playlists, tracks, etc.
├── hooks/         # ~40 hooks
├── mocks/         # MSW handlers
├── pages/         # Pages (6)
├── providers/     # AuthProvider
├── router/        # Routes, ProtectedRoute, PublicRoute
├── schemas/       # Validation Zod
├── services/      # ~69 services (API, auth, commerce, etc.)
├── stores/        # Zustand (cart, library, rateLimit, ui)
├── styles/        # CSS, design system
├── types/         # Types, DTO, generated (OpenAPI)
└── utils/         # Helpers, error handling, state invalidation

Sain : Séparation features / components / services. Structure feature-based claire. Exports centralisés.

Confus :

  • components/ mélange UI atoms, vues métier, layout. Plus de 900 fichiers. Pas de sous-structure claire (ex. components/ui/ vs components/views/ vs components/layout/).
  • pages/ vs features/*/pages/ — double convention. Certaines pages sont dans features, d'autres dans pages/.
  • context/ et providers/ — AuthContext vs AuthProvider. Redondance.
  • stores/ minimal (4 stores) ; beaucoup de state dans les features (useState, useReducer). Pas de stratégie claire pour state global vs local.

B.2 Séparation des responsabilités (UI / logique / data)

Couche État Exemples
UI Correcte Composants présentiels, Radix UI, Tailwind.
Logique Inégale Hooks use*Page bien structurés (useSearchPage, useUserProfilePage). Mais useLibraryManager fait du fetch direct avec apiClient plutôt que React Query.
Data Mélangée React Query (~35 usages) vs fetch manuel (useState + useEffect). MarketplaceHome, SellerDashboardView, useLibraryManager utilisent fetch manuel. Pas de cohérence.

Recommandation : Migrer progressivement vers React Query pour tout fetch de données. Éviter les hooks useState + useEffect + apiClient directs.

B.3 Composants "god components" ou anti-patterns

Composant Lignes Problème
client.ts 2238 Monolithe. Devrait être découpé en modules (interceptors, retry, validation, etc.).
GlobalPlayer.tsx 301 Proche de la limite 300. Waveform inline, logique de layout. Acceptable mais à surveiller.
SettingsPage ~36 kB chunk Page lourde (beaucoup de sous-vues).
TrackDetailPage 55 kB Chunk important.

Pas de god component évident dans les composants React. Le principal problème est le client API.

B.4 Dette technique invisible mais dangereuse

  1. Auth dual — Toute évolution auth nécessite de modifier Context ET Store. Risque de bugs subtils (race conditions, désync).

  2. main.tsx — 278 lignes. waitForStylesheets() avec 3x requestAnimationFrame + setTimeout. Complexité d'init excessive. MSW, preload toast, fixDisplayIssues, fixInputFocus. Beaucoup de "magie" pour faire fonctionner l'app.

  3. Types générés — OpenAPI génère des types dans types/generated/. Utilisation partielle (certains services ont des types manuels). Risque de drift API ↔ frontend.

  4. Pas de policy stricte pour les erreurs — Certaines pages affichent un toast, d'autres un ErrorDisplay, d'autres rien. Pas de contrat homogène.


C. UI / UX / Qualité Visuelle

C.1 Cohérence visuelle globale

Le design system KŌDŌ (index.css, design-tokens.css, design-system.css) définit une palette cohérente (cyan/magenta, oklch), des ombres, des transitions. En pratique : environ 40 fichiers utilisent des valeurs arbitraires (w-[...], h-[...], rounded-[...], etc.). La Sidebar utilise w-64, z-[90], z-[95]. Le design system est sous-exploité.

Hiérarchie typographique : Classes .text-heading-1, .text-body, .text-caption documentées. Utilisation partielle. Beaucoup de text-sm, text-lg en dur.

C.2 Gestion de l'espace, du rythme, de la densité

  • Layout primitives : max-w-layout-content, min-h-layout-main, min-h-layout-page définis. Peu utilisés.
  • Espacement : gap-4, gap-6 utilisés. Parfois gap-[7px] ou équivalents arbitraires.
  • Densité : Variable. Certaines pages (Dashboard, Library) sont denses ; d'autres (Login, 404) aérées. Pas de règle explicite.

C.3 Transitions, animations, micro-feedbacks

  • Tokens : --duration-fast, --duration-normal, --ease-out, --ease-bounce définis.
  • Usage : duration-[var(--duration-normal)] dans GlobalPlayer, PlayerControls. Framer Motion utilisé pour certaines animations.
  • Micro-feedbacks : Boutons avec active:scale-95, hover:scale-105. Pas de feedback systématique sur les actions (like, follow, add to playlist) — optimistic UI partiel.

C.4 Comparaison explicite avec Spotify / Discord / SoundCloud / Deezer / Splice

Dimension Spotify Discord SoundCloud Deezer Splice Veza
Shell Header compact, sidebar collapsible Channel list, barre fixe Header simple Header + nav Dashboard clair Sidebar + Header OK, mais recherche vide
Player Barre fixe, minimisable Pas de player central Waveform intégré Barre compacte Player dédié Barre glass, waveform décoratif (pas audio)
Transitions Fluides, skeleton systématiques Animations douces Transitions basiques Fluides Transitions nettes Inégales
Empty states Illustrés, CTA clairs Messages personnalisés Basiques Illustrés Clairs KodoEmptyState présent, pas partout
Error states Toast + retry Toast + retry Basiques Toast Toast Variable (toast, ErrorDisplay, rien)
Polish Très élevé Élevé Moyen Élevé Moyen-élevé Moyen

Où Veza est nettement en dessous :

  • Recherche header non fonctionnelle.
  • Pas de skeleton systématique sur toutes les pages.
  • Correctifs CSS visibles (fix-input-focus, fix-login-form).
  • Waveform du player décoratif (pas lié à l'audio réel).

Où Veza pourrait rivaliser rapidement :

  • Design system (tokens, palette) déjà solide.
  • Player bar visuellement correct (glass, gradients).
  • Layout shell (sidebar, header) cohérent.

Ce qui manque pour passer un cap perceptif :

  • Recherche globale fonctionnelle.
  • Micro-interactions systématiques (hover, focus, loading).
  • Suppression des correctifs par refonte des composants concernés.
  • Uniformisation des états empty/error.

D. Système de Design

D.1 Existence d'un design system réel

Oui. KŌDŌ v3 documenté dans DESIGN_TOKENS.md, APP_SHELL.md, COLOR_USAGE.md, SPACING_GUIDE.md. Tokens dans index.css, design-tokens.css, design-system.css.

D.2 Qualité des tokens

Catégorie Qualité Commentaire
Couleurs Bonne oklch, palette sémantique (primary, secondary, muted, destructive, etc.).
Typo Bonne Classes .text-heading-1 à .text-caption. Échelle Tailwind documentée.
Spacing Bonne --layout-gap, --layout-gap-sm, --layout-gap-lg. Scale 4px base.
Radius Bonne --radius, rounded-2xl pour cartes.
Shadows Bonne --shadow-card, --shadow-modal, --shadow-player-thumb, etc.
Transitions Bonne --duration-fast, --ease-out, --ease-bounce.

D.3 Composants réutilisables vs duplication

  • UI : components/ui/ — Button, Input, Slider, Dialog, etc. (~247 fichiers). Bonne couverture.
  • Duplication : Certains composants (ex. ErrorDisplay, KodoEmptyState) ont des variantes similaires. Pas de règle stricte pour éviter la duplication.

D.4 Capacité du système à évoluer sans chaos

Fragile. Les règles (pas d'arbitraires, utiliser les primitives) sont documentées mais non appliquées par un outil (lint, plugin Tailwind). La migration vers les primitives est manuelle et non priorisée. Risque de régression à chaque nouvelle feature.


E. Connexions au Backend

E.1 Clarté des flux de données

  • API REST : apiClient (axios) avec baseURL, withCredentials, interceptors.
  • Types : Générés depuis OpenAPI (types/generated/). Utilisation partielle.
  • Services : Un service par domaine (authService, trackService, playlistService, etc.). Appels à apiClient ou à des modules API dédiés (api/tracks.ts, api/users.ts).

Flux : Page → Hook (use*Page) → Service → apiClient → Backend. React Query pour le cache et les états.

E.2 Robustesse face aux erreurs réseau

  • Retry : Exponential backoff sur 500, 502, 503, 504.
  • Refresh token : Boucle avec file d'attente. Protection contre les boucles infinies.
  • Offline : offlineQueue, OfflineIndicator. Requêtes mises en file.
  • Toast : Erreurs API affichées (sauf 401, 404, requêtes annulées). Throttling pour les erreurs réseau.

E.3 Gestion des états loading / empty / error

État Usage Cohérence
Loading Skeletons, spinners, LoadingState Pas partout. MarketplaceHome, SellerDashboardView : spinner générique.
Empty KodoEmptyState, composants dédiés Variable. Certaines pages n'ont pas d'empty state.
Error ErrorDisplay, toast Variable. Certaines pages affichent un toast, d'autres un ErrorDisplay, d'autres rien.

E.4 Synchronisation UI ↔ données

  • React Query : Cache, invalidation, staleTime. Sync cross-tabs via reactQuerySync.
  • Zustand : authStore, uiStore, cartStore, libraryStore. Pas de sync serveur pour libraryStore (hydratation optionnelle).
  • WebSocket : Chat, notifications. wsService pour le chat.

E.5 Optimistic UI et cache intelligent

  • Optimistic : Documenté (OPTIMISTIC_UPDATES.md). Utilisé pour playlists, likes, commentaires.
  • Cache : React Query gcTime 5 min, staleTime 1 min. responseCache pour certaines requêtes. Pas de stratégie globale (ex. SWR avec revalidation).

F. Performances & Perception

F.1 Performances techniques

Métrique Valeur Commentaire
Bundle principal ~224 kB (gzip) index-BncWOOVU.js
Vendor ~2 Mo (minifié) vendor-Bo5_qjiz.js. Warning Vite.
Chunks ~70+ Code splitting par route.
Lazy routes Oui LazyComponent pour chaque page.

Problèmes :

  • Vendor chunk trop gros. Lucide-react, Framer Motion, HLS.js, Swagger UI, etc. Pas de lazy-load.
  • Pas de Suspense aux limites de route. Le shell s'affiche, puis le contenu. Pas de skeleton immédiat au niveau route.

F.2 Performances perçues

  • Time to interactive : correct grâce au lazy loading. Pas de mesure LCP/INP.
  • Skeleton : Présent sur plusieurs pages. Pas systématique.
  • Optimistic UI : Présent sur like, follow, playlists. Pas sur toutes les actions.

F.3 Points où l'UI "fait pauvre" ou "fait lent"

  1. Écran de chargement auth — Spinner générique pendant l'init auth. Pas de skeleton du shell.
  2. Recherche header — Placeholder "What do you want to play?" mais non fonctionnel. Donne l'impression d'une feature incomplète.
  3. Correctifs CSSfix-input-focus.css avec !important partout. Indique des problèmes de conception.
  4. Callbacks no-oponCreateProduct={() => {}} dans la config. Signe de dette visible.

G. Comparaison avec les Produits de Référence

G.1 Pourquoi Spotify / Discord / SoundCloud / Deezer / Splice paraissent plus solides

Produit Raison de la solidité perçue
Spotify Transitions fluides, skeleton partout, pas de "trous" visuels. Player bar toujours cohérente. Recherche centrale et fonctionnelle.
Discord États loading/empty/error partout. Modales et transitions prévisibles. Pas de correctifs visibles.
SoundCloud Waveform réel (audio). Interface simple mais cohérente.
Deezer Design system strict. Polish élevé. Pas de demi-mesures.
Splice Interface claire pour créateurs. Flux d'achat fluide.

G.2 Écarts principaux Veza vs références

  1. Une seule source d'auth — Pas de double Context/Store.
  2. Pas de callbacks dans la route config — Routing découplé du métier.
  3. Checklist loading/empty/error par écran — Aucun écran sans traitement.
  4. Suppression des fix- par refonte* — Résoudre les problèmes à la source.
  5. Lint pour les primitives — Interdire les arbitraires par outil.
  6. Recherche fonctionnelle — Header search reliée à la navigation.

H. Plan d'Action Stratégique

Niveau 1 — Gains rapides (12 semaines)

Action Bénéfice Coût Risques
Connecter la recherche header UX immédiate. Navigation vers /search avec query. 24 h Faible
Remplacer les callbacks no-op Supprimer la dette visible. Props via layout ou contexte. 48 h Moyen (tests à vérifier)
Skeleton systématique sur 5 pages critiques Dashboard, Library, Marketplace, Search, Playlists. 12 j Faible
Uniformiser les états error Chaque page avec fetch doit avoir ErrorDisplay + retry. 1 j Faible
Audit des valeurs arbitraires Lancer report-arbitrary-values.mjs, lister les 10 fichiers les plus critiques. 2 h Nul

Niveau 2 — Refonte intermédiaire

Action Bénéfice Coût Risques
Unifier l'auth (Context → Store) Une seule source de vérité. Supprimer AuthContext, migrer useAuth vers useAuthStore. 35 j Élevé (régression auth, tests)
Découper client.ts Module interceptor, retry, refresh, validation. Fichiers < 400 lignes. 23 j Moyen (imports, tests)
Refonte focus des inputs Supprimer fix-input-focus.css. Utiliser focus-visible, ring tokens dans les composants Input. 12 j Moyen (régression focus)
Migrer fetch manuel vers React Query useLibraryManager, MarketplaceHome, SellerDashboardView. 23 j Moyen
Lazy-load des dépendances lourdes Swagger UI, HLS.js chargés à la demande. 1 j Faible

Niveau 3 — Montée en gamme premium

Action Bénéfice Coût Risques
Suspense aux limites de route Shell + skeleton immédiat. Pas d'attente du bundle enfant. 23 j Moyen (compatibilité React Query)
Lint/rule pour arbitraires ESLint ou plugin Tailwind. Bloquer les PR avec arbitraires. 12 j Faible
Migration progressive vers primitives Remplacer w-[...], h-[...] par tokens. Prioriser les 20 fichiers les plus utilisés. 24 sem Moyen
Politique WCAG Critères de sortie a11y. Storybook a11y activé. Audit axe. 12 sem Faible
Waveform audio réel Remplacer le waveform décoratif par une visualisation basée sur les données audio. 12 sem Élevé (complexité audio)
Métriques perçues LCP, INP, TTI. Objectifs chiffrés. Dashboard de suivi. 1 sem Faible

I. Synthèse

L'application Veza dispose de fondations solides : architecture feature-based, design system documenté, stack moderne, MSW, Storybook, patterns de chargement et d'erreur, optimistic UI, API client robuste. Les faiblesses sont principalement liées à l'exécution : double auth, client API monolithique, correctifs CSS, callbacks no-op, recherche non fonctionnelle, règles de design system non appliquées par outil.

Pour atteindre une qualité perçue "produit de référence" (Spotify, Discord, Deezer), les actions prioritaires sont :

  1. Unifier l'auth (dette structurelle majeure).
  2. Connecter la recherche header (gain rapide, impact UX fort).
  3. Supprimer les correctifs par refonte des composants concernés.
  4. Systématiser loading/empty/error sur toutes les pages.
  5. Découper le client API et introduire un lint pour les arbitraires.

Le plan en 3 niveaux permet de progresser par paliers : gains rapides (12 semaines), refonte intermédiaire (24 semaines), montée en gamme premium (12 mois).