veza/docs/FRONTEND_DEEP_DIVE_AUDIT.md
senke 3298295d75 docs(audit): TrackDetailPage refactorised 2026-02-05
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 06:57:46 +01:00

326 lines
65 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Audit Deep Dive — Frontend Veza (vs standards SaaS type Discord/Spotify)
**Date** : 2026-02-05
**Périmètre** : `apps/web` — structure des composants, styles (Tailwind / KŌDŌ), stories Storybook, décorateur global, accessibilité.
**Référentiel** : cohérence design system, états dinterface, complexité des composants, illusion applicative, a11y.
---
## Synthèse exécutive
Le frontend sappuie sur un **système de design KŌDŌ** riche (tokens CSS, thème clair/sombre) et un **Storybook stabilisé** (0 erreur réseau/console, contrat documenté). Les écarts principaux par rapport à des standards type Discord/Spotify portent sur : **utilisation encore forte de valeurs arbitraires** malgré les tokens, **états dinterface incomplets** dans de nombreuses stories (Loading/Error/Disabled/Focus), **plusieurs composants “monolithes”** difficiles à tester et à faire évoluer, **décorateur Storybook** sans gestion des transitions ni du feedback tactile, et **a11y** partiellement couverte (addon présent, tests a11y en “todo”).
Les problèmes sont classés en **Bloquant**, **Amélioration** et **Perfectionnement**.
---
## 1. Cohérence du système de design
### Ce qui est en place
- **Tokens centralisés** dans `src/index.css` : palette (void, cyan, magenta, lime), sémantiques (primary, destructive, success, warning), radius (`--radius`), durées (`--duration-fast`, `--duration-normal`, etc.), easings, glows, glass.
- **Thème Tailwind v4** via `@theme inline` : couleurs (`--color-primary`, `--color-sidebar-*`), radius (`--radius-sm` à `--radius-2xl`), typo (font-sans, font-mono, font-display).
- **Composants UI de base** : `button.tsx` utilise des tokens (`bg-kodo-cyan`, `ring-kodo-cyan`, `focus-visible:ring-2`), CVA pour variants/sizes, pas de valeurs arbitraires dans les variants.
### Problèmes identifiés
| Criticité | Constat | Détail |
|-----------|--------|--------|
| **Amélioration** | Valeurs arbitraires nombreuses | Plus de **170 fichiers** contiennent des classes type `h-[…]`, `w-[…]`, `p-[…]`, `gap-[…]`, `rounded-[…]`. Ex. : `h-[400px]`, `w-[300px]`, `min-h-[600px]`, `w-[500px]`, `h-[70px]` dans stories et composants. |
| **Amélioration** | Stories comme source de dérive | Les stories utilisent souvent des conteneurs en `h-[600px]`, `w-[300px]` pour le rendu. Ces valeurs ne sappuient pas sur les tokens (ex. `--radius-lg`, `h-96`, `max-w-3xl`). |
| **Perfectionnement** | Échelle despacement | Les tokens despacement (4px, 8px, 16px, 24px…) sont partiellement reflétés en Tailwind ; des `p-4`, `p-8` coexistent avec des `p-[12px]` ou `gap-[11px]` ponctuels. |
### Recommandations
- **Remplacer progressivement** les valeurs arbitraires par des tokens : par ex. `h-[400px]``h-[var(--height-panel)]` ou `min-h-96` si une scale est définie.
- **Documenter une scale de hauteurs/largeurs** (cards, modals, sidebars) dans le design system et lutiliser dans les stories.
- **Linter / règle custom** (stylelint ou ESLint) pour limiter les `[…px]` / `[…]rem` hors tokens.
### Mise à jour (nettoyage systémique)
**Layout primitives** ont été ajoutées dans `src/index.css` pour **App/Layouts** et **App/Pages** :
- **Variables CSS** (`:root`) : `--layout-content-max-width` (100rem), `--layout-main-min-height`, `--layout-page-min-height` (37.5rem), `--layout-page-min-height-sm` (25rem), `--layout-story-decorator-min-height` (12rem).
- **Classes utilitaires** (`@layer utilities`) : `.max-w-layout-content`, `.min-h-layout-main`, `.min-h-layout-page`, `.min-h-layout-page-sm`, `.min-h-layout-story`.
- **Remplacements effectués** : `max-w-[1600px]``max-w-layout-content` (Layout, DashboardLayout, ChatPage) ; `min-h-[calc(100vh-64px)]``min-h-layout-main` (Layout) ; `min-h-[600px]``min-h-layout-page` (UserProfilePage, SettingsPage, PlaylistDetailPage) ; `min-h-[400px]``min-h-layout-page-sm` (LibraryPage, SessionsPage) ; `min-h-[200px]` (Navbar story) → `min-h-layout-story` ; `md:w-[400px]` (AudioPlayer) → `md:w-96` ; `min-h-[44px]``min-h-11` (PlaylistListPage) ; `min-w-[140px]``min-w-36` (SettingsPage) ; `h-[60%]` / `h-[40%]``h-3/5` / `h-2/5` (LibraryPage). Les ombres et valeurs viewport (ex. `h-[60vh]`) sont laissées en létat.
---
## 2. Qualité des états dinterface (stories)
### Ce qui est en place
- **Loading / Skeleton** : `LoadingState`, `Skeleton`, `TrackListSkeleton`, `PlayerLoading` ont des stories dédiées.
- **Error** : `ErrorDisplay`, `PlayerError`, `AuthErrorMessage`, `ErrorBoundary`, `Alert` (variant error) sont couverts.
- **Focus** : Le `Button` a `focus-visible:ring-2 focus-visible:ring-kodo-cyan` ; plusieurs composants UI (input, checkbox, select, tabs) ont du `focus:` ou `focus-visible:`.
- **Disabled** : Présent dans ~23 fichiers de stories (Button, Checkbox, VolumeControl, etc.).
### Problèmes identifiés
| Criticité | Constat | Détail |
|-----------|--------|--------|
| **Bloquant** | Addon a11y non exploité | Dans `.storybook/preview.tsx`, `a11y: { test: 'todo' }` — les tests a11y ne sont pas exécutés en CI ni utilisés comme garde-fou. |
| **Amélioration** | Loading “factice” sur Button | La story `LoadingState` du Button est un `disabled` + texte "Loading..." sans spinner ni `aria-busy`. Les standards SaaS montrent un état de chargement explicite (spinner + désactivation). |
| **Amélioration** | États manquants par type de composant | Beaucoup de composants “carte” ou “liste” nont quun état Default : pas de story **Empty**, **Error**, **Loading** ou **Disabled** (ex. plusieurs vues Playlist, Track, Chat, Commerce). |
| **Amélioration** | Hover / Active peu documentés | Peu de stories nommées "Hover" ou "Active" ; les variants sont surtout visuels. Pas de démo systématique des états interactifs (hover/active) pour les boutons et liens. |
| **Perfectionnement** | Focus visible inégal | Une soixantaine de fichiers de composants utilisent `focus:` ou `focus-visible:` ; dautres (cards cliquables, list items, custom controls) peuvent ne pas avoir de ring/outline visible. |
### Recommandations
- Passer **a11y.test** de `'todo'` à une config réelle (ex. `runOnly` avec règles WCAG 2.1 AA) et faire échouer le build/audit si des violations sont détectées.
- Ajouter une story **Loading** réaliste au Button (spinner + `disabled` + `aria-busy`) et un état **Disabled** explicite partout où laction peut être désactivée.
- Pour les listes/cartes (Playlist, Track, Chat, Commerce), ajouter au moins **Empty** et **Error** (et **Loading** si async).
- Documenter **Hover** / **Active** dans les stories des composants interactifs (boutons, nav, sidebar) pour valider la cohérence visuelle.
---
## 3. Complexité des composants (“composants dieux”)
### Composants les plus volumineux (≥ ~400 lignes)
| Fichier | Lignes | Responsabilités identifiées |
|---------|--------|------------------------------|
| ~~`ProfileForm.tsx`~~ | ~~678~~ | **Refactorisé 2026-02-05** : module `profile-form/` avec `useProfileForm`, `ProfileCompletionCard`, `ProfileFormSkeleton`, schéma dédié. Stories : Default, Loading, Error, ProfileFormSkeleton. Re-export depuis `ProfileForm.tsx`. |
| ~~`ProfileView.tsx`~~ | ~~602~~ | **Refactorisé 2026-02-05** : module `profile-view/` avec `useProfileViewData`, sous-composants (TrackCard, PlaylistCard, Sidebar, Overview, TracksTab, PlaylistsTab, AboutTab), `ProfileViewSkeleton`. Stories : Default, Loading, Error, ProfileViewSkeleton. Re-export depuis `ProfileView.tsx`. |
| ~~`GearView.tsx`~~ | ~~559~~ | **Refactorisé 2026-02-05** : module `gear-view/` avec `useGearView`, `GearViewToolbar`, `GearViewSkeleton` ; props pour stories. Stories : Default, Loading, Empty, Error, GearViewSkeleton. Re-export depuis `GearView.tsx`. |
| ~~`CommentThread.tsx`~~ | ~~547~~ | **Refactorisé 2026-02-05** : module `comment-thread/` avec hooks et sous-composants (voir ci-dessous). |
| ~~`LazyComponent.tsx`~~ | ~~505~~ | **Refactorisé 2026-02-05** : module `lazy-component/` avec `LazyErrorFallback`, `LazyErrorBoundary`, `createLazyComponent`, `lazyExports`. Stories : LazyErrorFallback (Default, WithRetry, NoError), LazyComponent (Default, Loading). Re-export depuis `LazyComponent.tsx`. |
| ~~`CloudFileBrowser.tsx`~~ | ~~503~~ | **Module existant** : `features/studio/components/cloud-file-browser/` — orchestrateur CloudFileBrowser.tsx (~188 lignes), FileToolbar, FileTable, FileGrid, FileGridCard, FileTableRow, CloudFileBrowserSkeleton, types. Ancien fichier monolithe `components/studio/CloudFileBrowser.tsx` supprimé. |
| ~~`router/index.tsx`~~ | ~~458~~ | **Refactorisé 2026-02-05** : module `router/` avec `types` (RouteEntry), `PublicRoute`, `ProtectedLayoutRoute`, `routeConfig` (getPublicRoutes, getPublicStandaloneRoutes, getProtectedRoutes, getErrorRoutes), `AppRouter`. Routes rendues par config. Tests mis à jour (mocks LazyComponent, PublicRoute, ProtectedRoute, ProtectedLayoutRoute). Re-export depuis `router/index.tsx`. |
| ~~`Search.tsx`~~ | ~~494~~ | **Refactorisé 2026-02-05** : module `features/search/components/search/` avec hooks et sous-composants (voir ci-dessous). |
| ~~`UploadModal.tsx`~~ | ~~486~~ | **Refactorisé 2026-02-05** : module `upload-modal/` avec `useUploadModal`, `UploadModalDropzone`, `UploadModalFileDisplay`, `UploadModalProgress`, `UploadModalErrorAlert`, `UploadModalMetadataForm`. Stories : Default, Open. Re-export depuis `UploadModal.tsx`. |
| ~~`file-upload.tsx`~~ | ~~478~~ | **Refactorisé 2026-02-05** : module `components/ui/file-upload/` avec `useFileUpload`, `FileUploadDropzone`, `FileUploadErrorList`, `FileUploadFileList`. Stories : Default, Empty, ImagesOnly, MaxSize, Disabled, Error, StateSimulation. Point dentrée `file-upload/index.ts`. |
| ~~`ChatSidebar.tsx`~~ | ~~469~~ | **Refactorisé 2026-02-05** : module `chat-sidebar/` avec hooks (`useChatConversations`, `useConversationActions`) et sous-composants (Header, Empty, Skeleton, ConversationItem). Stories : Default, Empty, Error, ChatSidebarSkeleton. |
| ~~`select.tsx`~~ | ~~466~~ | **Refactorisé 2026-02-05** : module `components/ui/select/` avec `useSelect`, `SelectTrigger`, `SelectDropdownContent`, `SelectOptionItem`. Stories : Default, Empty, Disabled, Grouped, MultiSelect. Point dentrée `select/index.ts`. |
| ~~`NotificationsPage.tsx`~~ | ~~421~~ | **Refactorisé 2026-02-05** : module `features/notifications/components/notifications-page/` avec `useNotificationsPage`, Header, Filters, Item, Empty, Error, Skeleton. Stories : Default, Loading, Error, Empty. Re-export depuis `pages/NotificationsPage.tsx`. |
| ~~`SearchPage.tsx`~~ | ~~235~~ | **Refactorisé 2026-02-05** : module `features/search/components/search-page/` avec `useSearchPage`, Header, Discovery, Empty, Error, Results, Skeleton. Stories : Default, Loading, Empty, Error. MSW : GET search → SearchResults. |
| ~~`FileManagerView.tsx`~~ | ~~449~~ | **Refactorisé 2026-02-05** : module `components/views/file-manager-view/` avec `useFileManagerView`, Header, Toolbar, Table, Grid, Empty, Skeleton. Stories : Default, Loading, Empty. Re-export depuis `FileManagerView.tsx`. |
| ~~`RegisterPage.tsx`~~ | ~~380~~ | **Refactorisé 2026-02-05** : module `features/auth/components/register-page/` avec `useRegisterPage`, RegisterPageForm, RegisterPageVerificationNotice, RegisterPageSkeleton. Stories : Default, Loading, WithError. Re-export depuis `pages/RegisterPage.tsx`. |
| ~~`MonitoringDashboard.tsx`~~ | ~~423~~ | **Refactorisé 2026-02-05** : module `components/monitoring/monitoring-dashboard/` avec `useMonitoringDashboard`, `MonitoringDashboardContent` (découpé en Header, Stats, ValidationCard, ErrorsCard, PerformanceCard), `MonitoringDashboardSkeleton`, types. Stories : Default, Loading, Error. Layout primitive `min-h-layout-page-sm` pour skeleton et erreur. Re-export depuis `MonitoringDashboard.tsx`. |
| ~~`PlaybackDashboard.tsx`~~ | ~~434~~ | **Refactorisé 2026-02-05** : module `features/streaming/components/playback-dashboard/` avec `usePlaybackDashboard`, StatsCard, TrendsCard, Charts, DetailedCard, Content, Skeleton. Stories : Default, Loading, Error, Empty. MSW : GET `/api/v1/tracks/:id/playback/dashboard`. Re-export depuis `PlaybackDashboard.tsx`. |
| ~~`ShareLinkManager.tsx`~~ | ~~413~~ | **Refactorisé 2026-02-05** : module `components/share/share-link-manager/` avec `useShareLinkManager`, CreateForm, Item, Empty, Content, Skeleton. Props optionnelles `initialLinks`, `isLoading`. Stories : Default, Empty, Loading, Error. Re-export depuis `ShareLinkManager.tsx`. |
| ~~`date-picker.tsx`~~ | ~~445~~ | **Refactorisé 2026-02-05** : module `components/ui/date-picker/` avec `useDatePicker`, `DatePickerTrigger`, `DatePickerCalendar`, types. Stories : SingleDate, DateRange, Disabled. Point dentrée `date-picker/index.ts`. |
| ~~`avatar-upload.tsx`~~ | ~~436~~ | **Refactorisé 2026-02-05** : module `components/ui/avatar-upload/` avec `useAvatarUpload`, `AvatarUploadDropzone`, `AvatarUploadActions`, `AvatarUploadSkeleton`. Stories : Default, WithExistingAvatar, Disabled, Large, Loading. MSW : POST avatar retourne `avatar_url`. Point dentrée `avatar-upload/index.ts`. |
| ~~`optimized-image.tsx`~~ | ~~407~~ | **Refactorisé 2026-02-05** : module `components/ui/optimized-image/` avec types, `generateImageSources`, `BlurPlaceholder`, `useImageFormatSupport`, `OptimizedImage`, `OptimizedImageSkeleton`, `useImagePreloader`, `ResponsiveImage`. Stories : Default, WithPlaceholder, ErrorState, Loading (skeleton). Re-export depuis `optimized-image.tsx`. |
| ~~`DataList.tsx`~~ | ~~398~~ | **Refactorisé 2026-02-05** : module `components/ui/data-list/` avec types, `DataListSkeleton`, `DataListEmpty`, `DataListError`, `DataList`. Modal/Dropdown retirés (doublons de `modal.tsx`/`dropdown.tsx`). Stories : Default, Loading, Empty, Error, Skeleton. Re-export depuis `DataList.tsx`. |
| ~~`components/player/AudioPlayer.tsx`~~ | ~~405~~ | **Refactorisé 2026-02-05** : module `components/player/audio-player/` avec types, `useAudioPlayerEffects`, `AudioPlayerTrackInfo`, `AudioPlayerControls`, `AudioPlayerProgress`, `AudioPlayerVolume`, `AudioPlayerSkeleton`, `AudioPlayer`. Stories : Default (avec mock store), Skeleton. Re-export depuis `AudioPlayer.tsx`. |
| ~~`TrackFilters.tsx`~~ | ~~401~~ | **Refactorisé 2026-02-05** : module `features/tracks/components/track-filters/` avec `useTrackFilters`, `TrackFiltersHeader`, `TrackFiltersSearch`, `TrackFiltersGrid`, `TrackFiltersClear`, `TrackFiltersSkeleton`. Stories : Default, Collapsible, Loading. Re-export depuis `TrackFilters.tsx`. |
| ~~`PlaylistList.tsx`~~ | ~~380~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-list/` avec `usePlaylistList`, `PlaylistListToolbar`, `PlaylistListEmpty`, `PlaylistListError`. Skeleton existant `PlaylistListSkeleton`. Stories : Default, Grid, Empty (MSW), Loading (skeleton). Re-export depuis `PlaylistList.tsx`. |
| ~~`dialog.tsx`~~ | ~~365~~ | **Refactorisé 2026-02-05** : module `components/ui/dialog/` avec types, `Dialog`, `DialogHeader`, `DialogBody`, `DialogFooter`, `DialogContent`, `DialogDescription`, `DialogTitle`, `DialogTrigger`, `DialogSkeleton`. Stories : Default, Alert, Composition, Loading. Re-export depuis `dialog.tsx`. |
| ~~`dropdown-menu.tsx`~~ | ~~345~~ | **Refactorisé 2026-02-05** : module `components/ui/dropdown-menu/` avec types, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioItem`, `DropdownMenuLabel`, `DropdownMenuSeparator`, `DropdownMenuShortcut`, `DropdownMenuPlaceholders` (Group, Portal, Sub, SubContent, SubTrigger, RadioGroup). Dropdown base (`dropdown.tsx`) : `open` / `defaultOpen` pour mode contrôlé. Conformité UI : `min-w-32` (pas de valeur arbitraire). Re-export depuis `dropdown-menu.tsx`. |
| ~~`accordion.tsx`~~ | ~~335~~ | **Refactorisé 2026-02-05** : module `components/ui/accordion/` avec types, `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`. Conformité UI : `max-h-[5000px]``max-h-none`, stories `w-[500px]``max-w-xl`. Re-export depuis `accordion.tsx`. |
| ~~`tabs.tsx`~~ | ~~330~~ | **Refactorisé 2026-02-05** : module `components/ui/tabs/` avec types, `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`. Stories `w-[400px]``max-w-md`. Re-export depuis `tabs.tsx`. |
| ~~`tooltip.tsx`~~ | ~~327~~ | **Refactorisé 2026-02-05** : module `components/ui/tooltip/` avec types, `useTooltip`, `TooltipContent`, `Tooltip`. Handlers hover sur wrapper, click/focus sur enfant (cloneElement). Conformité : `max-w-xs` par défaut, stories `h-[200px]``min-h-layout-story`. Re-export depuis `tooltip.tsx`. |
| ~~`Table.tsx` (data)~~ | ~~323~~ | **Refactorisé 2026-02-05** : module `components/data/table/` avec types, `useTable`, `TableHeadRow`, `TableBodyRows`, `Table`. Conformité : largeur colonnes via style (pas de classe arbitraire). Stories : Default, Empty, Paginated, Selectable (Data/Table). Re-export depuis `Table.tsx`. |
| ~~`FormBuilder.tsx`~~ | ~~316~~ | **Refactorisé 2026-02-05** : module `components/forms/form-builder/` avec types, `useFormBuilder`, `FormBuilderFieldWidget`, `FormBuilder`. Conformité : textarea `min-h-[80px]``min-h-20`. Stories : Default, Empty, Disabled (Components/Forms/FormBuilder). Re-export depuis `FormBuilder.tsx`. |
| ~~`EditProfile.tsx`~~ | ~~310~~ | **Refactorisé 2026-02-05** : module `components/settings/profile/edit-profile/` avec types, `cropUtils`, `useEditProfile`, `EditProfileImagesCard`, `EditProfileIdentityCard`, `EditProfileSidebar`, `EditProfileSkeleton`. Conformité : textarea `min-h-[100px]``min-h-24`. Stories : Default, Loading (Skeleton). Re-export depuis `EditProfile.tsx`. |
| ~~`GroupDetailView.tsx`~~ | ~~307~~ | **Refactorisé 2026-02-05** : module `components/social/groups/group-detail-view/` avec types (`ExtendedGroup`, `GroupMember`, `GroupEvent`), `useGroupDetailView`, `GroupDetailViewHeader`, `GroupDetailViewMembers`, `GroupDetailViewEvents`, `GroupDetailViewSidebar`, `GroupDetailViewSkeleton`. Conformité : `text-[10px]``text-xs`, `min-w-[80px]``min-w-20`. Stories : Default, Loading. Re-export depuis `GroupDetailView.tsx`. |
| ~~`UserProfilePage.tsx`~~ | ~~318~~ | **Refactorisé 2026-02-05** : module `features/profile/pages/user-profile-page/` avec `useUserProfilePage`, `UserProfilePageHero`, `UserProfilePageHeader`, `UserProfilePageTabs`, `UserProfilePageSkeleton`, `UserProfilePageError`. Conformité : stats `text-[10px]``text-xs`. Stories : Default (route /u/demo), Loading (Skeleton), NotFound (route /u/notfound). MSW : GET `/api/v1/users/by-username/:username` (404 pour notfound). Re-export depuis `UserProfilePage.tsx`. |
| ~~`DiscoverView.tsx`~~ | ~~300~~ | **Refactorisé 2026-02-05** : module `components/views/discover-view/` avec `useDiscoverView`, `DiscoverViewHero`, `DiscoverViewTrending`, `DiscoverViewNewReleases`, `DiscoverViewGenres`, `DiscoverViewSkeleton`, `DiscoverViewError`. Conformité : loading `h-[50vh]` → Skeleton ; badge UPDATED `text-[10px]``text-xs` ; erreur `min-h-layout-page-sm`. Stories : Default, Loading (Skeleton), Error. Re-export depuis `DiscoverView.tsx`. |
| ~~`features/library/UploadModal.tsx`~~ | ~~317~~ | **Refactorisé 2026-02-05** : module `features/library/components/upload-modal/` avec `useLibraryUploadModal`, `UploadModalForm`, `UploadModalFooter`, types (`UploadModalProps`, `UploadFormData`, `ALLOWED_AUDIO_TYPES`, `MAX_FILE_SIZE_BYTES`). Stories inchangées : Default, Controlled. Re-export depuis `UploadModal.tsx`. |
| ~~`features/player/components/AudioPlayer.tsx`~~ | ~~374~~ | **Refactorisé 2026-02-05** : module `features/player/components/audio-player/` avec `useAudioPlayerLifecycle`, `AudioPlayerCompact`, `AudioPlayerFull`, `AudioPlayerSkeleton`. Stories : Playing, Paused, Loading (Skeleton), Error. Re-export et default export depuis `AudioPlayer.tsx`. 20 tests passent. |
| ~~`AccountSettings.tsx`~~ | ~~362~~ | **Refactorisé 2026-02-05** : module `features/settings/components/account-settings/` avec `useAccountSettings`, `AccountSettingsErrorBanner`, `AccountSettingsPasswordCard`, `AccountSettingsExportCard`, `AccountSettingsDeleteCard`, `AccountSettingsSkeleton`. Stories : Default, Loading. Re-export depuis `AccountSettings.tsx`. |
| ~~`TrackSearchFilters.tsx`~~ | ~~348~~ | **Refactorisé 2026-02-05** : module `features/tracks/components/track-search-filters/` avec `useTrackSearchFilters`, `TrackSearchFiltersBasic`, `TrackSearchFiltersAdvanced`, `TrackSearchFiltersSkeleton`. Stories : Default, Applied, Loading. Re-export depuis `TrackSearchFilters.tsx`. |
| ~~`SessionsPage.tsx`~~ | ~~351~~ | **Refactorisé 2026-02-05** : module `features/auth/components/sessions-page/` avec `useSessionsPage`, `SessionsPageHeader`, `SessionsPageErrorBanner`, `SessionsPageRevokeAllButton`, `SessionsPageSessionItem`, `SessionsPageContent`, `SessionsPageEmpty`, `SessionsPageSkeleton`. Stories : Default, Loading, Empty, Error. MSW : GET/DELETE auth/sessions. Re-export depuis `pages/SessionsPage.tsx`. |
| ~~`ProjectDetailView.tsx`~~ | ~~367~~ | **Refactorisé 2026-02-05** : module `components/studio/projects/project-detail-view/` avec `useProjectDetailView`, `ProjectDetailViewHeader`, `ProjectDetailViewTabs`, `ProjectDetailViewOverview`, `ProjectDetailViewFiles`, `ProjectDetailViewSettings`, `ProjectDetailViewSidebar`, `ProjectDetailViewSkeleton`. Stories : Default, Loading, Empty. Re-export depuis `projects/ProjectDetailView.tsx`. |
| ~~`PlaybackHeatmap.tsx`~~ | ~~353~~ | **Refactorisé 2026-02-05** : module `features/streaming/components/playback-heatmap/` avec `usePlaybackHeatmap`, `PlaybackHeatmapHeader`, `PlaybackHeatmapStats`, `PlaybackHeatmapGrid`, `PlaybackHeatmapSkeleton`, `PlaybackHeatmapError`, `PlaybackHeatmapEmpty`. Stories : Default, CustomSegmentSize, Loading, Empty, Error. MSW : GET `/api/v1/tracks/:id/playback/heatmap`. Re-export depuis `PlaybackHeatmap.tsx`. |
| ~~`ProductDetailView.tsx`~~ | ~~352~~ | **Refactorisé 2026-02-05** : module `components/marketplace/product-detail-view/` avec `useProductDetailView`, `ProductDetailViewHeader`, `ProductDetailViewGallery`, `ProductDetailViewInfo`, `ProductDetailViewLicenses`, `ProductDetailViewDescription`, `ProductDetailViewReviews`, `ProductDetailViewSimilar`, `ProductDetailViewSkeleton`. Stories : Default, Loading, Empty, WithReviews. Re-export depuis `ProductDetailView.tsx`. |
| ~~`CourseLearningView.tsx`~~ | ~~353~~ | **Refactorisé 2026-02-05** : module `components/education/course-learning-view/` avec `useCourseLearningView`, `CourseLearningViewHeader`, `CourseLearningViewPlayer`, `CourseLearningViewTabs`, `CourseLearningViewSidebar`, `CourseLearningViewSkeleton`. Layout `min-h-layout-main`. Stories : Default, Loading, Empty, Complete. Re-export depuis `CourseLearningView.tsx`. |
| ~~`CourseDetailView.tsx`~~ | ~~348~~ | **Refactorisé 2026-02-05** : module `components/education/course-detail-view/` avec `useCourseDetailView`, `CourseDetailViewHeader`, `CourseDetailViewTabs`, `CourseDetailViewSidebar`, `CourseDetailViewSkeleton`. Stories : Default, Loading, Empty, Enrolled. Re-export depuis `CourseDetailView.tsx`. |
| ~~`LibraryManager.tsx`~~ | ~~337~~ | **Refactorisé 2026-02-05** : module `features/library/components/library-manager/` avec `useLibraryManager`, Header, Toolbar, Error, Empty, Content, Stats, `LibraryManagerSkeleton`. Layout `min-h-layout-page`. Stories : Default, Loading, Empty, Error. MSW : GET /api/v1/tracks. Re-export depuis `LibraryManager.tsx`. |
| ~~`features/library/pages/LibraryPage.tsx`~~ | ~~281~~ | **Refactorisé 2026-02-05** : module `features/library/pages/library-page/` avec types, utils (safeFormatDistanceToNow, getArtistName, formatDuration), `useLibraryPage`, `LibraryPageToolbar`, `LibraryPageEmpty`, `LibraryPageGrid`, `LibraryPageList`, `LibraryPageSkeleton`. Layout `min-h-layout-page-sm` (Empty). Stories : Default, Empty (initialTracks []), Loading (Skeleton). Re-export depuis `LibraryPage.tsx`. |
| ~~`features/chat/components/VirtualizedChatMessages.tsx`~~ | ~~287~~ | **Refactorisé 2026-02-05** : module `features/chat/components/virtualized-chat-messages/` avec types (MESSAGE_HEIGHT, CONTAINER_HEIGHT), `useChatMessages`, `VirtualizedChatMessageItem`, `VirtualizedChatMessagesEmpty`, `VirtualizedChatMessagesLoadingIndicator`, `VirtualizedChatMessagesScrollButton`, `VirtualizedChatMessagesSkeleton`. Layout `min-h-layout-page-sm` (Empty, Skeleton). Stories : Default, Empty, Loading (Skeleton). Re-export depuis `VirtualizedChatMessages.tsx`. |
| ~~`features/playlists/components/PlaylistAnalytics.tsx`~~ | ~~284~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-analytics/` avec types (`PlaylistAnalyticsData`), `usePlaylistAnalytics`, `PlaylistAnalyticsStatCard`, `PlaylistAnalyticsMainCard`, `PlaylistAnalyticsAdvancedCard`, `PlaylistAnalyticsZeroState`, `PlaylistAnalyticsError`, `PlaylistAnalyticsNoData`, `PlaylistAnalyticsSkeleton`. Layout `min-h-layout-story` (Skeleton, Error, NoData). Props `initialAnalytics`, `initialError`, `forceLoading` pour stories. Stories : Default, Empty, Error, Loading (Skeleton). Re-export depuis `PlaylistAnalytics.tsx`. |
| ~~`features/tracks/components/TrackListPagination.tsx`~~ | ~~283~~ | **Refactorisé 2026-02-05** : module `features/tracks/components/track-list-pagination/` avec types, `utils` (getVisiblePages, getItemsRange), `TrackListPaginationInfo`, `TrackListPaginationNav`, `TrackListPaginationSkeleton`. Conformité UI : `border-kodo-steel``border-border`, `text-kodo-*``text-foreground`/`text-muted-foreground`, `bg-kodo-cyan``bg-primary`, `focus:ring-blue-500``focus-visible:ring-ring`. Stories : Default, MiddlePage, LastPage, ManyPages, Disabled, Loading (Skeleton). Re-export depuis `TrackListPagination.tsx`. |
| ~~`components/inventory/EquipmentDetailView.tsx`~~ | ~~279~~ | **Refactorisé 2026-02-05** : module `components/inventory/equipment-detail-view/` avec types, `useEquipmentDetailView`, `EquipmentDetailViewNav`, `EquipmentDetailViewGallery`, `EquipmentDetailViewSpecsCard`, `EquipmentDetailViewHeader`, `EquipmentDetailViewWarrantyCard`, `EquipmentDetailViewDocsCard`, `EquipmentDetailViewServiceCard`, `EquipmentDetailViewNotFound`, `EquipmentDetailViewSkeleton`. Conformité : `text-kodo-*` → tokens, `text-[10px]``text-xs`, loading `h-[50vh]` → Skeleton. Props `initialItem`, `forceLoading` pour stories. Stories : Default (initialItem), Loading (Skeleton), NotFound. Re-export depuis `EquipmentDetailView.tsx`. |
| ~~`features/playlists/components/PlaylistActions.tsx`~~ | ~~277~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-actions/` avec types (`PlaylistActionsProps`), `usePlaylistActions`, `PlaylistActionsButtons`, `PlaylistActionsEditDialog`, `PlaylistActionsSkeleton`, `ConfirmationDialog` (suppression). Conformité : `min-h-11`, tokens success (`text-green-600`). Stories : Default, WithShare, Loading (Skeleton). ToastProvider dans décorateur. Ancien fichier monolithe supprimé ; import depuis `playlist-actions`. |
| ~~`features/playlists/pages/PlaylistDetailPage.tsx`~~ | ~~270~~ | **Refactorisé 2026-02-05** : module `features/playlists/pages/playlist-detail-page/` avec types (`PlaylistDetailPageProps`), `usePlaylistDetailPage`, `PlaylistDetailPageHero`, `PlaylistDetailPageCoverAndInfo`, `PlaylistDetailPageActionsBar`, `PlaylistDetailPageTabs`, `PlaylistDetailPageNotFound`, `PlaylistDetailPageSkeleton`. Layout `min-h-layout-page`. Stories : Default (route `/playlists/demo-playlist`), Loading (Skeleton), NotFound. Re-export depuis `PlaylistDetailPage.tsx`. |
| ~~`features/tracks/pages/TrackDetailPage.tsx`~~ | ~~238~~ | **Refactorisé 2026-02-05** : module `features/tracks/pages/track-detail-page/` avec types (`TrackDetailPageProps`), `utils` (formatDuration), `useTrackDetailPage`, `TrackDetailPageHero`, `TrackDetailPageCoverAndActions`, `TrackDetailPageInfo`, `TrackDetailPageTabs`, `TrackDetailPageNotFound`, `TrackDetailPageSkeleton`. Layout `min-h-layout-page`. Stories : Default (route `/tracks/demo-track`), Loading (Skeleton), NotFound. Re-export depuis `TrackDetailPage.tsx`. |
| ~~`NotificationMenu.tsx`~~ | ~~339~~ | **Refactorisé 2026-02-05** : module `components/notifications/notification-menu/` avec `useNotificationMenu`, Trigger, Dropdown, List, Item, `NotificationMenuSkeleton`. Dropdown `max-h-96`. Stories : Default, Loading, Empty, Error, Skeleton. Re-export depuis `NotificationMenu.tsx`. |
| ~~`PlaylistTrackList.tsx`~~ | ~~309~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-track-list/` avec `usePlaylistTrackList`, Empty, SortableItem, Skeleton, utils. Stories : Default, Loading, Empty, Reordering. Re-export depuis `PlaylistTrackList.tsx` et `PlaylistTrackListSkeleton.tsx`. |
| ~~`AddTrackToPlaylistModal.tsx`~~ | ~~324~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/add-track-to-playlist-modal/` avec `useAddTrackToPlaylistModal`, `AddTrackToPlaylistModalSearch`, `AddTrackToPlaylistModalList`, `AddTrackToPlaylistModalTrackRow`, `AddTrackToPlaylistModalFooter`, `AddTrackToPlaylistModalSkeleton`. Liste `max-h-96`. Stories : Default, Loading (Skeleton). Re-export depuis `AddTrackToPlaylistModal.tsx`. |
| ~~`PlaylistBatchActions.tsx`~~ | ~~323~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-batch-actions/` avec `usePlaylistBatchActions`, `exportUtils`, `PlaylistBatchActionsBar`, `PlaylistBatchActionsButtons`, `PlaylistBatchActionsDeleteDialog`, `PlaylistBatchActionsSkeleton`. Boutons `min-h-11`. Stories : Default, SingleSelection, Loading. Re-export depuis `PlaylistBatchActions.tsx`. |
| ~~`PlaylistSearch.tsx`~~ | ~~331~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/playlist-search/` avec `usePlaylistSearch`, `PlaylistSearchBar`, `PlaylistSearchFilters`, `PlaylistSearchResults`, `PlaylistSearchSkeleton`. Chargement avec Spinner. PLAYLIST_SEARCH activé en Storybook (VITE_STORYBOOK). MSW : GET `/api/v1/playlists/search`. Stories : Default, Loading, Empty, Error. Re-export depuis `PlaylistSearch.tsx`. |
| ~~`CreatePlaylistDialog.tsx`~~ | ~~186~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/create-playlist-dialog/` avec `schema`, `useCreatePlaylistDialog`, `CreatePlaylistDialogForm`, `CreatePlaylistDialogSkeleton`. Bouton Créer avec Spinner. Stories : Default, Loading. Re-export depuis `CreatePlaylistDialog.tsx`. |
| ~~`SharePlaylistModal.tsx`~~ | ~~145~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/share-playlist-modal/` avec `useSharePlaylistModal`, `SharePlaylistModalContent`, `SharePlaylistModalSkeleton`. ErrorDisplay + retry. Stories : Default, Loading, Error. Re-export depuis `SharePlaylistModal.tsx`. |
| ~~`AddCollaboratorModal.tsx`~~ | ~~200~~ | **Refactorisé 2026-02-05** : module `features/playlists/components/add-collaborator-modal/` avec `useAddCollaboratorModal`, `AddCollaboratorModalForm`, `AddCollaboratorModalSkeleton`. ErrorDisplay (validation + mutation, retry). Stories : Default, Loading, Error (MSW). Re-export depuis `AddCollaboratorModal.tsx`. |
| ~~`UploadView.tsx`~~ | ~~301~~ | **Refactorisé 2026-02-05** : module `components/views/upload-view/` avec `useUploadView`, `UploadViewStepper`, `UploadViewStep1`, `UploadViewStep2`, `UploadViewStep3`, `UploadViewSkeleton`. Layout `min-h-layout-page`, `max-h-96`. Stories : Default, Loading, Empty, Error. Re-export depuis `UploadView.tsx`. |
| ~~`TwoFactorSetup.tsx`~~ | ~~322~~ | **Refactorisé 2026-02-05** : module `components/settings/security/two-factor-setup/` avec `useTwoFactorSetup`, `TwoFactorSetupHeader`, `TwoFactorSetupStep1`, `TwoFactorSetupStep2`, `TwoFactorSetupStep3`, `TwoFactorSetupSkeleton`. Stories : Default, Step1, Step2, Loading, Error (MSW). Re-export depuis `TwoFactorSetup.tsx`. |
| ~~`TrackHistory.tsx`~~ | ~~324~~ | **Refactorisé 2026-02-05** : module `features/tracks/components/track-history/` avec `useTrackHistory`, `TrackHistoryHeader`, `TrackHistoryEmpty`, `TrackHistoryItemRow`, `TrackHistoryPagination`, `TrackHistorySkeleton`, `trackHistoryUtils`. Stories : Default, Loading, Empty, Error (MSW). Re-export depuis `TrackHistory.tsx`. |
| ~~`ProjectsManager.tsx`~~ | ~~322~~ | **Refactorisé 2026-02-05** : module `components/studio/projects-manager/` avec `useProjectsManager`, `ProjectsManagerHeader`, `ProjectsManagerFilterBar`, `ProjectsManagerCard`, `ProjectsManagerAddCard`, `ProjectsManagerEmpty`, `ProjectsManagerSkeleton`. Stories : Default, Loading, Empty. Re-export depuis `ProjectsManager.tsx`. |
| ~~`CreateProjectModal.tsx`~~ | ~~127~~ | **Refactorisé 2026-02-05** : module `components/studio/projects/create-project-modal/` avec `useCreateProjectModal`, `CreateProjectModalHeader`, `CreateProjectModalForm`, `CreateProjectModalFooter`, `CreateProjectModalSkeleton`. Stories : Default, Loading. Re-export depuis `projects/CreateProjectModal.tsx`. |
| ~~`GoLiveView.tsx`~~ | ~~255~~ | **Refactorisé 2026-02-05** : module `components/studio/go-live-view/` avec `useGoLiveView`, `GoLiveViewHeader`, `GoLiveViewPreview`, `GoLiveViewStreamInfo`, `GoLiveViewEncoderSetup`, `GoLiveViewQuickInstructions`, `GoLiveViewMicLevel`, `GoLiveViewSkeleton`. Stories : Default, Loading. Re-export depuis `GoLiveView.tsx`. |
| ~~`ConnectivityView.tsx`~~ | ~~192~~ | **Refactorisé 2026-02-05** : module `components/studio/connectivity-view/` avec `useConnectivityView`, `ConnectivityViewWebDAV`, `ConnectivityViewWebhooks`, `ConnectivityViewSkeleton`. Stories : Default, Loading. Re-export depuis `ConnectivityView.tsx`. |
| ~~`AIToolsView.tsx`~~ | ~~188~~ | **Refactorisé 2026-02-05** : module `components/studio/ai-tools-view/` avec `useAIToolsView`, `AIToolsViewToolGrid`, `AIToolsViewWorkspace`, `AIToolsViewSkeleton`, constantes `AI_TOOLS`. Stories : Default, Loading. Re-export depuis `AIToolsView.tsx`. |
| ~~`CloudSettingsView.tsx`~~ | ~~113~~ | **Refactorisé 2026-02-05** : module `components/studio/cloud-settings-view/` avec `useCloudSettingsView`, `CloudSettingsViewQuota`, `CloudSettingsViewPreferences`, `CloudSettingsViewSkeleton`. Stories : Default, Loading. Re-export depuis `CloudSettingsView.tsx`. |
| ~~`StudioView.tsx`~~ | ~~169~~ | **Refactorisé 2026-02-05** : module `components/views/studio-view/` avec `useStudioView`, `StudioViewHeader`, `StudioViewSidebar`, `StudioViewNavButton`, `StudioViewContent`, `StudioViewProjectsSwitch`, `StudioViewSkeleton`. Layout `min-h-layout-main` ; `w-[65%]``w-2/3`. Stories : Default, Projects, Loading. Re-export depuis `StudioView.tsx`. |
| ~~`context/AudioContext.tsx`~~ | ~~343~~ | **Refactorisé 2026-02-05** : module `context/audio-context/` avec `types` (VisualizerSettings, AudioContextType), `mockTracks`, `useAudioContextValue`, `AudioContext` (createContext, useAudio, AudioProvider). Re-export depuis `AudioContext.tsx`. 12 tests passent. Correction : `toggleMute` bascule `isMuted` (au lieu de play). |
| ~~`components/ui/virtualized-list.tsx`~~ | ~~295~~ | **Refactorisé 2026-02-05** : module `components/ui/virtualized-list/` avec `types` (VirtualizedListProps), `VirtualizedList`, `useInfiniteScroll`, `useScrollPosition`. Re-export depuis `virtualized-list.tsx` (import explicite depuis `./virtualized-list/index`). Stories : Default, SmallItems. 4 tests passent (mock useVirtualizer complété). |
| ~~`components/views/FileDetailsView.tsx`~~ | ~~292~~ | **Refactorisé 2026-02-05** : module `components/views/file-details-view/` avec `types` (FileDetailsViewProps, ActivityItem, VersionItem), `mockData` (MOCK_ACTIVITY, MOCK_VERSIONS, getMockFile), `useFileDetailsView`, Header, Preview, Metadata, Activity, Versions, Storage, `FileDetailsViewSkeleton`. Layout : `min-h-[400px]``min-h-layout-page-sm`, badge LATEST `text-[10px]``text-xs`. Stories : Default, Loading (Skeleton). Re-export depuis `FileDetailsView.tsx`. |
| ~~`components/seller/CreateProductView.tsx`~~ | ~~292~~ | **Refactorisé 2026-02-05** : module `components/seller/create-product-view/` avec `types` (LicenseConfig), `useCreateProductView`, Header, CoverCard, FilesCard, DetailsCard, PricingCard, `CreateProductViewSkeleton`. Textarea `min-h-[120px]``min-h-24`. MSW : POST `/api/v1/marketplace/products`. Stories : Default, Loading (Skeleton). Re-export depuis `CreateProductView.tsx`. |
| ~~`features/chat/components/ChatInterface.tsx`~~ | ~~291~~ | **Refactorisé 2026-02-05** : module `features/chat/components/chat-interface/` avec `types` (ChatInterfaceProps), `useChatInterface` (wsService, loadMessages, loadChatStats, formatTimestamp), Header, Messages, Input, `ChatInterfaceSkeleton`. Stories : Default, ProductionRoom, Loading (Skeleton). Decorator `h-[600px]``min-h-layout-page`. Re-export depuis `ChatInterface.tsx`. |
| ~~`components/settings/account/AccountSettings.tsx`~~ | ~~289~~ | **Refactorisé 2026-02-05** : module `components/settings/account/account-settings/` avec `types` (AccountSettingsUserMock, AccountSettingsToggles), `useAccountSettingsPage` (view, modals, user, toggles, theme), IdentityCard, PreferencesCard, NotificationsCard, PrivacyCard, DangerCard, `AccountSettingsSkeleton`. Privacy labels `text-[10px]``text-xs`. Stories : Default, Loading (Skeleton). Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `AccountSettings.tsx`. |
| ~~`components/admin/AdminDashboardView.tsx`~~ | ~~289~~ | **Refactorisé 2026-02-05** : module `components/admin/admin-dashboard-view/` avec `types` (DashboardStats, UploadItem, AuditLogItem, StatCardProps), `useAdminDashboardView`, Header, StatCard, TrafficCard, ProtocolsCard, NodeHealthCard, Tabs (Moderation/Signals/Logs), `AdminDashboardSkeleton`. Layout `max-w-[1600px]``max-w-layout-content`, `text-[10px]``text-xs`, `gap-[2px]``gap-0.5`. Stories : Default, Loading (Skeleton). Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `AdminDashboardView.tsx`. |
| ~~`components/views/CheckoutView.tsx`~~ | ~~288~~ | **Refactorisé 2026-02-05** : module `components/views/checkout-view/` avec `types` (CheckoutViewProps, CheckoutFormState), `useCheckoutView`, `CheckoutViewHeader`, `CheckoutViewBillingCard`, `CheckoutViewPaymentCard`, `CheckoutViewOrderSummary`, `CheckoutViewSkeleton`. Stories : Default, Loading (Skeleton), Processing, Success. Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `CheckoutView.tsx`. |
| ~~`components/views/LiveView.tsx`~~ | ~~270~~ | **Refactorisé 2026-02-05** : module `components/views/live-view/` avec `types` (LiveViewProps, LiveViewChatMessage), `mockData` (FEATURED_STREAM, CHAT_MESSAGES), `useLiveView`, `LiveViewPlayer`, `LiveViewStreamInfo`, `LiveViewRecommended`, `LiveViewChat`, `LiveViewSkeleton`. Layout `h-[calc(100vh-120px)]``min-h-layout-main` ; `text-[10px]``text-xs`. Stories : Default, Loading (Skeleton). Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `LiveView.tsx`. |
| ~~`components/views/AnalyticsView.tsx`~~ | ~~260~~ | **Refactorisé 2026-02-05** : module `components/views/analytics-view/` avec `types` (AnalyticsViewProps, DateRangeKey, GlobalStats, TopTrackRow, TrafficSource, DeviceStats, ChartHoverData), `useAnalyticsView`, `AnalyticsViewHeader`, `AnalyticsViewKpiGrid`, `AnalyticsViewChart`, `AnalyticsViewOrigins`, `AnalyticsViewPlatforms`, `AnalyticsViewTopTracks`, `AnalyticsViewSkeleton`. Données via `analyticsService`. Conformité : `text-[10px]``text-xs`, `tracking-[0.2em]``tracking-wide`. Stories : Default, Loading (Skeleton). Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `AnalyticsView.tsx`. |
| ~~`components/views/MarketplaceView.tsx`~~ | ~~196~~ | **Refactorisé 2026-02-05** : module `components/views/marketplace-view/` avec `types` (MarketplaceViewProps, MarketplaceCategory), `useMarketplaceView` (products, allProducts, filters, marketplaceService / fallback mock), `MarketplaceViewHeader`, `MarketplaceViewCategories`, `MarketplaceViewSidebar`, `MarketplaceViewGrid`, `MarketplaceViewSkeleton`. Layout `min-h-screen``min-h-layout-page`. Stories : Default, Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `MarketplaceView.tsx`. |
| ~~`components/views/SocialView.tsx`~~ | ~~189~~ | **Refactorisé 2026-02-05** : module `components/views/social-view/` avec `types` (SocialViewProps, SocialTabKey), `useSocialView` (feedTracks via trackService.list, activeTab, playTrack), `SocialViewSidebar`, `SocialViewFeed`, `SocialViewFeedItem`, `SocialViewTrending`, `SocialViewSkeleton`. Stories : Default, Loading (Skeleton). Decorator `min-h-screen``min-h-layout-page`. Re-export depuis `SocialView.tsx`. |
| ~~`components/views/PurchasesView.tsx`~~ | ~~175~~ | **Refactorisé 2026-02-05** : module `components/views/purchases-view/` avec `types` (PurchasesViewProps, Purchase), `usePurchasesView` (commerceService.getPurchases, search, refundOrderId, activeDownloadId, handleDownload), `PurchasesViewHeader`, `PurchasesViewItem`, `PurchasesViewList`, `PurchasesViewSkeleton`. RefundRequestModal dans lorchestrateur. Stories : Default, Empty (initialPurchases []), Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `PurchasesView.tsx`. |
| ~~`components/views/CartView.tsx`~~ | ~~176~~ | **Refactorisé 2026-02-05** : module `components/views/cart-view/` avec `types` (CartViewProps, CartDiscount), `useCartView` (useCartStore, promo, tax/finalTotal), `CartViewEmpty`, `CartViewHeader`, `CartViewSummary`, `CartViewSecure`, `CartViewSkeleton`. PromoCodeModal dans l'orchestrateur. Layout `min-h-[60vh]``min-h-layout-page-sm`. Stories : Default, Empty, Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `CartView.tsx`. |
| ~~`components/views/SettingsView.tsx`~~ | ~~167~~ | **Refactorisé 2026-02-05** : module `components/views/settings-view/` avec `types` (SettingsViewProps, SettingsTabId, SettingsTabConfig), `useSettingsView` (activeTab, setActiveTab, tabs avec icônes), `SettingsViewHeader`, `SettingsViewTabs`, `SettingsViewContent` (switch onglets), `SettingsViewSkeleton`. Layout `min-h-[500px]``min-h-layout-page`, placeholders audio/notifications `min-h-layout-page-sm`. Stories : Default (initialTab), Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `SettingsView.tsx`. |
| ~~`components/views/EducationView.tsx`~~ | ~~164~~ | **Refactorisé 2026-02-05** : module `components/views/education-view/` avec `types` (EducationViewProps, initialCourses), `useEducationView` (search, filters, courses, loading, filtered, educationService.getCatalog), `EducationViewHeader`, `EducationViewFilters`, `EducationViewEmpty`, `EducationViewSkeleton`. Layout `min-h-layout-page`. Stories : Default, Loading (Skeleton), Empty (initialCourses []). Decorator `min-h-layout-page`. Re-export depuis `EducationView.tsx`. |
| ~~`components/views/NotificationsView.tsx`~~ | ~~124~~ | **Refactorisé 2026-02-05** : module `components/views/notifications-view/` avec `types` (NotificationsViewProps, NotificationsFilterKey), `useNotificationsView` (socialService.getNotifications, filter, handleRead, handleMarkAllRead, handleClearAll), `NotificationsViewHeader`, `NotificationsViewFilters`, `NotificationsViewItem`, `NotificationsViewEmpty`, `NotificationsViewSkeleton`. Layout `min-h-layout-page`. Stories : Default, Loading (Skeleton), Empty (initialNotifications []). Decorator `min-h-layout-page`. Re-export depuis `NotificationsView.tsx`. |
| ~~`components/views/AdminView.tsx`~~ | ~~96~~ | **Refactorisé 2026-02-05** : module `components/views/admin-view/` avec `types` (AdminViewProps, AdminSubViewId, AdminTabConfig), `useAdminView` (activeTab, setActiveTab, tabs avec icônes), `AdminViewSidebar`, `AdminViewContent` (switch sous-vues), `AdminViewSkeleton`. Layout `h-[calc(100vh-140px)]``min-h-layout-main`, `text-[10px]``text-xs`. Stories : Default (currentSubView), Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `AdminView.tsx`. |
| ~~`components/views/AuthView.tsx`~~ | ~~77~~ | **Refactorisé 2026-02-05** : module `components/views/auth-view/` avec `types` (AuthViewProps, AuthStep), `useAuthView` (currentStep, show2FA, handleLoginSuccess, useAuth), `AuthViewContent` (LoginForm, RegisterForm, ForgotPasswordForm, TwoFactorVerify, placeholders), `AuthViewSkeleton`. Placeholders `min-h-layout-page-sm`. Stories : Default (LOGIN), Loading (Skeleton), RegisterStep. Decorator `min-h-layout-page`. Re-export depuis `AuthView.tsx`. |
| ~~`components/views/ChatView.tsx`~~ | ~~10~~ | **Refactorisé 2026-02-05** : module `components/views/chat-view/` avec `types` (ChatViewProps), `ChatView` (wrapper ChatInterface), `ChatViewSkeleton`. Layout `h-[calc(100vh-6rem)]``min-h-layout-main`. Stories : Default, Loading (Skeleton). Decorator `min-h-layout-page`. Re-export depuis `ChatView.tsx`. |
### Problèmes identifiés
| Criticité | Constat | Détail |
|-----------|--------|--------|
| **Amélioration** | Trop de responsabilités dans un seul fichier | Réduit : **CloudFileBrowser** est désormais un module (FileToolbar, FileTable, FileGrid, etc.) dans `features/studio/components/cloud-file-browser/`. |
| **Amélioration** | Logique métier + UI mélangées | **CommentThread**, **ProfileForm**, **Search** : logique (appels API, état) et rendu (JSX) dans le même composant ; pas de découpage net en hooks + sous-composants. |
| **Perfectionnement** | Réutilisabilité limitée | **GearView**, **ProfileView** : vues “pages” très spécifiques ; extraire des blocs (Header, Stats, List, Filters) permettrait des stories et des tests plus ciblés. |
### Recommandations
- **CloudFileBrowser** : déjà découpé dans `features/studio/components/cloud-file-browser/` (FileToolbar, FileTable, FileGrid, CloudFileBrowserSkeleton, etc.) ; ancien monolithe `components/studio/` supprimé.
- **CommentThread (fait 2026-02-05)** : logique extraite dans `useCommentReplies`, `useCommentActions` ; rendu délégué à `CommentThreadHeader`, `CommentThreadContent`, `CommentThreadActions`, `CommentReplyForm`, `CommentRepliesList` ; `CommentThreadSkeleton` pour létat Loading. Stories : Default, WithReplies, DeeplyNested, Edited, EmptyReplies, LoadingReplies, ReplyError. MSW : PUT `/api/v1/comments/:id` ajouté.
- **ProfileForm (fait 2026-02-05)** : module `features/user/components/profile-form/` avec `useProfileForm`, `ProfileCompletionCard`, `ProfileFormSkeleton`, schéma zod dédié. Stories : Default, Loading, Error, ProfileFormSkeleton. Re-export depuis `ProfileForm.tsx`.
- **ProfileView (fait 2026-02-05)** : module `components/views/profile-view/` avec `useProfileViewData` ; sous-composants `ProfileViewTrackCard`, `ProfileViewPlaylistCard`, `ProfileViewSidebar`, `ProfileViewOverview`, `ProfileViewTracksTab`, `ProfileViewPlaylistsTab`, `ProfileViewAboutTab`, `ProfileViewSkeleton`. Stories : Default, Loading, Error, ProfileViewSkeleton. Re-export depuis `ProfileView.tsx`.
- **Search (fait 2026-02-05)** : logique extraite dans `useSearchSuggestions` ; présentiel `SearchInput`, `SearchDropdown`, `SearchSkeleton` ; orchestrateur dans `Search.tsx`. Stories : Default, NoHistory, Loading, Empty, Error. Re-export depuis `components/search/Search`.
- **ChatSidebar (fait 2026-02-05)** : module `features/chat/components/chat-sidebar/` avec `useChatConversations`, `useConversationActions` ; sous-composants `ChatSidebarHeader`, `ChatSidebarEmpty`, `ChatSidebarSkeleton`, `ConversationItem`. Stories : Default, Empty, Error, ChatSidebarSkeleton. Re-export depuis `ChatSidebar.tsx`.
- **GearView (fait 2026-02-05)** : module `components/views/gear-view/` avec `useGearView` (filter, search, viewMode, itemsOverride, isLoading, error), `GearViewToolbar`, `GearViewSkeleton`. Stories : Default, Loading, Empty, Error, GearViewSkeleton. Re-export depuis `GearView.tsx`.
- **LazyComponent (fait 2026-02-05)** : module `components/ui/lazy-component/` avec `LazyErrorFallback`, `LazyErrorBoundary`, `createLazyComponent`, `lazyExports`. Stories : LazyErrorFallback (Default, WithRetry, NoError), LazyComponent (Default, Loading). Layout primitive `min-h-layout-page-sm` pour lerreur. Re-export depuis `LazyComponent.tsx`.
- **UploadModal (fait 2026-02-05)** : module `features/upload/components/upload-modal/` avec `useUploadModal`, sous-composants (Dropzone, FileDisplay, Progress, ErrorAlert, MetadataForm). Stories : Default, Open. Re-export depuis `UploadModal.tsx`.
- **file-upload (fait 2026-02-05)** : module `components/ui/file-upload/` avec `useFileUpload`, `FileUploadDropzone`, `FileUploadErrorList`, `FileUploadFileList`. Stories : Default, Empty, Error, Disabled, etc. Point dentrée `file-upload/index.ts`.
- **select (fait 2026-02-05)** : module `components/ui/select/` avec `useSelect`, `SelectTrigger`, `SelectDropdownContent`, `SelectOptionItem`. Stories : Default, Empty, Disabled, Grouped, MultiSelect. Point dentrée `select/index.ts`.
- **NotificationsPage (fait 2026-02-05)** : module `features/notifications/components/notifications-page/` avec `useNotificationsPage`, Header, Filters, Item, Empty, Error, Skeleton. Stories : Default, Loading, Error, Empty. MSW : GET notifications aligné avec notificationService.
- **SearchPage (fait 2026-02-05)** : module `features/search/components/search-page/` avec `useSearchPage`, Header, Discovery, Empty, Error, Results, Skeleton. Stories : Default, Loading, Empty, Error. MSW : GET /api/v1/search → SearchResults.
- **FileManagerView (fait 2026-02-05)** : module `components/views/file-manager-view/` avec `useFileManagerView`, Header, Toolbar, Table, Grid, Empty, Skeleton. Stories : Default, Loading, Empty.
- **RegisterPage (fait 2026-02-05)** : module `features/auth/components/register-page/` avec `useRegisterPage`, Form, VerificationNotice, Skeleton. Stories : Default, Loading, WithError.
- **MonitoringDashboard (fait 2026-02-05)** : module `components/monitoring/monitoring-dashboard/` avec `useMonitoringDashboard`, Content, Skeleton, état Error avec réessai. Stories : Default, Loading, Error.
- **PlaybackDashboard (fait 2026-02-05)** : module `features/streaming/components/playback-dashboard/` avec `usePlaybackDashboard`, StatsCard, TrendsCard, Charts, DetailedCard, Skeleton. Stories : Default, Loading, Error, Empty. MSW playback dashboard.
- **ShareLinkManager (fait 2026-02-05)** : module `components/share/share-link-manager/` avec `useShareLinkManager`, CreateForm, Item, Empty, Content, Skeleton. Stories : Default, Empty, Loading, Error.
- **date-picker (fait 2026-02-05)** : module `components/ui/date-picker/` avec `useDatePicker`, Trigger, Calendar. Stories : SingleDate, DateRange, Disabled.
- **avatar-upload (fait 2026-02-05)** : module `components/ui/avatar-upload/` avec `useAvatarUpload`, Dropzone, Actions, Skeleton. Stories : Default, WithExistingAvatar, Disabled, Large, Loading.
- **optimized-image (fait 2026-02-05)** : module `components/ui/optimized-image/` avec types, `generateImageSources`, `BlurPlaceholder`, `useImageFormatSupport`, `OptimizedImage`, `OptimizedImageSkeleton`, `useImagePreloader`, `ResponsiveImage`. Stories : Default, WithPlaceholder, ErrorState, Loading.
- **DataList (fait 2026-02-05)** : module `components/ui/data-list/` avec types, `DataListSkeleton`, `DataListEmpty`, `DataListError`, `DataList`. Stories : Default, Loading, Empty, Error, Skeleton.
- **AudioPlayer components/player (fait 2026-02-05)** : module `components/player/audio-player/` avec `useAudioPlayerEffects`, `AudioPlayerTrackInfo`, `AudioPlayerControls`, `AudioPlayerProgress`, `AudioPlayerVolume`, `AudioPlayerSkeleton`. Stories : Default, Skeleton.
- **TrackFilters (fait 2026-02-05)** : module `features/tracks/components/track-filters/` avec `useTrackFilters`, `TrackFiltersHeader`, `TrackFiltersSearch`, `TrackFiltersGrid`, `TrackFiltersClear`, `TrackFiltersSkeleton`. Stories : Default, Collapsible, Loading.
- **TrackSearchFilters (fait 2026-02-05)** : module `features/tracks/components/track-search-filters/` avec `useTrackSearchFilters`, `TrackSearchFiltersBasic`, `TrackSearchFiltersAdvanced`, `TrackSearchFiltersSkeleton`. Stories : Default, Applied, Loading.
- **SessionsPage (fait 2026-02-05)** : module `features/auth/components/sessions-page/` avec `useSessionsPage`, Header, ErrorBanner, RevokeAllButton, SessionItem, Content, Empty, Skeleton. Stories : Default, Loading, Empty, Error. MSW : GET/DELETE auth/sessions.
- **ProjectDetailView (fait 2026-02-05)** : module `components/studio/projects/project-detail-view/` avec `useProjectDetailView`, Header, Tabs, Overview, Files, Settings, Sidebar, Skeleton. Stories : Default, Loading, Empty.
- **PlaybackHeatmap (fait 2026-02-05)** : module `features/streaming/components/playback-heatmap/` avec `usePlaybackHeatmap`, Header, Stats, Grid, Skeleton, Error, Empty. Stories : Default, CustomSegmentSize, Loading, Empty, Error. MSW : GET heatmap.
- **ProductDetailView (fait 2026-02-05)** : module `components/marketplace/product-detail-view/` avec `useProductDetailView`, Header, Gallery, Info, Licenses, Description, Reviews, Similar, Skeleton. Stories : Default, Loading, Empty, WithReviews.
- **CourseLearningView (fait 2026-02-05)** : module `components/education/course-learning-view/` avec `useCourseLearningView`, Header, Player, Tabs, Sidebar, Skeleton. Layout `min-h-layout-main`. Stories : Default, Loading, Empty, Complete.
- **CourseDetailView (fait 2026-02-05)** : module `components/education/course-detail-view/` avec `useCourseDetailView`, Header, Tabs, Sidebar, Skeleton. Stories : Default, Loading, Empty, Enrolled.
- **LibraryManager (fait 2026-02-05)** : module `features/library/components/library-manager/` avec `useLibraryManager`, Header, Toolbar, Error, Empty, Content, Stats, Skeleton. Stories : Default, Loading, Empty, Error. MSW GET /tracks.
- **NotificationMenu (fait 2026-02-05)** : module `components/notifications/notification-menu/` avec `useNotificationMenu`, Trigger, Dropdown, List, Item, Skeleton. Stories : Default, Loading, Empty, Error, Skeleton.
- **PlaylistTrackList (fait 2026-02-05)** : module `features/playlists/components/playlist-track-list/` avec `usePlaylistTrackList`, Empty, SortableItem, Skeleton. Stories : Default, Loading, Empty, Reordering.
- **AddTrackToPlaylistModal (fait 2026-02-05)** : module `features/playlists/components/add-track-to-playlist-modal/` avec `useAddTrackToPlaylistModal`, Search, List, TrackRow, Footer, Skeleton. Stories : Default, Loading.
- **PlaylistBatchActions (fait 2026-02-05)** : module `features/playlists/components/playlist-batch-actions/` avec `usePlaylistBatchActions`, exportUtils, Bar, Buttons, DeleteDialog, Skeleton. Stories : Default, SingleSelection, Loading.
- **PlaylistSearch (fait 2026-02-05)** : module `features/playlists/components/playlist-search/` avec `usePlaylistSearch`, Bar, Filters, Results, Skeleton. Stories : Default, Loading, Empty, Error. MSW playlists/search.
- **CreatePlaylistDialog (fait 2026-02-05)** : module `features/playlists/components/create-playlist-dialog/` avec schema zod, `useCreatePlaylistDialog`, Form, Skeleton. Stories : Default, Loading.
- **SharePlaylistModal (fait 2026-02-05)** : module `features/playlists/components/share-playlist-modal/` avec `useSharePlaylistModal`, Content, Skeleton. Stories : Default, Loading, Error.
- **AddCollaboratorModal (fait 2026-02-05)** : module `features/playlists/components/add-collaborator-modal/` avec `useAddCollaboratorModal`, Form, Skeleton. Stories : Default, Loading, Error (MSW). ErrorDisplay pour validation et mutation avec retry.
- **UploadView (fait 2026-02-05)** : module `components/views/upload-view/` avec `useUploadView`, Stepper, Step1/2/3, Skeleton. Stories : Default, Loading, Empty, Error.
- **TwoFactorSetup (fait 2026-02-05)** : module `components/settings/security/two-factor-setup/` avec `useTwoFactorSetup`, Header, Step1/2/3, Skeleton. Stories : Default, Step1, Step2, Loading, Error (MSW).
- **TrackHistory (fait 2026-02-05)** : module `features/tracks/components/track-history/` avec `useTrackHistory`, Header, Empty, ItemRow, Pagination, Skeleton, trackHistoryUtils. Stories : Default, Loading, Empty, Error (MSW).
- **ProjectsManager (fait 2026-02-05)** : module `components/studio/projects-manager/` avec `useProjectsManager`, Header, FilterBar, Card, AddCard, Empty, Skeleton. Stories : Default, Loading, Empty.
- **CreateProjectModal (fait 2026-02-05)** : module `components/studio/projects/create-project-modal/` avec `useCreateProjectModal`, Header, Form, Footer, Skeleton. Stories : Default, Loading.
- **GoLiveView (fait 2026-02-05)** : module `components/studio/go-live-view/` avec `useGoLiveView`, Header, Preview, StreamInfo, EncoderSetup, QuickInstructions, MicLevel, Skeleton. Stories : Default, Loading.
- **ConnectivityView (fait 2026-02-05)** : module `components/studio/connectivity-view/` avec `useConnectivityView`, WebDAV, Webhooks, Skeleton. Stories : Default, Loading.
- **AIToolsView (fait 2026-02-05)** : module `components/studio/ai-tools-view/` avec `useAIToolsView`, ToolGrid, Workspace, Skeleton, AI_TOOLS. Stories : Default, Loading. Conformité : text-xs, min-h-layout-page-sm ; pas de ToastProvider en story.
- **CloudSettingsView (fait 2026-02-05)** : module `components/studio/cloud-settings-view/` avec `useCloudSettingsView`, Quota, Preferences, Skeleton. Stories : Default, Loading.
- **StudioView (fait 2026-02-05)** : module `components/views/studio-view/` avec `useStudioView`, Header, Sidebar, NavButton, Content, ProjectsSwitch, Skeleton. Stories : Default, Projects, Loading. Conformité : h-[calc(...)] → min-h-layout-main, w-[65%] → w-2/3.
- **PlaylistList (fait 2026-02-05)** : module `features/playlists/components/playlist-list/` avec `usePlaylistList`, `PlaylistListToolbar`, `PlaylistListEmpty`, `PlaylistListError`. Stories : Default, Grid, Empty (MSW), Loading (skeleton).
- **dialog (fait 2026-02-05)** : module `components/ui/dialog/` avec Dialog, Header, Body, Footer, Content, Description, Title, Trigger, DialogSkeleton. Stories : Default, Alert, Composition, Loading.
- **dropdown-menu (fait 2026-02-05)** : module `components/ui/dropdown-menu/` avec types, Trigger, Content, Item, CheckboxItem, RadioItem, Label, Separator, Shortcut, Placeholders. Dropdown base : open/defaultOpen. Re-export depuis `dropdown-menu.tsx`.
- **accordion (fait 2026-02-05)** : module `components/ui/accordion/` avec types, Accordion, AccordionItem, AccordionTrigger, AccordionContent. Stories : Default, Multiple. Re-export depuis `accordion.tsx`.
- **tabs (fait 2026-02-05)** : module `components/ui/tabs/` avec types, Tabs, TabsList, TabsTrigger, TabsContent. Stories : Default. Re-export depuis `tabs.tsx`.
- **tooltip (fait 2026-02-05)** : module `components/ui/tooltip/` avec useTooltip, TooltipContent, Tooltip. Stories : Default, Positions, ManualTrigger. Re-export depuis `tooltip.tsx`.
- **AccountSettings (fait 2026-02-05)** : module `features/settings/components/account-settings/` avec `useAccountSettings`, ErrorBanner, PasswordCard, ExportCard, DeleteCard, AccountSettingsSkeleton. Stories : Default, Loading.
- Les autres composants volumineux restants : appliquer le même principe pour améliorer la testabilité et la maintenabilité.
---
## 4. Fidélité de lillusion applicative (StorybookDecorator)
### Ce qui est en place
- **Providers centralisés** : `I18nextProvider`, `ThemeProvider`, `QueryClientProvider`, `ToastProvider`, `AudioProvider`, `AuthProvider`, `MemoryRouter`.
- **Router** : `parameters.router.initialEntries` pour les stories dépendant dune route.
- **Thème** : bascule light/dark via globals Storybook (backgrounds).
- **Toasts** : en mode Storybook, toasts loggés en console (pas daffichage intrusif).
### Problèmes identifiés
| Criticité | Constat | Détail |
|-----------|--------|--------|
| **Amélioration** | Pas de gestion des transitions | Aucun wrapper `prefers-reduced-motion` ni fourniture de context pour désactiver les animations en Storybook. Les transitions CSS (`--duration-*`) sont appliquées telles quelles ; pas de mode “réduit” pour les tests ou laccessibilité. |
| **Amélioration** | Feedback tactile non simulé | Pas de décorateur ou paramètre pour simuler états tactiles (active, press) ou pointer (hover) de façon déterministe. Utile pour valider les états “pressed” / “hover” de boutons et cartes. |
| **Perfectionnement** | Couleurs de fond en dur | Le décorateur utilise `#0a0a0a` et `#ffffff` en inline style au lieu des tokens (`var(--background)`). En cas dévolution du thème, le conteneur Storybook peut diverger de lapp. |
| **Perfectionnement** | Pas de “viewport” par défaut | Des viewports custom (mobile, tablet, desktop) existent ; le décorateur ne force pas de viewport par story. Pour un rendu type “app”, un conteneur largeur max (ex. 1440px) pourrait être optionnel. |
### Recommandations
- Ajouter un **paramètre** (ex. `parameters.motion: 'reduce'`) et un wrapper qui applique `prefers-reduced-motion: reduce` (media query ou class) pour tester le comportement sans animations.
- Utiliser **les tokens** pour le fond du conteneur : `background: 'var(--background)'` (et sassurer que les variables sont bien appliquées dans liframe).
- Optionnel : décorateur ou paramètre pour forcer un **état “interaction”** (hover/active) sur le premier élément focusable, pour valider le focus visible et les états actifs dans les stories.
---
## 5. Accessibilité (a11y)
### Ce qui est en place
- **ARIA / rôles** : utilisés dans une soixantaine de composants (table, select, modal, tabs, pagination, breadcrumbs, tooltip, checkbox, progress, alert, etc.).
- **Contrastes** : palette KŌDŌ en oklch avec séparation sémantique (primary, destructive, muted, etc.) ; fonds et textes prévus pour être lisibles.
- **Addon a11y** : présent dans Storybook ; config actuelle `a11y: { test: 'todo' }`.
- **Focus visible** : `button`, `input`, `checkbox`, `select`, `tabs` ont des styles `focus-visible:ring` ou équivalent.
### Problèmes identifiés
| Criticité | Constat | Détail |
|-----------|--------|--------|
| **Bloquant** | Tests a11y non actifs | Tant que `test: 'todo'`, aucune violation a11y ne fait échouer laudit ni le build. Risque de régressions (contraste, labels, rôles). |
| **Amélioration** | Contraste à vérifier sur cas réels | Les combinaisons `muted-foreground` sur `muted`, ou textes sur “glass” / dégradés, nont pas été vérifiées automatiquement. Un audit manuel ou des tests a11y ciblés (contrast, label) sont recommandés. |
| **Amélioration** | Zones cliquables non boutons | Cartes ou lignes entières cliquables sans `role="button"` ni `tabIndex={0}` ni gestion clavier (Enter/Space) — à vérifier dans les composants “card” et “list”. |
| **Perfectionnement** | Annonces live (toasts, chargement) | Pas de revue systématique des `aria-live`, `aria-busy`, `aria-atomic` pour les toasts et états de chargement. |
### Recommandations
- **Activer les tests a11y** dans Storybook : définir `a11y: { runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa'] } }` (ou équivalent) et intégrer le résultat à laudit (ou au moins au build Storybook) pour faire échouer en cas de violations.
- Vérifier les **cartes et listes cliquables** : soit `<button>` ou `div` avec `role="button"`, `tabIndex={0}`, et gestion `onKeyDown` (Enter/Space).
- Planifier un **audit contraste** (manuel ou outil) sur les écrans clés (login, player, sidebar, modales) et documenter les ratios pour les combinaisons utilisées.
---
## 6. Tableau de synthèse par criticité
| Criticité | Thème | Action prioritaire |
|-----------|--------|--------------------|
| **Bloquant** | a11y | Activer les tests a11y dans Storybook (retirer `test: 'todo'`, définir des règles WCAG et les faire échouer le job si besoin). |
| **Amélioration** | Design system | Réduire les valeurs arbitraires (h-[…], w-[…]) en les remplaçant par des tokens ou des utilitaires Tailwind cohérents. |
| **Amélioration** | États dinterface | Compléter les stories : Loading réaliste (Button), Empty/Error/Loading pour listes et cartes, états Disabled et si possible Hover/Active. |
| **Amélioration** | Composants dieux | Découper CloudFileBrowser, CommentThread, ProfileForm/ProfileView en sous-composants et hooks testables. |
| **Amélioration** | Illusion applicative | Utiliser les tokens pour le fond du décorateur ; ajouter support reduced-motion et optionnellement états hover/active. |
| **Amélioration** | a11y | Vérifier cartes/listes cliquables (rôle, clavier) ; audit contraste sur écrans clés. |
| **Perfectionnement** | Design system | Scale despacement/hauteurs documentée ; linter pour limiter les valeurs arbitraires. |
| **Perfectionnement** | États dinterface | Stories Hover/Active explicites ; revue focus visible sur tous les contrôles. |
| **Perfectionnement** | Composants | Extraire blocs réutilisables des vues “page” (GearView, ProfileView, Search). |
| **Perfectionnement** | a11y | Revue `aria-live` / `aria-busy` pour toasts et chargement. |
---
## 7. Prochaines étapes suggérées
1. **Court terme** : Activer a11y dans Storybook et corriger les violations bloquantes ; ajouter les stories Empty/Error (et Loading si pertinent) aux composants listes/cartes les plus utilisés.
2. **Moyen terme** : Découper 23 composants “dieux” (ex. CloudFileBrowser, CommentThread) et aligner les nouvelles stories sur les tokens (réduction des valeurs arbitraires).
3. **Long terme** : Documenter une grille de hauteurs/largeurs et une checklist “états dinterface” pour toute nouvelle story ; intégrer reduced-motion et feedback tactile dans le décorateur.
---
*Rapport généré dans le cadre de laudit frontend Veza — Storybook stabilisé, contrat dans `docs/STORYBOOK_CONTRACT.md`.*