diff --git a/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json b/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json new file mode 100644 index 000000000..bf01fa808 --- /dev/null +++ b/VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json @@ -0,0 +1,1097 @@ +{ + "meta": { + "title": "Veza Integration Perfection TodoList", + "description": "TodoList focalisée exclusivement sur la connexion parfaite Backend Go ↔ Frontend React. Ignorer modules Rust.", + "generated_at": "2025-12-25T12:00:00Z", + "version": "2.0.0", + "scope": { + "included": ["apps/web/", "veza-backend-api/"], + "excluded": ["veza-chat-server/", "veza-stream-server/", "veza-common/"] + }, + "target": "Score intégration 10/10 - Connexion parfaite backend/frontend", + "current_score": "6.5/10", + "target_score": "10/10", + "audit_date": "2025-12-25" + }, + "summary": { + "by_priority": { + "P0_blocker": 3, + "P1_critical": 8, + "P2_major": 15, + "P3_minor": 6 + }, + "by_category": { + "INT-CORS": 2, + "INT-AUTH": 4, + "INT-TYPE": 8, + "INT-API": 5, + "INT-ENDPOINT": 6, + "INT-CLEANUP": 4, + "INT-TEST": 2, + "INT-DOC": 1 + }, + "by_side": { + "backend_only": 10, + "frontend_only": 14, + "both_sides": 8 + }, + "estimated_total_hours": 48 + }, + "categories": { + "INT-CORS": "Configuration CORS et origins pour production", + "INT-AUTH": "Authentification, tokens, refresh, CSRF", + "INT-TYPE": "Alignement parfait types TypeScript ↔ Go DTOs", + "INT-API": "Client API, intercepteurs, services, format réponses", + "INT-ENDPOINT": "Endpoints manquants ou avec incohérences", + "INT-CLEANUP": "Suppression duplication, code legacy, standardisation", + "INT-TEST": "Tests d'intégration E2E frontend ↔ backend", + "INT-DOC": "Documentation API OpenAPI/Swagger" + }, + "phases": [ + { + "id": "PHASE-INT-1", + "name": "Production Blockers", + "description": "Problèmes qui empêchent le déploiement en production - À résoudre IMMÉDIATEMENT", + "priority": "P0", + "estimated_hours": 6, + "tasks": ["INT-CORS-001", "INT-CORS-002", "INT-AUTH-001"] + }, + { + "id": "PHASE-INT-2", + "name": "Critical Type Fixes", + "description": "Incohérences de types causant des erreurs runtime", + "priority": "P1", + "estimated_hours": 12, + "tasks": ["INT-TYPE-001", "INT-TYPE-002", "INT-TYPE-003", "INT-TYPE-004", "INT-TYPE-005", "INT-TYPE-006", "INT-TYPE-007", "INT-TYPE-008"] + }, + { + "id": "PHASE-INT-3", + "name": "API Client Standardization", + "description": "Unifier les clients API et corriger les formats", + "priority": "P1", + "estimated_hours": 8, + "tasks": ["INT-API-001", "INT-API-002", "INT-API-003", "INT-API-004", "INT-API-005"] + }, + { + "id": "PHASE-INT-4", + "name": "Auth Flow Perfection", + "description": "Parfaire le flow d'authentification complet", + "priority": "P1", + "estimated_hours": 6, + "tasks": ["INT-AUTH-002", "INT-AUTH-003", "INT-AUTH-004"] + }, + { + "id": "PHASE-INT-5", + "name": "Cleanup Duplication", + "description": "Supprimer tout le code dupliqué et legacy", + "priority": "P2", + "estimated_hours": 6, + "tasks": ["INT-CLEANUP-001", "INT-CLEANUP-002", "INT-CLEANUP-003", "INT-CLEANUP-004"] + }, + { + "id": "PHASE-INT-6", + "name": "Missing Endpoints", + "description": "Implémenter endpoints manquants des deux côtés", + "priority": "P2", + "estimated_hours": 8, + "tasks": ["INT-ENDPOINT-001", "INT-ENDPOINT-002", "INT-ENDPOINT-003", "INT-ENDPOINT-004", "INT-ENDPOINT-005", "INT-ENDPOINT-006"] + }, + { + "id": "PHASE-INT-7", + "name": "Integration Tests & Docs", + "description": "Tests E2E et documentation finale", + "priority": "P2", + "estimated_hours": 4, + "tasks": ["INT-TEST-001", "INT-TEST-002", "INT-DOC-001"] + } + ], + "tasks": [ + { + "id": "INT-CORS-001", + "category": "INT-CORS", + "title": "Configure CORS_ALLOWED_ORIGINS for production", + "description": "En production, si CORS_ALLOWED_ORIGINS est vide, le backend rejette TOUTES les requêtes cross-origin. Cela bloque complètement l'application.", + "priority": "P0", + "priority_rank": 1, + "status": "completed", + "estimated_hours": 1, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/middleware/cors.go", + "veza-backend-api/.env.production", + "veza-backend-api/internal/config/config.go" + ], + "implementation_steps": [ + "Ouvrir veza-backend-api/internal/middleware/cors.go", + "Vérifier la fonction validateCORSConfig() - elle rejette si allowedOrigins vide en prod", + "Créer .env.production si inexistant", + "Ajouter CORS_ALLOWED_ORIGINS=https://app.veza.com,https://www.veza.com", + "Ajouter validation explicite au démarrage avec message clair", + "Tester: ENVIRONMENT=production go run cmd/server/main.go" + ], + "acceptance_criteria": [ + "CORS_ALLOWED_ORIGINS défini dans .env.production", + "Backend démarre sans erreur en mode production", + "Requêtes depuis frontend autorisées", + "Requêtes depuis domaines non autorisés rejetées" + ], + "dependencies": [], + "blocks": ["INT-TEST-001"], + "verification_command": "ENVIRONMENT=production go run cmd/server/main.go" + }, + { + "id": "INT-CORS-002", + "category": "INT-CORS", + "title": "Add preflight request handling validation", + "description": "Vérifier que les requêtes OPTIONS (preflight) sont correctement gérées pour tous les endpoints.", + "priority": "P0", + "priority_rank": 2, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/middleware/cors.go" + ], + "implementation_steps": [ + "Vérifier AllowMethods inclut toutes les méthodes utilisées (GET, POST, PUT, PATCH, DELETE, OPTIONS)", + "Vérifier AllowHeaders inclut tous les headers custom (Authorization, X-CSRF-Token, Content-Type)", + "Ajouter ExposeHeaders pour headers de réponse custom", + "Tester preflight avec curl: curl -X OPTIONS -H 'Origin: http://localhost:3000' http://localhost:8080/api/v1/auth/me" + ], + "acceptance_criteria": [ + "AllowMethods contient toutes les méthodes HTTP utilisées", + "AllowHeaders contient Authorization, X-CSRF-Token, Content-Type", + "Preflight requests retournent 200 avec headers CORS corrects" + ], + "dependencies": ["INT-CORS-001"], + "blocks": [], + "verification_command": "curl -v -X OPTIONS -H 'Origin: http://localhost:3000' http://localhost:8080/api/v1/auth/me" + }, + { + "id": "INT-AUTH-001", + "category": "INT-AUTH", + "title": "Ensure CSRF protection active in production", + "description": "Le middleware CSRF est désactivé si Redis n'est pas disponible. En production, Redis DOIT être disponible et CSRF actif.", + "priority": "P0", + "priority_rank": 3, + "status": "todo", + "estimated_hours": 2, + "side": "both_sides", + "files_to_modify": [ + "veza-backend-api/internal/middleware/csrf.go", + "veza-backend-api/internal/config/config.go", + "apps/web/src/services/csrf.ts" + ], + "implementation_steps": [ + "Backend: Vérifier que CSRF middleware fail-fast si Redis indisponible en prod", + "Backend: Ajouter log explicite quand CSRF activé/désactivé", + "Frontend: Vérifier que csrfService récupère le token avant chaque mutation", + "Frontend: Ajouter retry si token CSRF expiré", + "Tester: Requête POST sans X-CSRF-Token doit retourner 403" + ], + "acceptance_criteria": [ + "Backend refuse de démarrer en prod si Redis indisponible", + "Toutes les requêtes POST/PUT/DELETE/PATCH nécessitent X-CSRF-Token", + "Frontend ajoute automatiquement X-CSRF-Token à toutes les mutations", + "Token refresh automatique si expiré" + ], + "dependencies": ["INT-CORS-001"], + "blocks": ["INT-TEST-001"], + "verification_command": "curl -X POST http://localhost:8080/api/v1/tracks -H 'Authorization: Bearer xxx' (doit retourner 403)" + }, + { + "id": "INT-TYPE-001", + "category": "INT-TYPE", + "title": "Standardize User.id to string everywhere", + "description": "User.id est uuid.UUID (string) côté backend mais parfois number côté frontend. Cela cause des erreurs de comparaison.", + "priority": "P1", + "priority_rank": 4, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/user.ts", + "apps/web/src/types/index.ts", + "apps/web/src/features/auth/types/index.ts" + ], + "implementation_steps": [ + "Rechercher toutes les occurrences de 'id: number' dans types user", + "Remplacer par 'id: string'", + "Vérifier tous les composants qui comparent user.id", + "Mettre à jour les comparaisons: userId === user.id (pas ===)", + "Ajouter commentaire: // UUID from backend - always string", + "Compiler TypeScript pour trouver les erreurs restantes" + ], + "acceptance_criteria": [ + "User.id est string dans tous les fichiers types", + "Aucune erreur TypeScript liée à User.id", + "Comparaisons fonctionnent correctement" + ], + "dependencies": [], + "blocks": ["INT-TYPE-002"], + "verification_command": "cd apps/web && npm run type-check" + }, + { + "id": "INT-TYPE-002", + "category": "INT-TYPE", + "title": "Standardize Track.id to string everywhere", + "description": "Même problème que User.id - Track.id doit être string (UUID) partout.", + "priority": "P1", + "priority_rank": 5, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/track.ts", + "apps/web/src/features/tracks/types/index.ts" + ], + "implementation_steps": [ + "Rechercher 'id: number' dans types track", + "Remplacer par 'id: string'", + "Vérifier composants qui utilisent track.id", + "Compiler TypeScript" + ], + "acceptance_criteria": [ + "Track.id est string dans tous les fichiers", + "Aucune erreur TypeScript" + ], + "dependencies": ["INT-TYPE-001"], + "blocks": [], + "verification_command": "cd apps/web && npm run type-check" + }, + { + "id": "INT-TYPE-003", + "category": "INT-TYPE", + "title": "Standardize Playlist.id to string everywhere", + "description": "Playlist.id doit être string (UUID) partout.", + "priority": "P1", + "priority_rank": 6, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/playlist.ts", + "apps/web/src/features/playlists/types/index.ts" + ], + "implementation_steps": [ + "Rechercher 'id: number' dans types playlist", + "Remplacer par 'id: string'", + "Compiler TypeScript" + ], + "acceptance_criteria": [ + "Playlist.id est string partout", + "Aucune erreur TypeScript" + ], + "dependencies": ["INT-TYPE-001"], + "blocks": [], + "verification_command": "cd apps/web && npm run type-check" + }, + { + "id": "INT-TYPE-004", + "category": "INT-TYPE", + "title": "Create TrackStatus enum aligned with backend", + "description": "Track.status utilise des strings arbitraires. Créer un enum aligné avec le backend.", + "priority": "P1", + "priority_rank": 7, + "status": "todo", + "estimated_hours": 1, + "side": "both_sides", + "files_to_modify": [ + "veza-backend-api/internal/models/track.go", + "apps/web/src/types/track.ts", + "apps/web/src/features/tracks/types/index.ts" + ], + "implementation_steps": [ + "Backend: Vérifier les valeurs possibles de track.status dans models/track.go", + "Frontend: Créer enum TrackStatus avec mêmes valeurs", + "Frontend: Utiliser enum dans type Track", + "Ajouter validation Zod si utilisé" + ], + "acceptance_criteria": [ + "Enum TrackStatus créé avec valeurs: 'draft', 'processing', 'ready', 'error'", + "Type Track utilise TrackStatus au lieu de string", + "Backend et frontend utilisent mêmes valeurs" + ], + "dependencies": ["INT-TYPE-002"], + "blocks": [], + "verification_command": "grep -r 'status' apps/web/src/types/track.ts" + }, + { + "id": "INT-TYPE-005", + "category": "INT-TYPE", + "title": "Create PlaylistVisibility enum aligned with backend", + "description": "Playlist.visibility doit utiliser un enum aligné avec le backend.", + "priority": "P1", + "priority_rank": 8, + "status": "todo", + "estimated_hours": 1, + "side": "both_sides", + "files_to_modify": [ + "veza-backend-api/internal/models/playlist.go", + "apps/web/src/types/playlist.ts" + ], + "implementation_steps": [ + "Backend: Vérifier valeurs de visibility", + "Frontend: Créer enum PlaylistVisibility", + "Utiliser dans type Playlist" + ], + "acceptance_criteria": [ + "Enum créé avec valeurs: 'public', 'private', 'unlisted'", + "Type Playlist utilise l'enum" + ], + "dependencies": ["INT-TYPE-003"], + "blocks": [], + "verification_command": "grep -r 'visibility' apps/web/src/types/playlist.ts" + }, + { + "id": "INT-TYPE-006", + "category": "INT-TYPE", + "title": "Complete ApiError interface with all backend fields", + "description": "L'interface ApiError frontend est incomplète par rapport aux erreurs retournées par le backend.", + "priority": "P1", + "priority_rank": 9, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/api.ts", + "apps/web/src/services/api/client.ts" + ], + "implementation_steps": [ + "Analyser le format d'erreur backend dans handlers/errors.go", + "Mettre à jour interface ApiError avec tous les champs", + "Ajouter: code, message, details, field_errors, request_id", + "Mettre à jour parseApiError() dans client.ts" + ], + "acceptance_criteria": [ + "ApiError contient: code, message, details?, field_errors?, request_id?", + "parseApiError gère tous les formats d'erreur backend", + "Erreurs de validation affichent les champs concernés" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -A 10 'interface ApiError' apps/web/src/types/api.ts" + }, + { + "id": "INT-TYPE-007", + "category": "INT-TYPE", + "title": "Create PaginatedResponse generic type", + "description": "Créer un type générique pour les réponses paginées aligné avec le format backend.", + "priority": "P1", + "priority_rank": 10, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/api.ts" + ], + "implementation_steps": [ + "Analyser format de pagination backend (page, limit, total, items)", + "Créer type générique PaginatedResponse", + "Utiliser dans tous les services qui retournent des listes" + ], + "acceptance_criteria": [ + "PaginatedResponse créé avec: items: T[], total: number, page: number, limit: number, has_more: boolean", + "Utilisé dans tracks, playlists, users list endpoints" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -r 'PaginatedResponse' apps/web/src/" + }, + { + "id": "INT-TYPE-008", + "category": "INT-TYPE", + "title": "Validate AuthResponse matches backend exactly", + "description": "Vérifier que AuthResponse correspond exactement à la réponse de /auth/login.", + "priority": "P1", + "priority_rank": 11, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/features/auth/types/index.ts" + ], + "implementation_steps": [ + "Comparer AuthResponse avec handlers/auth.go LoginResponse", + "Vérifier: access_token, refresh_token, expires_in, token_type, user", + "S'assurer que l'interceptor unwrap correctement" + ], + "acceptance_criteria": [ + "AuthResponse match exactement le format backend", + "Login flow fonctionne sans erreur de type" + ], + "dependencies": ["INT-TYPE-001"], + "blocks": [], + "verification_command": "grep -A 15 'interface AuthResponse' apps/web/src/features/auth/types/index.ts" + }, + { + "id": "INT-API-001", + "category": "INT-API", + "title": "Remove duplicate API client (lib/apiClient.ts)", + "description": "Il existe potentiellement deux clients API. Garder uniquement services/api/client.ts.", + "priority": "P1", + "priority_rank": 12, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/lib/apiClient.ts", + "apps/web/src/services/api/client.ts" + ], + "implementation_steps": [ + "Vérifier si lib/apiClient.ts existe", + "Si oui, lister tous les fichiers qui l'importent", + "Migrer ces imports vers services/api/client.ts", + "Supprimer lib/apiClient.ts", + "Compiler et tester" + ], + "acceptance_criteria": [ + "Un seul client API: services/api/client.ts", + "Aucun import de lib/apiClient", + "Application fonctionne correctement" + ], + "dependencies": [], + "blocks": ["INT-CLEANUP-002"], + "verification_command": "grep -r 'lib/apiClient' apps/web/src/" + }, + { + "id": "INT-API-002", + "category": "INT-API", + "title": "Verify response unwrapping in interceptor", + "description": "Vérifier que l'interceptor unwrap correctement {success: true, data: ...} → data.", + "priority": "P1", + "priority_rank": 13, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts" + ], + "implementation_steps": [ + "Ouvrir services/api/client.ts", + "Vérifier l'interceptor de réponse", + "S'assurer qu'il détecte {success, data} et retourne data", + "S'assurer qu'il gère {success: false, error} correctement", + "Ajouter logs de debug si nécessaire" + ], + "acceptance_criteria": [ + "Interceptor unwrap {success: true, data: X} → X", + "Interceptor throw sur {success: false, error: E}", + "Services reçoivent directement les données sans wrapper" + ], + "dependencies": ["INT-API-001"], + "blocks": [], + "verification_command": "grep -A 30 'response interceptor' apps/web/src/services/api/client.ts" + }, + { + "id": "INT-API-003", + "category": "INT-API", + "title": "Standardize error handling across all services", + "description": "Tous les services API doivent utiliser la même méthode de gestion d'erreurs.", + "priority": "P1", + "priority_rank": 14, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts", + "apps/web/src/features/*/api/*.ts", + "apps/web/src/features/*/services/*.ts" + ], + "implementation_steps": [ + "Créer fonction handleApiError() centralisée", + "Standardiser le format d'erreur retourné", + "Mettre à jour tous les services pour utiliser cette fonction", + "Ajouter types pour les erreurs" + ], + "acceptance_criteria": [ + "Une seule fonction handleApiError", + "Tous les services l'utilisent", + "Erreurs ont un format prévisible" + ], + "dependencies": ["INT-TYPE-006"], + "blocks": [], + "verification_command": "grep -r 'handleApiError' apps/web/src/" + }, + { + "id": "INT-API-004", + "category": "INT-API", + "title": "Add request timeout configuration per endpoint type", + "description": "Configurer des timeouts différents pour uploads (long) vs requêtes normales.", + "priority": "P2", + "priority_rank": 15, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts", + "apps/web/src/features/tracks/api/uploadApi.ts" + ], + "implementation_steps": [ + "Définir timeouts: default 10s, upload 5min, long-polling 30s", + "Permettre override par requête", + "Appliquer timeout long pour uploads" + ], + "acceptance_criteria": [ + "Timeout par défaut: 10s", + "Upload timeout: 5min", + "Configurable par requête" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -r 'timeout' apps/web/src/services/api/" + }, + { + "id": "INT-API-005", + "category": "INT-API", + "title": "Add retry logic for 429 rate limit responses", + "description": "Détecter les réponses 429 et retry avec backoff basé sur Retry-After header.", + "priority": "P2", + "priority_rank": 16, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts" + ], + "implementation_steps": [ + "Ajouter 429 aux status codes retryables", + "Lire header Retry-After si présent", + "Utiliser Retry-After comme délai, sinon exponential backoff", + "Limiter à 3 retries pour 429" + ], + "acceptance_criteria": [ + "429 déclenche retry automatique", + "Respecte Retry-After header", + "Max 3 retries pour rate limit" + ], + "dependencies": ["INT-API-002"], + "blocks": [], + "verification_command": "grep -r 'retryableStatusCodes' apps/web/src/services/api/" + }, + { + "id": "INT-AUTH-002", + "category": "INT-AUTH", + "title": "Remove duplicate auth store if exists", + "description": "Vérifier s'il y a deux stores auth et garder uniquement features/auth/store/authStore.ts.", + "priority": "P1", + "priority_rank": 17, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/stores/auth.ts", + "apps/web/src/features/auth/store/authStore.ts" + ], + "implementation_steps": [ + "Vérifier si stores/auth.ts existe", + "Comparer avec features/auth/store/authStore.ts", + "Migrer les imports vers le nouveau store", + "Supprimer l'ancien store", + "Tester auth flow complet" + ], + "acceptance_criteria": [ + "Un seul store auth", + "Tous les composants utilisent le même store", + "Auth flow fonctionne" + ], + "dependencies": [], + "blocks": ["INT-CLEANUP-003"], + "verification_command": "grep -r 'from.*stores/auth' apps/web/src/" + }, + { + "id": "INT-AUTH-003", + "category": "INT-AUTH", + "title": "Verify refresh token flow handles edge cases", + "description": "S'assurer que le refresh token gère: expiration, révocation, erreurs réseau.", + "priority": "P1", + "priority_rank": 18, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts", + "apps/web/src/features/auth/store/authStore.ts" + ], + "implementation_steps": [ + "Vérifier que 401 sur /auth/refresh redirige vers login", + "Vérifier que les requêtes en attente sont rejouées après refresh", + "Vérifier protection contre boucle infinie", + "Ajouter logs pour debug" + ], + "acceptance_criteria": [ + "401 sur refresh → logout + redirect login", + "Requêtes en queue rejouées après refresh réussi", + "Pas de boucle infinie possible" + ], + "dependencies": ["INT-AUTH-002"], + "blocks": [], + "verification_command": "grep -A 20 'refreshToken' apps/web/src/services/api/client.ts" + }, + { + "id": "INT-AUTH-004", + "category": "INT-AUTH", + "title": "Add token expiration pre-check", + "description": "Vérifier l'expiration du token AVANT d'envoyer une requête pour éviter 401 inutiles.", + "priority": "P2", + "priority_rank": 19, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/api/client.ts", + "apps/web/src/services/tokenStorage.ts" + ], + "implementation_steps": [ + "Décoder le JWT pour extraire exp", + "Comparer avec Date.now() - marge de 60s", + "Si proche expiration, refresh proactivement", + "Ajouter fonction isTokenExpiringSoon()" + ], + "acceptance_criteria": [ + "Token refresh proactif 60s avant expiration", + "Moins de requêtes 401", + "Performance améliorée" + ], + "dependencies": ["INT-AUTH-003"], + "blocks": [], + "verification_command": "grep -r 'isTokenExpiring' apps/web/src/" + }, + { + "id": "INT-CLEANUP-001", + "category": "INT-CLEANUP", + "title": "Remove all unused API service files", + "description": "Identifier et supprimer les fichiers de services API non utilisés.", + "priority": "P2", + "priority_rank": 20, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/services/*.ts" + ], + "implementation_steps": [ + "Lister tous les fichiers dans services/", + "Pour chaque fichier, vérifier s'il est importé quelque part", + "Supprimer les fichiers non importés", + "Commit avec liste des fichiers supprimés" + ], + "acceptance_criteria": [ + "Tous les fichiers services/ sont utilisés", + "Aucun code mort" + ], + "dependencies": ["INT-API-001"], + "blocks": [], + "verification_command": "find apps/web/src/services -name '*.ts' -exec basename {} \\;" + }, + { + "id": "INT-CLEANUP-002", + "category": "INT-CLEANUP", + "title": "Consolidate type definitions in single location", + "description": "Tous les types partagés doivent être dans types/ et non dupliqués dans features/.", + "priority": "P2", + "priority_rank": 21, + "status": "todo", + "estimated_hours": 2, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/*.ts", + "apps/web/src/features/*/types/*.ts" + ], + "implementation_steps": [ + "Identifier les types dupliqués entre types/ et features/*/types/", + "Garder une seule définition dans types/", + "Mettre à jour les imports", + "Features peuvent avoir des types spécifiques, pas des duplications" + ], + "acceptance_criteria": [ + "Pas de duplication de types", + "Types partagés dans types/", + "Types feature-specific dans features/*/types/" + ], + "dependencies": ["INT-TYPE-001"], + "blocks": [], + "verification_command": "grep -r 'interface User' apps/web/src/ | wc -l" + }, + { + "id": "INT-CLEANUP-003", + "category": "INT-CLEANUP", + "title": "Remove legacy hooks using old API client", + "description": "Supprimer les hooks qui utilisent encore l'ancien client API.", + "priority": "P2", + "priority_rank": 22, + "status": "todo", + "estimated_hours": 1.5, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/hooks/api/*.ts" + ], + "implementation_steps": [ + "Identifier hooks utilisant l'ancien client", + "Migrer vers nouveau client ou supprimer si inutilisés", + "Mettre à jour composants qui les utilisent" + ], + "acceptance_criteria": [ + "Tous les hooks utilisent le nouveau client API", + "Aucun import de l'ancien client" + ], + "dependencies": ["INT-API-001", "INT-AUTH-002"], + "blocks": [], + "verification_command": "grep -r 'lib/apiClient' apps/web/src/hooks/" + }, + { + "id": "INT-CLEANUP-004", + "category": "INT-CLEANUP", + "title": "Add barrel exports for clean imports", + "description": "Créer des fichiers index.ts pour faciliter les imports.", + "priority": "P3", + "priority_rank": 23, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/types/index.ts", + "apps/web/src/services/api/index.ts" + ], + "implementation_steps": [ + "Créer index.ts dans types/ qui exporte tout", + "Créer index.ts dans services/api/ qui exporte client et services", + "Mettre à jour imports pour utiliser barrels" + ], + "acceptance_criteria": [ + "Import possible via '@/types' et '@/services/api'", + "Imports plus propres dans le code" + ], + "dependencies": ["INT-CLEANUP-002"], + "blocks": [], + "verification_command": "cat apps/web/src/types/index.ts" + }, + { + "id": "INT-ENDPOINT-001", + "category": "INT-ENDPOINT", + "title": "Add frontend service for GET /api/v1/sessions/stats", + "description": "Le backend expose cet endpoint mais le frontend ne l'utilise pas.", + "priority": "P2", + "priority_rank": 24, + "status": "todo", + "estimated_hours": 1, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/src/features/sessions/api/sessionsApi.ts" + ], + "implementation_steps": [ + "Créer fonction getSessionStats() dans sessionsApi.ts", + "Définir type SessionStats aligné avec backend", + "Ajouter hook useSessionStats() si nécessaire" + ], + "acceptance_criteria": [ + "sessionsApi.getSessionStats() existe", + "Type SessionStats défini", + "Endpoint accessible depuis frontend" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -r 'sessions/stats' apps/web/src/" + }, + { + "id": "INT-ENDPOINT-002", + "category": "INT-ENDPOINT", + "title": "Implement backend GET /api/v1/users/search", + "description": "Le frontend appelle cet endpoint mais il n'existe pas côté backend.", + "priority": "P2", + "priority_rank": 25, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/api/router.go", + "veza-backend-api/internal/handlers/users.go" + ], + "implementation_steps": [ + "Ajouter route GET /api/v1/users/search dans router.go", + "Créer handler SearchUsers dans handlers/users.go", + "Paramètres: q (query), limit, offset", + "Retourner liste d'utilisateurs paginée" + ], + "acceptance_criteria": [ + "Endpoint GET /api/v1/users/search existe", + "Recherche par username et display_name", + "Pagination fonctionnelle" + ], + "dependencies": [], + "blocks": [], + "verification_command": "curl 'http://localhost:8080/api/v1/users/search?q=test'" + }, + { + "id": "INT-ENDPOINT-003", + "category": "INT-ENDPOINT", + "title": "Implement backend GET /api/v1/tracks/search", + "description": "Le frontend appelle cet endpoint mais il n'existe pas côté backend.", + "priority": "P2", + "priority_rank": 26, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/api/router.go", + "veza-backend-api/internal/handlers/tracks.go" + ], + "implementation_steps": [ + "Ajouter route GET /api/v1/tracks/search dans router.go", + "Créer handler SearchTracks dans handlers/tracks.go", + "Paramètres: q (query), genre, limit, offset", + "Retourner liste de tracks paginée" + ], + "acceptance_criteria": [ + "Endpoint GET /api/v1/tracks/search existe", + "Recherche par title et genre", + "Pagination fonctionnelle" + ], + "dependencies": [], + "blocks": [], + "verification_command": "curl 'http://localhost:8080/api/v1/tracks/search?q=test'" + }, + { + "id": "INT-ENDPOINT-004", + "category": "INT-ENDPOINT", + "title": "Implement backend GET /api/v1/playlists/search", + "description": "Le frontend appelle cet endpoint mais il n'existe pas côté backend.", + "priority": "P2", + "priority_rank": 27, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/api/router.go", + "veza-backend-api/internal/handlers/playlists.go" + ], + "implementation_steps": [ + "Ajouter route GET /api/v1/playlists/search dans router.go", + "Créer handler SearchPlaylists dans handlers/playlists.go", + "Paramètres: q (query), visibility, limit, offset", + "Retourner liste de playlists paginée" + ], + "acceptance_criteria": [ + "Endpoint GET /api/v1/playlists/search existe", + "Recherche par name et description", + "Filtre par visibility" + ], + "dependencies": [], + "blocks": [], + "verification_command": "curl 'http://localhost:8080/api/v1/playlists/search?q=test'" + }, + { + "id": "INT-ENDPOINT-005", + "category": "INT-ENDPOINT", + "title": "Implement backend playlist collaborator endpoints", + "description": "Les endpoints de gestion des collaborateurs de playlist sont appelés par le frontend mais n'existent pas.", + "priority": "P2", + "priority_rank": 28, + "status": "todo", + "estimated_hours": 3, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/api/router.go", + "veza-backend-api/internal/handlers/playlists.go" + ], + "implementation_steps": [ + "Ajouter POST /api/v1/playlists/:id/collaborators", + "Ajouter DELETE /api/v1/playlists/:id/collaborators/:userId", + "Ajouter PUT /api/v1/playlists/:id/collaborators/:userId", + "Implémenter handlers correspondants", + "Ajouter validation des permissions" + ], + "acceptance_criteria": [ + "3 endpoints collaborators fonctionnels", + "Seul le owner peut gérer les collaborateurs", + "Collaborators peuvent être ajoutés/supprimés/mis à jour" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -r 'collaborators' veza-backend-api/internal/api/router.go" + }, + { + "id": "INT-ENDPOINT-006", + "category": "INT-ENDPOINT", + "title": "Implement backend conversation management endpoints", + "description": "DELETE /api/v1/conversations/:id et endpoints participants manquants.", + "priority": "P3", + "priority_rank": 29, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/internal/api/router.go", + "veza-backend-api/internal/handlers/conversations.go" + ], + "implementation_steps": [ + "Ajouter DELETE /api/v1/conversations/:id", + "Ajouter POST /api/v1/conversations/:id/participants", + "Ajouter DELETE /api/v1/conversations/:id/participants/:userId", + "Implémenter handlers" + ], + "acceptance_criteria": [ + "Conversations peuvent être supprimées par le créateur", + "Participants peuvent être ajoutés/supprimés" + ], + "dependencies": [], + "blocks": [], + "verification_command": "grep -r 'conversations' veza-backend-api/internal/api/router.go" + }, + { + "id": "INT-TEST-001", + "category": "INT-TEST", + "title": "Create E2E test for complete auth flow", + "description": "Test Playwright pour: register → verify email → login → refresh → logout.", + "priority": "P2", + "priority_rank": 30, + "status": "todo", + "estimated_hours": 3, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/e2e/auth-flow.spec.ts" + ], + "implementation_steps": [ + "Créer fichier e2e/auth-flow.spec.ts", + "Test: register avec email valide", + "Test: login et vérification du token", + "Test: refresh token automatique", + "Test: logout et redirection" + ], + "acceptance_criteria": [ + "Tests couvrent le flow auth complet", + "Tests passent avec backend réel", + "CI/CD peut exécuter ces tests" + ], + "dependencies": ["INT-CORS-001", "INT-AUTH-001"], + "blocks": [], + "verification_command": "cd apps/web && npx playwright test auth-flow" + }, + { + "id": "INT-TEST-002", + "category": "INT-TEST", + "title": "Create E2E test for CRUD operations", + "description": "Test Playwright pour: create track → update → delete, create playlist → add tracks → delete.", + "priority": "P2", + "priority_rank": 31, + "status": "todo", + "estimated_hours": 3, + "side": "frontend_only", + "files_to_modify": [ + "apps/web/e2e/crud-operations.spec.ts" + ], + "implementation_steps": [ + "Créer fichier e2e/crud-operations.spec.ts", + "Test: CRUD complet sur tracks", + "Test: CRUD complet sur playlists", + "Test: ajout de tracks à une playlist" + ], + "acceptance_criteria": [ + "Tests couvrent CRUD tracks et playlists", + "Tests passent avec backend réel", + "Données de test nettoyées après exécution" + ], + "dependencies": ["INT-TEST-001"], + "blocks": [], + "verification_command": "cd apps/web && npx playwright test crud-operations" + }, + { + "id": "INT-DOC-001", + "category": "INT-DOC", + "title": "Generate OpenAPI/Swagger documentation", + "description": "Générer une documentation OpenAPI complète pour tous les endpoints.", + "priority": "P3", + "priority_rank": 32, + "status": "todo", + "estimated_hours": 2, + "side": "backend_only", + "files_to_modify": [ + "veza-backend-api/docs/swagger.yaml", + "veza-backend-api/cmd/server/main.go" + ], + "implementation_steps": [ + "Installer swag: go install github.com/swaggo/swag/cmd/swag@latest", + "Ajouter annotations Swagger aux handlers", + "Générer docs: swag init -g cmd/server/main.go", + "Exposer /docs endpoint avec Swagger UI" + ], + "acceptance_criteria": [ + "swagger.yaml généré", + "Swagger UI accessible à /docs", + "Tous les endpoints documentés" + ], + "dependencies": [], + "blocks": [], + "verification_command": "curl http://localhost:8080/docs" + } + ], + "integration_matrix": { + "endpoints_analysis": [], + "type_mismatches": [], + "duplicate_code": [], + "missing_frontend_calls": [], + "missing_backend_routes": [] + }, + "risk_register": [ + { + "id": "RISK-INT-001", + "risk": "CORS bloque toutes les requêtes en production si CORS_ALLOWED_ORIGINS vide", + "severity": "critical", + "probability": "certain", + "impact": "Application totalement inaccessible", + "mitigation_tasks": ["INT-CORS-001", "INT-CORS-002"], + "owner": "backend" + }, + { + "id": "RISK-INT-002", + "risk": "CSRF désactivé en production si Redis indisponible", + "severity": "critical", + "probability": "possible", + "impact": "Vulnérabilité de sécurité majeure", + "mitigation_tasks": ["INT-AUTH-001"], + "owner": "backend" + }, + { + "id": "RISK-INT-003", + "risk": "Incohérences de types causent des erreurs runtime imprévisibles", + "severity": "high", + "probability": "certain", + "impact": "Bugs intermittents difficiles à débugger", + "mitigation_tasks": ["INT-TYPE-001", "INT-TYPE-002", "INT-TYPE-003"], + "owner": "frontend" + }, + { + "id": "RISK-INT-004", + "risk": "Duplication de code rend la maintenance difficile", + "severity": "medium", + "probability": "certain", + "impact": "Bugs par désynchronisation, confusion des développeurs", + "mitigation_tasks": ["INT-API-001", "INT-AUTH-002", "INT-CLEANUP-001"], + "owner": "frontend" + } + ], + "validation_checklist": { + "pre_deployment": [ + {"check": "CORS_ALLOWED_ORIGINS configuré pour production", "task_id": "INT-CORS-001", "verified": false}, + {"check": "CSRF activé avec Redis", "task_id": "INT-AUTH-001", "verified": false}, + {"check": "Tous les IDs sont des strings (UUID)", "task_ids": ["INT-TYPE-001", "INT-TYPE-002", "INT-TYPE-003"], "verified": false}, + {"check": "Un seul client API utilisé", "task_id": "INT-API-001", "verified": false}, + {"check": "Un seul store auth utilisé", "task_id": "INT-AUTH-002", "verified": false} + ], + "integration_tests": [ + {"test": "Auth flow complet E2E", "task_id": "INT-TEST-001", "passed": false}, + {"test": "CRUD operations E2E", "task_id": "INT-TEST-002", "passed": false} + ] + }, + "progress_tracking": { + "total_tasks": 32, + "completed": 1, + "in_progress": 0, + "todo": 31, + "blocked": 0, + "completion_percentage": 3, + "last_updated": "2025-01-27T12:00:00Z", + "estimated_completion_date": null, + "estimated_hours_remaining": 47 + } +}