{
  "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": "completed",
      "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": "completed",
      "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": "completed",
      "completed_at": "2025-01-27T12:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T12:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T13:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T13:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T13:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T13:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T14:00:00Z",
      "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<T>",
        "Utiliser dans tous les services qui retournent des listes"
      ],
      "acceptance_criteria": [
        "PaginatedResponse<T> 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": "completed",
      "completed_at": "2025-01-27T14:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T14:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T14:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T15:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T15:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T15:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T15:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T16:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T16:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T16:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T16:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T17:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T17:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T17:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T17:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T18:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T18:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T18:30:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T18:45:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T19:00:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T19:15:00Z",
      "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": "completed",
      "completed_at": "2025-01-27T19:30:00Z",
      "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": 32,
    "in_progress": 0,
    "todo": 0,
    "blocked": 0,
    "completion_percentage": 100,
    "last_updated": "2025-01-27T19:30:00Z",
    "estimated_completion_date": null,
    "estimated_hours_remaining": 0.0
  }
}
