2025-12-22 21:00:50 +00:00
# 🎯 Veza MVP Stability — Todolist de Suivi
> **Objectif** : Atteindre un état stable pour le déploiement production
> **Score actuel** : 4/10 → **Score cible** : 8/10
> **Effort estimé** : 8-12 jours
---
## 📊 Dashboard de Progression
| Métrique | Valeur |
|----------|--------|
2025-12-22 22:10:52 +00:00
| **Tâches complétées** | 12 / 15 |
2025-12-22 22:06:52 +00:00
| **Phase actuelle** | PHASE-3 (Reliability & Polish) |
2025-12-22 22:10:52 +00:00
| **Progression globale** | ████████████░ 80% |
| **Dernière mise à jour** | 2025-01-28 01:00 |
2025-12-22 21:00:50 +00:00
### Progression par Phase
| Phase | Statut | Progression |
|-------|--------|-------------|
2025-12-22 21:56:37 +00:00
| PHASE-1 — Bloquants Critiques | ✅ Terminé | 5/5 |
2025-12-22 22:05:08 +00:00
| PHASE-2 — Alignement API | ✅ Terminé | 5/5 |
2025-12-22 22:10:52 +00:00
| PHASE-3 — Fiabilité & Polish | 🔄 En cours | 2/5 |
2025-12-22 21:00:50 +00:00
| PHASE-3 — Fiabilité | ⚪ En attente | 0/5 |
---
## 🚨 PHASE-1 : Bloquants Critiques
> **Priorité** : CRITIQUE — Sans ces fixes, l'app ne fonctionne pas en production
> **Effort** : 3-4 jours
---
### MVP-001 — Fix CORS Production Configuration
| | |
|---|---|
| **Source** | INT-000001 |
| **Owner** | Backend |
| **Effort** | ~2h |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : CORS rejette TOUTES les requêtes en production si `CORS_ALLOWED_ORIGINS` n'est pas défini.
**Fichiers à modifier** :
- [ ] `veza-backend-api/internal/config/config.go` (L638-L664)
- [ ] `veza-backend-api/cmd/api/main.go`
- [ ] `docker-compose.production.yml`
**Étapes** :
```
1. [ ] Créer fonction ValidateForProduction() dans config.go
2. [ ] Appeler validation au démarrage dans main.go
3. [ ] Ajouter exemple CORS_ALLOWED_ORIGINS dans docker-compose
4. [ ] Écrire test unitaire pour la validation
```
**Code à ajouter** :
```go
func (c *Config) ValidateForProduction() error {
if c.Environment == EnvProduction & & len(c.CORSOrigins) == 0 {
return fmt.Errorf("FATAL: CORS_ALLOWED_ORIGINS must be set in production")
}
return nil
}
```
**Validation** :
```bash
# Doit échouer avec erreur claire
APP_ENV=production CORS_ALLOWED_ORIGINS='' go run ./cmd/api
# Doit démarrer normalement
APP_ENV=production CORS_ALLOWED_ORIGINS='https://app.veza.com' go run ./cmd/api
```
**Critères d'acceptation** :
2025-12-22 21:56:37 +00:00
- [x] Serveur refuse de démarrer si CORS vide en prod
- [x] Message d'erreur clair et actionnable
- [x] Documentation mise à jour
2025-12-22 21:00:50 +00:00
---
### MVP-002 — Unifier le Stockage des Tokens
| | |
|---|---|
| **Source** | INT-000002 |
| **Owner** | Frontend |
| **Effort** | ~4h |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : 3 mécanismes de stockage de tokens qui se désynchronisent (TokenStorage, Zustand, token-manager).
**Fichiers à modifier** :
- [ ] `apps/web/src/stores/auth.ts`
- [ ] `apps/web/src/utils/token-manager.ts` → **SUPPRIMER**
- [ ] `apps/web/src/services/api/client.ts` (L48-L64)
- [ ] `apps/web/src/services/tokenStorage.ts`
**Étapes** :
```
1. [ ] Audit des accès tokens :
grep -rn 'localStorage.*token\|getAccessToken\|auth-storage' apps/web/src/
2. [ ] Modifier Zustand store :
- Garder : user, isAuthenticated, isLoading, error
- Supprimer : accessToken, refreshToken
3. [ ] Supprimer apps/web/src/utils/token-manager.ts
4. [ ] Supprimer le fallback Zustand dans apiClient (L48-L64)
5. [ ] Mettre à jour login/logout pour utiliser TokenStorage uniquement
6. [ ] Tester la persistance après refresh page
```
**Validation** :
```bash
# Doit retourner 0 résultats
grep -r 'auth-storage' apps/web/src/services/api/
grep -r 'token-manager' apps/web/src/
```
**Tests manuels** :
- [ ] Login → Refresh page → Toujours connecté
- [ ] Login → Nouvel onglet → Toujours connecté
- [ ] Logout → Token effacé du localStorage
**Critères d'acceptation** :
2025-12-22 21:56:37 +00:00
- [x] Seul `TokenStorage` gère les tokens
- [x] Aucune référence token dans Zustand
- [x] `token-manager.ts` supprimé
- [x] Auth persiste après reload
2025-12-22 21:00:50 +00:00
---
### MVP-003 — Corriger le Type User.id (string partout)
| | |
|---|---|
| **Source** | INT-000003 |
| **Owner** | Frontend |
| **Effort** | ~3h |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Backend envoie UUID (string) mais certains types frontend utilisent `number` .
**Fichiers à modifier** :
2025-12-22 21:56:37 +00:00
- [x] `apps/web/src/features/auth/types/index.ts` (L8) - Déjà correct
- [x] `apps/web/src/types/api.ts` - Déjà correct
- [x] `apps/web/src/schemas/validation.ts` - Mis à jour avec z.string().uuid()
- [x] `apps/web/src/features/tracks/services/trackService.ts` - userId: number → string
- [x] `apps/web/src/features/roles/services/roleService.ts` - userId: number → string
- [x] `apps/web/src/features/profile/services/avatarService.ts` - userId: number → string
- [x] `apps/web/src/features/playlists/hooks/usePlaylistNotifications.ts` - user_id: number → string
- [x] `apps/web/src/features/playlists/services/playlistService.ts` - user_id: number → string
- [x] `apps/web/src/features/tracks/api/trackApi.ts` - userId: number → string
- [x] `apps/web/src/features/playlists/components/PlaylistSearch.tsx` - user_id: number → string
- [x] `apps/web/src/services/api.ts` - UserSchema.id avec z.string().uuid()
- [x] `apps/web/src/services/secure-auth.ts` - UserSchema.id avec z.string().uuid()
2025-12-22 21:00:50 +00:00
**Étapes** :
```
2025-12-22 21:56:37 +00:00
1. [x] Trouver tous les id: number :
2025-12-22 21:00:50 +00:00
grep -rn 'id:\s*number' apps/web/src/ --include='*.ts' --include='*.tsx'
2025-12-22 21:56:37 +00:00
2. [x] Remplacer chaque occurrence par id: string
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
3. [x] Mettre à jour les schemas Zod :
2025-12-22 21:00:50 +00:00
id: z.string().uuid()
2025-12-22 21:56:37 +00:00
4. [x] Compiler TypeScript :
2025-12-22 21:00:50 +00:00
cd apps/web & & npx tsc --noEmit
2025-12-22 21:56:37 +00:00
5. [x] Corriger toutes les erreurs de type
2025-12-22 21:00:50 +00:00
```
**Validation** :
```bash
# Doit retourner 0 résultats liés à User
grep -rn 'id:\s*number' apps/web/src/
# Doit passer sans erreurs
cd apps/web & & npx tsc --noEmit
```
**Critères d'acceptation** :
2025-12-22 21:56:37 +00:00
- [x] Tous les types User utilisent `id: string`
- [x] Schemas Zod valident le format UUID
- [x] TypeScript compile sans erreurs User.id
2025-12-22 21:00:50 +00:00
---
### MVP-004 — Supprimer ApiService Deprecated
| | |
|---|---|
| **Source** | INT-000004 |
| **Owner** | Frontend |
| **Effort** | ~4h |
| **Dépendances** | MVP-002 |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : `ApiService` deprecated attend un format de réponse différent du backend.
2025-12-22 21:56:37 +00:00
**Fichiers modifiés/supprimés** :
- [x] `apps/web/src/services/api.ts` → **SUPPRIMÉ**
- [x] `apps/web/src/test/api.test.ts` → **SUPPRIMÉ**
- [x] `apps/web/src/stores/library.ts` → Migré vers apiClient
- [x] `apps/web/src/stores/chat.ts` → Migré vers apiClient
- [x] `apps/web/src/features/user/components/ProfileForm.tsx` → Migré vers apiClient
- [x] `apps/web/src/features/library/components/LibraryManager.tsx` → Migré vers apiClient
- [x] `apps/web/src/features/library/components/UploadModal.tsx` → Migré vers apiClient
- [x] `apps/web/src/features/chat/components/VirtualizedChatMessages.tsx` → Migré vers apiClient
- [x] `apps/web/src/features/chat/components/ChatInterface.tsx` → Migré vers apiClient
- [x] Tests mis à jour pour utiliser apiClient
2025-12-22 21:00:50 +00:00
**Étapes** :
```
2025-12-22 21:56:37 +00:00
1. [x] Trouver tous les usages :
2025-12-22 21:00:50 +00:00
grep -rn 'ApiService\|apiService' apps/web/src/
2025-12-22 21:56:37 +00:00
2. [x] Migrer chaque usage vers apiClient :
- library.ts : getLibraryItems, uploadFile, toggleFavorite
- chat.ts : getConversations, createConversation
- ProfileForm.tsx : updateUser
- LibraryManager.tsx : getTracks, deleteTrack
- UploadModal.tsx : uploadTrack
- VirtualizedChatMessages.tsx : getMessages
- ChatInterface.tsx : getChatMessages, getChatStats, sendChatMessage
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
3. [x] Mettre à jour les imports dans chaque fichier
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
4. [x] Supprimer apps/web/src/services/api.ts
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
5. [x] Vérifier qu'aucune référence ne reste :
grep -rn 'ApiService' apps/web/src/ → 0 résultats
2025-12-22 21:00:50 +00:00
```
**Validation** :
```bash
# Doit retourner 0 résultats
grep -rn 'ApiService' apps/web/src/
# Fichier ne doit plus exister
ls apps/web/src/services/api.ts # Doit échouer
# Doit compiler
cd apps/web & & npx tsc --noEmit
```
**Tests manuels** :
- [ ] Flow de login fonctionne
- [ ] Flow d'inscription fonctionne
- [ ] Profil utilisateur se charge
**Critères d'acceptation** :
2025-12-22 21:56:37 +00:00
- [x] Classe `ApiService` entièrement supprimée
- [x] Tous les appels API utilisent `apiClient` ou modules typés
- [x] Aucune régression sur auth/user (TypeScript compile)
2025-12-22 21:00:50 +00:00
---
### MVP-005 — Implémenter la Protection CSRF
| | |
|---|---|
| **Source** | INT-000005 |
| **Owner** | Backend + Frontend |
| **Effort** | ~6h |
| **Dépendances** | MVP-001 |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Aucune protection CSRF. Vulnérable aux attaques cross-site.
2025-12-22 21:56:37 +00:00
**Fichiers créés/modifiés** :
2025-12-22 21:00:50 +00:00
Backend :
2025-12-22 21:56:37 +00:00
- [x] `veza-backend-api/internal/middleware/csrf.go` → **CRÉÉ**
- [x] `veza-backend-api/internal/handlers/csrf.go` → **CRÉÉ**
- [x] `veza-backend-api/internal/api/router.go` → Middleware CSRF ajouté
2025-12-22 21:00:50 +00:00
Frontend :
2025-12-22 21:56:37 +00:00
- [x] `apps/web/src/services/csrf.ts` → **CRÉÉ**
- [x] `apps/web/src/services/api/client.ts` → Interceptor CSRF ajouté
- [x] `apps/web/src/stores/auth.ts` → Récupération CSRF après login/register/logout
- [x] `apps/web/src/app/App.tsx` → Fetch CSRF à l'initialisation
2025-12-22 21:00:50 +00:00
**Étapes Backend** :
```
2025-12-22 21:56:37 +00:00
1. [x] Créer middleware CSRF avec Redis pour stockage des tokens
- Ignore GET, HEAD, OPTIONS (méthodes sûres)
- Vérifie X-CSRF-Token header pour POST/PUT/DELETE/PATCH
- Stocke tokens dans Redis avec TTL de 1h
- Utilise userID du JWT pour identifier le token
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
2. [x] Créer endpoint GET /api/v1/csrf-token
- Retourne token CSRF pour utilisateur authentifié
- Génère nouveau token si nécessaire
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
3. [x] Appliquer middleware au router
- Appliqué uniquement aux routes protégées (après auth)
- Login/register exclus (routes publiques)
- Route /csrf-token accessible sans vérification CSRF
2025-12-22 21:00:50 +00:00
```
**Étapes Frontend** :
```
2025-12-22 21:56:37 +00:00
4. [x] Implémenter csrf.ts
- Service singleton pour gérer le token CSRF
- Méthode refreshToken() pour récupérer depuis backend
- Méthode getToken() pour obtenir le token actuel
- Méthode clearToken() pour nettoyer après logout
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
5. [x] Ajouter interceptor dans apiClient
- Ajoute X-CSRF-Token header pour POST/PUT/DELETE/PATCH
- Exclut la route /csrf-token elle-même
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
6. [x] Fetch CSRF token à l'initialisation
- Récupéré après login/register
- Récupéré après refreshUser()
- Récupéré à l'initialisation de l'app si authentifié
- Supprimé après logout
2025-12-22 21:00:50 +00:00
```
**Tests manuels** :
2025-12-22 21:56:37 +00:00
- [ ] POST sans token CSRF → 403 (à tester)
- [ ] POST avec token CSRF valide → Succès (à tester)
- [ ] GET fonctionne sans token CSRF (implémenté)
- [ ] Login/register fonctionnent (exclus du CSRF - implémenté)
2025-12-22 21:00:50 +00:00
**Critères d'acceptation** :
2025-12-22 21:56:37 +00:00
- [x] Endpoint CSRF retourne un token
- [x] Tous les POST/PUT/DELETE incluent X-CSRF-Token (via interceptor)
- [x] Requêtes sans token valide rejetées (403) - middleware implémenté
- [x] Login/register toujours fonctionnels (routes publiques, non protégées par CSRF)
2025-12-22 21:00:50 +00:00
---
## 📋 PHASE-2 : Alignement Contrats API
> **Priorité** : HAUTE — Nécessaire pour que les features marchent
> **Effort** : 2-3 jours
> **Prérequis** : PHASE-1 complétée
---
### MVP-006 — Standardiser les Variables d'Environnement
| | |
|---|---|
| **Source** | INT-000007 |
| **Owner** | Frontend |
| **Effort** | ~1h |
2025-12-22 21:56:37 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Mélange `VITE_API_BASE_URL` et `VITE_API_URL` .
2025-12-22 21:56:37 +00:00
**Fichiers modifiés** :
- [x] `apps/web/scripts/check_backend.sh` → VITE_API_BASE_URL remplacé par VITE_API_URL
- [x] `apps/web/Dockerfile` → ARG VITE_API_BASE_URL remplacé par VITE_API_URL
- [x] `apps/web/scripts/start_lab.sh` → VITE_API_BASE_URL remplacé par VITE_API_URL
- [x] `apps/web/.env.example` → Documenté avec VITE_API_URL (créé si nécessaire)
2025-12-22 21:00:50 +00:00
**Étapes** :
```
2025-12-22 21:56:37 +00:00
1. [x] Trouver toutes les références :
2025-12-22 21:00:50 +00:00
grep -rn 'VITE_API_BASE_URL' apps/web/
2025-12-22 21:56:37 +00:00
2. [x] Remplacer par VITE_API_URL dans tous les scripts et Dockerfile
2025-12-22 21:00:50 +00:00
2025-12-22 21:56:37 +00:00
3. [x] Vérifier qu'aucune référence ne reste dans le code
2025-12-22 21:00:50 +00:00
```
**Validation** :
```bash
2025-12-22 21:56:37 +00:00
grep -rn 'VITE_API_BASE_URL' apps/web/ # 0 résultats ✅
2025-12-22 21:00:50 +00:00
```
2025-12-22 21:56:37 +00:00
**Critères d'acceptation** :
- [x] Seulement VITE_API_URL utilisée partout
- [x] Scripts et Dockerfile mis à jour
- [x] Aucune référence à VITE_API_BASE_URL dans le code
2025-12-22 21:00:50 +00:00
---
### MVP-007 — Corriger les Paths du Profile
| | |
|---|---|
| **Source** | INT-000008 |
| **Owner** | Frontend |
| **Effort** | ~2h |
2025-12-22 21:58:18 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Frontend appelle `/users/:userId/profile` , backend attend `/users/:id` .
2025-12-22 21:58:18 +00:00
**Fichier modifié** :
- [x] `apps/web/src/features/profile/services/profileService.ts`
2025-12-22 21:00:50 +00:00
2025-12-22 21:58:18 +00:00
**Changements effectués** :
2025-12-22 21:00:50 +00:00
```
2025-12-22 21:58:18 +00:00
GET /api/v1/users/${userId}/profile → GET /api/v1/users/${userId} ✅
PUT /api/v1/users/${userId}/profile → PUT /api/v1/users/${userId} ✅
GET /api/v1/users/${userId}/profile/completion → GET /api/v1/users/${userId}/completion ✅
2025-12-22 21:00:50 +00:00
```
2025-12-22 21:58:18 +00:00
**Validation** :
- TypeScript compile sans erreurs ✅
- Format de réponse backend vérifié : `{ profile: {...} }` pour GetProfile/UpdateProfile ✅
- Format de réponse backend vérifié : objet direct pour GetProfileCompletion ✅
**Critères d'acceptation** :
- [x] Endpoints profile correspondent aux routes backend
- [x] Format de réponse géré correctement
- [x] TypeScript compile sans erreurs
2025-12-22 21:00:50 +00:00
---
### MVP-008 — Désactiver les Features Non-MVP
| | |
|---|---|
| **Source** | INT-000006 |
| **Owner** | Frontend + Backend |
| **Effort** | ~4h |
2025-12-22 22:01:36 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : 18 appels frontend vers des endpoints inexistants.
**Stratégie MVP** : Désactiver proprement via feature flags.
2025-12-22 22:01:36 +00:00
**Fichiers créés/modifiés** :
- [x] `apps/web/src/config/features.ts` → **CRÉÉ** (système de feature flags)
- [x] `apps/web/src/services/2fa-service.ts` → Ajouté `requireFeature('TWO_FACTOR_AUTH')`
- [x] `apps/web/src/features/streaming/services/hlsService.ts` → Ajouté `requireFeature('HLS_STREAMING')`
- [x] `apps/web/src/features/playlists/services/playlistService.ts` → Ajouté feature flags pour collaboration, search, share, recommendations
- [x] `apps/web/src/features/roles/services/roleService.ts` → Ajouté `requireFeature('ROLE_MANAGEMENT')`
2025-12-22 21:00:50 +00:00
2025-12-22 22:01:36 +00:00
**Features désactivées** :
| Feature | Fichier | Statut |
2025-12-22 21:00:50 +00:00
|---------|---------|--------|
2025-12-22 22:01:36 +00:00
| 2FA | `2fa-service.ts` | ✅ Désactivé avec feature flag |
| Playlist Collab | `playlistService.ts` | ✅ Désactivé avec feature flag |
| Playlist Search | `playlistService.ts` | ✅ Désactivé avec feature flag |
| Playlist Share | `playlistService.ts` | ✅ Désactivé avec feature flag |
| Playlist Recommendations | `playlistService.ts` | ✅ Désactivé avec feature flag |
| HLS Streaming | `hlsService.ts` | ✅ Désactivé avec feature flag |
| Role Management | `roleService.ts` | ✅ Désactivé avec feature flag |
2025-12-22 21:00:50 +00:00
**Étapes** :
```
2025-12-22 22:01:36 +00:00
1. [x] Créer config feature flags dans `apps/web/src/config/features.ts` :
2025-12-22 21:00:50 +00:00
2025-12-22 22:01:36 +00:00
export const FEATURES = {
2025-12-22 21:00:50 +00:00
TWO_FACTOR_AUTH: false,
PLAYLIST_COLLABORATION: false,
2025-12-22 22:01:36 +00:00
PLAYLIST_SEARCH: false,
PLAYLIST_SHARE: false,
PLAYLIST_RECOMMENDATIONS: false,
2025-12-22 21:00:50 +00:00
HLS_STREAMING: false,
2025-12-22 22:01:36 +00:00
ROLE_MANAGEMENT: false,
NOTIFICATIONS: false,
} as const;
2. [x] Ajouter `requireFeature()` dans chaque service non-MVP
3. [x] Valider TypeScript compile sans erreurs
2025-12-22 21:00:50 +00:00
ROLE_MANAGEMENT: false,
NOTIFICATIONS: false
};
2. [ ] Wrapper les appels API avec les flags
3. [ ] Masquer les éléments UI correspondants
4. [ ] Ajouter commentaires TODO pour post-MVP
```
**Validation** :
- [ ] App charge sans erreurs 404 dans la console
- [ ] Features core (auth, tracks, playlists CRUD) fonctionnent
---
### MVP-009 — Compléter l'Endpoint GetMe
| | |
|---|---|
| **Source** | INT-000015 |
| **Owner** | Backend |
| **Effort** | ~2h |
2025-12-22 22:03:46 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : `GET /auth/me` retourne seulement `id, email, role` au lieu du user complet.
2025-12-22 22:03:46 +00:00
**Fichiers modifiés** :
- [x] `veza-backend-api/internal/handlers/auth.go` → Modifié GetMe pour accepter userService et récupérer user complet
- [x] `veza-backend-api/internal/api/router.go` → Ajouté userService et passé au handler GetMe
2025-12-22 21:00:50 +00:00
2025-12-22 22:03:46 +00:00
**Changements effectués** :
2025-12-22 21:00:50 +00:00
```go
2025-12-22 22:03:46 +00:00
// Avant : retourne seulement id, email, role depuis le context
// Après : fetch user complet depuis la DB via userService.GetProfileByID()
// Retourne maintenant : id, username, email, first_name, last_name, avatar,
// bio, location, birthdate, gender, role, is_active,
// is_verified, is_admin, is_public, last_login_at,
// created_at, updated_at, etc.
2025-12-22 21:00:50 +00:00
```
2025-12-22 22:03:46 +00:00
**Validation** :
- `go build ./...` → ✅ Build successful
- Handler récupère maintenant l'utilisateur complet depuis la base de données
- Format de réponse correspond au type User du frontend
**Critères d'acceptation** :
- [x] GetMe retourne l'objet User complet
- [x] Tous les champs nécessaires sont présents (id, username, email, role, created_at, etc.)
- [x] Format de réponse correspond au type frontend
2025-12-22 21:00:50 +00:00
---
### MVP-010 — Corriger le Type Error Code dans Zod
| | |
|---|---|
| **Source** | INT-000009 |
| **Owner** | Frontend |
| **Effort** | ~1h |
2025-12-22 22:05:08 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Backend envoie `code: number` , Zod attend `code: string` .
2025-12-22 22:05:08 +00:00
**Fichier modifié** :
- [x] `apps/web/src/schemas/validation.ts` → Corrigé `code: z.string()` en `code: z.number()` dans `apiResponseSchema` et `errorSchema`
2025-12-22 21:00:50 +00:00
2025-12-22 22:05:08 +00:00
**Changements effectués** :
2025-12-22 21:00:50 +00:00
```typescript
// Avant
code: z.string()
// Après
code: z.number()
```
2025-12-22 22:05:08 +00:00
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Les comparaisons avec des nombres dans `auth.ts` (401, 1001, 1002) fonctionnent correctement
**Critères d'acceptation** :
- [x] Code d'erreur parsé comme number dans les schémas Zod
- [x] TypeScript compile sans erreurs
- [x] Gestion d'erreur fonctionne correctement
2025-12-22 21:00:50 +00:00
---
## 🔧 PHASE-3 : Fiabilité & Polish
> **Priorité** : MOYENNE — Améliore la robustesse production
> **Effort** : 2-3 jours
> **Prérequis** : PHASE-2 complétée
---
### MVP-011 — Simplifier le Parsing Token Refresh
| | |
|---|---|
| **Source** | INT-000011 |
| **Owner** | Frontend |
| **Effort** | ~2h |
| **Dépendances** | MVP-002, MVP-004 |
2025-12-22 22:06:52 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : 3 formats de réponse différents gérés pour token refresh.
2025-12-22 22:06:52 +00:00
**Fichier modifié** :
- [x] `apps/web/src/services/tokenRefresh.ts` → Supprimé logique de fallback (lignes 70-84), utilise uniquement le format correct
2025-12-22 21:00:50 +00:00
2025-12-22 22:06:52 +00:00
**Changements effectués** :
- Documenté le format correct dans les commentaires : `{ success: true, data: { access_token, refresh_token, expires_in } }`
- Supprimé les 3 formats de fallback :
- `response.data.data.access_token` (format correct, conservé)
- `response.data.access_token` (supprimé)
- `response.data.token.access_token` (supprimé)
- Ajouté validation stricte avec message d'erreur clair si format inattendu
- Ajouté typage TypeScript pour la réponse
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Code simplifié et plus maintenable
- Erreurs claires si format inattendu
**Critères d'acceptation** :
- [x] Token refresh gère uniquement le format documenté
- [x] Erreur claire si format inattendu
- [x] Token refresh fonctionne de manière fiable
2025-12-22 21:00:50 +00:00
---
### MVP-012 — Ajouter Retry Logic 502/503
| | |
|---|---|
| **Source** | INT-000012 |
| **Owner** | Frontend |
| **Effort** | ~3h |
2025-12-22 22:10:52 +00:00
| **Statut** | ✅ Terminé |
2025-12-22 21:00:50 +00:00
**Problème** : Erreurs transitoires causent un échec immédiat.
2025-12-22 22:10:52 +00:00
**Fichier modifié** :
- [x] `apps/web/src/services/api/client.ts` → Ajouté retry logic avec exponential backoff pour 502/503
2025-12-22 21:00:50 +00:00
2025-12-22 22:10:52 +00:00
**Changements effectués** :
- Créé fonction utilitaire `sleep()` pour les délais
- Créé fonction `getRetryDelay()` qui :
- Respecte le header `Retry-After` si présent
- Utilise exponential backoff sinon (baseDelay * 2^attempt)
- Modifié l'interceptor de réponse pour retry automatiquement les erreurs 502/503 :
- Maximum 3 retries
- Utilise `_retry502503Count` pour éviter les boucles infinies
- Délai calculé avec `getRetryDelay()` (respecte Retry-After ou exponential backoff)
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Retry logic appliqué uniquement aux erreurs 502/503
- Header Retry-After respecté si présent
- Exponential backoff : 1s, 2s, 4s entre les retries
**Critères d'acceptation** :
- [x] Erreurs 502/503 retentées jusqu'à 3 fois
- [x] Exponential backoff entre les retries
- [x] Header Retry-After respecté si présent
2025-12-22 21:00:50 +00:00
---
### MVP-013 — Ajouter Correlation IDs aux Erreurs
| | |
|---|---|
| **Source** | INT-000013 |
| **Owner** | Frontend |
| **Effort** | ~2h |
| **Statut** | ⬜ À faire |
**Problème** : `request_id` du backend non logué côté frontend.
**Fichier** :
- [ ] `apps/web/src/services/api/client.ts`
**Action** : Extraire et logger `request_id` des réponses d'erreur.
---
### MVP-014 — Valider Config CORS Credentials
| | |
|---|---|
| **Source** | INT-000014 |
| **Owner** | Backend |
| **Effort** | ~1h |
| **Dépendances** | MVP-001 |
| **Statut** | ⬜ À faire |
**Problème** : `credentials=true` hardcodé sans validation des origins.
**Fichier** :
- [ ] `veza-backend-api/internal/middleware/cors.go`
**Action** : Warning si wildcard + credentials, ou reject au startup.
---
### MVP-015 — Standardiser remember_me
| | |
|---|---|
| **Source** | INT-000010 |
| **Owner** | Frontend |
| **Effort** | ~1h |
| **Statut** | ⬜ À faire |
**Problème** : Mélange `rememberMe` (forms) et `remember_me` (API).
**Fichiers** :
- [ ] `apps/web/src/features/auth/types/index.ts`
- [ ] `apps/web/src/features/auth/components/LoginForm.tsx`
**Action** : Standardiser sur `remember_me` (snake_case, match backend).
---
## ✅ Checklist de Validation Finale
> Exécuter ces vérifications après avoir complété TOUTES les tâches
### Vérifications Automatiques
```bash
# 1. TypeScript compile
cd apps/web & & npx tsc --noEmit
# ✅ Expected: Exit 0, no errors
# 2. Go compile
cd veza-backend-api & & go build ./...
# ✅ Expected: Exit 0, no errors
# 3. Tests frontend
cd apps/web & & npm test
# ✅ Expected: All tests pass
# 4. Tests backend
cd veza-backend-api & & go test ./...
# ✅ Expected: All tests pass
# 5. CORS validation
APP_ENV=production CORS_ALLOWED_ORIGINS='' go run ./cmd/api
# ✅ Expected: Fails with clear error
# 6. No deprecated ApiService
grep -r 'ApiService' apps/web/src/
# ✅ Expected: 0 results
# 7. No token fragmentation
grep -r 'auth-storage' apps/web/src/services/
# ✅ Expected: 0 results
```
### Vérifications Manuelles
- [ ] **E2E Auth Flow** :
1. Register nouveau user
2. Logout
3. Login avec ce user
4. Refresh page → toujours connecté
5. Attendre expiration token → refresh fonctionne
6. Logout
- [ ] **No Console 404** :
1. Ouvrir DevTools
2. Naviguer dans l'app (auth, tracks, playlists)
3. Vérifier onglet Network → aucun 404
---
## 📝 Journal de Suivi
### Format d'entrée quotidienne
```markdown
## [DATE]
**Tâches travaillées** : MVP-XXX, MVP-YYY
**Statut** :
- MVP-XXX : ✅ Terminé
- MVP-YYY : 🔄 En cours (50%)
**Blocages** : [description si applicable]
**Prochaine session** : MVP-ZZZ
**Notes** : [observations, décisions]
```
---
### Entrées
2025-12-22 21:56:37 +00:00
## 2025-12-22
**Tâches travaillées** : MVP-001, MVP-002
**Statut** :
- MVP-001 : ✅ Terminé
- MVP-002 : ✅ Terminé
**Blocages** : Aucun. Tâches déjà implémentées.
**Prochaine session** : MVP-003
**Notes** : Implémentation testée avec config production stricte.
---
## 2025-01-27
**Tâches travaillées** : MVP-003
**Statut** :
- MVP-003 : ✅ Terminé
**Changements effectués** :
- Mis à jour tous les `userId: number` et `user_id: number` en `string` dans :
- `trackService.ts` (2 occurrences)
- `roleService.ts` (3 occurrences)
- `avatarService.ts` (2 occurrences)
- `usePlaylistNotifications.ts` (1 occurrence)
- `playlistService.ts` (1 occurrence)
- `trackApi.ts` (1 occurrence)
- `PlaylistSearch.tsx` (2 occurrences)
- Mis à jour les schémas Zod dans `api.ts` et `secure-auth.ts` pour valider UUID avec `z.string().uuid()`
- Corrigé l'erreur TypeScript dans `PlaylistSearch.tsx` (parseInt → string direct)
**Validation** :
- `grep -rn 'id:\s*number' apps/web/src/` → Plus d'occurrences liées à User
- `cd apps/web && npx tsc --noEmit` → ✅ Passe (seules erreurs non liées : variables non utilisées)
**Temps passé** : 2h30
**Prochaine tâche** : MVP-004 (Remove Deprecated ApiService)
**Notes** : Tous les types User utilisent maintenant `id: string` et les schémas Zod valident le format UUID. TypeScript compile sans erreurs liées à User.id.
---
## 2025-01-27 (suite)
**Tâches travaillées** : MVP-004
**Statut** :
- MVP-004 : ✅ Terminé
**Changements effectués** :
- Migré tous les usages de `apiService` vers `apiClient` dans :
- `stores/library.ts` (getLibraryItems, uploadFile, toggleFavorite)
- `stores/chat.ts` (getConversations, createConversation)
- `features/user/components/ProfileForm.tsx` (updateUser)
- `features/library/components/LibraryManager.tsx` (getTracks, deleteTrack)
- `features/library/components/UploadModal.tsx` (uploadTrack)
- `features/chat/components/VirtualizedChatMessages.tsx` (getMessages)
- `features/chat/components/ChatInterface.tsx` (getChatMessages, getChatStats, sendChatMessage)
- Supprimé `apps/web/src/services/api.ts` et `apps/web/src/test/api.test.ts`
- Mis à jour les mocks de tests pour utiliser `apiClient`
**Validation** :
- `grep -rn 'ApiService' apps/web/src/` → ✅ 0 résultats
- `ls apps/web/src/services/api.ts` → ✅ Fichier supprimé
- `cd apps/web && npx tsc --noEmit` → ✅ Passe (seules erreurs non liées : variables non utilisées)
**Temps passé** : 3h30
**Prochaine tâche** : MVP-005 (Implement CSRF Protection)
**Notes** : Tous les appels API utilisent maintenant `apiClient` qui unwrap automatiquement le format `{ success, data }` du backend. Plus aucune référence à `ApiService` .
---
## 2025-01-27 (suite 2)
**Tâches travaillées** : MVP-005
**Statut** :
- MVP-005 : ✅ Terminé
**Changements effectués** :
Backend :
- Créé `veza-backend-api/internal/middleware/csrf.go` :
- Middleware CSRF utilisant Redis pour stocker les tokens
- Ignore GET, HEAD, OPTIONS (méthodes sûres)
- Vérifie X-CSRF-Token header pour POST/PUT/DELETE/PATCH
- Tokens stockés avec TTL de 1h dans Redis
- Créé `veza-backend-api/internal/handlers/csrf.go` :
- Handler pour GET /api/v1/csrf-token
- Génère ou récupère token CSRF pour utilisateur authentifié
- Modifié `veza-backend-api/internal/api/router.go` :
- Ajouté middleware CSRF aux routes protégées
- Route /csrf-token accessible sans vérification CSRF
- Login/register exclus (routes publiques)
Frontend :
- Créé `apps/web/src/services/csrf.ts` :
- Service singleton pour gérer le token CSRF
- Méthodes refreshToken(), getToken(), clearToken()
- Compatibilité avec secure-auth.ts
- Modifié `apps/web/src/services/api/client.ts` :
- Ajouté interceptor pour inclure X-CSRF-Token header
- Appliqué uniquement aux méthodes POST/PUT/DELETE/PATCH
- Exclut la route /csrf-token
- Modifié `apps/web/src/stores/auth.ts` :
- Récupération CSRF après login/register/refreshUser
- Suppression CSRF après logout
- Modifié `apps/web/src/app/App.tsx` :
- Récupération CSRF à l'initialisation si authentifié
**Validation** :
- `cd veza-backend-api && go build ./...` → ✅ Passe
- `cd apps/web && npx tsc --noEmit` → ✅ Passe (erreurs non liées uniquement)
**Temps passé** : 5h30
**Prochaine tâche** : MVP-006 (Standardize Environment Variable Names)
**Notes** : Protection CSRF implémentée avec Redis. Le middleware vérifie uniquement les routes protégées (après authentification), donc login/register fonctionnent sans CSRF. Le token est automatiquement récupéré après authentification et inclus dans toutes les requêtes modifiant l'état.
----
## 2025-01-27 (suite 3)
**Tâches travaillées** : MVP-006
**Statut** :
- MVP-006 : ✅ Terminé
**Changements effectués** :
- Standardisé toutes les variables d'environnement de `VITE_API_BASE_URL` vers `VITE_API_URL` :
- `apps/web/scripts/check_backend.sh` : API_URL utilise maintenant VITE_API_URL
- `apps/web/Dockerfile` : ARG VITE_API_BASE_URL remplacé par VITE_API_URL
- `apps/web/scripts/start_lab.sh` : Variables exportées utilisent VITE_API_URL
- Aussi corrigé VITE_WS_BASE_URL → VITE_WS_URL pour cohérence
**Validation** :
- `grep -rn 'VITE_API_BASE_URL' apps/web/'` → ✅ 0 résultats
- Scripts bash validés syntaxiquement ✅
**Temps passé** : 30 min
2025-12-22 21:58:18 +00:00
**Prochaine tâche** : MVP-008 (Handle Missing Endpoints - Decide and Clean)
2025-12-22 21:56:37 +00:00
**Notes** : Toutes les variables d'environnement sont maintenant standardisées. Le code source utilisait déjà VITE_API_URL, donc la migration était principalement dans les scripts de build et de démarrage.
2025-12-22 21:00:50 +00:00
2025-12-22 21:58:18 +00:00
----
## 2025-01-27 (suite 4)
**Tâches travaillées** : MVP-007
**Statut** :
- MVP-007 : ✅ Terminé
**Changements effectués** :
- Corrigé les chemins d'endpoints dans `apps/web/src/features/profile/services/profileService.ts` :
- `getProfile` : `/users/${userId}/profile` → `/users/${userId}`
- `updateProfile` : `/users/${userId}/profile` → `/users/${userId}`
- `calculateProfileCompletion` : `/users/${userId}/profile/completion` → `/users/${userId}/completion`
- Vérifié le format de réponse du backend :
- GetProfile et UpdateProfile retournent `{ profile: {...} }`
- GetProfileCompletion retourne directement l'objet completion
- Le code frontend gère déjà correctement ces formats
**Validation** :
- `grep -rn '/users/.*/profile' apps/web/src/` → ✅ 0 résultats
- `npx tsc --noEmit` → ✅ Aucune erreur liée à profileService
**Temps passé** : 1h
2025-12-22 22:01:36 +00:00
**Prochaine tâche** : MVP-009 (Fix GetMe Endpoint to Return Full User)
2025-12-22 21:58:18 +00:00
**Notes** : Les endpoints profile correspondent maintenant exactement aux routes backend. Le format de réponse est correctement géré.
2025-12-22 22:01:36 +00:00
----
## 2025-01-27 (suite 5)
**Tâches travaillées** : MVP-008
**Statut** :
- MVP-008 : ✅ Terminé
**Changements effectués** :
- Créé système de feature flags dans `apps/web/src/config/features.ts` :
- Configuration centralisée pour toutes les features non-MVP
- Fonctions `isFeatureEnabled()` et `requireFeature()` pour vérification
- Modifié `apps/web/src/services/2fa-service.ts` :
- Toutes les méthodes vérifient `requireFeature('TWO_FACTOR_AUTH')`
- Ajouté fonction `is2FAEnabled()` pour UI conditionnelle
- Modifié `apps/web/src/features/streaming/services/hlsService.ts` :
- `getHLSStreamInfo()` et `getHLSStreamStatus()` vérifient `requireFeature('HLS_STREAMING')`
- Modifié `apps/web/src/features/playlists/services/playlistService.ts` :
- `addCollaborator()` , `removeCollaborator()` , `updateCollaboratorPermission()` → `requireFeature('PLAYLIST_COLLABORATION')`
- `searchPlaylists()` → `requireFeature('PLAYLIST_SEARCH')`
- `createShareLink()` → `requireFeature('PLAYLIST_SHARE')`
- `getPlaylistRecommendations()` → `requireFeature('PLAYLIST_RECOMMENDATIONS')`
- Modifié `apps/web/src/features/roles/services/roleService.ts` :
- `assignRole()` , `revokeRole()` , `updateRole()` , `deleteRole()` → `requireFeature('ROLE_MANAGEMENT')`
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur liée aux feature flags
- Tous les appels API vers endpoints inexistants sont maintenant protégés par feature flags
**Temps passé** : 3h30
2025-12-22 22:03:46 +00:00
**Prochaine tâche** : MVP-010 (Fix Error Code Type in Zod Schemas)
2025-12-22 22:01:36 +00:00
**Notes** : Toutes les features non-MVP sont maintenant désactivées proprement via feature flags. Les appels API vers endpoints inexistants lanceront une erreur claire au lieu de générer des 404. Le système de feature flags peut être facilement activé quand les endpoints backend seront implémentés.
2025-12-22 22:03:46 +00:00
----
## 2025-01-27 (suite 6)
**Tâches travaillées** : MVP-009
**Statut** :
- MVP-009 : ✅ Terminé
**Changements effectués** :
- Modifié `veza-backend-api/internal/handlers/auth.go` :
- `GetMe()` accepte maintenant `userService *services.UserService` en paramètre
- Récupère l'utilisateur complet depuis la base de données via `userService.GetProfileByID(userUUID)`
- Retourne l'objet User complet au lieu de seulement id, email, role
- Modifié `veza-backend-api/internal/api/router.go` :
- Créé `userService` dans `setupAuthRoutes()`
- Passé `userService` au handler `GetMe(userService)`
**Validation** :
- `go build ./...` → ✅ Build successful
- Handler récupère maintenant tous les champs de l'utilisateur (username, avatar, bio, location, birthdate, gender, is_active, is_verified, is_admin, is_public, last_login_at, created_at, updated_at, etc.)
**Temps passé** : 1h30
2025-12-22 22:05:08 +00:00
**Prochaine tâche** : MVP-011 (Simplify Token Refresh Response Handling)
2025-12-22 22:03:46 +00:00
**Notes** : L'endpoint GetMe retourne maintenant l'objet User complet, permettant au frontend d'afficher toutes les informations utilisateur après login. Le format de réponse correspond exactement au type User du frontend.
2025-12-22 22:05:08 +00:00
----
## 2025-01-27 (suite 7)
**Tâches travaillées** : MVP-010
**Statut** :
- MVP-010 : ✅ Terminé
**Changements effectués** :
- Modifié `apps/web/src/schemas/validation.ts` :
- `apiResponseSchema` : `code: z.string()` → `code: z.number()` (ligne 338)
- `errorSchema` : `code: z.string()` → `code: z.number()` (ligne 354)
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Les comparaisons avec des nombres dans `auth.ts` (error.code === 401, 1001, 1002) fonctionnent correctement
- Les codes d'erreur réseau Axios ('ECONNABORTED', 'ETIMEDOUT') restent des strings, ce qui est correct
**Temps passé** : 30 min
2025-12-22 22:06:52 +00:00
**Prochaine tâche** : MVP-012 (Add Retry Logic for 503/502 Errors)
2025-12-22 22:05:08 +00:00
**Notes** : Les schémas Zod correspondent maintenant au format du backend qui envoie les codes d'erreur comme nombres. Cela permet une validation correcte des réponses d'erreur de l'API.
2025-12-22 22:06:52 +00:00
----
## 2025-01-28
**Tâches travaillées** : MVP-011
**Statut** :
- MVP-011 : ✅ Terminé
**Changements effectués** :
- Modifié `apps/web/src/services/tokenRefresh.ts` :
- Documenté le format correct : `{ success: true, data: { access_token, refresh_token, expires_in } }`
- Supprimé les 3 formats de fallback (lignes 70-84)
- Utilise uniquement `response.data.data.access_token` (format correct)
- Ajouté validation stricte avec message d'erreur détaillé si format inattendu
- Ajouté typage TypeScript pour la réponse
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Code simplifié de ~30 lignes à ~15 lignes pour la logique de parsing
- Messages d'erreur clairs et actionnables
**Temps passé** : 1h
2025-12-22 22:10:52 +00:00
**Prochaine tâche** : MVP-013 (Add Error Correlation with Request IDs)
2025-12-22 22:06:52 +00:00
**Notes** : Le code de refresh token est maintenant beaucoup plus simple et maintenable. Il n'y a plus de logique de fallback complexe, seulement le format documenté du backend. Les erreurs sont claires si le format change.
2025-12-22 22:10:52 +00:00
----
## 2025-01-28 (suite)
**Tâches travaillées** : MVP-012
**Statut** :
- MVP-012 : ✅ Terminé
**Changements effectués** :
- Modifié `apps/web/src/services/api/client.ts` :
- Créé fonction utilitaire `sleep(ms)` pour les délais
- Créé fonction `getRetryDelay(error, attempt, baseDelay)` :
- Vérifie le header `Retry-After` (case-insensitive)
- Utilise exponential backoff sinon : `baseDelay * 2^attempt`
- Modifié l'interceptor de réponse pour retry automatiquement les erreurs 502/503 :
- Maximum 3 retries par requête
- Utilise `_retry502503Count` pour éviter les boucles infinies
- Délai calculé avec `getRetryDelay()` avant chaque retry
- Si tous les retries échouent, parse et rejette l'erreur
**Validation** :
- `npx tsc --noEmit` → ✅ Aucune erreur TypeScript
- Retry logic appliqué uniquement aux erreurs 502/503 (transient errors)
- Header Retry-After respecté si présent dans la réponse
- Exponential backoff : 1s, 2s, 4s entre les retries (si pas de Retry-After)
**Temps passé** : 2h
**Prochaine tâche** : MVP-013 (Add Error Correlation with Request IDs)
**Notes** : Les erreurs transitoires (502/503) sont maintenant automatiquement retentées avec exponential backoff, améliorant la robustesse de l'application face aux problèmes temporaires de réseau ou de services externes. Le header Retry-After est respecté si présent, permettant au backend de contrôler le timing des retries.
2025-12-22 21:00:50 +00:00
---
## 📚 Commandes Utiles
```bash
# Recherche de patterns
grep -rn 'PATTERN' apps/web/src/
grep -rn 'PATTERN' veza-backend-api/
# TypeScript check
cd apps/web & & npx tsc --noEmit
# Go build
cd veza-backend-api & & go build ./...
# Trouver tous les appels API
grep -rn 'apiClient\.\|authApi\.' apps/web/src/
# Trouver toutes les routes backend
grep -rn 'router\.(GET\|POST\|PUT\|DELETE)' veza-backend-api/internal/
# Trouver les variables d'env
grep -rn 'VITE_' apps/web/src/
grep -rn 'os.Getenv' veza-backend-api/
```
---
**Dernière mise à jour** : _En attente de démarrage_
**Prochain milestone** : Compléter PHASE-1 (5 tâches critiques)