544 lines
33 KiB
Markdown
544 lines
33 KiB
Markdown
|
|
I'll conduct this audit systematically by exploring the entire frontend codebase. Let me start by gathering information across multiple dimensions in parallel.
|
||
|
|
|
||
|
|
[4 tools called]
|
||
|
|
|
||
|
|
Now let me dig deeper into specific critical areas I need to validate.
|
||
|
|
|
||
|
|
[1 tool called]
|
||
|
|
|
||
|
|
Let me now gather a few more specific data points needed for the final audit.
|
||
|
|
|
||
|
|
[6 tools called]
|
||
|
|
|
||
|
|
Good - no cross-feature imports. Let me check a few more things.
|
||
|
|
|
||
|
|
[5 tools called]
|
||
|
|
|
||
|
|
Now I have all the data I need for a comprehensive audit. Let me compile the final report.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# AUDIT TECHNIQUE INTÉGRAL — FRONTEND & DESIGN SYSTEM
|
||
|
|
|
||
|
|
**Projet :** Veza — Plateforme Audio Collaborative
|
||
|
|
**Date :** 13 février 2026
|
||
|
|
**Auditeur :** Architecte frontend indépendant
|
||
|
|
**Branche :** `main`
|
||
|
|
**Dernière mise à jour du document :** 13 février 2026
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. EXECUTIVE SUMMARY
|
||
|
|
|
||
|
|
Ce frontend est **techniquement ambitieux et structurellement solide**, mais souffre d'un **décalage significatif entre l'ampleur du code produit et la maturité réelle du produit**. L'architecture est bien pensée (feature-based, lazy loading, stores Zustand, React Query, i18n), le design system SUMI v2.0 est remarquablement complet dans sa couche tokens/CSS, et la couverture de tests (~287 fichiers) et stories (~323 fichiers) est substantielle.
|
||
|
|
|
||
|
|
**Cependant :** au moins 5 routes majeures pointent vers des placeholders "Coming Soon" (Gear, Live, Education, Queue, Developer), 3 feature flags restent désactivées par défaut (PLAYLIST_RECOMMENDATIONS, HLS_STREAMING, ROLE_MANAGEMENT) ; NOTIFICATIONS et PLAYLIST_SHARE sont à true, le code contient des `any` dans des services critiques (auth), des `setTimeout` sans cleanup, et la base de code frôle le **surdimensionnement** pour un produit en phase MVP. Le risque principal n'est pas la qualité du code mais la **dispersion** : trop de surface frontale pour un backend partiellement implémenté. Un investisseur verrait un produit impressionnant en démo superficielle, mais fragile dès qu'on sort du chemin heureux.
|
||
|
|
|
||
|
|
**Verdict : Refactoring ciblé, pas de réécriture.** Score global : **6.8/10**.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. CARTOGRAPHIE FRONTEND
|
||
|
|
|
||
|
|
### Stack & Tooling
|
||
|
|
|
||
|
|
| Composant | Technologie | Version |
|
||
|
|
|-----------|-------------|---------|
|
||
|
|
| Framework | React | ^18.2.0 |
|
||
|
|
| Language | TypeScript | ^5.3.3 |
|
||
|
|
| Build tool | Vite | ^7.1.5 |
|
||
|
|
| State management | Zustand + Immer | ^4.5.0 / ^10.0.3 |
|
||
|
|
| Routing | React Router DOM | ^6.22.0 |
|
||
|
|
| Data fetching | TanStack React Query + Axios | ^5.17.0 / ^1.13.5 |
|
||
|
|
| CSS | Tailwind CSS v4 (CSS-first) | ^4.0.0 |
|
||
|
|
| Forms | React Hook Form + Zod | ^7.49.3 / ^3.25.76 |
|
||
|
|
| i18n | i18next + react-i18next | ^25.5.2 / ^15.7.3 |
|
||
|
|
| Animation | Framer Motion | ^12.29.2 |
|
||
|
|
| Icons | Lucide React | ^0.321.0 |
|
||
|
|
| Monitoring | Sentry | ^10.32.1 |
|
||
|
|
| Linting | ESLint 9 (flat config) | ^9.0.0 |
|
||
|
|
| Formatting | Prettier | ^3.2.5 |
|
||
|
|
| Testing | Vitest + Testing Library + Playwright | ^3.2.4 / ^14.2.1 / ^1.58.2 |
|
||
|
|
| Storybook | Storybook | ^8.6.15 |
|
||
|
|
| Mocking | MSW | ^2.11.2 |
|
||
|
|
|
||
|
|
### Organisation du code
|
||
|
|
|
||
|
|
```
|
||
|
|
src/
|
||
|
|
├── app/ # Root component
|
||
|
|
├── components/ # Composants partagés (~248 UI + ~545 feature-specific)
|
||
|
|
│ ├── ui/ # Primitives design system (248 fichiers)
|
||
|
|
│ ├── layout/ # Header, Sidebar, DashboardLayout
|
||
|
|
│ ├── admin/ # Admin components
|
||
|
|
│ ├── auth/ # Auth components
|
||
|
|
│ ├── settings/ # Settings (57 fichiers)
|
||
|
|
│ ├── social/ # Social features
|
||
|
|
│ ├── studio/ # Studio/editing (76 fichiers)
|
||
|
|
│ └── views/ # View components (211 fichiers)
|
||
|
|
├── config/ # Feature flags, env, constants
|
||
|
|
├── context/ # AudioContext, AuthContext
|
||
|
|
├── features/ # Feature modules (878 fichiers)
|
||
|
|
│ ├── tracks/ # 189 fichiers — plus gros module
|
||
|
|
│ ├── playlists/ # 148 fichiers
|
||
|
|
│ ├── player/ # 77 fichiers
|
||
|
|
│ ├── chat/ # 56 fichiers
|
||
|
|
│ ├── auth/ # Complet
|
||
|
|
│ ├── search/ # 23 fichiers
|
||
|
|
│ └── ... (14 autres features)
|
||
|
|
├── hooks/ # 41 custom hooks
|
||
|
|
├── services/ # 28 fichiers API/domain services
|
||
|
|
├── stores/ # 11 Zustand stores
|
||
|
|
├── types/ # 144 fichiers de types
|
||
|
|
├── locales/ # en.json, fr.json (~528 lignes chaque)
|
||
|
|
├── mocks/ # MSW handlers (1717 lignes)
|
||
|
|
└── utils/ # 50+ utilitaires
|
||
|
|
```
|
||
|
|
|
||
|
|
**Mise à jour 13/02/2026 :** `mocks/handlers.ts` ~1606 lignes ; `services/api/interceptors.ts` ~1203 lignes.
|
||
|
|
|
||
|
|
**Convention de nommage :** PascalCase pour composants, camelCase pour hooks/utils/services. Cohérent.
|
||
|
|
|
||
|
|
**Découpage :** Hybride feature-based + type-based. Le dossier `components/` contient à la fois des UI primitives (`ui/`) et des composants feature-specific (`admin/`, `social/`, `studio/`, `views/`) qui devraient logiquement vivre dans `features/`. Cette duplication structurelle crée une ambiguité : un développeur cherchant les composants social ne sait pas s'il doit regarder `components/social/` ou `features/social/`.
|
||
|
|
|
||
|
|
**Co-location :** Partielle. Les features co-localisent composants + hooks + services + types. Mais les tests sont co-localisés avec les composants (bon), tandis que les stories sont parfois dans le même dossier, parfois dans `stories/` (incohérent).
|
||
|
|
|
||
|
|
**Barrel exports :** Présents dans les modules UI (`LazyComponent.ts`, `lazyExports.ts`). Pas de barrel systématique par feature.
|
||
|
|
|
||
|
|
### Dépendances — Analyse critique
|
||
|
|
|
||
|
|
**Redondances identifiées :**
|
||
|
|
- `Spinner.tsx` + `LoadingSpinner.tsx` + `LoadingState.tsx` : trois composants de loading différents
|
||
|
|
- `Modal.tsx` (marqué deprecated) + `Dialog.tsx` : coexistence avec note de migration inachevée
|
||
|
|
- `components/feedback/Alert.tsx` potentiellement dupliqué avec `components/ui/alert.tsx`
|
||
|
|
|
||
|
|
**Dépendances lourdes :**
|
||
|
|
- `swagger-ui-react` + `swagger-ui-dist` (^5.31.0) : en **devDependencies** (corrigé).
|
||
|
|
- `framer-motion` (^12.29.2) : justifié pour les animations, mais certaines animations CSS pures suffiraient
|
||
|
|
- `emoji-picker-react` (^4.16.1) : lazy-loaded (correct)
|
||
|
|
|
||
|
|
**Dépendances en production qui devraient être en dev :**
|
||
|
|
- `rollup-plugin-visualizer` (^6.0.5) : dans `dependencies` au lieu de `devDependencies`
|
||
|
|
|
||
|
|
**Tree-shaking :** Lucide React est correctement importé par icône individuelle. TanStack et date-fns sont tree-shakeable. Le chunk splitting manuel dans `vite.config.ts` est fonctionnel mais basique (tout `node_modules` non catégorisé va dans un seul chunk `vendor`).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. INVENTAIRE DESIGN SYSTEM
|
||
|
|
|
||
|
|
### Maturité : **Niveau 3.5 / 4**
|
||
|
|
|
||
|
|
Le design system SUMI v2.0 ("L'encre et la lumière") est **remarquablement complet en tokens** mais **incomplètement consommé** par les composants.
|
||
|
|
|
||
|
|
### Tokens & Variables
|
||
|
|
|
||
|
|
**Forces :**
|
||
|
|
|
||
|
|
| Catégorie | État | Détail |
|
||
|
|
|-----------|------|--------|
|
||
|
|
| Couleurs | Sémantique | `--sumi-bg-void` à `--sumi-bg-wash`, accents (vermillion, sage, gold), états sémantiques (success, warning, error, info) |
|
||
|
|
| Typographie | Complet | 4 familles (Inter, Space Grotesk, JetBrains Mono, Noto Serif JP), échelle `xs` à `4xl`, weights, tracking, leading |
|
||
|
|
| Espacement | Complet | Échelle `0.5` (2px) à `20` (80px) sur base 4px |
|
||
|
|
| Radius | Complet | `xs` (2px) à `full` (9999px) |
|
||
|
|
| Shadows | Complet | `xs` à `2xl` + glow effects |
|
||
|
|
| Motion | Complet | Durées (75ms à 500ms), easings (6 courbes), transitions prédéfinies |
|
||
|
|
| Z-index | Complet | Échelle `base` (0) à `max` (999) |
|
||
|
|
| Layout | Complet | Max-widths, sidebar, header, player dimensions |
|
||
|
|
| Dark/Light | Fonctionnel | Dark par défaut, light mode avec overrides complets |
|
||
|
|
| Glass effects | Défini | `--sumi-glass-bg`, `--sumi-glass-border`, `--sumi-glass-blur` |
|
||
|
|
|
||
|
|
**Localisation :** Tous les tokens vivent dans `src/index.css` via `@theme inline` de Tailwind v4. C'est un fichier unique, bien organisé par sections. Les tokens sont mappés vers les utilities Tailwind correctement.
|
||
|
|
|
||
|
|
**Faiblesses :**
|
||
|
|
- Les tokens sont définis dans CSS mais certains composants utilisent des valeurs Tailwind directes (`rounded-xl`) au lieu de `rounded-[var(--sumi-radius-xl)]` — incohérence entre ce qui est déclaré et ce qui est consommé.
|
||
|
|
- ~100+ valeurs arbitraires Tailwind trouvées dans le code source (bien que beaucoup soient dans les stories ou des cas justifiés comme les SVG).
|
||
|
|
|
||
|
|
### Composants UI — Inventaire classé
|
||
|
|
|
||
|
|
**Composants solides (reusables, testés, accessibles) :**
|
||
|
|
|
||
|
|
| Composant | Imports | Tests | A11y | Notes |
|
||
|
|
|-----------|---------|-------|------|-------|
|
||
|
|
| Button | ~150+ | button.test.tsx | Focus ring, ARIA | 8 variants, 4 sizes, loading state |
|
||
|
|
| Card | ~150+ | card.test.tsx | Standard | 9 variants, 4 paddings, spotlight effect |
|
||
|
|
| Input | ~70+ | input.test.tsx | aria-invalid, describedby | Icon, label, error props |
|
||
|
|
| Skeleton | ~100+ | skeleton.test.tsx | aria-hidden | 3 variants |
|
||
|
|
| Checkbox | ~15+ | checkbox.test.tsx | useId, aria-label | Proper labeling |
|
||
|
|
| Switch | Low | switch.test.tsx | role="switch", aria-checked | Complete |
|
||
|
|
| RadioGroup | Low | radio-group.test.tsx | Arrow key nav, tabIndex | Full keyboard support |
|
||
|
|
| Slider | Low | slider.test.tsx | aria-valuenow/min/max | Complete ARIA |
|
||
|
|
| Badge | ~20+ | badge.test.tsx | Standard | Multiple variants, pulse |
|
||
|
|
| Alert | ~10+ | alert.test.tsx | role="alert" | 6 variants, dismissible |
|
||
|
|
| Progress | ~5+ | progress.test.tsx | role="progressbar", ARIA | Gaming variant |
|
||
|
|
| Dialog | ~30+ | dialog.test.tsx | role="dialog", aria-modal | Focus trap |
|
||
|
|
| Tabs | ~10+ | tabs.test.tsx | Tab pattern | Sub-components |
|
||
|
|
| Table | None found | table.test.tsx | aria-label, sortable | Complete sub-components |
|
||
|
|
| Avatar | ~15+ | avatar.test.tsx | Standard | 7 sizes, 6 status |
|
||
|
|
| Tooltip | Low | tooltip.test.tsx | Standard | Multiple positions |
|
||
|
|
| FocusTrap | Internal | focus-trap.test.tsx | Tab trapping, Escape | Used by Dialog/Modal |
|
||
|
|
| Select | ~20+ | select.test.tsx | aria-label | Searchable, multi |
|
||
|
|
| ScrollArea | Low | scroll-area.test.tsx | Standard | Custom scrollbar |
|
||
|
|
|
||
|
|
**Composants fragiles (fonctionnels mais problématiques) :**
|
||
|
|
|
||
|
|
| Composant | Problème | Impact |
|
||
|
|
|-----------|----------|--------|
|
||
|
|
| ErrorDisplay | Testé (`ErrorDisplay.test.tsx`) | — |
|
||
|
|
| LoadingState | Testé (`LoadingState.test.tsx`) | — |
|
||
|
|
| Accordion | Testé (`Accordion.test.tsx`) | — |
|
||
|
|
| Collapsible | Testé (`collapsible.test.tsx`) | — |
|
||
|
|
| FAB | Testé (`FAB.test.tsx`) | — |
|
||
|
|
| FloatingInput | Testé (`floating-input.test.tsx`), utilise `oklch()` hardcodé | Hors design system (mineur) |
|
||
|
|
| TrackCard | Utilise `(track as any).like_count` (l.43) | Contournement TypeScript |
|
||
|
|
| Modal | **Marqué deprecated** mais encore 6+ imports | Migration inachevée |
|
||
|
|
|
||
|
|
**Composants morts ou en doublon :**
|
||
|
|
|
||
|
|
| Composant | Statut |
|
||
|
|
|-----------|--------|
|
||
|
|
| `Spinner.tsx` + `LoadingSpinner.tsx` + `LoadingState.tsx` | 3 implémentations du même concept |
|
||
|
|
| `Modal.tsx` (deprecated) | Coexiste avec `Dialog.tsx` — 6 fichiers l'importent encore |
|
||
|
|
| `components/feedback/Alert.tsx` | Potentiel doublon de `components/ui/alert.tsx` |
|
||
|
|
| `ComingSoon.tsx` | Testé (`ComingSoon.test.tsx`) |
|
||
|
|
| `AnimatedNumber.tsx` | Testé (`AnimatedNumber.test.tsx`) |
|
||
|
|
|
||
|
|
### Cohérence visuelle
|
||
|
|
|
||
|
|
**`!important` :** 4 occurrences dans `index.css`, toutes justifiées (réduction de mouvement `prefers-reduced-motion` et animation d'entrée player). Aucun `!important` abusif.
|
||
|
|
|
||
|
|
**Styles inline contredisant le système :** Non identifiés (les composants utilisent `cn()` de `clsx`/`tailwind-merge` systématiquement).
|
||
|
|
|
||
|
|
**Espacements :** Cohérents — la majorité utilise l'échelle Tailwind native (`gap-2`, `p-4`, `space-y-1`). Les valeurs arbitraires sont concentrées dans les stories et les cas justifiés (SVG charts).
|
||
|
|
|
||
|
|
**Typographie :** L'échelle est définie mais les classes utilitaires SUMI (`sumi-h1`, `sumi-body`, etc.) coexistent avec les classes Tailwind standard (`text-xs`, `font-medium`). Double système typographique non unifié.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. DIAGNOSTIC FONCTIONNEL — CE QUE LE FRONTEND PERMET RÉELLEMENT
|
||
|
|
|
||
|
|
### Pages/Views fonctionnelles
|
||
|
|
|
||
|
|
| Route | Composant | État |
|
||
|
|
|-------|-----------|------|
|
||
|
|
| `/login` | LoginPage | Fonctionnel (MSW) |
|
||
|
|
| `/register` | RegisterPage | Fonctionnel (MSW) |
|
||
|
|
| `/forgot-password` | ForgotPasswordPage | Fonctionnel (MSW) |
|
||
|
|
| `/verify-email` | VerifyEmailPage | Fonctionnel (MSW) |
|
||
|
|
| `/reset-password` | ResetPasswordPage | Fonctionnel (MSW) |
|
||
|
|
| `/dashboard` | DashboardPage | Fonctionnel (MSW, données statiques) |
|
||
|
|
| `/library` | LibraryPage | Fonctionnel (MSW) |
|
||
|
|
| `/tracks/:id` | TrackDetailPage | Fonctionnel (MSW) |
|
||
|
|
| `/playlists/*` | PlaylistRoutes | Fonctionnel (MSW, collaboration) |
|
||
|
|
| `/chat` | ChatPage | Fonctionnel (MSW) |
|
||
|
|
| `/search` | SearchPage | Fonctionnel (MSW) |
|
||
|
|
| `/settings` | SettingsPage | Fonctionnel (MSW) |
|
||
|
|
| `/settings/sessions` | SessionsPage | Fonctionnel (MSW) |
|
||
|
|
| `/profile` | UserProfilePage | Fonctionnel (MSW) |
|
||
|
|
| `/u/:username` | UserProfilePage (public) | Fonctionnel |
|
||
|
|
| `/social` | SocialView | Fonctionnel (MSW) |
|
||
|
|
| `/notifications` | NotificationsPage | Fonctionnel (MSW) |
|
||
|
|
| `/marketplace` | MarketplaceHome | Fonctionnel (MSW) |
|
||
|
|
| `/design-system` | DesignSystemDemo | Fonctionnel (statique) |
|
||
|
|
|
||
|
|
### Pages partiellement implémentées
|
||
|
|
|
||
|
|
| Route | État | Détail |
|
||
|
|
|-------|------|--------|
|
||
|
|
| `/analytics` | MSW-only | Backend `NOT IMPLEMENTED` (config/features.ts) |
|
||
|
|
| `/webhooks` | MSW-only | Backend MSW-only |
|
||
|
|
| `/admin` | MSW-only | Backend partiellement implémenté |
|
||
|
|
| `/admin/roles` | MSW-only, flag `ROLE_MANAGEMENT: false` | Backend `NOT IMPLEMENTED` |
|
||
|
|
| `/sell` | MSW-only | Commerce backend non confirmé |
|
||
|
|
| `/wishlist` | MSW-only | Commerce backend non confirmé |
|
||
|
|
| `/purchases` | MSW-only | Commerce backend non confirmé |
|
||
|
|
|
||
|
|
### Pages mortes (Coming Soon)
|
||
|
|
|
||
|
|
| Route | Statut |
|
||
|
|
|-------|--------|
|
||
|
|
| `/gear` | ComingSoon placeholder |
|
||
|
|
| `/live` | ComingSoon placeholder |
|
||
|
|
| `/education` | ComingSoon placeholder |
|
||
|
|
| `/queue` | ComingSoon placeholder |
|
||
|
|
| `/developer` | ComingSoon placeholder |
|
||
|
|
|
||
|
|
### Feature flags désactivés par défaut
|
||
|
|
|
||
|
|
| Flag | Default | Raison documentée |
|
||
|
|
|------|---------|-------------------|
|
||
|
|
| `PLAYLIST_SEARCH` | `false` | Backend pas implémenté |
|
||
|
|
| `PLAYLIST_SHARE` | `true` | Backend implémenté |
|
||
|
|
| `PLAYLIST_RECOMMENDATIONS` | `false` | Backend pas implémenté |
|
||
|
|
| `HLS_STREAMING` | `false` | Backend `NOT IMPLEMENTED` |
|
||
|
|
| `ROLE_MANAGEMENT` | `false` | Backend `NOT IMPLEMENTED` |
|
||
|
|
| `NOTIFICATIONS` | `true` | Backend implémenté |
|
||
|
|
|
||
|
|
### Parcours utilisateur complets
|
||
|
|
|
||
|
|
1. **Inscription → Vérification email → Connexion → Dashboard** : complet
|
||
|
|
2. **Connexion → Bibliothèque → Upload track → Détail track** : complet (MSW)
|
||
|
|
3. **Connexion → Recherche → Résultats → Lecture** : complet (MSW)
|
||
|
|
4. **Connexion → Playlists → Création → Ajout de tracks → Collaboration** : complet (MSW)
|
||
|
|
5. **Connexion → Chat → Conversations → Envoi messages** : complet (MSW)
|
||
|
|
6. **Connexion → Settings → Profil / Sécurité / Sessions** : complet (MSW)
|
||
|
|
7. **Connexion → Social → Feed → Posts** : complet (MSW)
|
||
|
|
|
||
|
|
### Parcours cassés
|
||
|
|
|
||
|
|
1. **Connexion → Gear** : se termine sur ComingSoon
|
||
|
|
2. **Connexion → Live** : se termine sur ComingSoon
|
||
|
|
3. **Connexion → Education** : se termine sur ComingSoon — pourtant 76 fichiers de composants studio existent dans `components/studio/`
|
||
|
|
4. **Connexion → Marketplace → Achat** : le flow checkout n'est pas confirmé côté backend
|
||
|
|
5. **2FA Login Verification** : TODO critique dans `TwoFactorVerify.tsx:47` — le service appelé est celui du setup, pas celui de la vérification login
|
||
|
|
|
||
|
|
### Incohérences produit/code
|
||
|
|
|
||
|
|
- **76 fichiers studio** existent dans `components/studio/` mais aucune route `/studio` n'est définie
|
||
|
|
- **Education** a un service (`educationService.ts`), des handlers MSW complets (courses, enrollments), des composants (`components/education/`) mais est gated derrière ComingSoon
|
||
|
|
- **Gamification** (achievements, leaderboard, XP) a des handlers MSW mais aucune route ni composant visible
|
||
|
|
- **Inventory/Gear** a des composants (`features/inventory/`, `components/inventory/`) et des handlers MSW mais est gated derrière ComingSoon
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. AUDIT ACCESSIBILITÉ (WCAG 2.1 AA)
|
||
|
|
|
||
|
|
### Perception
|
||
|
|
|
||
|
|
| Critère | Verdict | Détail |
|
||
|
|
|---------|---------|--------|
|
||
|
|
| Contrastes | Correct | Les tokens SUMI définissent des couleurs avec bon contraste dark/light |
|
||
|
|
| Alt text images | Correct | TrackCard utilise `alt={Cover de ${track.title}}`, Avatar a fallback |
|
||
|
|
| Contenu sans couleur | Non vérifié | Badges utilisent couleurs + texte (OK) |
|
||
|
|
| Mode réduit | Correct | `prefers-reduced-motion` respecté dans index.css (l.869-873) |
|
||
|
|
|
||
|
|
### Opérabilité
|
||
|
|
|
||
|
|
| Critère | Verdict | Sévérité |
|
||
|
|
|---------|---------|----------|
|
||
|
|
| Navigation clavier | Bonne | RadioGroup, Dropdown, Dialog ont keyboard nav |
|
||
|
|
| Focus visible | Bon | `focus-visible:ring-2` systématique |
|
||
|
|
| Skip link | **Présent** | Lien dans App.tsx (href="#main-content", sr-only focus:not-sr-only) |
|
||
|
|
| Focus trap modals | Présent | FocusTrap component utilisé |
|
||
|
|
| Focus trap sidebar mobile | **Absent** | **Majeure** — sidebar mobile n'a pas de focus trap |
|
||
|
|
|
||
|
|
### Compréhension
|
||
|
|
|
||
|
|
| Critère | Verdict | Sévérité |
|
||
|
|
|---------|---------|----------|
|
||
|
|
| Labels formulaires | Partiel | Input/Textarea ont labels, ChatInput n'a pas d'aria-label | **Majeure** |
|
||
|
|
| Messages erreur | Partiel | Input a `aria-describedby`, ChatInput non |
|
||
|
|
| Langue HTML | Non vérifié | Dépend de index.html |
|
||
|
|
| Instructions | Correct | HelpText component existe |
|
||
|
|
|
||
|
|
### Robustesse
|
||
|
|
|
||
|
|
| Critère | Verdict | Détail |
|
||
|
|
|---------|---------|--------|
|
||
|
|
| HTML sémantique | Bon | `<article>`, `<aside>`, `<nav>`, `<header>`, `<main>` utilisés |
|
||
|
|
| Rôles ARIA | Corrects | `role="dialog"`, `role="alert"`, `role="switch"`, etc. |
|
||
|
|
| Landmarks | Bon | Sidebar (`<aside>`), Header (`<header>`), Navigation (`<nav>`) |
|
||
|
|
| Composants custom | Bon | RadioGroup, Tabs, Accordion suivent les patterns WAI-ARIA |
|
||
|
|
|
||
|
|
### Violations classées
|
||
|
|
|
||
|
|
| Violation | Sévérité | Fichier |
|
||
|
|
|-----------|----------|---------|
|
||
|
|
| Skip link | **Corrigé** | Lien présent dans `App.tsx` |
|
||
|
|
| ChatInput sans aria-label | **Majeure** | `features/chat/components/ChatInput.tsx` |
|
||
|
|
| Sidebar mobile sans focus trap | **Majeure** | `components/layout/Sidebar.tsx` |
|
||
|
|
| MiniPlayer sans aria-live pour changement de track | **Mineure** | `features/player/components/MiniPlayer.tsx` |
|
||
|
|
| Sidebar status indicator aria-hidden contient du texte | **Mineure** | `components/layout/Sidebar.tsx:136` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. ARCHITECTURE FRONTEND
|
||
|
|
|
||
|
|
### Patterns & Qualité du code
|
||
|
|
|
||
|
|
**Séparation logique métier / UI :** Bonne. Les hooks (`usePlayer`, `useChat`, `useAuth`) encapsulent la logique. Les composants sont principalement présentationnels. Les services gèrent l'API.
|
||
|
|
|
||
|
|
**Custom hooks :** Bien découpés dans l'ensemble. 41 hooks dans `hooks/` + hooks par feature. Quelques hooks complexes (`usePlaylistCollaboration`, `usePlaylistKeyboardShortcuts`) qui pourraient être décomposés.
|
||
|
|
|
||
|
|
**State management :**
|
||
|
|
- Local : React state pour l'UI locale (correct)
|
||
|
|
- Global : Zustand pour l'auth, UI, cart, rate limiting (correct)
|
||
|
|
- Server : React Query pour les données API (correct)
|
||
|
|
- Persistance : Zustand persist + broadcast sync cross-tab (avancé)
|
||
|
|
|
||
|
|
**Props drilling :** Modéré. Certains composants comme `CourseLearningView` passent 20+ props. Le pattern "composition + context" serait préférable dans 3-4 cas.
|
||
|
|
|
||
|
|
**Re-renders :**
|
||
|
|
- `DashboardPage.tsx` : arrays d'objets recréés à chaque render (l.66-71, l.131-164, l.300-304) — manque de `useMemo`
|
||
|
|
- `TrackCard` est correctement mémorisé avec `React.memo` (l.200)
|
||
|
|
- `MiniPlayer` : `handlePlayPause` recréé à chaque render (l.39-45) — mineur car composant léger
|
||
|
|
|
||
|
|
**TypeScript :** `strict: true` activé avec toutes les options. Mais `@typescript-eslint/no-explicit-any: off` dans ESLint — contredit la strictness. Résultat : `any` utilisé dans des services critiques (`authService.ts` l.35, l.54).
|
||
|
|
|
||
|
|
**Side effects :** Cleanup manquant sur `setTimeout` dans :
|
||
|
|
- `ChatInput.tsx:106` — timeout sans cleanup
|
||
|
|
- `SocialViewFeedItem.tsx:25,31` — setTimeout en callback sans ref
|
||
|
|
- `PostCard.tsx:94,101` — même pattern
|
||
|
|
|
||
|
|
### Couplage & Modularité
|
||
|
|
|
||
|
|
**Cross-feature imports :** Aucun trouvé. Les features sont correctement isolées.
|
||
|
|
|
||
|
|
**Design system couplage :** Faible — les composants UI sont indépendants. Changer un token dans `index.css` se propage correctement.
|
||
|
|
|
||
|
|
**Backend couplage :** Le code frontend est **partiellement découplé** grâce à MSW. Tous les services passent par `apiClient`. Cependant, les types API sont partiellement générés (`types/generated/`) et partiellement manuels — source d'incohérences potentielles.
|
||
|
|
|
||
|
|
### Scalabilité
|
||
|
|
|
||
|
|
- Ajout d'une feature : **faisable** sans toucher plus de 3-4 fichiers (route, lazy export, feature directory, MSW handler)
|
||
|
|
- Changement de state management : **modéré** — Zustand est utilisé dans ~11 stores mais bien encapsulé derrière des hooks
|
||
|
|
- Extraction du design system : **possible** — les tokens sont dans `index.css`, les composants dans `components/ui/`. Le découplage est suffisant.
|
||
|
|
- Scaling 10x pages : **possible** — le lazy loading par route et le code splitting sont en place
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. DETTE TECHNIQUE DÉTAILLÉE
|
||
|
|
|
||
|
|
### Dette critique (bloquante)
|
||
|
|
|
||
|
|
| Item | Fichier(s) | Impact | Effort |
|
||
|
|
|------|-----------|--------|--------|
|
||
|
|
| Bug 2FA login vs setup | `features/auth/components/TwoFactorVerify.tsx:47` | Authentification 2FA potentiellement cassée en production | S |
|
||
|
|
| ~~`swagger-ui-react` en dépendance production~~ | ~~`package.json`~~ | **Corrigé** : en devDependencies | — |
|
||
|
|
| ~~`rollup-plugin-visualizer` en dependencies~~ | ~~`package.json`~~ | **Corrigé** : en devDependencies | — |
|
||
|
|
| `any` dans authService login/register | `services/authService.ts:35,54` | Pas de validation de types sur l'authentification | S |
|
||
|
|
| setTimeout sans cleanup | `ChatInput.tsx:106`, `SocialViewFeedItem.tsx:25,31`, `PostCard.tsx:94,101` | Memory leaks / state updates après unmount | S |
|
||
|
|
|
||
|
|
### Dette structurante
|
||
|
|
|
||
|
|
| Item | Fichier(s) | Impact | Effort |
|
||
|
|
|------|-----------|--------|--------|
|
||
|
|
| 3 composants de loading (Spinner, LoadingSpinner, LoadingState) | `components/ui/` | Confusion, incohérence visuelle | M |
|
||
|
|
| Modal deprecated non migré (6 imports restants) | `components/ui/modal.tsx` | Deux systèmes de modales coexistent | M |
|
||
|
|
| Composants feature dans `components/` au lieu de `features/` | `components/admin/`, `components/social/`, `components/studio/`, `components/settings/` etc. | Ambiguité structurelle sur où trouver le code | L |
|
||
|
|
| ~~ErrorDisplay non testé~~ | `components/ui/ErrorDisplay.tsx` | **Corrigé** : ErrorDisplay.test.tsx présent | — |
|
||
|
|
| Double système typographique (SUMI classes + Tailwind direct) | Toute la codebase | Incohérence dans l'usage | L |
|
||
|
|
| 76 fichiers studio sans route | `components/studio/` | Code mort ou feature orpheline | M |
|
||
|
|
| `console.log` dans GlobalSearchBar (16 occurrences) | `components/search/GlobalSearchBar.tsx` | Logs en production | S |
|
||
|
|
| `as unknown as` assertions (15 occurrences) | Services divers | Contournement TypeScript | M |
|
||
|
|
| Stories manquant Loading/Error/Empty states | Majorité des stories | Contrat Storybook non respecté | L |
|
||
|
|
| `noUncheckedIndexedAccess` commenté dans tsconfig.app.json | `tsconfig.app.json` | ~234 erreurs potentielles non détectées | L |
|
||
|
|
|
||
|
|
### Dette cosmétique
|
||
|
|
|
||
|
|
| Item | Fichier(s) | Impact | Effort |
|
||
|
|
|------|-----------|--------|--------|
|
||
|
|
| ~26 TODO/FIXME non résolus | Fichiers divers | Maintenance | S |
|
||
|
|
| Gamification handlers MSW sans UI | `mocks/handlers.ts` | Code mort | S |
|
||
|
|
| ~~ComingSoon.tsx / AnimatedNumber.tsx non testés~~ | `components/ui/` | **Corrigé** : tests présents | — |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. SCORES
|
||
|
|
|
||
|
|
| Critère | Score /10 | Justification |
|
||
|
|
|---------|-----------|---------------|
|
||
|
|
| Architecture frontend | **7.5** | Feature-based bien exécuté, lazy loading, séparation des concerns. Points perdus : duplication components/features, scalabilité prouvée mais non testée à l'échelle. |
|
||
|
|
| Qualité du design system | **8.0** | Tokens SUMI exceptionnellement complets (couleurs, typo, espacement, motion, glass). Points perdus : double système typo, consommation incohérente des tokens, ~100 valeurs arbitraires. |
|
||
|
|
| Cohérence visuelle | **7.0** | Classes utilitaires SUMI bien définies, pas de !important abusif, cn() systématique. Points perdus : 3 composants loading, modal deprecated, FreeSans vs design tokens dans quelques composants. |
|
||
|
|
| Accessibilité | **6.5** | Bonne base (ARIA roles, focus visible, semantic HTML, keyboard nav, reduced motion). Points perdus : pas de skip link, ChatInput sans labels, sidebar mobile sans focus trap. |
|
||
|
|
| Performance perçue | **7.5** | Lazy loading routes, Skeleton screens, React Query cache, code splitting. Points perdus : pas d'optimistic updates systématiques, images non optimisées (pas de srcset), DashboardPage re-renders. |
|
||
|
|
| Maintenabilité | **7.0** | TypeScript strict, bonne couverture tests/stories, hooks bien découpés. Points perdus : any dans services critiques, cleanup manquants, console.log en production, double système typo. |
|
||
|
|
| Couverture de test frontend | **7.5** | ~287 fichiers tests, ~323 stories. ErrorDisplay, LoadingState, Accordion, Collapsible, FAB, ComingSoon, AnimatedNumber ont des tests. Points perdus : stories sans Loading/Error/Empty, éventuels échecs tests tracks. |
|
||
|
|
| Scalabilité | **7.0** | Structure extensible, features découplées, no cross-imports. Points perdus : déjà trop de surface pour le backend actuel, components/ vs features/ ambiguité. |
|
||
|
|
| Expérience développeur (DX) | **7.5** | Path aliases, MSW complet, Storybook, ESLint flat config avec rules custom Tailwind. Points perdus : 55+ fichiers docs d'audit (bruit), lack of contributing guide, no ADR format. |
|
||
|
|
|
||
|
|
**Score global pondéré : 6.8/10**
|
||
|
|
|
||
|
|
Le score est tiré vers le bas par le décalage backend/frontend (features affichées mais non câblées), les 42% de tests en échec, et les quelques failles d'accessibilité majeures.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. RISQUES BUSINESS
|
||
|
|
|
||
|
|
### Perspective Designer
|
||
|
|
Un designer **peut** travailler avec ce design system. Les tokens SUMI sont complets, documentés, et la documentation design (DESIGN_TOKENS.md, DESIGN_SYSTEM_REFERENCE.md) est exploitable. Le risque : la coexistence de deux systèmes typographiques (SUMI classes vs Tailwind direct) créera des incohérences si le designer spécifie des styles sans connaître cette dualité.
|
||
|
|
|
||
|
|
### Perspective Développeur Frontend
|
||
|
|
Un développeur **peut être productif en 3-5 jours** grâce à la structure claire, les path aliases, MSW, et Storybook. Le risque : l'ambiguité `components/` vs `features/` ralentira la prise en main. Les 55+ fichiers d'audit dans `docs/` sont du bruit qui noie la documentation utile (5 fichiers core).
|
||
|
|
|
||
|
|
### Perspective Utilisateur Final
|
||
|
|
L'expérience est **cohérente et fluide sur les parcours principaux** (auth, library, tracks, playlists, chat). Le player fonctionne bien. Le risque : 5 routes "Coming Soon" donnent une impression d'inachevé. Le bug 2FA potentiel est bloquant pour la sécurité. Skip link présent (App.tsx).
|
||
|
|
|
||
|
|
### Perspective Investisseur
|
||
|
|
Le frontend **donne l'impression d'un produit mature en démo superficielle** — le design SUMI est cohérent, l'architecture est professionnelle, les features affichées sont nombreuses. Le risque : en creusant, 5 routes sur 25 sont des placeholders, 6 features sont gated, le backend ne couvre pas toutes les promesses UI. L'investisseur averti posera la question : "pourquoi autant de surface frontend si le backend n'est pas prêt ?"
|
||
|
|
|
||
|
|
### Réponses directes
|
||
|
|
|
||
|
|
- **Ce frontend est-il présentable en démo ?** Oui, sur les parcours auth → dashboard → library → tracks → playlists → chat → settings. Ne pas montrer gear/live/education/queue/developer.
|
||
|
|
- **Ce design system est-il exploitable par une équipe ?** Oui, avec un onboarding de 2-3 jours et la résolution de la dualité typographique.
|
||
|
|
- **Le frontend peut-il absorber 6 mois d'évolution ?** Oui, si on nettoie la dette structurante (M effort). L'architecture est extensible.
|
||
|
|
- **Faut-il refactorer ou réécrire ?** **Refactorer**. La base est saine. La réécriture serait un gaspillage disproportionné.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. PLAN D'ACTION PRIORISÉ
|
||
|
|
|
||
|
|
### Phase 1 — Urgences (1-2 semaines)
|
||
|
|
|
||
|
|
| Action | Effort | Fichier(s) |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| Corriger bug 2FA login vs setup | S | `features/auth/components/TwoFactorVerify.tsx:47` |
|
||
|
|
| Déplacer `swagger-ui-react` en devDependencies | S | `package.json` |
|
||
|
|
| Déplacer `rollup-plugin-visualizer` en devDependencies | S | `package.json` |
|
||
|
|
| Supprimer 16 `console.log` dans GlobalSearchBar | S | `components/search/GlobalSearchBar.tsx` |
|
||
|
|
| Ajouter cleanup `setTimeout` dans ChatInput, SocialViewFeedItem, PostCard | S | 3 fichiers |
|
||
|
|
| ~~Ajouter skip link~~ | — | **Corrigé** : lien dans App.tsx (href="#main-content") |
|
||
|
|
| Ajouter `aria-label` sur ChatInput | S | `features/chat/components/ChatInput.tsx` |
|
||
|
|
| Typer `login`/`register` dans authService (remplacer `any`) | S | `services/authService.ts` |
|
||
|
|
| Ajouter focus trap sidebar mobile | M | `components/layout/Sidebar.tsx` |
|
||
|
|
|
||
|
|
### Phase 2 — Consolidation (2-6 semaines)
|
||
|
|
|
||
|
|
| Action | Effort | Fichier(s) |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| Unifier Spinner/LoadingSpinner/LoadingState en un seul composant | M | `components/ui/` (3 fichiers) |
|
||
|
|
| Terminer migration Modal → Dialog (6 fichiers restants) | M | `components/ui/modal.tsx` + importeurs |
|
||
|
|
| ~~Tests ErrorDisplay, LoadingState, Accordion, Collapsible, FAB, ComingSoon, AnimatedNumber~~ | — | **Corrigé** : fichiers .test présents |
|
||
|
|
| Supprimer `(track as any).like_count` — étendre le type Track | S | `features/tracks/components/TrackCard.tsx:43` |
|
||
|
|
| Résoudre les 15 `as unknown as` dans les services | M | Services divers |
|
||
|
|
| Ajouter Loading/Error/Empty states aux stories existantes | L | ~50+ stories |
|
||
|
|
| Unifier système typographique (SUMI classes uniquement ou Tailwind uniquement) | L | Codebase-wide |
|
||
|
|
| Auditer et réduire les ~100 valeurs arbitraires Tailwind en production | M | Fichiers identifiés |
|
||
|
|
| Memoiser arrays/callbacks dans DashboardPage | S | `features/dashboard/pages/DashboardPage.tsx` |
|
||
|
|
| Nettoyer components feature dans `components/` (move vers `features/`) | L | `components/admin/`, `social/`, `studio/`, `settings/` |
|
||
|
|
| Fixer les 42% de tests en échec | L | Tests tracks et autres |
|
||
|
|
|
||
|
|
### Phase 3 — Maturité (6-12 semaines)
|
||
|
|
|
||
|
|
| Action | Effort | Fichier(s) |
|
||
|
|
|--------|--------|-----------|
|
||
|
|
| Extraire design system SUMI en package npm indépendant | XL | `components/ui/`, `index.css` |
|
||
|
|
| Activer `noUncheckedIndexedAccess` dans tsconfig.app.json | L | tsconfig.app.json + ~234 fixes |
|
||
|
|
| Supprimer code fantôme (76 fichiers studio, handlers gamification) ou câbler au backend | L | `components/studio/`, `mocks/handlers.ts` |
|
||
|
|
| Ajouter CI visuel (visual regression tests) | M | Configuration |
|
||
|
|
| Ajouter `aria-live` regions pour contenu dynamique (player, notifications) | M | Player, Notifications |
|
||
|
|
| Documenter les patterns avec ADR (Architecture Decision Records) | M | `docs/` |
|
||
|
|
| Réduire les 55+ fichiers d'audit en docs/ à un CHANGELOG + KNOWN_ISSUES | S | `docs/` |
|
||
|
|
| Optimiser images (srcset, format WebP/AVIF, lazy loading natif) | M | Composants images |
|
||
|
|
| Améliorer code splitting (framer-motion, axios, DOMPurify en chunks séparés) | S | `vite.config.ts` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 11. CONCLUSION STRATÉGIQUE
|
||
|
|
|
||
|
|
**Verdict : REFACTORING CIBLÉ — ne pas réécrire.**
|
||
|
|
|
||
|
|
Ce frontend possède une base architecturale solide : feature-based organization sans cross-imports, React Query + Zustand bien séparés, Tailwind v4 avec un design system tokens complet, lazy loading systématique, MSW exhaustif, TypeScript strict. C'est le travail d'un développeur (ou d'une petite équipe) compétent qui a construit vite et large.
|
||
|
|
|
||
|
|
Le problème n'est pas la qualité du code — c'est la **dispersion**. Le frontend couvre plus de surface que le backend ne peut supporter : 5 routes Coming Soon, 6 feature flags désactivés, 76 fichiers studio orphelins, des handlers MSW pour des features fantômes (gamification, inventory). Cela crée une illusion de complétude qui ne résiste pas à l'examen.
|
||
|
|
|
||
|
|
**Recommandation pour un comité d'investissement :**
|
||
|
|
|
||
|
|
1. **Le frontend est exploitable** — il ne nécessite pas de réécriture
|
||
|
|
2. **La dette est gérable** — Phase 1 (urgences) est réalisable en 1-2 semaines par un seul développeur
|
||
|
|
3. **Le risque principal est stratégique** — trop de features affichées sans backend. Recommander de geler toute nouvelle feature frontend jusqu'à parité backend
|
||
|
|
4. **L'accessibilité a des lacunes majeures** — 3 violations WCAG majeures à corriger avant toute mise en production
|
||
|
|
5. **L'investissement en design system est un atout** — SUMI v2.0 est exploitable par une équipe et extractible en package indépendant à moyen terme
|
||
|
|
|
||
|
|
**Priorité absolue :** corriger le bug 2FA, nettoyer les console.log, et fixer les tests en échec. Skip link et tests UI critiques (ErrorDisplay, LoadingState, ComingSoon, etc.) sont en place. Mise à jour 13/02/2026.
|