veza/apps/web/dev_audit/frontend/08_technical_debt_frontend.md
senke 5f88c56113 fix: UI remediation Phase 1 (S0-S5) + Phase 2 Sprint 6 shadow system
Phase 1:
- S0: Fix open redirect (safeNavigate), delete AuthContext/legacy auth, encrypt API keys, gitignore .env files
- S1: Split client.ts god object into 5 modules, unify toast system, delete unused Sidebar
- S2: Add glass button variant, migrate 32 z-index to SUMI tokens, fix card dark mode
- S3: Skip nav link, aria-hidden on icons, focus-visible ring fixes, alt attrs, aria-live regions
- S4: React.memo on list items, fix key={index}, loading=lazy on images
- S5: Branded loading screen, page transitions respect reduced-motion, LikeButton micro-interaction, i18n sidebar/header

Phase 2 Sprint 6:
- Wire Tailwind shadow utilities to SUMI tokens in @theme block (fixes 50+ files)
- Define shadow-card/shadow-card-hover tokens
- Remove dark:shadow-none workarounds from card.tsx (SUMI handles per-theme shadows)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 10:13:44 +01:00

9.5 KiB

Phase H — Dette Technique Frontend


H1. Complexité excessive

Fichiers > 300 lignes (source, hors tests/generated)

Fichier Lignes Raison probable Split possible ? Complexité
services/api/client.ts 2 237 Client HTTP + validation + caching + retry + dedup + metrics Oui, 5 modules 🔴 Élevée
mocks/handlers.ts 1 716 MSW handlers pour toutes les routes Par feature 🟡 Linéaire
features/tracks/api/trackApi.ts 848 API tracks complète CRUD/Upload/Share/Analytics 🟠 Moyenne
utils/optimisticUpdates.ts 682 Optimistic updates multi-feature ⚠️ Difficilement 🟠 Moyenne
features/streaming/services/playbackAnalyticsService.ts 656 Analytics streaming ⚠️ Cohérent 🟡 Linéaire
features/playlists/hooks/usePlaylist.ts 631 Hook playlist (CRUD + collab + analytics) 3 hooks 🔴 Élevée
utils/apiErrorHandler.ts 578 Error parsing exhaustif ⚠️ Cohérent 🟡 Linéaire
features/streaming/hooks/usePlaybackRealtime.ts 496 WebSocket + state + analytics ⚠️ Justifié temps réel 🟠 Moyenne
services/api/auth.ts 493 Auth API (login, register, 2FA, OAuth) ⚠️ Cohérent 🟡 Linéaire
schemas/apiRequestSchemas.ts 476 Zod schemas Normal 🟢 Faible
schemas/apiSchemas.ts 468 Zod schemas Normal 🟢 Faible
features/tracks/services/trackService.ts 453 Service tracks ⚠️ Cohérent 🟡 Linéaire
features/playlists/services/playlistService.ts 448 Service playlists ⚠️ Cohérent 🟡 Linéaire
utils/sanitize.ts 429 Sanitization XSS Critique 🟢 Faible
features/chat/hooks/useChat.ts 360 Hook chat 2-3 hooks 🟠 Moyenne
features/auth/store/authStore.ts 330 Store auth ⚠️ Acceptable 🟡 Linéaire
features/dashboard/pages/DashboardPage.tsx 328 Page dashboard Extraire sections 🟡 Moyenne
features/tracks/components/TrackListRow.tsx 320 Ligne de track Sous-composants 🟡 Moyenne

Priorité de split :

  1. client.ts (2237L) → httpClient.ts, validators.ts, caching.ts, interceptors.ts, metrics.ts
  2. usePlaylist.ts (631L) → usePlaylistCrud.ts, usePlaylistCollaboration.ts, usePlaylistAnalytics.ts
  3. useChat.ts (360L) → useChatMessages.ts, useChatConnection.ts

H2. Props drilling

Grâce à l'utilisation de Zustand (7 stores) et React Query, le prop drilling est minimal. Aucune chaîne de props > 3 niveaux intermédiaires identifiée dans le code audité.

Pattern positif : Les stores Zustand sont accédés directement dans les composants enfants via useAuthStore(), useUIStore(), useCartStore(), etc. — pas besoin de passer les props à travers les composants intermédiaires.


H3. Hooks complexes

Custom hooks > 50 lignes

Hook Lignes Responsabilités Testé ?
features/playlists/hooks/usePlaylist.ts 631 CRUD + collaboration + analytics + permissions (595L de tests)
features/streaming/hooks/usePlaybackRealtime.ts 496 WebSocket + state + analytics + reconnection (490L de tests)
features/chat/hooks/useChat.ts 360 Messages + connection + typing + presence Non vérifié
features/tracks/hooks/useTrackList.ts 286 List + filters + sort + pagination + localStorage (761L de tests)
features/playlists/hooks/usePlaylistNotifications.ts 264 Notification handling + navigation Peu testé
features/player/hooks/usePlayer.ts 249 Playback control + queue + history Tests partiels
hooks/useRoutePreload.ts 239 Route prefetching + intersection observer Tests
features/library/hooks/useLibraryItems.ts 152 Library items + filters Non vérifié

Verdict : Les 3 plus gros hooks (usePlaylist, usePlaybackRealtime, useTrackList) sont bien testés. Les hooks de taille moyenne (useChat, usePlaylistNotifications) sont moins bien couverts.


