# 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) et `features/*/pages/` — deux patterns coexistent pour le même rôle [components/views/analytics-view/], [features/dashboard/pages/] - `pages/auth/` (Login.tsx, Register.tsx) et `features/auth/pages/` (LoginPage.tsx, RegisterPage.tsx) — **duplication directe** [pages/auth/Login.tsx vs features/auth/pages/LoginPage.tsx] - `context/AuthContext.tsx` et `features/auth/store/authStore.ts` — **deux sources de vérité pour l'auth** [context/AuthContext.tsx:54, features/auth/store/authStore.ts:55] - `providers/AuthProvider.tsx` et `context/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 vers `features/auth/pages/` via LazyComponent [routeConfig.tsx:59-63] - `components/views/*.tsx` (fichiers plats type `AnalyticsView.tsx`, `CartView.tsx`) — semblent être des **wrappers legacy** vers les sous-dossiers refactorés - `stories/` — contient uniquement `decorators.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.] - `useQuery` pour lectures, `useMutation` pour é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** avec `authStore` : deux sources de vérité pour l'auth - `AudioContext` [context/audio-context/AudioContext.tsx] — contexte audio player - `ThemeProvider` [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** : `ProtectedRoute` component wrapper [routeConfig.tsx:47-55] + `ProtectedLayoutRoute` pour le layout dashboard - **Lazy loading** : ✅ Toutes les routes sont lazy via `LazyComponent` [routeConfig.tsx:5-33] — pattern `React.lazy` centralisé - **404** : ✅ `LazyNotFound` route + catch-all `*` → `/404` [AppRouter.tsx:30-31] - **500** : ✅ `LazyServerError` route [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** : `ErrorBoundary` wrapping `App` [app/App.tsx:171] - **Route level** : Chaque route wrappée dans `ErrorBoundary` [routeConfig.tsx:40-55] - **Composant** : `ErrorBoundary` class 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 - `parseApiError` centralisé [utils/apiErrorHandler.ts] — 578L, parsing exhaustif des erreurs Axios - `formatUserFriendlyError` [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 `ErrorDisplay` component [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.