{ "_meta": { "project": "Veza/Talas", "version": "0.101-MVP", "created": "2025-01-28", "last_updated": "2025-12-28T11:19:17Z", "total_tasks": 156, "completed_tasks": 1, "in_progress_task": null, "current_phase": "PHASE_0", "estimated_total_hours": 1480, "hours_completed": 6 }, "_instructions": { "how_to_use": "Ce fichier est lu et modifié automatiquement par le prompt Cursor", "status_values": ["pending", "in_progress", "completed", "blocked", "skipped"], "priority_order": ["P0", "P1", "P2", "P3"], "next_task_logic": "Prendre la première tâche 'pending' dont toutes les dépendances sont 'completed'" }, "tasks": [ { "id": "T0-001", "phase": "PHASE_0", "type": "FIX", "domain": "BACKEND", "title": "Corriger erreurs compilation Go", "description": "Résoudre toutes les erreurs de compilation dans le backend Go", "priority": "P0", "status": "completed", "estimated_hours": 6, "actual_hours": 1, "started_at": "2025-12-28T11:19:17Z", "completed_at": "2025-12-28T11:19:17Z", "dependencies": [], "acceptance_criteria": [ "go build ./... réussit sans erreur", "go vet ./... retourne 0 warnings critiques", "Aucune erreur de type dans les handlers" ], "files": { "to_check": ["veza-backend-api/"], "to_modify": ["veza-backend-api/go.mod", "veza-backend-api/go.sum"], "created": [] }, "commands": { "verify": ["cd veza-backend-api && go build ./...", "cd veza-backend-api && go vet ./..."], "test": ["cd veza-backend-api && go test ./... -short"] }, "implementation_notes": "Vérification complète effectuée: go build, go vet, go mod verify et go mod tidy tous réussis sans erreur. Le code compile déjà correctement, aucune correction nécessaire.", "blockers": [] }, { "id": "T0-002", "phase": "PHASE_0", "type": "FIX", "domain": "RUST", "title": "Corriger erreurs compilation Rust", "description": "Résoudre toutes les erreurs de compilation dans les modules Rust", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": [], "acceptance_criteria": [ "cargo build --release réussit pour chat/", "cargo build --release réussit pour streaming/", "cargo clippy ne retourne aucune erreur" ], "files": { "to_check": ["rust/chat/", "rust/streaming/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd rust/chat && cargo build", "cd rust/streaming && cargo build"], "test": ["cd rust/chat && cargo test", "cd rust/streaming && cargo test"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-003", "phase": "PHASE_0", "type": "FIX", "domain": "FRONTEND", "title": "Corriger erreurs TypeScript/React", "description": "Résoudre toutes les erreurs TypeScript et de build React", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": [], "acceptance_criteria": [ "npm run build réussit sans erreur", "npm run lint retourne 0 erreurs", "npm run typecheck réussit" ], "files": { "to_check": ["frontend/src/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd frontend && npm run build", "cd frontend && npm run lint"], "test": ["cd frontend && npm run test -- --run"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-004", "phase": "PHASE_0", "type": "CONFIG", "domain": "DEVOPS", "title": "Valider Docker Compose", "description": "S'assurer que tous les services Docker démarrent correctement", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-001", "T0-002", "T0-003"], "acceptance_criteria": [ "docker-compose up -d démarre tous les services", "Healthchecks passent pour tous les containers", "Pas d'erreurs critiques dans les logs" ], "files": { "to_check": ["docker-compose.yml", "docker-compose.dev.yml"], "to_modify": [], "created": [] }, "commands": { "verify": ["docker-compose config", "docker-compose up -d", "docker-compose ps"], "test": ["docker-compose logs --tail=50"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-005", "phase": "PHASE_0", "type": "CONFIG", "domain": "DATABASE", "title": "Valider migrations PostgreSQL", "description": "S'assurer que toutes les migrations s'appliquent correctement", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-004"], "acceptance_criteria": [ "Migrations up s'appliquent sans erreur", "Migrations down fonctionnent (rollback)", "Schéma cohérent avec ORIGIN_DATABASE_SCHEMA.md" ], "files": { "to_check": ["backend/migrations/"], "to_modify": [], "created": [] }, "commands": { "verify": ["make migrate-up", "make migrate-status"], "test": ["make migrate-down", "make migrate-up"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-006", "phase": "PHASE_0", "type": "TEST", "domain": "BACKEND", "title": "Tests Go - Couverture 80%", "description": "Atteindre 80% de couverture de tests sur le backend Go", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-001", "T0-005"], "acceptance_criteria": [ "go test -cover ./... >= 80%", "Tous les handlers ont des tests", "Tous les services ont des tests" ], "files": { "to_check": ["backend/internal/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd backend && go test -cover ./..."], "test": ["cd backend && go test -coverprofile=coverage.out ./...", "go tool cover -html=coverage.out"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-007", "phase": "PHASE_0", "type": "TEST", "domain": "RUST", "title": "Tests Rust - Couverture 75%", "description": "Atteindre 75% de couverture de tests sur les modules Rust", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-002"], "acceptance_criteria": [ "cargo test passe à 100%", "Tests WebSocket fonctionnels", "Tests streaming fonctionnels" ], "files": { "to_check": ["rust/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd rust/chat && cargo test", "cd rust/streaming && cargo test"], "test": ["cargo tarpaulin --out Html"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-008", "phase": "PHASE_0", "type": "TEST", "domain": "FRONTEND", "title": "Tests Frontend - Couverture 70%", "description": "Atteindre 70% de couverture de tests sur le frontend", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-003"], "acceptance_criteria": [ "npm run test:coverage >= 70%", "Composants critiques testés", "Stores testés" ], "files": { "to_check": ["frontend/src/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd frontend && npm run test -- --coverage --run"], "test": ["cd frontend && npm run test:coverage"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-009", "phase": "PHASE_0", "type": "CONFIG", "domain": "DEVOPS", "title": "CI/CD GitHub Actions", "description": "Configurer pipeline CI/CD complet", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-006", "T0-007", "T0-008"], "acceptance_criteria": [ "Workflow CI déclenché sur PR", "Tests automatiques passent", "Build Docker automatique" ], "files": { "to_check": [".github/workflows/"], "to_modify": [".github/workflows/ci.yml"], "created": [] }, "commands": { "verify": ["gh workflow list", "gh run list"], "test": ["gh workflow run ci.yml"] }, "implementation_notes": null, "blockers": [] }, { "id": "T0-010", "phase": "PHASE_0", "type": "DOC", "domain": "DOCS", "title": "README et documentation setup", "description": "Mettre à jour README avec instructions de démarrage", "priority": "P1", "status": "pending", "estimated_hours": 3, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-004"], "acceptance_criteria": [ "README avec quick start", "CONTRIBUTING.md à jour", "Architecture documentée" ], "files": { "to_check": ["README.md", "CONTRIBUTING.md"], "to_modify": ["README.md"], "created": [] }, "commands": { "verify": [], "test": [] }, "implementation_notes": null, "blockers": [] }, { "id": "T1-001", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Register", "description": "POST /auth/register avec validation et email de confirmation", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-006"], "acceptance_criteria": [ "Validation email format + unicité", "Hash bcrypt du password (cost=12)", "Email de confirmation envoyé", "Token de vérification (24h expiry)", "Réponse 201 avec user sans password" ], "files": { "to_check": ["backend/internal/handlers/", "backend/internal/services/"], "to_modify": [ "backend/internal/handlers/auth_handler.go", "backend/internal/services/auth_service.go", "backend/internal/services/email_service.go" ], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v"] }, "api": { "method": "POST", "path": "/api/v1/auth/register", "request_body": { "email": "string", "password": "string", "username": "string" }, "response": { "201": {"user": {}}, "400": {"error": "validation_error"}, "409": {"error": "email_already_exists"} } }, "implementation_notes": null, "blockers": [] }, { "id": "T1-002", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Login", "description": "POST /auth/login avec JWT access + refresh token", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-001"], "acceptance_criteria": [ "Validation credentials", "JWT access token (15min expiry)", "Refresh token (7 jours, httpOnly cookie)", "Rate limiting (5/min par IP)" ], "files": { "to_check": [], "to_modify": [ "backend/internal/handlers/auth_handler.go", "backend/internal/services/jwt_service.go", "backend/internal/middleware/rate_limiter.go" ], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v -run TestLogin"] }, "api": { "method": "POST", "path": "/api/v1/auth/login", "request_body": { "email": "string", "password": "string" }, "response": { "200": {"access_token": "string", "expires_in": 900}, "401": {"error": "invalid_credentials"}, "429": {"error": "rate_limit_exceeded"} } }, "implementation_notes": null, "blockers": [] }, { "id": "T1-003", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Refresh Token", "description": "POST /auth/refresh pour renouveler l'access token", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "Lecture refresh token depuis cookie", "Validation du refresh token", "Rotation du refresh token", "Nouveau access token généré" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/auth_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v -run TestRefresh"] }, "api": { "method": "POST", "path": "/api/v1/auth/refresh", "response": { "200": {"access_token": "string", "expires_in": 900}, "401": {"error": "invalid_refresh_token"} } }, "implementation_notes": null, "blockers": [] }, { "id": "T1-004", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Logout", "description": "POST /auth/logout pour invalider les tokens", "priority": "P0", "status": "pending", "estimated_hours": 2, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-003"], "acceptance_criteria": [ "Refresh token ajouté à blacklist Redis", "Cookie refresh_token supprimé", "Réponse 204" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/auth_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v -run TestLogout"] }, "api": { "method": "POST", "path": "/api/v1/auth/logout", "response": { "204": null } }, "implementation_notes": null, "blockers": [] }, { "id": "T1-005", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Verify Email", "description": "GET /auth/verify/:token pour confirmer l'email", "priority": "P0", "status": "pending", "estimated_hours": 3, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-001"], "acceptance_criteria": [ "Validation token", "Mise à jour user.verified = true", "Redirection vers frontend" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/auth_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v -run TestVerifyEmail"] }, "api": { "method": "GET", "path": "/api/v1/auth/verify/:token", "response": { "302": "redirect to frontend", "400": {"error": "invalid_token"}, "410": {"error": "token_expired"} } }, "implementation_notes": null, "blockers": [] }, { "id": "T1-006", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Password Reset", "description": "Flux complet de reset password", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-001"], "acceptance_criteria": [ "POST /auth/password/forgot - envoie email", "POST /auth/password/reset - reset avec token", "Token temporaire 1h", "Invalidation anciens tokens" ], "files": { "to_check": [], "to_modify": [ "backend/internal/handlers/auth_handler.go", "backend/internal/services/auth_service.go" ], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/auth_handler_test.go -v -run TestPasswordReset"] }, "api": { "method": "POST", "path": "/api/v1/auth/password/forgot", "request_body": {"email": "string"}, "response": {"200": {"message": "email_sent"}} }, "implementation_notes": null, "blockers": [] }, { "id": "T1-007", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "OAuth Google", "description": "Authentification via Google OAuth2", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "GET /auth/google - redirection OAuth", "GET /auth/google/callback - traitement callback", "Création compte si nouveau", "Liaison si compte existe" ], "files": { "to_check": [], "to_modify": [ "backend/internal/handlers/oauth_handler.go", "backend/internal/services/oauth_service.go" ], "created": ["backend/internal/handlers/oauth_handler.go"] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/oauth_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/auth/google" }, "implementation_notes": null, "blockers": [] }, { "id": "T1-008", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "OAuth GitHub", "description": "Authentification via GitHub OAuth2", "priority": "P1", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-007"], "acceptance_criteria": [ "GET /auth/github - redirection OAuth", "GET /auth/github/callback - traitement callback", "Récupération email primary" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/oauth_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/oauth_handler_test.go -v -run TestGitHub"] }, "api": { "method": "GET", "path": "/api/v1/auth/github" }, "implementation_notes": null, "blockers": [] }, { "id": "T1-009", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API User Profile CRUD", "description": "Endpoints pour gestion profil utilisateur", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "GET /users/me - profil courant", "PATCH /users/me - mise à jour", "GET /users/:id - profil public", "DELETE /users/me - suppression compte" ], "files": { "to_check": [], "to_modify": [ "backend/internal/handlers/user_handler.go", "backend/internal/services/user_service.go" ], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/user_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/users/me" }, "implementation_notes": null, "blockers": [] }, { "id": "T1-010", "phase": "PHASE_1", "type": "FEATURE", "domain": "BACKEND", "title": "API Avatar Upload", "description": "Upload et gestion de l'avatar utilisateur", "priority": "P1", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-009"], "acceptance_criteria": [ "POST /users/me/avatar - upload image", "Validation format (jpg, png, webp)", "Resize automatique (400x400)", "Stockage S3/MinIO" ], "files": { "to_check": [], "to_modify": [ "backend/internal/handlers/user_handler.go", "backend/internal/services/storage_service.go" ], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/user_handler_test.go -v -run TestAvatar"] }, "api": { "method": "POST", "path": "/api/v1/users/me/avatar" }, "implementation_notes": null, "blockers": [] }, { "id": "T1-011", "phase": "PHASE_1", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Login", "description": "Interface de connexion complète", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002", "T0-008"], "acceptance_criteria": [ "Formulaire email/password", "Boutons OAuth (Google, GitHub)", "Validation temps réel", "Messages d'erreur clairs", "Lien vers register/forgot" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/auth/LoginPage.tsx", "frontend/src/components/auth/LoginForm.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run LoginForm"] }, "ui_components": ["Button", "Input", "Card", "Alert", "Divider", "Link"], "implementation_notes": null, "blockers": [] }, { "id": "T1-012", "phase": "PHASE_1", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Register", "description": "Interface d'inscription complète", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-001", "T0-008"], "acceptance_criteria": [ "Formulaire (email, password, username)", "Indicateur force mot de passe", "Validation temps réel", "Checkbox CGU", "Confirmation envoi email" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/auth/RegisterPage.tsx", "frontend/src/components/auth/RegisterForm.tsx", "frontend/src/components/auth/PasswordStrength.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run RegisterForm"] }, "ui_components": ["Button", "Input", "Checkbox", "PasswordStrength", "Alert"], "implementation_notes": null, "blockers": [] }, { "id": "T1-013", "phase": "PHASE_1", "type": "FEATURE", "domain": "FRONTEND", "title": "Auth Store (Zustand)", "description": "Gestion globale de l'état d'authentification", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002", "T1-003"], "acceptance_criteria": [ "Store Zustand auth", "Actions: login, logout, refresh", "Persistance localStorage", "Refresh automatique token" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/stores/authStore.ts", "frontend/src/hooks/useAuth.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run authStore"] }, "ui_components": [], "implementation_notes": null, "blockers": [] }, { "id": "T1-014", "phase": "PHASE_1", "type": "FEATURE", "domain": "FRONTEND", "title": "Protected Routes", "description": "Composant pour protéger les routes authentifiées", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-013"], "acceptance_criteria": [ "Redirection vers /login si non-auth", "Loading state pendant vérification", "Préservation URL destination" ], "files": { "to_check": [], "to_modify": ["frontend/src/router/index.tsx"], "created": [ "frontend/src/components/auth/ProtectedRoute.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run ProtectedRoute"] }, "ui_components": ["Spinner"], "implementation_notes": null, "blockers": [] }, { "id": "T1-015", "phase": "PHASE_1", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Profile", "description": "Page de profil utilisateur avec édition", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-009", "T1-010", "T1-013"], "acceptance_criteria": [ "Affichage infos profil", "Upload/change avatar", "Édition bio, links", "Changement mot de passe", "Suppression compte" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/profile/ProfilePage.tsx", "frontend/src/components/profile/ProfileHeader.tsx", "frontend/src/components/profile/ProfileForm.tsx", "frontend/src/components/profile/AvatarUpload.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run Profile"] }, "ui_components": ["Avatar", "Button", "Input", "Textarea", "ImageUpload", "Tabs", "Modal"], "implementation_notes": null, "blockers": [] }, { "id": "T1-016", "phase": "PHASE_1", "type": "TEST", "domain": "E2E", "title": "Tests E2E Auth Flow", "description": "Tests Playwright pour le flux d'authentification complet", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-011", "T1-012", "T1-015"], "acceptance_criteria": [ "Test register complet", "Test login/logout", "Test password reset", "Test profile edit" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/tests/e2e/auth.spec.ts" ] }, "commands": { "verify": ["cd frontend && npx playwright test auth --reporter=list"], "test": ["cd frontend && npx playwright test auth"] }, "ui_components": [], "implementation_notes": null, "blockers": [] }, { "id": "T2-001", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "API Upload Init", "description": "Initier un upload multipart pour gros fichiers audio", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "POST /tracks/upload/init", "Validation format (mp3, wav, flac, aac)", "Validation taille (max 500MB)", "Génération upload_id unique", "Création entrée DB pending" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/upload_handler.go", "backend/internal/services/upload_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/upload_handler_test.go -v"] }, "api": { "method": "POST", "path": "/api/v1/tracks/upload/init", "request_body": { "filename": "string", "size": "number", "content_type": "string" }, "response": { "200": {"upload_id": "string", "chunk_size": 5242880} } }, "implementation_notes": null, "blockers": [] }, { "id": "T2-002", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "API Upload Chunk", "description": "Upload des chunks individuels", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-001"], "acceptance_criteria": [ "PUT /tracks/upload/:id/chunk/:index", "Validation checksum MD5", "Stockage temporaire chunks", "Tracking progression" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/upload_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/upload_handler_test.go -v -run TestChunk"] }, "api": { "method": "PUT", "path": "/api/v1/tracks/upload/:id/chunk/:index" }, "implementation_notes": null, "blockers": [] }, { "id": "T2-003", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "API Upload Complete", "description": "Finaliser l'upload et déclencher le traitement", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-002"], "acceptance_criteria": [ "POST /tracks/upload/:id/complete", "Assemblage des chunks", "Stockage S3 final", "Job processing en queue" ], "files": { "to_check": [], "to_modify": ["backend/internal/handlers/upload_handler.go"], "created": [] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/upload_handler_test.go -v -run TestComplete"] }, "api": { "method": "POST", "path": "/api/v1/tracks/upload/:id/complete" }, "implementation_notes": null, "blockers": [] }, { "id": "T2-004", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "Service S3/MinIO", "description": "Service de stockage compatible S3", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-004"], "acceptance_criteria": [ "Upload vers bucket", "Download avec presigned URL", "Delete fichier", "Configuration multi-bucket" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/services/storage_service.go", "backend/internal/config/storage.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/services/storage_service_test.go -v"] }, "implementation_notes": null, "blockers": [] }, { "id": "T2-005", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "Worker Metadata Extraction", "description": "Job pour extraire les métadonnées audio", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-003"], "acceptance_criteria": [ "Extraction ID3/Vorbis tags", "Durée, bitrate, sample rate", "Format, codec detection", "Cover art extraction" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/workers/metadata_worker.go", "backend/internal/services/metadata_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/workers/metadata_worker_test.go -v"] }, "implementation_notes": null, "blockers": [] }, { "id": "T2-006", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "Worker Waveform Generation", "description": "Générer les données de waveform", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-003"], "acceptance_criteria": [ "Peaks data JSON (1000 points)", "Cache Redis", "Endpoint GET /tracks/:id/waveform" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/workers/waveform_worker.go", "backend/internal/services/waveform_service.go", "backend/internal/handlers/waveform_handler.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/workers/waveform_worker_test.go -v"] }, "implementation_notes": null, "blockers": [] }, { "id": "T2-007", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "Worker HLS Transcoding", "description": "Transcoder audio en HLS pour streaming adaptatif", "priority": "P0", "status": "pending", "estimated_hours": 18, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-003", "T2-004"], "acceptance_criteria": [ "Génération segments HLS", "Multiple qualités (128k, 256k, 320k)", "Playlist master.m3u8", "Stockage segments S3" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/workers/transcoding_worker.go", "backend/internal/services/transcoding_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/workers/transcoding_worker_test.go -v"] }, "implementation_notes": "Utiliser FFmpeg via exec ou go-ffmpeg wrapper", "blockers": [] }, { "id": "T2-008", "phase": "PHASE_2", "type": "FEATURE", "domain": "BACKEND", "title": "API Track CRUD", "description": "Endpoints pour gestion des tracks", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-005"], "acceptance_criteria": [ "GET /tracks - liste avec pagination", "GET /tracks/:id - détails", "PATCH /tracks/:id - update metadata", "DELETE /tracks/:id" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/track_handler.go", "backend/internal/services/track_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/track_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/tracks" }, "implementation_notes": null, "blockers": [] }, { "id": "T2-009", "phase": "PHASE_2", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant UploadZone", "description": "Zone d'upload avec drag & drop", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-003", "T0-008"], "acceptance_criteria": [ "Drag & drop zone", "Click to select", "Multi-file support", "Validation types/taille", "Preview fichiers" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/upload/UploadZone.tsx", "frontend/src/components/upload/FilePreview.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run UploadZone"] }, "ui_components": ["DropZone", "FileList", "Icon", "Badge"], "implementation_notes": null, "blockers": [] }, { "id": "T2-010", "phase": "PHASE_2", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant UploadProgress", "description": "Barre de progression avec états", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-009"], "acceptance_criteria": [ "Barre progression animée", "États: uploading, processing, complete, error", "Bouton annuler/retry", "Vitesse upload affichée" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/upload/UploadProgress.tsx", "frontend/src/hooks/useUpload.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run UploadProgress"] }, "ui_components": ["ProgressBar", "Button", "Badge", "Spinner"], "implementation_notes": null, "blockers": [] }, { "id": "T2-011", "phase": "PHASE_2", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Upload", "description": "Page complète d'upload avec métadonnées", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-009", "T2-010"], "acceptance_criteria": [ "Upload + formulaire métadonnées", "Tags, genre, BPM", "Cover art upload", "Preview avant publish" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/upload/UploadPage.tsx", "frontend/src/components/upload/MetadataForm.tsx", "frontend/src/components/upload/CoverUpload.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run Upload"] }, "ui_components": ["UploadZone", "Input", "Select", "TagInput", "ImageUpload", "Button"], "implementation_notes": null, "blockers": [] }, { "id": "T2-012", "phase": "PHASE_2", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant WaveformViewer", "description": "Visualisation waveform avec Canvas", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-006"], "acceptance_criteria": [ "Rendu Canvas responsive", "Indicateur position lecture", "Click to seek", "Hover preview time", "Couleurs personnalisables" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/audio/WaveformViewer.tsx", "frontend/src/hooks/useWaveform.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run WaveformViewer"] }, "ui_components": [], "implementation_notes": null, "blockers": [] }, { "id": "T2-013", "phase": "PHASE_2", "type": "FEATURE", "domain": "FRONTEND", "title": "Page My Tracks", "description": "Liste des tracks de l'utilisateur", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008"], "acceptance_criteria": [ "Liste avec pagination", "Filtres (status, date)", "Actions (edit, delete)", "Stats basiques" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/library/MyTracksPage.tsx", "frontend/src/components/track/TrackListItem.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run MyTracks"] }, "ui_components": ["Table", "Pagination", "Button", "Badge", "ContextMenu"], "implementation_notes": null, "blockers": [] }, { "id": "T3-001", "phase": "PHASE_3", "type": "FEATURE", "domain": "RUST", "title": "Serveur HLS Streaming", "description": "Serveur Rust pour delivery HLS haute performance", "priority": "P0", "status": "pending", "estimated_hours": 20, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-007", "T0-007"], "acceptance_criteria": [ "Serving .m3u8 et .ts", "Range requests support", "Signed URL validation", "Rate limiting par user" ], "files": { "to_check": [], "to_modify": [], "created": [ "rust/streaming/src/handlers/hls.rs", "rust/streaming/src/auth/verify.rs" ] }, "commands": { "verify": ["cd rust/streaming && cargo build"], "test": ["cd rust/streaming && cargo test"] }, "implementation_notes": null, "blockers": [] }, { "id": "T3-002", "phase": "PHASE_3", "type": "FEATURE", "domain": "BACKEND", "title": "API Stream URL", "description": "Générer URL signée pour accès au stream", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-001"], "acceptance_criteria": [ "GET /tracks/:id/stream", "URL signée (1h expiry)", "Vérification droits d'accès", "Log play event" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/stream_handler.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/stream_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/tracks/:id/stream" }, "implementation_notes": null, "blockers": [] }, { "id": "T3-003", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Audio Engine", "description": "Moteur audio avec HLS.js", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-002"], "acceptance_criteria": [ "Playback HLS via hls.js", "Fallback audio natif", "Events: timeupdate, ended, error", "Quality switching" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/lib/audioEngine.ts", "frontend/src/hooks/useAudioEngine.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run audioEngine"] }, "implementation_notes": "npm install hls.js", "blockers": [] }, { "id": "T3-004", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Player Store", "description": "State management global pour le player", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-003"], "acceptance_criteria": [ "Current track state", "Playback state", "Volume state", "Queue management", "Shuffle/Repeat" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/stores/playerStore.ts", "frontend/src/hooks/usePlayer.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run playerStore"] }, "implementation_notes": null, "blockers": [] }, { "id": "T3-005", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant PlayerBar", "description": "Barre de lecture persistante", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-004", "T2-012"], "acceptance_criteria": [ "Cover, title, artist", "Play/pause, prev/next", "Progress bar cliquable", "Volume slider", "Expand vers full player" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/player/PlayerBar.tsx", "frontend/src/components/player/PlayerControls.tsx", "frontend/src/components/player/VolumeControl.tsx", "frontend/src/components/player/ProgressBar.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run PlayerBar"] }, "ui_components": ["Button", "Slider", "Avatar", "WaveformViewer"], "implementation_notes": null, "blockers": [] }, { "id": "T3-006", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant FullPlayer", "description": "Player plein écran", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-005"], "acceptance_criteria": [ "Waveform grande taille", "Cover art large", "Contrôles avancés", "Queue visible", "Animation transition" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/player/FullPlayer.tsx", "frontend/src/components/player/QueuePanel.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run FullPlayer"] }, "ui_components": ["WaveformViewer", "Button", "Avatar", "List"], "implementation_notes": null, "blockers": [] }, { "id": "T3-007", "phase": "PHASE_3", "type": "FEATURE", "domain": "BACKEND", "title": "API Playlists CRUD", "description": "Endpoints pour gestion des playlists", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008"], "acceptance_criteria": [ "CRUD playlists", "Add/remove tracks", "Reorder tracks", "Public/private visibility" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/playlist_handler.go", "backend/internal/services/playlist_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/playlist_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/playlists" }, "implementation_notes": null, "blockers": [] }, { "id": "T3-008", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Playlist", "description": "Vue playlist avec tracks", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-007"], "acceptance_criteria": [ "Header playlist", "Liste tracks ordonnée", "Play all / Shuffle", "Reorder drag & drop", "Share" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/playlist/PlaylistPage.tsx", "frontend/src/components/playlist/PlaylistHeader.tsx", "frontend/src/components/playlist/PlaylistTrackList.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run Playlist"] }, "ui_components": ["Avatar", "Button", "DraggableList", "TrackListItem"], "implementation_notes": null, "blockers": [] }, { "id": "T3-009", "phase": "PHASE_3", "type": "FEATURE", "domain": "FRONTEND", "title": "Keyboard Shortcuts & Media Session", "description": "Raccourcis clavier et intégration OS", "priority": "P1", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T3-004"], "acceptance_criteria": [ "Space = play/pause", "Arrows = seek/volume", "Media Session API", "Notifications OS" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/hooks/useKeyboardShortcuts.ts", "frontend/src/lib/mediaSession.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run useKeyboardShortcuts"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-001", "phase": "PHASE_4", "type": "FEATURE", "domain": "RUST", "title": "WebSocket Server Core", "description": "Serveur WebSocket avec Tokio/Axum", "priority": "P0", "status": "pending", "estimated_hours": 20, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-007"], "acceptance_criteria": [ "Connexion WS authentifiée (JWT)", "Heartbeat/Ping-Pong", "Reconnexion handling", "Connection pool management" ], "files": { "to_check": [], "to_modify": [], "created": [ "rust/chat/src/ws/server.rs", "rust/chat/src/ws/connection.rs", "rust/chat/src/auth/jwt.rs" ] }, "commands": { "verify": ["cd rust/chat && cargo build"], "test": ["cd rust/chat && cargo test"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-002", "phase": "PHASE_4", "type": "FEATURE", "domain": "RUST", "title": "Room Management", "description": "Gestion des rooms de chat", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-001"], "acceptance_criteria": [ "Join/Leave room", "Broadcast to room", "Room state tracking", "Member list" ], "files": { "to_check": [], "to_modify": [], "created": [ "rust/chat/src/room/manager.rs", "rust/chat/src/room/room.rs" ] }, "commands": { "verify": ["cd rust/chat && cargo build"], "test": ["cd rust/chat && cargo test room"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-003", "phase": "PHASE_4", "type": "FEATURE", "domain": "RUST", "title": "Message Handling", "description": "Traitement et broadcast des messages", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-002"], "acceptance_criteria": [ "Send/Receive messages", "Message validation", "Rate limiting", "Persistence via Go API" ], "files": { "to_check": [], "to_modify": [], "created": [ "rust/chat/src/message/handler.rs", "rust/chat/src/message/types.rs" ] }, "commands": { "verify": ["cd rust/chat && cargo build"], "test": ["cd rust/chat && cargo test message"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-004", "phase": "PHASE_4", "type": "FEATURE", "domain": "RUST", "title": "Presence System", "description": "Tracking présence utilisateurs", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-001"], "acceptance_criteria": [ "Online/Offline status", "Typing indicators", "Last seen", "Broadcast presence" ], "files": { "to_check": [], "to_modify": [], "created": [ "rust/chat/src/presence/tracker.rs", "rust/chat/src/presence/types.rs" ] }, "commands": { "verify": ["cd rust/chat && cargo build"], "test": ["cd rust/chat && cargo test presence"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-005", "phase": "PHASE_4", "type": "FEATURE", "domain": "BACKEND", "title": "API Rooms & Messages", "description": "REST API pour rooms et messages", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "CRUD rooms", "GET messages history", "Pagination cursor-based" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/room_handler.go", "backend/internal/handlers/message_handler.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/room_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/rooms" }, "implementation_notes": null, "blockers": [] }, { "id": "T4-006", "phase": "PHASE_4", "type": "FEATURE", "domain": "FRONTEND", "title": "WebSocket Client", "description": "Client WebSocket avec reconnexion", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-001"], "acceptance_criteria": [ "Connexion avec JWT", "Reconnexion exponentielle", "Queue messages offline", "Events handling" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/lib/websocket.ts", "frontend/src/hooks/useWebSocket.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run websocket"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-007", "phase": "PHASE_4", "type": "FEATURE", "domain": "FRONTEND", "title": "Chat Store", "description": "State management pour le chat", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-006"], "acceptance_criteria": [ "Rooms list", "Messages par room", "Presence state", "Unread counts" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/stores/chatStore.ts", "frontend/src/hooks/useChat.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run chatStore"] }, "implementation_notes": null, "blockers": [] }, { "id": "T4-008", "phase": "PHASE_4", "type": "FEATURE", "domain": "FRONTEND", "title": "Composant ChatWindow", "description": "Fenêtre de chat complète", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-007"], "acceptance_criteria": [ "Liste messages virtualisée", "Input avec validation", "Typing indicator", "Load more historique", "Auto-scroll" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/chat/ChatWindow.tsx", "frontend/src/components/chat/MessageList.tsx", "frontend/src/components/chat/ChatInput.tsx", "frontend/src/components/chat/MessageBubble.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run ChatWindow"] }, "ui_components": ["Input", "Button", "Avatar", "Spinner", "VirtualList"], "implementation_notes": null, "blockers": [] }, { "id": "T4-009", "phase": "PHASE_4", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Chat", "description": "Page principale de chat", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T4-008"], "acceptance_criteria": [ "Layout sidebar + main", "Room list", "Create room modal", "Responsive mobile" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/chat/ChatPage.tsx", "frontend/src/components/chat/RoomList.tsx", "frontend/src/components/chat/RoomItem.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run ChatPage"] }, "ui_components": ["ChatWindow", "RoomList", "Modal", "Button"], "implementation_notes": null, "blockers": [] }, { "id": "T5-001", "phase": "PHASE_5", "type": "FEATURE", "domain": "BACKEND", "title": "Meilisearch Integration", "description": "Intégration moteur de recherche", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008"], "acceptance_criteria": [ "Index tracks, users, playlists", "Sync automatique", "Recherche fuzzy", "Facettes (genre, BPM)" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/services/search_service.go", "backend/internal/workers/indexer_worker.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/services/search_service_test.go -v"] }, "implementation_notes": null, "blockers": [] }, { "id": "T5-002", "phase": "PHASE_5", "type": "FEATURE", "domain": "BACKEND", "title": "API Search", "description": "Endpoint de recherche unifié", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T5-001"], "acceptance_criteria": [ "GET /search?q=...", "Filtres: type, genre, bpm", "Pagination", "Highlighting" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/search_handler.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/search_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/search" }, "implementation_notes": null, "blockers": [] }, { "id": "T5-003", "phase": "PHASE_5", "type": "FEATURE", "domain": "FRONTEND", "title": "SearchBar avec Autocomplete", "description": "Barre de recherche globale", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T5-002"], "acceptance_criteria": [ "Input avec debounce", "Dropdown suggestions", "Keyboard navigation", "Recent searches" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/search/SearchBar.tsx", "frontend/src/components/search/SuggestionList.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run SearchBar"] }, "ui_components": ["Input", "Dropdown", "List", "Avatar"], "implementation_notes": null, "blockers": [] }, { "id": "T5-004", "phase": "PHASE_5", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Search Results", "description": "Page de résultats de recherche", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T5-002"], "acceptance_criteria": [ "Tabs: All, Tracks, Users, Playlists", "Filtres sidebar", "Sort options", "Pagination" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/search/SearchPage.tsx", "frontend/src/components/search/SearchFilters.tsx", "frontend/src/components/search/SearchResults.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run SearchPage"] }, "ui_components": ["Tabs", "Select", "Pagination", "Card", "TrackCard", "UserCard"], "implementation_notes": null, "blockers": [] }, { "id": "T5-005", "phase": "PHASE_5", "type": "FEATURE", "domain": "BACKEND", "title": "API Explore", "description": "Contenu à découvrir", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008"], "acceptance_criteria": [ "GET /explore/trending", "GET /explore/new", "GET /explore/genres" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/explore_handler.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/explore_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/explore/trending" }, "implementation_notes": null, "blockers": [] }, { "id": "T5-006", "phase": "PHASE_5", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Explore/Home", "description": "Page d'accueil avec découverte", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T5-005"], "acceptance_criteria": [ "Hero section", "Trending carousel", "New releases", "Genre grid", "Featured playlists" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/explore/ExplorePage.tsx", "frontend/src/components/explore/TrendingSection.tsx", "frontend/src/components/explore/GenreGrid.tsx", "frontend/src/components/explore/FeaturedPlaylists.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run ExplorePage"] }, "ui_components": ["Carousel", "Card", "Grid", "TrackCard", "PlaylistCard"], "implementation_notes": null, "blockers": [] }, { "id": "T5-007", "phase": "PHASE_5", "type": "FEATURE", "domain": "FRONTEND", "title": "Page Track Detail", "description": "Page détail d'un track", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008", "T2-012"], "acceptance_criteria": [ "Waveform large", "Metadata complètes", "Actions (play, add, share)", "Related tracks" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/track/TrackPage.tsx", "frontend/src/components/track/TrackHeader.tsx", "frontend/src/components/track/RelatedTracks.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run TrackPage"] }, "ui_components": ["WaveformViewer", "Button", "Avatar", "Card"], "implementation_notes": null, "blockers": [] }, { "id": "T6-001", "phase": "PHASE_6", "type": "FEATURE", "domain": "BACKEND", "title": "API Notifications", "description": "Système de notifications", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-002"], "acceptance_criteria": [ "GET /notifications", "PATCH /notifications/:id/read", "Types: follow, like, comment" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/notification_handler.go", "backend/internal/services/notification_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/notification_handler_test.go -v"] }, "api": { "method": "GET", "path": "/api/v1/notifications" }, "implementation_notes": null, "blockers": [] }, { "id": "T6-002", "phase": "PHASE_6", "type": "FEATURE", "domain": "FRONTEND", "title": "Notification Bell", "description": "Composant notification header", "priority": "P0", "status": "pending", "estimated_hours": 8, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-001"], "acceptance_criteria": [ "Badge unread count", "Dropdown liste", "Mark all as read", "Link vers page" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/notification/NotificationBell.tsx", "frontend/src/components/notification/NotificationDropdown.tsx", "frontend/src/stores/notificationStore.ts" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run NotificationBell"] }, "ui_components": ["Badge", "Dropdown", "List", "Button"], "implementation_notes": null, "blockers": [] }, { "id": "T6-003", "phase": "PHASE_6", "type": "FEATURE", "domain": "BACKEND", "title": "API Follow", "description": "Système de follow/unfollow", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-009"], "acceptance_criteria": [ "POST /users/:id/follow", "DELETE /users/:id/follow", "GET followers/following" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/follow_handler.go", "backend/internal/services/follow_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/follow_handler_test.go -v"] }, "api": { "method": "POST", "path": "/api/v1/users/:id/follow" }, "implementation_notes": null, "blockers": [] }, { "id": "T6-004", "phase": "PHASE_6", "type": "FEATURE", "domain": "BACKEND", "title": "API Likes", "description": "Système de likes", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T2-008"], "acceptance_criteria": [ "POST /tracks/:id/like", "DELETE /tracks/:id/like", "GET /users/me/likes" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/internal/handlers/like_handler.go", "backend/internal/services/like_service.go" ] }, "commands": { "verify": ["cd backend && go build ./..."], "test": ["cd backend && go test ./internal/handlers/like_handler_test.go -v"] }, "api": { "method": "POST", "path": "/api/v1/tracks/:id/like" }, "implementation_notes": null, "blockers": [] }, { "id": "T6-005", "phase": "PHASE_6", "type": "FEATURE", "domain": "FRONTEND", "title": "Composants Social", "description": "FollowButton et LikeButton", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-003", "T6-004"], "acceptance_criteria": [ "FollowButton avec états", "LikeButton avec animation", "Optimistic updates" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/social/FollowButton.tsx", "frontend/src/components/social/LikeButton.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run Social"] }, "ui_components": ["Button"], "implementation_notes": null, "blockers": [] }, { "id": "T6-006", "phase": "PHASE_6", "type": "FEATURE", "domain": "FRONTEND", "title": "Page User Profile Public", "description": "Profil public d'un utilisateur", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T1-009", "T6-003"], "acceptance_criteria": [ "Header profil", "Tabs: Tracks, Playlists, Likes", "Follow button", "Stats followers" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/user/UserProfilePage.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run UserProfile"] }, "ui_components": ["Avatar", "Button", "Tabs", "Grid", "FollowButton"], "implementation_notes": null, "blockers": [] }, { "id": "T7-001", "phase": "PHASE_7", "type": "PERF", "domain": "FRONTEND", "title": "Performance Optimization", "description": "Optimisation performance frontend", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "Lighthouse >= 90", "FCP < 1.5s", "Bundle size optimisé", "Code splitting" ], "files": { "to_check": ["frontend/src/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd frontend && npm run build:analyze"], "test": ["npx lighthouse http://localhost:3000 --output=json"] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-002", "phase": "PHASE_7", "type": "A11Y", "domain": "FRONTEND", "title": "Accessibility Audit", "description": "Validation accessibilité WCAG AA", "priority": "P0", "status": "pending", "estimated_hours": 16, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "0 erreurs Axe", "Navigation clavier complète", "ARIA labels", "Focus visible" ], "files": { "to_check": ["frontend/src/"], "to_modify": [], "created": [] }, "commands": { "verify": ["cd frontend && npm run test:a11y"], "test": ["npx axe-core http://localhost:3000"] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-003", "phase": "PHASE_7", "type": "SEO", "domain": "FRONTEND", "title": "SEO Implementation", "description": "Optimisation SEO", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "Meta tags dynamiques", "Open Graph", "Sitemap.xml", "robots.txt" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/components/SEO.tsx", "frontend/public/sitemap.xml", "frontend/public/robots.txt" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": [] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-004", "phase": "PHASE_7", "type": "SECURITY", "domain": "ALL", "title": "Security Audit", "description": "Audit sécurité complet", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "OWASP Top 10 vérifié", "Dependencies scan", "Secrets management", "CSP headers" ], "files": { "to_check": [], "to_modify": [], "created": [] }, "commands": { "verify": ["npm audit", "cd backend && go mod verify"], "test": ["trivy fs ."] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-005", "phase": "PHASE_7", "type": "CONFIG", "domain": "DEVOPS", "title": "Production Deployment", "description": "Configuration déploiement production", "priority": "P0", "status": "pending", "estimated_hours": 14, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T0-009"], "acceptance_criteria": [ "HTTPS configuré", "CDN pour assets", "Monitoring (Prometheus/Grafana)", "Backups automatiques" ], "files": { "to_check": [], "to_modify": [], "created": [ "docker-compose.prod.yml", "deploy/kubernetes/", "monitoring/" ] }, "commands": { "verify": ["make deploy-prod"], "test": ["curl -I https://veza.app"] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-006", "phase": "PHASE_7", "type": "DOC", "domain": "DOCS", "title": "API Documentation", "description": "Documentation Swagger/OpenAPI", "priority": "P0", "status": "pending", "estimated_hours": 10, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "Swagger UI accessible", "Tous endpoints documentés", "Exemples requêtes/réponses", "Auth documentation" ], "files": { "to_check": [], "to_modify": [], "created": [ "backend/docs/swagger.yaml" ] }, "commands": { "verify": ["make swagger"], "test": ["curl http://localhost:8080/swagger/"] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-007", "phase": "PHASE_7", "type": "FEATURE", "domain": "FRONTEND", "title": "Landing Page", "description": "Page d'accueil marketing", "priority": "P0", "status": "pending", "estimated_hours": 12, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": [], "acceptance_criteria": [ "Hero section", "Features showcase", "CTA inscription", "Responsive" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/LandingPage.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": ["cd frontend && npm run test -- --run LandingPage"] }, "ui_components": ["Button", "Card", "Carousel"], "implementation_notes": null, "blockers": [] }, { "id": "T7-008", "phase": "PHASE_7", "type": "FEATURE", "domain": "FRONTEND", "title": "Error Pages", "description": "Pages d'erreur personnalisées", "priority": "P0", "status": "pending", "estimated_hours": 4, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": [], "acceptance_criteria": [ "404 avec suggestions", "500 avec retry", "Offline page" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/errors/NotFoundPage.tsx", "frontend/src/pages/errors/ServerErrorPage.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": [] }, "ui_components": ["Button", "Card"], "implementation_notes": null, "blockers": [] }, { "id": "T7-009", "phase": "PHASE_7", "type": "LEGAL", "domain": "FRONTEND", "title": "Pages Légales", "description": "CGU, Privacy, RGPD", "priority": "P0", "status": "pending", "estimated_hours": 6, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": [], "acceptance_criteria": [ "CGU/CGV", "Politique confidentialité", "Cookie banner RGPD" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/src/pages/legal/TermsPage.tsx", "frontend/src/pages/legal/PrivacyPage.tsx", "frontend/src/components/CookieBanner.tsx" ] }, "commands": { "verify": ["cd frontend && npm run build"], "test": [] }, "implementation_notes": null, "blockers": [] }, { "id": "T7-010", "phase": "PHASE_7", "type": "TEST", "domain": "E2E", "title": "Tests E2E Complets", "description": "Suite complète tests Playwright", "priority": "P0", "status": "pending", "estimated_hours": 20, "actual_hours": null, "started_at": null, "completed_at": null, "dependencies": ["T6-006"], "acceptance_criteria": [ "Tous flows critiques testés", "Tests cross-browser", "CI integration" ], "files": { "to_check": [], "to_modify": [], "created": [ "frontend/tests/e2e/critical-flows.spec.ts" ] }, "commands": { "verify": ["cd frontend && npx playwright test"], "test": ["cd frontend && npx playwright test --reporter=html"] }, "implementation_notes": null, "blockers": [] } ] }