veza/AUDIT_TESTS_ET_COUVERTURE_2025_02.md
senke 8a0f008345 chore: playwright workflow, docs, rapports audit, visual-tests, tmt unit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 22:19:34 +01:00

429 lines
22 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 DES TESTS ET DE LA COUVERTURE — VEZA
**Date** : 2025-02-10
**Mandat** : Comité d'architecture — décision sur la fiabilité à moyen terme et la valeur de la base de tests
**Périmètre** : Intégralité du dépôt (monorepo)
**Ton** : Sans complaisance. Faits observables > interprétations.
---
## 0. SYNTHÈSE EXÉCUTIVE (CTO)
### Verdict global
**La base de tests de Veza n'est pas un actif fiable.** Elle ressemble à un dispositif de sécurité (Vitest, Playwright, Jest, Storybook, MSW, 261 tests Go, 288+ tests frontend) mais, en pratique :
- **Les tests unitaires frontend bloquent désormais le build** — le `|| true` a été supprimé (`.github/workflows/ci.yml:148`).
- **Le backend contient 445 échecs documentés** (TEST_FAILS.md), dont 23 P0, 176 tests skippés, 6 panics, 3 erreurs de compilation.
- **Les tests critiques d'authentification (auth middleware, RBAC)** échouent en série (mock expectations non satisfaites).
- **Les workflows frontend-ci et backend-ci pointent vers des chemins inexistants** (`apps/web-frontend`, `apps/backend-api`).
- **La couverture mesurée (seuils 80%) n'est pas vérifiée en CI** — aucune étape n'exige le respect des seuils.
En résumé : **une couverture élevée pourrait masquer une faible résilience.** La CI frontend protège désormais le main (tests bloquants). Le backend reste fragilisé par les échecs documentés et les tests d'intégration en quarantaine.
### Indicateurs clés
| Indicateur | État | Commentaire |
|------------|------|-------------|
| Tests unitaires bloquants | ✅ Oui | `npm run test -- --run` — sans `\|\| true` |
| Tests Go exécutables en CI | ⚠️ Partiel | Seulement `handlers` et `services` avec `-short` |
| Tests E2E en CI | ⚠️ Incertain | playwright.yml sans `working-directory: apps/web` |
| Couverture vérifiée | ❌ Non | Pas de step qui valide les seuils |
| Tests auth / RBAC | ❌ Échouent | Mocks fragiles |
| Tests d'intégration | 🟡 Quarantaine | Beaucoup skippés ou manuels |
### Recommandation stratégique
**Court terme (12 semaines)** : Corriger les chemins des workflows frontend-ci/backend-ci, rendre les tests Go exécutables (exclure les packages qui paniquent), et corriger l'erreur de compilation `playlist_duplicate_transaction_test.go`.
**Moyen terme (13 mois)** : Réparer les tests auth/RBAC, réintégrer les tests d'intégration critiques, et ajouter une étape de validation des seuils de couverture.
**Long terme** : Restructurer la pyramide de tests, éliminer la dette de mocks fragiles, et aligner l'architecture sur la testabilité.
---
## 1. PÉRIMÈTRE D'ANALYSE
### 1.1 Langages et frameworks
| Composant | Langage | Framework | Outil de test |
|-----------|---------|-----------|---------------|
| **Frontend** | TypeScript | React 18, Vite 7, TanStack Query, Zustand | Vitest, Playwright, MSW |
| **Backend API** | Go | Echo/Gin (serveur HTTP) | `go test` |
| **Chat Server** | Rust | Actix/Axum | `cargo test` |
| **Stream Server** | Rust | idem | `cargo test` |
| **Shared** | Rust | veza-common | `cargo test` |
### 1.2 Architecture
- **Monorepo** : `apps/web`, `veza-backend-api`, `veza-chat-server`, `veza-stream-server`, `veza-common`, `packages/`, `fixtures/`
- **Front** : SPA React, feature-based, ~2500+ fichiers TS/TSX
- **Back** : API REST Go, services, handlers, middleware, migrations SQL
- **Rust** : Services temps réel (chat, streaming)
### 1.3 Ce qui est testé vs non testé
| Catégorie | État | Fichiers / Indices |
|-----------|------|--------------------|
| **Testé** | Composants UI, hooks, utils, services frontend, handlers/services Go | ~288 fichiers `.test.ts(x)`, ~261 `*_test.go`, E2E Playwright |
| **Implicitement non testable** | Client API monolithique (2238 lignes), main.tsx (278 lignes), correctifs CSS globaux | `client.ts`, `main.tsx`, `fix-*.css` |
| **Non testé par choix** | Cmd packages Go (migrate, generate-config-docs, etc.) | `t.Skip()` dans packages |
| **Non testé par négligence** | Zones critiques : auth dual (Context + Store), RBAC, permissions, webhooks, marché | Peu de tests sur `authStore` vs `AuthContext`, `webhookService` |
---
## 2. CARTOGRAPHIE DES TESTS EXISTANTS
### 2.1 Typologie
#### Tests unitaires purs
| Composant | Nombre approx. | Répartition | Ratio code critique |
|-----------|----------------|-------------|---------------------|
| **Frontend** | ~250+ | `utils/`, `hooks/`, `components/ui/`, `features/auth/`, `features/playlists/` | Bon sur utils, hooks, auth. Faible sur services API, stores |
| **Backend** | ~150+ | `internal/config/`, `internal/response/`, `internal/validators/`, nombreux handlers | Inégale. Config bien couverte. Handlers/services partiellement |
#### Tests unitaires avec mocks lourds
| Composant | Exemples | Problème |
|-----------|----------|----------|
| **Frontend** | `LoginForm.test.tsx`, `auth.integration.test.tsx` | Mocks de `authStore`, `authService`, `useAuth`, `useLogin`, etc. — 10+ mocks par fichier |
| **Backend** | `auth_middleware_test.go`, `rbac_auth_middleware_test.go` | Mocks `ValidateSession`, `HasRole`, `HasPermission`**échouent** (`0 out of 1 expectation(s) were met`) |
#### Tests d'intégration
| Composant | Fichiers | État |
|-----------|----------|------|
| **Frontend** | `auth.integration.test.tsx`, `playlist.integration.test.tsx`, `collaboration.integration.test.tsx`, `trackUpload.integration.test.tsx` | Présents mais dépendent de mocks MSW |
| **Backend** | `tests/integration/*.go` | Quarantaine. `api_health_test.go` corrigé. `upload_async_polling_test.go` partiellement. `playlist_duplicate_transaction_test.go`**erreur de compilation** (ligne 80) |
#### Tests contractuels
| Composant | Fichier | État |
|-----------|---------|------|
| **Backend** | `tests/contract/api_contract_test.go` | Présent. Non exécuté en CI standard (nécessite `-tags integration`) |
#### Tests end-to-end
| Composant | Fichiers | État |
|-----------|----------|------|
| **Frontend** | `e2e/tests/*.spec.ts` (auth, smoke, playlists, profile, upload, mobile, cross-browser, ui-audit, visual) | Playwright. `globalSetup` requiert API disponible. `workers: 1` (rate limiting). |
| **Tools** | `tools/tests/e2e/specs/*.spec.ts` | Auth, chat, docs, files, profile, stream |
| **Desktop** | `veza-desktop/tests/e2e/*.spec.ts` | Transcoding, library, playlists, settings |
#### Tests de non-régression
| Type | Fichiers | État |
|------|----------|------|
| **Visuels** | `e2e/tests/visual/*.spec.ts`, `visual-regression.spec.ts` | Playwright snapshots. Baselines dans `__snapshots__/` |
| **Storybook** | `scripts/audit-storybook.js`, `test:storybook:playwright` | Audit console/network errors. Workflow séparé |
#### Tests de snapshot
| Composant | Usage | État |
|-----------|-------|------|
| **Frontend** | Vitest snapshots — peu utilisés explicitement | Snapshot tests non dominants |
| **E2E** | Playwright `toHaveScreenshot()` | Utilisé pour visual regression |
### 2.2 Localisation et structure
#### Organisation des dossiers
```
# Frontend
apps/web/src/
├── __tests__/ # Tests transversaux (accessibility, contrast)
├── test/ # setup.ts, test-utils, setup.test.tsx
├── mocks/ # handlers.ts (MSW), test-setup.ts
├── features/*/__tests__/ # Intégration par feature
├── **/*.test.ts(x) # Colocalisés avec le code
└── e2e/ # Playwright (global-setup, tests, utils)
# Backend
veza-backend-api/
├── internal/**/*_test.go # Colocalisés
├── tests/ # integration, contract, security, transactions, etc.
└── docs/ # TEST_FAILS.md, QUARANTINE.md
```
#### Cohérence des conventions
- **Frontend** : `*.test.tsx` ou `*.test.ts` à côté du fichier. Cohérent.
- **Backend** : `*_test.go` standard Go. Cohérent.
- **E2E** : `*.spec.ts` dans `e2e/tests/`. Cohérent.
#### Signes problématiques
| Signe | Fichier / Indice |
|-------|-------------------|
| **Tests orphelins** | `jest.config.js` présent alors que `package.json` utilise `vitest` — configuration dupliquée |
| **Tests redondants** | `PlaylistErrorBoundary.test.tsx` utilise `jest.spyOn` alors que le projet est sur Vitest (`vi` attendu) |
| **Tests trop larges** | `auth.integration.test.tsx` — 600+ lignes, mocks massifs |
| **Tests trop spécifiques** | Certains tests UI vérifient des détails d'implémentation (classes CSS, structure DOM) |
---
## 3. QUALITÉ INTRINSÈQUE DES TESTS
### 3.1 Lisibilité
| Critère | Évaluation | Exemples |
|---------|------------|----------|
| **Clarté de l'intention** | Inégale | `LoginForm.test.tsx` : intentions claires. `auth.integration.test.tsx` : nécessite de lire l'implémentation pour comprendre les mocks |
| **Lisibilité des données** | Correcte | Factories, fixtures dans `fixtures/`. Parfois données inline |
| **Explicitation des cas limites** | Partielle | `serviceErrorHandler.test.ts`, `apiErrorHandler.test.ts` couvrent erreurs. Beaucoup de tests ne couvrent que le chemin heureux |
### 3.2 Robustesse
| Problème | Indice |
|----------|--------|
| **Dépendance à l'ordre** | Vitest exécute en parallèle par défaut. Pas de dépendance explicite à l'ordre |
| **Dépendance à l'horloge** | `MockWebSocket` utilise `setTimeout(100)` — délai fixe. Risque de flakiness si timeout trop court |
| **Dépendance au réseau** | E2E `globalSetup` requiert API. Sans API, les tests E2E échouent |
| **Dépendance au système de fichiers** | Handlers MSW, pas de dépendance directe |
| **Flakiness** | Backend : 14 race conditions (logging), 12 timeouts. Tests middleware auth : couplage fort aux mocks |
### 3.3 Couplage
| Problème | Impact |
|----------|--------|
| **Mocks auth** | Toute refactorisation de l'auth (Context vs Store) casse les tests |
| **Structure DOM** | `screen.getByText(/resend verification email/i)` — couplé au libellé. Changement de traduction = échec |
| **Mock expectations** | Backend : `FAIL: 0 out of 1 expectation(s) were met` — mocks trop stricts, implémentation a changé |
---
## 4. ANALYSE DE LA COUVERTURE
### 4.1 Données brutes
| Composant | Outil | Seuils configurés | Vérification en CI |
|-----------|-------|-------------------|--------------------|
| **Frontend** | Vitest (v8) | branches: 80, functions: 80, lines: 80, statements: 80 | ⚠️ Non vérifié (pas de step `--coverage` en CI) |
| **Frontend** | Jest (legacy) | Idem | Jest non utilisé (Vitest actif) |
| **Backend** | `go test -coverprofile` | — | ✅ Workflow `test-coverage.yml` (séparé, artifacts) |
**Chiffre global** : Non mesuré de manière fiable en CI. Les seuils Vitest sont définis mais aucune étape CI n'exécute `--coverage` ni ne valide les seuils.
### 4.2 Illusions de couverture
| Illusion | Indice |
|----------|--------|
| **Code couvert mais jamais asserté** | Tests qui render sans `expect` sur le comportement. Risque de tests "passants" qui ne valident rien |
| **Chemins heureux uniquement** | Beaucoup de tests ne mockent que le succès. `handleServiceError`, `apiErrorHandler` font exception |
| **Branches d'erreur non exercées** | `client.ts` (2238 lignes) : interceptors, retry, refresh, offline queue — peu de tests directs |
| **Couverture élevée ≠ résilience** | Seuils 80% pourraient être atteints sur des fichiers peu critiques (utils) tout en laissant le cœur métier (auth, RBAC, payments) sous-testé |
---
## 5. ANALYSE PAR DOMAINE MÉTIER
### 5.1 Logique métier à fort risque
| Domaine | Niveau de couverture | Type de tests | Faille potentielle |
|---------|----------------------|---------------|---------------------|
| **Auth / Sessions** | Moyen (front) ; Échec (back) | Unitaires avec mocks ; Middleware Go | Backend : tests auth middleware échouent. Double source auth (Context + Store) non testée |
| **RBAC / Permissions** | Échec | `rbac_auth_middleware_test.go` | Mocks `HasRole`, `HasPermission` non satisfaits. Droits non validés |
| **Upload / Tracks** | Partiel | Intégration quarantaine, handlers | `playlist_duplicate_transaction_test.go` ne compile pas. Upload async partiellement testé |
| **Commerce / Marketplace** | Faible | Peu de tests dédiés | `marketplaceService`, `cartStore``cartStore.test.ts` présent. Services commerce peu couverts |
| **Webhooks** | Faible | `webhook_service_test.go`, `webhook_handlers_test.go` | Présents. Pas de test E2E de livraison |
| **Synchronisation d'état** | Moyen | Offline queue, optimistic updates | `optimisticUpdates.ts` documenté. Peu de tests sur rollback, invalidation |
### 5.2 Invariants métier
- **Propriété des ressources** : `ownership_integration_test.go` présent. Résultat non vérifié en CI.
- **Transactions** : `rbac_transaction_test`, `social_transaction_test`, `playlist_duplicate_transaction_test` — dernier ne compile pas.
---
## 6. TESTABILITÉ DE L'ARCHITECTURE
### 6.1 Points favorables
- **MSW** : Handlers centralisés (~1682 lignes). Développement et tests sans backend.
- **Feature-based** : Structure modulaire. Features isolables.
- **React Query** : Fetch centralisé. Mockable via MSW.
- **Dependency injection** : Go utilise des interfaces. Services injectables.
### 6.2 Points bloquants
| Problème | Fichier / Indice |
|----------|-------------------|
| **Singletons globaux** | `authStore` (Zustand) + `AuthContext` — deux sources. Tests doivent mocker les deux |
| **Dépendances cachées** | `client.ts` — interceptors, retry, CSRF, offline queue. Pas de découpage. Difficile à tester unitairement |
| **Effets de bord** | `main.tsx` — waitForStylesheets, fixDisplayIssues, fixInputFocus. Init complexe |
| **Mocking excessif** | Tests auth : 10+ `vi.mock()`. Toute évolution casse les tests |
### 6.3 Mélange orchestration / logique
- **Pages** : Certaines pages font fetch direct (`useState` + `useEffect` + `apiClient`) au lieu de React Query. Difficile à isoler.
- **Client API** : Logique métier (retry, refresh, validation) mélangée avec transport. Pas de séparation nette.
---
## 7. DETTE DE TEST
### 7.1 Classification
| Dette | Gravité | Coût de correction | Impact sur vélocité |
|------|---------|-------------------|--------------------|
| ~~Tests non bloquants~~ | ~~Critique~~ | — | ✅ **Corrigé** : tests bloquants |
| **Tests Go auth/RBAC échouants** | Critique | Moyen (corriger mocks) | Blocage si activés |
| **176 tests skippés (Backend)** | Élevée | Élevé | Inconnu — tests ignorés |
| **Config Jest obsolète** | Faible | Faible (supprimer) | Confusion |
| **playwright.yml sans working-directory** | Moyenne | Faible | E2E peuvent échouer si exécutés depuis la racine |
| **Workflows frontend/backend ci inutilisables** | Moyenne | Faible (corriger chemins) | Aucun — jamais déclenchés |
### 7.2 Tests lents
- **Vitest** : Timeout observé lors de l'exécution (commande interrompue après 120s). Suite conséquente.
- **Backend** : `go test ./internal/...` timeout également. Suite très volumineuse.
- **E2E** : `workers: 1` — séquentiel. Timeout 60s par test.
### 7.3 Tests fragiles
- **Backend auth** : Changement de signature ou comportement de `ValidateSession` casse tous les tests middleware.
- **Frontend** : Libellés i18n en dur dans les assertions. Changement de traduction = échec.
- **PlaylistErrorBoundary** : Utilise `jest.spyOn` (Jest) au lieu de `vi.spyOn` (Vitest) — incohérence.
---
## 8. CI / AUTOMATISATION
### 8.1 Workflows actifs
| Workflow | Déclenchement | Contenu | Problème |
|----------|---------------|---------|----------|
| **ci.yml** | push/PR main, remediation/*, feature/mvp-complete | Backend (vet, lint, test -short, build), Rust (fmt, build, test chat), Frontend (lint, format, typecheck, **test** (bloquant), build) | ✅ Tests frontend bloquants |
| **playwright.yml** | push/PR main, master | `npx playwright test` | Pas de `working-directory: apps/web`. Dépendances `npm ci` à la racine — peut échouer |
| **storybook-audit.yml** | push/PR apps/web | build-storybook, serve, audit-storybook.js | Correct |
| **test-coverage.yml** (backend) | push/PR main, develop | `go test -coverprofile` | Correct. Artifacts. |
| **frontend-ci.yml** | paths: apps/web-frontend | pnpm test | **Chemin inexistant** (apps/web-frontend) |
| **backend-ci.yml** | paths: apps/backend-api | go test | **Chemin inexistant** (apps/backend-api) |
### 8.2 Fréquence, temps, seuils
- **Fréquence** : À chaque push/PR sur les branches configurées.
- **Temps** : Non mesuré. Playwright timeout 60 min.
- **Seuils bloquants** : Tests unitaires frontend **bloquent** le build. Couverture : pas de seuils vérifiés. Backend : tests exécutés, résultats bloquants si échecs.
### 8.3 Protection du main
**La CI frontend protège désormais le main** — les tests unitaires bloquent le build. **La CI backend reste fragile** : exécution d'un sous-ensemble (`handlers`, `services`, `-short`). Les tests auth/RBAC qui échouent font partie des packages exécutés — la CI backend peut être instable ou les tests skippés. À clarifier.
---
## 9. RISQUES MAJEURS IDENTIFIÉS
### R1. Régression auth / RBAC non détectée
- **Probabilité** : Élevée
- **Impact** : Critique (accès non autorisé, fuite de données)
- **Indice** : Tests auth middleware et RBAC échouent. Toute modification du flux auth n'est pas validée par les tests.
### R2. Déploiement de code cassé
- **Probabilité** : Réduite (frontend)
- **Impact** : Élevé
- **Indice** : Tests frontend bloquants — correction appliquée. Backend : risque persistant si tests skippés ou exclus.
### R3. Désynchronisation auth (Context vs Store)
- **Probabilité** : Moyenne
- **Impact** : Élevé (comportement incohérent, bugs subtils)
- **Indice** : Double source de vérité. Aucun test ne valide la cohérence.
### R4. Régression API non détectée
- **Probabilité** : Moyenne
- **Impact** : Élevé
- **Indice** : Tests d'intégration en quarantaine. Contract tests non exécutés en CI standard. Client API monolithique peu testé.
### R5. E2E fragiles ou non exécutés
- **Probabilité** : Élevée
- **Impact** : Moyen
- **Indice** : `playwright.yml` sans working-directory. `globalSetup` requiert API. Workers=1. Pas de preuve que les E2E passent en CI.
---
## 10. RECOMMANDATIONS STRATÉGIQUES
### 10.1 Court terme (12 semaines)
1. ~~Supprimer `|| true`~~**Fait** : les tests frontend bloquent désormais.
2. **Corriger les chemins** des workflows `frontend-ci.yml` et `backend-ci.yml` (ou les supprimer s'ils sont obsolètes).
3. **Ajouter `working-directory: apps/web`** au workflow `playwright.yml`.
4. **Exclure les packages Go qui paniquent** de la CI : `internal/testutils` (TestRunParallelTests), ou les corriger.
5. **Corriger l'erreur de compilation** `playlist_duplicate_transaction_test.go:80` (utilisation incorrecte de `file`).
### 10.2 Moyen terme (13 mois)
1. **Réparer les tests auth/RBAC** : Aligner les mocks sur l'implémentation actuelle ou refactoriser les mocks pour qu'ils soient moins fragiles.
2. **Réintégrer les tests d'intégration critiques** : `api_health_test.go` (déjà corrigé), contract tests. Exécuter en CI avec tag `integration` sur un environnement dédié.
3. **Ajouter une étape de validation des seuils de couverture** : `vitest run --coverage` et fail si en dessous de 80% sur les répertoires critiques (features/auth, features/playlists, services).
4. **Unifier auth** : Éliminer la double source (Context + Store). Réduire le coût des mocks dans les tests.
5. **Remplacer `jest.spyOn` par `vi.spyOn`** dans tous les tests frontend (ex. PlaylistErrorBoundary.test.tsx).
6. **Découper `client.ts`** : Extraire interceptors, retry, validation en modules testables.
### 10.3 Long terme
1. **Pyramide de tests** : Rééquilibrer — plus de tests unitaires ciblés (logique pure), moins de tests avec mocks massifs. Tests d'intégration avec MSW pour les flux critiques.
2. **Tests par contrat** : OpenAPI comme source de vérité. Tests contractuels automatisés en CI.
3. **Environnement de test dédié** : Base de données, Redis, services pour les tests d'intégration backend. CI nightly ou staging.
4. **Politique de couverture par domaine** : 80% sur auth, RBAC, commerce. 60% sur le reste. Métriques par module.
---
## 11. MÉTRIQUES DE SUIVI
Au-delà du simple % de coverage, proposer :
| Indicateur | Cible | Mesure |
|------------|-------|--------|
| **Taux de tests bloquants** | 100% | Nombre de branches où les tests peuvent échouer sans bloquer → 0 |
| **Taux de tests passants (Backend)** | 95% | (Total - Skip - Fail) / Total |
| **Couverture des branches d'erreur** | 70% | Branches catch/error exercées / total |
| **Temps de suite unitaire** | < 2 min | Frontend Vitest |
| **Temps de suite E2E** | < 15 min | Playwright (chromium uniquement en CI) |
| **Dette de skip** | -10% / mois | Réduire le nombre de tests skippés |
| **Flakiness** | 0% | Nombre de tests flaky sur 10 runs |
---
## 12. RÉFÉRENCES ET FICHIERS CITÉS
| Fichier | Rôle |
|---------|------|
| `apps/web/package.json` | Scripts test, vitest |
| `apps/web/jest.config.js` | Config obsolète (Jest) |
| `apps/web/vitest.config.ts` | Config Vitest, coverage, thresholds |
| `apps/web/src/test/setup.ts` | Setup Vitest, mocks |
| `apps/web/src/mocks/handlers.ts` | MSW handlers |
| `apps/web/e2e/global-setup.ts` | Playwright auth |
| `apps/web/playwright.config.ts` | Config E2E |
| `.github/workflows/ci.yml` | Pipeline principal |
| `.github/workflows/playwright.yml` | E2E |
| `.github/workflows/storybook-audit.yml` | Storybook |
| `veza-backend-api/tests/integration/QUARANTINE.md` | Classification tests |
| `veza-backend-api/docs/TEST_FAILS.md` | Inventaire 445 échecs |
| `veza-backend-api/.github/workflows/test-coverage.yml` | Coverage Go |
---
## 13. FEUILLE DE ROUTE PRIORISÉE
| Priorité | Action | Effort | Impact |
|----------|--------|--------|--------|
| ~~P0~~ | ~~Supprimer `\|\| true`~~ | | **Fait** |
| P0 | Corriger `playlist_duplicate_transaction_test.go` (compile) | 2 h | Critique |
| P1 | Ajouter working-directory à playwright.yml | 30 min | Élevé |
| P1 | Corriger ou supprimer frontend-ci/backend-ci workflows | 30 min | Moyen |
| P1 | Exclure/corriger tests Go qui paniquent | 4 h | Élevé |
| P2 | Réparer tests auth middleware (Go) | 8 h | Critique |
| P2 | Validation seuils coverage en CI | 2 h | Élevé |
| P2 | Remplacer jest par vi dans tests frontend | 2 h | Moyen |
| P3 | Découper client.ts | 40 h | Moyen |
| P3 | Unifier auth (Context vs Store) | 24 h | Élevé |
---
**Fin du rapport.**