H4. Duplication

Patterns CSS les plus répétés

Pattern Occurrences approximatives Action recommandée
flex items-center ~230 Normal (utility-first)
flex flex-col ~230 Normal
text-muted-foreground ~145 Normal (sémantique)
rounded-* ~230 Normal
w-full h-full ~90 Normal

Ces répétitions sont attendues avec Tailwind utility-first et ne constituent pas de la dette technique.

Composants dupliqués

Duplication Fichiers Impact
layout/Sidebar.tsx (294L) + ui/Sidebar.tsx (217L) 2 fichiers 🟠 Confusion
components/player/ (14 fichiers) + features/player/components/ (~20 fichiers) 34 fichiers 🟠 Migration incomplète
pages/auth/ + features/auth/pages/ 4+ fichiers 🟠 Legacy
context/AuthContext.tsx + features/auth/store/authStore.ts 2 fichiers 🔴 Deux sources de vérité
ui/modal.tsx + ui/dialog/ 2 systèmes 🟡 Redondance
ui/dropdown-menu.tsx + ui/dropdown-menu/ Fichier plat + dossier 🟡 Legacy wrapper

Logique métier dupliquée

  • Auth : authService.login() est appelé par authStore.login() ET AuthContext.login() — deux chemins d'exécution pour la même action.
  • Toast : toast() (react-hot-toast) et addToast() (custom) — deux APIs pour le même feedback.

H5. TypeScript

Statistiques

Métrique Nombre Zone
: any explicites (prod) ~82 Code source hors tests/generated
as any casts (prod) ~180 Code source hors tests/generated
as any dans generated/api.ts 145 Auto-généré — acceptable
@ts-ignore / @ts-expect-error 7 fichiers Minimal

Fichiers avec le plus de as any (source)

Fichier as any Justification
services/api/client.ts 48 Error handling, interceptors — type narrowing difficile
utils/typeGuards.ts 44 Type guards by design — acceptable
utils/toast.ts 11 Wrapper react-hot-toast
features/playlists/services/playlistService.ts 9 API response casting
utils/apiErrorHandler.ts 7 Error type narrowing
features/tracks/services/trackListService.ts 7 API response casting

Configuration TypeScript

  • Mode strict complet [tsconfig.json] : strict: true, noImplicitAny, strictNullChecks, strictFunctionTypes, noUnusedLocals, noUnusedParameters, noImplicitReturns, noFallthroughCasesInSwitch
  • noUncheckedIndexedAccess: true — option avancée (peu de projets l'activent)
  • @typescript-eslint/no-explicit-any: off — ESLint n'interdit pas any ⚠️

Verdict TS : Configuration stricte exemplaire mais no-explicit-any désactivé dans ESLint permet l'accumulation de any. Le comptage (~82 source + ~180 as any) est modéré pour un projet de 218K LOC.


H6. Code mort

Orphelins structurels identifiés

Fichier/Dossier Raison Impact
pages/auth/Login.tsx, pages/auth/Register.tsx Remplacés par features/auth/pages/ 🟡 Dead code
context/AuthContext.tsx Remplacé par features/auth/store/authStore.ts 🟠 Source de confusion
providers/AuthProvider.tsx Wrapper de AuthContext — non utilisé dans App.tsx 🟡 Dead code
components/views/*.tsx (fichiers plats) Wrappers vers les sous-dossiers refactorés 🟡 Indirection inutile
ui/dropdown-menu.tsx, ui/tabs.tsx, ui/accordion.tsx (plats) Re-exports vers les dossiers refactorés 🟢 Acceptable

Recommandation

Exécuter npx ts-prune ou npx madge --extensions ts,tsx --circular src/ pour un rapport complet d'orphelins et de dépendances circulaires.


H7. Dépendances inutilisées

Potentiellement inutilisées

Dépendance Status Raison
@dnd-kit/utilities ⚠️ À vérifier Peut être importé indirectement par @dnd-kit/sortable
swagger-ui-dist ⚠️ À vérifier swagger-ui-react pourrait l'importer en interne
rollup-plugin-visualizer OK Utilisé dans vite.config.ts (pas dans src/)

[DONNÉES INSUFFISANTES — nécessite npx depcheck pour un rapport exhaustif]


Priorisation de la dette

Priorité Élément Impact Effort Ratio
P0 Split client.ts (2237L) Maintenabilité, testabilité L Élevé
P0 Résoudre dualité AuthContext vs authStore Bugs auth, confusion M Très élevé
P1 Supprimer pages/auth/ legacy Clarté code S Élevé
P1 Unifier toast API (addToast vs toast) Cohérence DX M Élevé
P1 Split usePlaylist.ts (631L) Maintenabilité M Moyen
P1 Résoudre layout/Sidebar vs ui/Sidebar Clarté S Élevé
P2 Migrer z-[N] vers tokens SUMI Cohérence design M Moyen
P2 Ajouter React.memo sur les composants de liste Performance S Moyen
P2 Réduire as any dans client.ts (48 occ.) Type safety L Faible
P2 Nettoyer components/views/ wrappers legacy Clarté M Moyen

Score dette technique implicite : 6/10 — Dette structurelle significative (migration incomplète) mais codebase fonctionnelle avec de bons patterns.