# Progression de la remédiation — Stabilisation frontend **Référence** : [Plan de remédiation](.cursor/plans/frontend_stabilization_remediation_b9e1b51d.plan.md) **Dernière mise à jour** : 19 février 2026 (Phase v0.101 stabilisation) --- ## Phase v0.101 — Version stable (février 2026) ✅ Référence : [V0_101_RELEASE_SCOPE.md](V0_101_RELEASE_SCOPE.md), [Plan v0.101](.cursor/plans/plan_v0.101_stable_95772ea5.plan.md). ### Infra Docker - **ClamAV** : Ajouté à docker-compose (dev + prod), port 3310, `CLAMAV_REQUIRED=false` en dev. - **Chat/Stream servers** : Ajoutés à docker-compose dev avec veza-common (build context repo root). - **Full stack** : `make dev-full-docker` et procédure dans ONBOARDING.md. ### Build - **Stream server** : Docker build avec veza-common, migrations copiées. - **Chat server** : sqlx-data.json inclus, SQLX_OFFLINE, build context repo root. ### Streaming HLS - **HAProxy** : Route `/hls` vers stream server. - **Vite proxy** : `/ws`, `/stream`, `/hls` pour dev. - **HLS_BASE_URL** : Dérivation relative quand STREAM_URL est `/stream`. - **FEATURE_STATUS** : HLS_STREAMING opérationnel. ### Chat WebSocket - **Auth** : Token depuis query `?token=` ou cookie `access_token` (httpOnly). - **Frontend** : Token ajouté à l’URL WS quand disponible. ### Documentation - **ENV_CONFIG** : Variables ClamAV documentées. - **ONBOARDING** : Procédure full stack v0.101. --- ### Phase 2 — Stabilisation (Audit technique) ✅ - **P2.1 OAuth** : Vérifié — `GetUserByOAuthID` et `getOrCreateUser` en place. - **P2.2 Education** : Vérifié — aucune route education dans `internal/`. - **P2.3 npm** : Vérifié — `npm audit --audit-level=critical` = 0 vulnérabilités. - **P2.4 Bypass flags** : Vérifié — `validateNoBypassFlagsInProduction` rejette en prod. - **P2.5 E2E auth** : Corrigé — `VITE_API_URL=/api/v1` en CI, health check global-setup pour URLs relatives, timeouts et sélecteurs auth renforcés (commit 85267d2b). ### Phase 3 — Finalisation v0.101 (19 février 2026) ✅ - **E2E** : Officialisation CI-only — case cochée dans V0_101_RELEASE_SCOPE §5.2 ; README e2e mis à jour. - **E2E local** : Script `./scripts/run-e2e-local.sh` pour alignement CI ; validation E2E documentée en CI uniquement. - **Flows critiques** : Aucune régression (auth, upload, playlists, player, streaming) — validé via CI E2E. - **Tag v0.101** : Mis à jour sur commit final. ### Clôture v0.101 (19 février 2026) - **Validation** : validate-light et validate-full OK. - **Tag** : v0.101 poussé sur origin. - **CI** : Tous les jobs passent. --- ## Audit sécurité (AUDIT_TECHNIQUE_INTEGRAL_2026_02_16) Référence : [archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md](archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md). **Référence** : [Plan de remédiation sécurité](.cursor/plans/remédiation_sécurité_audit_veza_0de3fd35.plan.md) ### Lot 2 — Routes Education fantômes (A01) ✅ - **Constat** : Les packages `internal/api/education/` et `internal/core/education/` étaient des répertoires vides (aucun fichier Go, aucune route enregistrée). - **Action** : Suppression des répertoires vides. Aucune route Education n'était exposée ; le risque identifié dans l'audit ne s'appliquait pas au code actuel. ### Lot 6 — Bypass flags (A05) ✅ - **Constat** : `BYPASS_CONTENT_CREATOR_ROLE` et `CSRF_DISABLED` sont déjà rejetés en production via `validateNoBypassFlagsInProduction()`. - **Vérification** : `NewConfig()` appelle `ValidateForEnvironment()` qui invoque `validateNoBypassFlagsInProduction(c.Env)` au démarrage. Aucun changement nécessaire. ### Lot 8 — Vulnérabilités npm (A06) ✅ - **Action** : Suppression de `@lhci/cli`, `newman`, `pa11y-ci` (devDependencies avec vulnérabilités, utilisées uniquement par Makefile.old obsolète). - **Scripts** : `qa:postman`, `qa:lh`, `qa:a11y` redirigés vers message explicatif. - **Résultat** : 25 vulnérabilités → 0 (npm audit fix pour lodash). ### Lot 9 — 2FA login flow (A07) ✅ - **Vérification** : Flow correct — Login → requires_2fa → TwoFactorVerify → onSuccess(code) → complete2FALogin → POST /auth/login/2fa. - **Tests** : E2E existant dans `auth.spec.ts` (« should complete login with 2FA code ») avec E2E_2FA_CODE. Aucune correction nécessaire. ### Lot 10 — OAuth user lookup (A07) ✅ - **Vérification** : `GetUserByOAuthID(oauthID, provider)` déjà implémenté dans `database.go` (lignes 557-576). Utilise `federated_identities` avec `provider` et `provider_id`. `OAuthService.getOrCreateUser` appelle ce lookup en priorité (ligne 403). Aucune correction nécessaire. ### Lot 11 — Download tracks public (A04) ✅ - **Action** : Vérification des droits avant téléchargement pour les tracks payants. Nouveau service `TrackDownloadLicenseChecker` (`internal/services/track_download_license.go`) qui vérifie si le track est vendu comme produit et si l'utilisateur a une licence valide. Injection dans `TrackHandler.DownloadTrack` — si track vendu et utilisateur non propriétaire, 403 sans licence. ### Lot 12 — Alignement Go version (CI) ✅ - **Action** : `go-version` dans `.github/workflows/ci.yml` aligné sur `1.24` pour correspondre à `go.mod`. ### Lot 13 — .unwrap() / .expect() critiques en Rust (Stabilité) ✅ - **Action** : Remplacement des unwrap critiques dans `veza-stream-server/src/utils/mod.rs` — `validate_signature` et `generate_signature`. `duration_since(UNIX_EPOCH)` gère maintenant l'erreur (retourne false). `generate_signature` retourne `Option` au lieu de paniquer sur HMAC invalide. ~80+ unwraps restants (tests, regex statiques) — risque accepté pour l'instant. --- ## Vulnérabilités npm (A06 — Phase 1) ✅ Référence : [archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md](archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md) section A06. ### Correctifs appliqués - **npm audit fix** : brace-expansion, diff, undici corrigés automatiquement. - **React Router XSS (GHSA-2w69-qvjg-hvjx)** : `react-router-dom` mis à jour vers ^6.30.3 (@remix-run/router 1.23.2). - **Axios DoS (GHSA-43fc-jf86-j433)** : override `axios >= 1.13.5` dans `package.json` racine. - **class-variance-authority** : réintégré (dépendance manquante pour button/card). - **CI** : `npm audit --audit-level=high` exécuté depuis la racine du monorepo. ### Vulnérabilités restantes (devDependencies uniquement) 25 vulnérabilités dans @lhci/cli, newman, pa11y-ci (cookie, jose, lodash, node-forge, qs, semver, tar-fs, tmp, ws). **Risque accepté** : ces packages ne sont pas inclus dans le build de production. Correction via `npm audit fix --force` entraînerait des breaking changes (downgrade @lhci/cli, newman, pa11y-ci). --- ## Rate limiting (A04) ✅ Référence : [archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md](archive/AUDIT_TECHNIQUE_INTEGRAL_2026_02_16.md) — Points de rupture (ligne 170), A04 (ligne 232). ### Correctifs appliqués - **Rate limiting toujours actif** : suppression de la condition `Env != EnvDevelopment` pour le rate limit global et register. - **Limites assouplies en dev** : `getDefaultRateLimitLimit(env)` — 1000 req/min en dev/test, 200 en staging/prod. - **Register assoupli en dev** : `getDefaultRegisterAttempts(env)` — 20 inscriptions/heure en dev/test, 3 en staging/prod. - **Documentation** : README mis à jour avec tableau des limites par environnement. --- ## Phase 1 — Backend solide ✅ ### 1.1 Sécurité backend ✅ - **.gitignore** : Renforcement des patterns pour `.env`, `.env.*`, `**/.env`, `**/.env.local`, `veza-*/.env`, `apps/web/.env.local` (ne jamais committer de secrets). - **Chat server** : Dans `veza-chat-server/src/jwt_manager.rs`, `validate_access_token` vérifie désormais en base que l’utilisateur existe (si `db_pool` disponible) ; pas de fallback « user » si absent en DB — connexion refusée. - **Backend Go** : Le handler de refresh token vérifie déjà l’existence de l’utilisateur en DB (voir `internal/core/auth/service.go` RefreshToken). - **Pagination** : Contrôle strict `page >= 1` et `1 <= limit <= 100` avec retour **400** et message clair dans : - `internal/handlers/playlist_handler.go` (GetPlaylists), - `internal/handlers/profile_handler.go` (ListUsers), - `internal/core/track/handler.go` (ListTracks). ### 1.2 API et contrats ✅ - **Healthcheck** : Les Dockerfiles (Dockerfile, Dockerfile.production) utilisent déjà `http://localhost:8080/api/v1/health`. - **go-clamd** : Documenté dans `veza-backend-api/docs/CLAMAV_SETUP.md` (limitation : lib abandonnée ; désactivation via `ENABLE_CLAMAV=false` = pas de scan). - **Search** : Contrat documenté dans `veza-backend-api/docs/API_DOCUMENTATION.md` — recherche par ressource (`/api/v1/tracks/search`, `/api/v1/playlists/search`, `/api/v1/users/search`) ; pas d’endpoint unifié `GET /api/v1/search`. - **Endpoints marketplace / social** : Routes existantes (wishlist, panier, groups) ; pas de 501 ajouté. ### 1.3 Services Rust ✅ - **Redis** : Versions alignées (redis 0.32) dans `veza-chat-server` et `veza-stream-server` (Cargo.toml). ### 1.4 Infra et CD ✅ - **Docker-compose** : Mots de passe en dur remplacés par variables d’environnement (`POSTGRES_PASSWORD`, `RABBITMQ_DEFAULT_PASS`, etc.) avec valeurs par défaut pour le dev dans `docker-compose.yml`. - **CD** : Commentaire ajouté dans `.github/workflows/cd.yml` : pour pousser vers un registry, configurer les secrets `DOCKER_REGISTRY`, `DOCKER_REGISTRY_USERNAME`, `DOCKER_REGISTRY_PASSWORD`. --- ## Phase 2 — Frontend : bugs et comportements critiques ### 2.1 Auth et 2FA ✅ - **2FA login** : Implémenté. Backend : `POST /api/v1/auth/login/2fa` (body : `email`, `password`, `code`, `remember_me`) ; frontend : `completeLogin2FA()` dans `apps/web/src/services/api/auth.ts`, action `complete2FALogin` dans le store, flux dans LoginPage (affichage TwoFactorVerify quand `requires_2fa`, puis appel API et redirection). - **Typage auth** : Traité dans `apps/web/src/services/api/auth.ts` (réponse typée `LoginResponse`/`RegisterResponse`, options logout typées, `isAxiosError` pour les erreurs). - **Redirect si déjà authentifié** : LoginPage / RegisterPage utilisent `authStore` / `useUser` ; à vérifier en conditions réelles (pas de boucle login → redirect). ### 2.2 Memory leaks et logs ✅ - **setTimeout** : ChatInput, SocialViewFeedItem, PostCard ont déjà un cleanup (clearTimeout dans le return du `useEffect`). - **console.log** : GlobalSearchBar utilise `logger.debug` ; pas de suppression massive demandée pour l’instant. ### 2.3 Accessibilité ✅ - **ChatInput** : Le champ principal a déjà `aria-label="Type a message"`. - **Sidebar (layout)** : `components/layout/Sidebar.tsx` utilise déjà `FocusTrap` quand la sidebar est ouverte en mobile (`sidebarOpen && isMobile`). --- ## Phase 3 — Tests (en cours) ### 19 février 2026 — Lint v0.101 - **eslint** : 0 erreur atteint. Ignores (e2e, scripts, playwright-report, src/types/generated), globals ajoutés, react-hooks désactivé dans stories. Corrections empty catch, PlayerExpanded hooks order, TrackHistory.test no-redeclare. - **Vitest** : Suite complète **0 échec** (265 fichiers passés, 4 skippés ; 3230 tests passés, 87 skippés). Corrections appliquées : - **SettingsPage.test.tsx** : Load error → assertion sur `getByRole('alert')` + contenu flexible ; save error → reset de `settingsSchema.safeParse` dans `beforeEach` (évite que le test « validation errors » laisse `safeParse` en échec pour le test suivant) ; userEvent pour le clic Save. - **RegisterPage.test.tsx** : Terms → assertion sur « handleRegister non appelé » + optionnel message terms ; username « déjà pris » → `getAllByText` (plusieurs nœuds affichent le message) ; vérification notice → `findByText` + `act` autour du mock + rerender ; email dans la notice → texte partiel + `test@example.com` (texte split dans le DOM). - **ForgotPasswordForm.test.tsx** : « should disable form while loading » → attente après `waitFor` pour que la promesse mock se résolve avant teardown (évite « state update after unmount »). - **usePlaybackRealtime.test.ts** : 8 tests réactivés dans un second `describe` avec vrais timers (WebSocket lifecycle) ; plus de skip. - **Tests par groupes (machines limitées)** : Vitest configuré pour limiter RAM/CPU (`pool: 'threads'`, `maxThreads: 2`, `fileParallelism: false`). Scripts npm ajoutés pour exécuter les tests par groupe : `test:auth`, `test:tracks`, `test:playlists`, `test:player`, `test:streaming`, `test:settings-profile-chat`, `test:components-ui`, `test:components-other`, `test:services`, `test:hooks`, `test:misc`. Commande `test:groups` lance tous les groupes séquentiellement. Ordre recommandé pour le diagnostic : petits groupes d'abord (settings-profile-chat, streaming, hooks, misc) puis les plus gros. - **Providers / mocks** : Wrappers dans `src/test/` ; MSW dans `src/mocks/`. À aligner sur les contrats API si besoin. - **Storybook** : `npm run test:storybook` (script `scripts/audit-storybook.js`) nécessite Storybook servi sur **port 6007** ; lancer `npm run build-storybook` puis servir le dossier `storybook-static` sur 6007, puis `npm run test:storybook`. - **E2E** : Playwright (`npm run test:e2e`). Parcours critiques et fichiers listés dans `apps/web/e2e/README.md` (auth, smoke, playlists, search, profile, upload). Test search : `e2e/tests/search.spec.ts` (navigation `/search`, saisie requête, résultats ou état vide). Test 2FA : dans `auth.spec.ts` (skippé sauf si `E2E_2FA_CODE` et compte 2FA configurés). ## Phase 4 — Dette structurante ✅ - **Loading** : Composants centralisés en place — `LoadingState`, `LoadingSpinner`, `Skeleton`, `ButtonLoading` ; guide `apps/web/src/docs/LOADING_STATES_PATTERN.md` mis à jour avec section **LoadingState** et recommandation (full-page/block → LoadingState, list/card → Skeleton). - **Modal → Dialog** : `Modal` déprécié (S1.4) ; `Dialog` s’appuie dessus. Feature modals récents utilisent déjà `Dialog`. Préférer `Dialog` pour tout nouveau code. - **Track type** : Commentaire ajouté dans `apps/web/src/features/tracks/types.ts` — source of truth pour Track = `features/player/types` ; champs upload/backend = `features/tracks/types/track.ts`. - **Interceptors** : Documenté en en-tête dans `interceptors.ts` ; pas de découpage supplémentaire pour l’instant. ## Phase 5 — Features fantômes et cohérence ✅ - **Coming Soon** : Routes documentées dans `apps/web/docs/FEATURE_STATUS.md` — `/gear`, `/live`, `/education`, `/queue`, `/developer` (placeholder `ComingSoon` dans `routeConfig.tsx`). - **Feature flags** : Référence dans `FEATURE_STATUS.md` vers `src/config/features.ts` et `VITE_FEATURE_*` ; liste des flags (TWO_FACTOR_AUTH, PLAYLIST_*, HLS_STREAMING, ROLE_MANAGEMENT, NOTIFICATIONS). - **Marketplace / groups / search** : Mention dans `FEATURE_STATUS.md` (routes marketplace, search par ressource, groups dans Social). - **Typo** : `useLibraryManager.ts` — message « coming soon available » corrigé en « coming soon — available in the next release ». ## Phase 6 — Maturité ✅ - **TypeScript** : `npx tsc --noEmit` exécuté — 0 erreur. - **Docs** : `FEATURE_STATUS.md` créé (Coming Soon + feature flags + marketplace/search) ; `LOADING_STATES_PATTERN.md` enrichi ; `REMEDIATION_PROGRESS.md` à jour. - **UX** : Checklist finale rappelée ci-dessous (skip link, aria-label, focus trap, pas de console.log en prod). --- ## Checklist de validation finale (rappel) - **Validation légère (machine limitée)** : `./scripts/validate-light.sh` — évite `go test ./...` et Playwright qui peuvent saturer la RAM. Lance : go build, tsc, npm build, tests auth/hooks/services/misc, cargo build. - `npx vitest run` : 0 échec (ou < 5 % skippés avec ticket). Sur machine limitée en RAM/CPU : utiliser `npm run test:groups` ou les scripts par groupe (`test:auth`, `test:tracks`, etc.) pour éviter la saturation des ressources. - `npm run build` : succès sans warning bloquant. - `npx tsc --noEmit` : 0 erreur. - `npm run test:storybook` : 0 erreur. **Procédure de validation Storybook sur 6007** : 1. `cd apps/web && npm run build-storybook` 2. Démarrer le serveur sur le port **6007** : `node scripts/serve-storybook-static.cjs` (ou `npx serve storybook-static -l 6007`) et le laisser tourner 3. Dans un autre terminal : `npm run test:storybook` (le script [scripts/audit-storybook.js](apps/web/scripts/audit-storybook.js) cible `http://localhost:6007` et ne démarre pas le serveur). Option : `npm run test:storybook:playwright` démarre automatiquement le serveur via [playwright.config.storybook.ts](apps/web/playwright.config.storybook.ts). - Aucun `console.log` / debug en prod. - Skip link + aria-label ChatInput + focus trap Sidebar en place. - 2FA login : backend à compléter puis frontend à brancher.