- 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
21 KiB
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 (5–6/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
-
Design system KŌDŌ v3 —
index.csscontient 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. -
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.
-
Patterns de chargement et d'erreur —
LOADING_STATES_PATTERN.md, composantLoadingState, skeletons dédiés par page. Données via React Query avec états loading/error gérés au niveau page (mais pas partout). -
Optimistic UI —
OPTIMISTIC_UPDATES.mdetoptimisticUpdates.ts. Utilisation dans playlists, likes, commentaires. Rollback et invalidation documentés. -
API client robuste — Requêtes avec retry, exponential backoff, refresh token, CSRF, validation Zod, déduplication, cache, offline queue. Gestion des erreurs centralisée.
-
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
-
Double source de vérité pour l'auth —
AuthContext+useAuth()(Storybook, ProtectedRoute, pages) vsauthStore(Zustand) +useAuthStore()(App, Sidebar, Login). Risque de désync et confusion pour tout nouveau dev. Dette d'architecture prioritaire. -
Client API monolithique —
client.ts= 2238 lignes. ValidationMetricsTracker, ValidationAlerting, NetworkFailureTracker, interceptors, retry, refresh, CSRF, offline queue, etc. Tout dans un seul fichier. Maintenance et testabilité difficiles. -
Correctifs applicatifs visibles —
main.tsxchargefix-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. -
Route config et couplage produit —
routeConfig.tsxinjecte des callbacks vides :onCreateProduct={() => {}},onNavigateTrack={() => {}}. La routing ne doit pas porter de callbacks métier. -
Bundle vendor énorme —
vendor-Bo5_qjiz.js≈ 2 Mo (minifié). Lucide-react, Framer Motion, HLS.js, Swagger UI, etc. Pas de lazy-load des dépendances lourdes. -
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/vscomponents/views/vscomponents/layout/).pages/vsfeatures/*/pages/— double convention. Certaines pages sont dansfeatures, d'autres danspages/.context/etproviders/— 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
-
Auth dual — Toute évolution auth nécessite de modifier Context ET Store. Risque de bugs subtils (race conditions, désync).
-
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. -
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. -
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-pagedéfinis. Peu utilisés. - Espacement :
gap-4,gap-6utilisés. Parfoisgap-[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-bouncedé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 à
apiClientou à 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.
wsServicepour 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.
responseCachepour 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"
- Écran de chargement auth — Spinner générique pendant l'init auth. Pas de skeleton du shell.
- Recherche header — Placeholder "What do you want to play?" mais non fonctionnel. Donne l'impression d'une feature incomplète.
- Correctifs CSS —
fix-input-focus.cssavec!importantpartout. Indique des problèmes de conception. - Callbacks no-op —
onCreateProduct={() => {}}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
- Une seule source d'auth — Pas de double Context/Store.
- Pas de callbacks dans la route config — Routing découplé du métier.
- Checklist loading/empty/error par écran — Aucun écran sans traitement.
- Suppression des fix- par refonte* — Résoudre les problèmes à la source.
- Lint pour les primitives — Interdire les arbitraires par outil.
- Recherche fonctionnelle — Header search reliée à la navigation.
H. Plan d'Action Stratégique
Niveau 1 — Gains rapides (1–2 semaines)
| Action | Bénéfice | Coût | Risques |
|---|---|---|---|
| Connecter la recherche header | UX immédiate. Navigation vers /search avec query. | 2–4 h | Faible |
| Remplacer les callbacks no-op | Supprimer la dette visible. Props via layout ou contexte. | 4–8 h | Moyen (tests à vérifier) |
| Skeleton systématique sur 5 pages critiques | Dashboard, Library, Marketplace, Search, Playlists. | 1–2 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. | 3–5 j | Élevé (régression auth, tests) |
| Découper client.ts | Module interceptor, retry, refresh, validation. Fichiers < 400 lignes. | 2–3 j | Moyen (imports, tests) |
| Refonte focus des inputs | Supprimer fix-input-focus.css. Utiliser focus-visible, ring tokens dans les composants Input. | 1–2 j | Moyen (régression focus) |
| Migrer fetch manuel vers React Query | useLibraryManager, MarketplaceHome, SellerDashboardView. | 2–3 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. | 2–3 j | Moyen (compatibilité React Query) |
| Lint/rule pour arbitraires | ESLint ou plugin Tailwind. Bloquer les PR avec arbitraires. | 1–2 j | Faible |
| Migration progressive vers primitives | Remplacer w-[...], h-[...] par tokens. Prioriser les 20 fichiers les plus utilisés. | 2–4 sem | Moyen |
| Politique WCAG | Critères de sortie a11y. Storybook a11y activé. Audit axe. | 1–2 sem | Faible |
| Waveform audio réel | Remplacer le waveform décoratif par une visualisation basée sur les données audio. | 1–2 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 :
- Unifier l'auth (dette structurelle majeure).
- Connecter la recherche header (gain rapide, impact UX fort).
- Supprimer les correctifs par refonte des composants concernés.
- Systématiser loading/empty/error sur toutes les pages.
- Découper le client API et introduire un lint pour les arbitraires.
Le plan en 3 niveaux permet de progresser par paliers : gains rapides (1–2 semaines), refonte intermédiaire (2–4 semaines), montée en gamme premium (1–2 mois).