Phase 1:
- S0: Fix open redirect (safeNavigate), delete AuthContext/legacy auth, encrypt API keys, gitignore .env files
- S1: Split client.ts god object into 5 modules, unify toast system, delete unused Sidebar
- S2: Add glass button variant, migrate 32 z-index to SUMI tokens, fix card dark mode
- S3: Skip nav link, aria-hidden on icons, focus-visible ring fixes, alt attrs, aria-live regions
- S4: React.memo on list items, fix key={index}, loading=lazy on images
- S5: Branded loading screen, page transitions respect reduced-motion, LikeButton micro-interaction, i18n sidebar/header
Phase 2 Sprint 6:
- Wire Tailwind shadow utilities to SUMI tokens in @theme block (fixes 50+ files)
- Define shadow-card/shadow-card-hover tokens
- Remove dark:shadow-none workarounds from card.tsx (SUMI handles per-theme shadows)
Co-authored-by: Cursor <cursoragent@cursor.com>
13 KiB
Phase A — Architecture Frontend Analysis
Score Architecture : 7/10
A1. Structure des dossiers
Organisation réelle
src/
├── app/ → Shell applicatif (App.tsx)
├── components/ → Composants partagés (30+ sous-dossiers)
├── config/ → Configuration (env, features flags)
├── context/ → React Context (AuthContext, AudioContext)
├── features/ → Modules feature-based (24 features)
├── hooks/ → Hooks partagés (~30 hooks)
├── lib/ → Init librairies (i18n, sentry)
├── locales/ → Traductions i18n
├── mocks/ → MSW handlers
├── pages/ → Pages legacy (auth, marketplace)
├── providers/ → AuthProvider
├── router/ → Routing centralisé
├── schemas/ → Schémas Zod
├── services/ → Services API (~35 services)
├── stores/ → Zustand stores partagés
├── stories/ → Storybook decorators
├── test/ → Test setup
├── types/ → Types globaux et générés
└── utils/ → Utilitaires (~25 fichiers)
Séparation features/ vs components/
Positif : La codebase utilise un pattern feature-based dans features/ avec des modules autonomes contenant chacun api/, components/, hooks/, services/, store/, pages/. [features/auth/store/authStore.ts], [features/playlists/hooks/usePlaylist.ts], [features/tracks/api/trackApi.ts]
Problème majeur : Dualité non résolue entre :
components/views/(analytics-view, cart-view, chat-view, discover-view, etc. — ~20 vues) etfeatures/*/pages/— deux patterns coexistent pour le même rôle [components/views/analytics-view/], [features/dashboard/pages/]pages/auth/(Login.tsx, Register.tsx) etfeatures/auth/pages/(LoginPage.tsx, RegisterPage.tsx) — duplication directe [pages/auth/Login.tsx vs features/auth/pages/LoginPage.tsx]context/AuthContext.tsxetfeatures/auth/store/authStore.ts— deux sources de vérité pour l'auth [context/AuthContext.tsx:54, features/auth/store/authStore.ts:55]providers/AuthProvider.tsxetcontext/AuthContext.tsx— coexistence redondante
Barrel exports (index.ts)
Présents et cohérents dans les feature views refactorées :
components/views/analytics-view/index.ts✅components/views/cart-view/index.ts✅components/views/settings-view/index.ts✅features/*/index.ts— absents dans la plupart des features ❌
Routes colocalisées
Les routes sont centralisées dans router/routeConfig.tsx [routeConfig.tsx:57-109], pas colocalisées avec les features. C'est un choix acceptable pour un projet de cette taille, mais limite la découvrabilité.
Dossiers morts ou orphelins
pages/auth/— probablement orphelin : contient Login.tsx et Register.tsx mais les routes pointent versfeatures/auth/pages/via LazyComponent [routeConfig.tsx:59-63]components/views/*.tsx(fichiers plats typeAnalyticsView.tsx,CartView.tsx) — semblent être des wrappers legacy vers les sous-dossiers refactorésstories/— contient uniquementdecorators.tsx, pourrait être dans.storybook/
Verdict structure : Organisation feature-based ambitieuse mais migration incomplète. La dualité components/views/ vs features/*/pages/ et les vestiges legacy (pages/, context/AuthContext.tsx) créent de la confusion. -2 points.
A2. Séparation des responsabilités
Composants > 100 lignes (source, hors tests)
| Composant | Lignes | Type | Responsabilités mélangées ? | Verdict |
|---|---|---|---|---|
services/api/client.ts |
2 237 | Service | API client + validation + caching + retry + dedup + metrics | ❌ Monolithe |
features/tracks/api/trackApi.ts |
848 | Service | CRUD tracks + upload + share + analytics | ⚠️ Large mais cohérent |
utils/optimisticUpdates.ts |
682 | Utilitaire | Optimistic updates multi-feature | ⚠️ Acceptable |
features/streaming/services/playbackAnalyticsService.ts |
656 | Service | Analytics streaming | ⚠️ Complexité justifiée |
features/playlists/hooks/usePlaylist.ts |
631 | Hook smart | CRUD + collaboration + analytics | ❌ Trop de responsabilités |
utils/apiErrorHandler.ts |
578 | Utilitaire | Error parsing + categorization | ⚠️ Acceptable |
features/streaming/hooks/usePlaybackRealtime.ts |
496 | Hook smart | WebSocket + state + analytics | ⚠️ Justifié par temps réel |
services/api/auth.ts |
493 | Service | Auth API complète | ⚠️ Cohérent |
schemas/apiRequestSchemas.ts |
476 | Types | Schémas Zod | ✅ Naturellement grand |
schemas/apiSchemas.ts |
468 | Types | Schémas Zod | ✅ Naturellement grand |
features/tracks/services/trackService.ts |
453 | Service | Service tracks | ⚠️ Cohérent |
features/playlists/services/playlistService.ts |
448 | Service | Service playlists | ⚠️ Cohérent |
utils/sanitize.ts |
429 | Utilitaire | Sanitization XSS | ✅ Sécurité critique |
Point critique : client.ts (2237L) est un God Object. Il cumule : instance Axios, interceptors, validation Zod, caching, request deduplication, metrics tracking, offline queue, rate limiting, CSRF. Il devrait être éclaté en 4-5 modules. [services/api/client.ts:1-80]
Positif : La séparation services/hooks/components est généralement respectée dans les features refactorées (auth, playlists, tracks, streaming).
A3. Gestion d'état
Couches identifiées
1. Zustand Stores (7 stores) :
| Store | Fichier | Contenu | Persisté | Sync tabs |
|---|---|---|---|---|
authStore |
features/auth/store/authStore.ts |
isAuthenticated, isLoading, error | ✅ localStorage | ✅ broadcastSync |
uiStore |
stores/ui.ts |
theme, language, sidebarOpen, notifications | ✅ localStorage | ✅ broadcastSync |
cartStore |
stores/cartStore.ts |
items, actions CRUD | ✅ localStorage | ❌ |
playerStore |
features/player/store/playerStore.ts |
Playback state | Probable | À vérifier |
chatStore |
features/chat/store/chatStore.ts |
Chat state | À vérifier | À vérifier |
libraryStore |
stores/library.ts |
Library state | À vérifier | À vérifier |
rateLimitStore |
stores/rateLimit.ts |
Rate limit tracking | ❌ | ❌ |
2. React Query (TanStack Query v5) — Server state principal :
- Utilisé dans ~30+ fichiers [features/playlists/hooks/usePlaylist.ts, features/tracks/components/LikeButton.tsx, etc.]
useQuerypour lectures,useMutationpour écritures- Optimistic updates via
utils/optimisticUpdates.ts[utils/optimisticUpdates.ts] - Cache sync cross-tabs via
utils/reactQuerySync.ts[app/App.tsx:47-54] - QueryClient config :
staleTime: 1min,gcTime: 5min,retry: false[main.tsx:43-55]
3. React Context (4 contextes) :
AuthContext[context/AuthContext.tsx] — CONFLIT avecauthStore: deux sources de vérité pour l'authAudioContext[context/audio-context/AudioContext.tsx] — contexte audio playerThemeProvider[components/theme/ThemeProvider.tsx] — thème (mais aussi géré par uiStore)ToastProvider[components/feedback/ToastProvider.tsx] — gestion toasts
4. State local (useState) — usage standard dans les composants
Diagnostique
Conflit critique : AuthContext [context/AuthContext.tsx:54] utilise authService directement avec useState pour user, tandis que authStore [features/auth/store/authStore.ts:55] utilise Zustand avec loginService et gère isAuthenticated sans user (délégué à React Query). L'App.tsx utilise authStore [app/App.tsx:4], mais AuthContext existe toujours et pourrait être importé par erreur. → Source de bugs potentiels.
Duplication thème : Le thème est géré par uiStore [stores/ui.ts:35-51] ET ThemeProvider [components/theme/ThemeProvider.tsx]. L'App.tsx applique le thème via uiStore [app/App.tsx:80-94].
Prop drilling : Minimisé grâce à Zustand + React Query. Pas de chaîne > 3 niveaux identifiée dans le code audité.
A4. Gestion des requêtes réseau
Architecture réseau
Le projet utilise un client Axios centralisé dans services/api/client.ts [services/api/client.ts:1-80] qui fournit :
- Interceptors pour JWT (Authorization header) [client.ts:9]
- Refresh token automatique [client.ts:10]
- Validation Zod des requêtes et réponses [client.ts:24-25]
- Request deduplication [client.ts:21]
- Response caching [client.ts:22]
- Offline queue [client.ts:20]
- Rate limiting tracking [client.ts:27]
- CSRF protection [client.ts:14]
- Validation metrics [client.ts:33-41]
Patterns observés
| Fichier | Méthode | Loading | Error | Cancel | Typé | Centralisé |
|---|---|---|---|---|---|---|
features/tracks/api/trackApi.ts |
Axios client | Via React Query | Via React Query | Via React Query | ✅ Zod | ✅ |
services/api/auth.ts |
Axios client | Manual/Store | ✅ parseApiError | ❌ | ✅ Zod | ✅ |
features/playlists/services/playlistService.ts |
Axios client | Via hooks | ✅ | ❌ | ✅ | ✅ |
services/websocket.ts |
WebSocket natif | ❌ | ✅ reconnect | N/A | ⚠️ any (8x) |
✅ |
context/AuthContext.tsx |
authService direct | ✅ useState | ✅ toast | ❌ | ❌ any (4x) |
⚠️ Parallèle |
Positif : Architecture réseau très mature avec dedup, caching, offline queue, validation Zod end-to-end, CSRF. C'est au-dessus de la moyenne.
Négatif : Le client.ts est un monolithe de 2237L qui concentre trop de responsabilités. L'AbortController n'est pas systématiquement utilisé pour annuler les requêtes au démontage.
A5. Routing
- Solution : React Router DOM v6.22 [package.json]
- Routes protégées :
ProtectedRoutecomponent wrapper [routeConfig.tsx:47-55] +ProtectedLayoutRoutepour le layout dashboard - Lazy loading : ✅ Toutes les routes sont lazy via
LazyComponent[routeConfig.tsx:5-33] — patternReact.lazycentralisé - 404 : ✅
LazyNotFoundroute + catch-all*→/404[AppRouter.tsx:30-31] - 500 : ✅
LazyServerErrorroute [routeConfig.tsx:107] - Deep linking : ✅ Routes paramétrées (
/tracks/:id,/u/:username,/playlists/*) [routeConfig.tsx:87-88] - ComingSoon : Routes planifiées mais non implémentées utilisent un placeholder
ComingSoon[routeConfig.tsx:96-101] — propre - v7 migration : Flags de préparation activés
v7_startTransition,v7_relativeSplatPath[main.tsx:221-222]
Verdict routing : Solide, bien structuré, lazy loading systématique. +1 point.
A6. Gestion des erreurs
Error Boundaries
- Root level :
ErrorBoundarywrappingApp[app/App.tsx:171] - Route level : Chaque route wrappée dans
ErrorBoundary[routeConfig.tsx:40-55] - Composant :
ErrorBoundaryclass component avec UI de fallback, retry et go-home [components/ui/ErrorBoundary.tsx:16-77] - Fallback configurable : ✅ via prop
fallback[ErrorBoundary.tsx:13]
Erreurs réseau
parseApiErrorcentralisé [utils/apiErrorHandler.ts] — 578L, parsing exhaustif des erreurs AxiosformatUserFriendlyError[utils/errorMessages.ts] — messages user-friendly- Toast pour feedback utilisateur [utils/toast.ts]
- Rate limit indicator [components/RateLimitIndicator.tsx]
- Offline indicator [components/OfflineIndicator.tsx]
Logging
- Sentry intégré [lib/sentry.ts, main.tsx:28,41]
- Logger structuré custom [utils/logger.ts] avec niveaux et contexte
Fallback UI
- Error states avec
ErrorDisplaycomponent [components/ui/ErrorDisplay.tsx] - Loading states avec spinners et skeletons (chaque view a un Skeleton)
- Empty states gérés dans les features refactorées
Verdict erreurs : Gestion des erreurs très complète — error boundaries, parsing centralisé, Sentry, toasts, offline detection. +1 point.
Score Architecture détaillé
| Critère | Points | Justification |
|---|---|---|
| Structure feature-based | +2 | Organisation claire en features avec séparation concerns |
| Migration incomplète | -2 | Dualité components/views vs features/pages, fichiers legacy |
| State management | +1.5 | Zustand + React Query bien intégré, sync cross-tabs |
| Conflit AuthContext vs authStore | -1 | Deux sources de vérité pour l'auth |
| Client API centralisé | +1.5 | Validation Zod, dedup, caching, offline queue |
| client.ts monolithe | -0.5 | 2237L, trop de responsabilités |
| Routing | +1.5 | Lazy loading systématique, 404/500, guards |
| Error handling | +1.5 | ErrorBoundary, Sentry, toast, offline indicator |
| Barrel exports partiels | -0.5 | Incohérents entre features et components |
| TypeScript strict | +1 | Mode strict complet avec noUncheckedIndexedAccess |
| Total | 7/10 | Solide, mais dette structurelle de migration |
Résumé : L'architecture est ambitieuse et globalement solide, avec des patterns modernes (feature-based, server state séparé, validation Zod). Le principal problème est la migration incomplète qui laisse coexister deux patterns architecturaux (components/views/ vs features/pages/, AuthContext vs authStore). Le client HTTP centralisé est puissant mais devenu un monolithe à découper.