17 KiB
đŻ 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 |
|---|---|
| Tùches complétées | 0 / 15 |
| Phase actuelle | PHASE-1 (Critical) |
| Progression globale | ââââââââââ 0% |
| DerniÚre mise à jour | non démarré |
Progression par Phase
| Phase | Statut | Progression |
|---|---|---|
| PHASE-1 â Bloquants Critiques | đŽ Ă faire | 0/5 |
| PHASE-2 â Alignement API | âȘ En attente | 0/5 |
| 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 |
| Statut | ⏠à faire |
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.godocker-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 :
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 :
# 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 :
- Serveur refuse de démarrer si CORS vide en prod
- Message d'erreur clair et actionnable
- Documentation mise Ă jour
MVP-002 â Unifier le Stockage des Tokens
| Source | INT-000002 |
| Owner | Frontend |
| Effort | ~4h |
| Statut | ⏠à faire |
ProblÚme : 3 mécanismes de stockage de tokens qui se désynchronisent (TokenStorage, Zustand, token-manager).
Fichiers Ă modifier :
apps/web/src/stores/auth.tsapps/web/src/utils/token-manager.tsâ SUPPRIMERapps/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 :
# 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 :
- Seul
TokenStoragegÚre les tokens - Aucune référence token dans Zustand
token-manager.tssupprimé- Auth persiste aprÚs reload
MVP-003 â Corriger le Type User.id (string partout)
| Source | INT-000003 |
| Owner | Frontend |
| Effort | ~3h |
| Statut | ⏠à faire |
ProblĂšme : Backend envoie UUID (string) mais certains types frontend utilisent number.
Fichiers Ă modifier :
apps/web/src/features/auth/types/index.ts(L8)apps/web/src/types/api.ts(vérifier)apps/web/src/schemas/validation.ts
Ătapes :
1. [ ] Trouver tous les id: number :
grep -rn 'id:\s*number' apps/web/src/ --include='*.ts' --include='*.tsx'
2. [ ] Remplacer chaque occurrence par id: string
3. [ ] Mettre Ă jour les schemas Zod :
id: z.string().uuid()
4. [ ] Compiler TypeScript :
cd apps/web && npx tsc --noEmit
5. [ ] Corriger toutes les erreurs de type
Validation :
# 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 :
- Tous les types User utilisent
id: string - Schemas Zod valident le format UUID
- TypeScript compile sans erreurs User.id
MVP-004 â Supprimer ApiService Deprecated
| Source | INT-000004 |
| Owner | Frontend |
| Effort | ~4h |
| Dépendances | MVP-002 |
| Statut | ⏠à faire |
ProblÚme : ApiService deprecated attend un format de réponse différent du backend.
Fichier Ă supprimer :
apps/web/src/services/api.tsâ SUPPRIMER
Ătapes :
1. [ ] Trouver tous les usages :
grep -rn 'ApiService\|apiService' apps/web/src/
2. [ ] Migrer chaque usage :
âââââââââââââââââââââââŹââââââââââââââââââââââ
â Ancien â Nouveau â
âââââââââââââââââââââââŒââââââââââââââââââââââ€
â apiService.login() â authApi.login() â
â apiService.register()â authApi.register() â
â apiService.getUser()â apiClient.get() â
â apiService.refresh()â authApi.refresh() â
âââââââââââââââââââââââŽââââââââââââââââââââââ
3. [ ] Mettre Ă jour les imports dans chaque fichier
4. [ ] Supprimer apps/web/src/services/api.ts
5. [ ] Vérifier qu'aucune référence ne reste :
grep -rn 'ApiService' apps/web/src/
Validation :
# 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 :
- Classe
ApiServiceentiÚrement supprimée - Tous les appels API utilisent
apiClientou modules typés - Aucune régression sur auth/user
MVP-005 â ImplĂ©menter la Protection CSRF
| Source | INT-000005 |
| Owner | Backend + Frontend |
| Effort | ~6h |
| Dépendances | MVP-001 |
| Statut | ⏠à faire |
ProblÚme : Aucune protection CSRF. Vulnérable aux attaques cross-site.
Fichiers à créer/modifier :
Backend :
veza-backend-api/internal/middleware/csrf.goâ CRĂERveza-backend-api/internal/handlers/csrf.goâ CRĂERveza-backend-api/internal/api/router.go
Frontend :
apps/web/src/services/csrf.tsapps/web/src/services/api/client.ts
Ătapes Backend :
1. [ ] Créer middleware CSRF :
func CSRFMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method == "GET" || c.Request.Method == "OPTIONS" {
c.Next()
return
}
token := c.GetHeader("X-CSRF-Token")
sessionToken := getSessionCSRFToken(c)
if token == "" || token != sessionToken {
c.AbortWithStatusJSON(403, gin.H{"error": "Invalid CSRF token"})
return
}
c.Next()
}
}
2. [ ] Créer endpoint GET /api/v1/csrf-token
3. [ ] Appliquer middleware au router (exclure login/register)
Ătapes Frontend :
4. [ ] Implémenter csrf.ts :
async refreshToken(): Promise<void> {
const response = await fetch('/api/v1/csrf-token', {
credentials: 'include'
});
const data = await response.json();
this.token = data.csrf_token;
}
5. [ ] Ajouter interceptor dans apiClient :
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) {
config.headers['X-CSRF-Token'] = csrfService.getToken();
}
6. [ ] Fetch CSRF token Ă l'initialisation de l'app
Tests manuels :
- POST sans token CSRF â 403
- POST avec token CSRF valide â SuccĂšs
- GET fonctionne sans token CSRF
- Login/register fonctionnent (exclus du CSRF)
CritĂšres d'acceptation :
- Endpoint CSRF retourne un token
- Tous les POST/PUT/DELETE incluent X-CSRF-Token
- RequĂȘtes sans token valide rejetĂ©es (403)
- Login/register toujours fonctionnels
đ 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 |
| Statut | ⏠à faire |
ProblÚme : Mélange VITE_API_BASE_URL et VITE_API_URL.
Fichiers :
apps/web/scripts/check_backend.shapps/web/Dockerfileapps/web/.env.example
Ătapes :
1. [ ] Trouver toutes les références :
grep -rn 'VITE_API_BASE_URL' apps/web/
2. [ ] Remplacer par VITE_API_URL
3. [ ] Mettre Ă jour .env.example
Validation :
grep -rn 'VITE_API_BASE_URL' apps/web/ # 0 résultats
MVP-007 â Corriger les Paths du Profile
| Source | INT-000008 |
| Owner | Frontend |
| Effort | ~2h |
| Statut | ⏠à faire |
ProblĂšme : Frontend appelle /users/:userId/profile, backend attend /users/:id.
Fichier :
apps/web/src/features/profile/services/profileService.ts
Changements :
GET /api/v1/users/${userId}/profile â GET /api/v1/users/${userId}
PUT /api/v1/users/${userId}/profile â PUT /api/v1/users/${userId}
Tests manuels :
- Page profil se charge
- Modification profil sauvegarde
MVP-008 â DĂ©sactiver les Features Non-MVP
| Source | INT-000006 |
| Owner | Frontend + Backend |
| Effort | ~4h |
| Statut | ⏠à faire |
ProblĂšme : 18 appels frontend vers des endpoints inexistants.
Stratégie MVP : Désactiver proprement via feature flags.
Features à désactiver :
| Feature | Fichier | Action |
|---|---|---|
| 2FA | 2fa-service.ts |
Désactiver/commenter |
| Playlist Collab | playlistService.ts |
Masquer UI |
| HLS Streaming | hlsService.ts |
Stub/désactiver |
| Role Management | roleService.ts |
Masquer UI admin |
| Notifications | notificationsApi.ts |
Désactiver |
Ătapes :
1. [ ] Créer config feature flags :
const FEATURES = {
TWO_FACTOR_AUTH: false,
PLAYLIST_COLLABORATION: false,
HLS_STREAMING: false,
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 |
| Statut | ⏠à faire |
ProblĂšme : GET /auth/me retourne seulement id, email, role au lieu du user complet.
Fichier :
veza-backend-api/internal/handlers/auth.go(L369-L373)
Changement :
// Avant : retourne données du context
// AprĂšs : fetch user complet depuis la DB et retourne UserResponse
Test :
curl -H "Authorization: Bearer $TOKEN" /api/v1/auth/me
# Doit retourner: id, email, username, avatar, role, created_at, etc.
MVP-010 â Corriger le Type Error Code dans Zod
| Source | INT-000009 |
| Owner | Frontend |
| Effort | ~1h |
| Statut | ⏠à faire |
ProblĂšme : Backend envoie code: number, Zod attend code: string.
Fichier :
apps/web/src/schemas/validation.ts(L338)
Changement :
// Avant
code: z.string()
// AprĂšs
code: z.number()
đ§ 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 |
| Statut | ⏠à faire |
ProblÚme : 3 formats de réponse différents gérés pour token refresh.
Fichier :
apps/web/src/services/tokenRefresh.ts(L70-L84)
Action : Supprimer les fallbacks, garder uniquement :
// Format attendu : { success: true, data: { access_token, refresh_token, expires_in } }
MVP-012 â Ajouter Retry Logic 502/503
| Source | INT-000012 |
| Owner | Frontend |
| Effort | ~3h |
| Statut | ⏠à faire |
ProblÚme : Erreurs transitoires causent un échec immédiat.
Fichier :
apps/web/src/services/api/client.ts
Implémentation :
async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
if (!isRetryableError(error)) throw error;
await sleep(baseDelay * Math.pow(2, attempt));
}
}
throw new Error('Max retries exceeded');
}
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.tsapps/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
# 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 :
- Register nouveau user
- Logout
- Login avec ce user
- Refresh page â toujours connectĂ©
- Attendre expiration token â refresh fonctionne
- Logout
-
No Console 404 :
- Ouvrir DevTools
- Naviguer dans l'app (auth, tracks, playlists)
- VĂ©rifier onglet Network â aucun 404
đ Journal de Suivi
Format d'entrée quotidienne
## [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
Aucune entrée pour le moment. Commencer par MVP-001.
đ Commandes Utiles
# 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)