[INT-AUTH-002] Remove duplicate auth store - migrate to features/auth/store/authStore.ts
This commit is contained in:
parent
55f357803a
commit
c70dc23e70
66 changed files with 2079 additions and 79 deletions
502
CURSOR_INTEGRATION_AUDIT_PROMPT.md
Normal file
502
CURSOR_INTEGRATION_AUDIT_PROMPT.md
Normal file
|
|
@ -0,0 +1,502 @@
|
|||
# 🎯 PROMPT CURSOR : Audit Intégration Backend/Frontend + Nouvelle TodoList JSON
|
||||
|
||||
## 📋 INSTRUCTIONS POUR CURSOR
|
||||
|
||||
Copie ce prompt complet dans Cursor pour lancer l'audit et générer la nouvelle todolist.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 LE PROMPT À COPIER
|
||||
|
||||
```markdown
|
||||
# MISSION : Audit Complet Intégration Backend/Frontend Veza + TodoList JSON
|
||||
|
||||
Tu es un expert en intégration full-stack. Ta mission est de scanner EXHAUSTIVEMENT le codebase Veza pour :
|
||||
1. Générer un rapport ULTRA-DÉTAILLÉ de l'état d'intégration backend/frontend
|
||||
2. Créer une nouvelle TodoList JSON PARFAITE focalisée uniquement sur la connexion backend/frontend
|
||||
|
||||
## 🚫 SCOPE EXCLUSIONS
|
||||
- **IGNORER COMPLÈTEMENT** : `veza-chat-server/` (Rust)
|
||||
- **IGNORER COMPLÈTEMENT** : `veza-stream-server/` (Rust)
|
||||
- **IGNORER** : Tout ce qui concerne WebSocket Rust
|
||||
- **FOCUS UNIQUEMENT** : `apps/web/` ↔ `veza-backend-api/`
|
||||
|
||||
## 📂 FICHIERS À SCANNER
|
||||
|
||||
### Backend Go (`veza-backend-api/`)
|
||||
```
|
||||
veza-backend-api/
|
||||
├── internal/
|
||||
│ ├── api/router.go # TOUTES les routes définies
|
||||
│ ├── handlers/*.go # TOUS les handlers
|
||||
│ ├── dto/*.go # TOUS les DTOs (request/response)
|
||||
│ ├── models/*.go # TOUS les modèles
|
||||
│ ├── middleware/*.go # CORS, Auth, CSRF, etc.
|
||||
│ └── config/config.go # Configuration
|
||||
├── cmd/server/main.go # Point d'entrée
|
||||
└── .env.example # Variables d'environnement
|
||||
```
|
||||
|
||||
### Frontend React (`apps/web/`)
|
||||
```
|
||||
apps/web/src/
|
||||
├── services/
|
||||
│ ├── api/client.ts # Client API principal
|
||||
│ ├── api/*.ts # Tous les services API
|
||||
│ └── *.ts # Anciens services (duplication?)
|
||||
├── features/
|
||||
│ ├── auth/api/*.ts # API auth
|
||||
│ ├── auth/store/*.ts # Store auth
|
||||
│ ├── tracks/api/*.ts # API tracks
|
||||
│ ├── playlists/services/*.ts # Services playlists
|
||||
│ └── */ # Autres features
|
||||
├── stores/*.ts # Stores globaux (duplication?)
|
||||
├── types/*.ts # Types TypeScript
|
||||
├── lib/apiClient.ts # Ancien client API?
|
||||
├── config/
|
||||
│ ├── env.ts # Variables d'environnement
|
||||
│ └── constants.ts # Constantes API
|
||||
└── hooks/api/*.ts # Hooks API
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 PHASE 1 : GÉNÉRATION DU RAPPORT
|
||||
|
||||
Crée un fichier `INTEGRATION_AUDIT_REPORT_2025.md` avec :
|
||||
|
||||
### 1.1 Executive Summary
|
||||
- Score global /10
|
||||
- Nombre d'endpoints backend total
|
||||
- Nombre d'endpoints utilisés par frontend
|
||||
- Nombre d'endpoints manquants côté frontend
|
||||
- Nombre d'appels frontend sans endpoint backend
|
||||
- Nombre d'incohérences de types
|
||||
|
||||
### 1.2 Analyse des Endpoints - TABLEAU EXHAUSTIF
|
||||
|
||||
Pour CHAQUE route dans `router.go`, génère :
|
||||
|
||||
```markdown
|
||||
| Endpoint Backend | Handler | Frontend Service | Frontend Hook | Types Alignés | Status |
|
||||
|------------------|---------|------------------|---------------|---------------|--------|
|
||||
| GET /api/v1/auth/me | GetMe | authApi.getMe() | useAuth | ✅ | OK |
|
||||
| POST /api/v1/tracks | CreateTrack | trackApi.create() | useTracks | ⚠️ ID type | PARTIEL |
|
||||
| ... | ... | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.3 Analyse des Incohérences de Types
|
||||
|
||||
Pour CHAQUE type partagé, compare :
|
||||
|
||||
```markdown
|
||||
| Type | Backend Go (DTO) | Frontend TS | Différences | Impact |
|
||||
|------|------------------|-------------|-------------|--------|
|
||||
| User.id | uuid.UUID (string) | string | number dans certains composants | 🔴 CRITIQUE |
|
||||
| Track.status | string | enum TrackStatus | Valeurs différentes | ⚠️ MOYEN |
|
||||
| ... | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.4 Analyse des Clients API
|
||||
|
||||
Identifie TOUS les clients/services API :
|
||||
|
||||
```markdown
|
||||
| Fichier | Type | Utilisé par | Problèmes |
|
||||
|---------|------|-------------|-----------|
|
||||
| services/api/client.ts | Axios + interceptors | Nouveau code | ✅ OK |
|
||||
| lib/apiClient.ts | Axios basic | Ancien code? | ⚠️ Duplication |
|
||||
| ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.5 Analyse des Stores
|
||||
|
||||
Identifie TOUS les stores liés à l'auth/state API :
|
||||
|
||||
```markdown
|
||||
| Store | Fichier | Utilisé | Duplication avec |
|
||||
|-------|---------|---------|------------------|
|
||||
| authStore | features/auth/store/authStore.ts | ✅ | stores/auth.ts? |
|
||||
| ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.6 Analyse CORS/CSRF/Security
|
||||
|
||||
```markdown
|
||||
| Aspect | Backend Config | Frontend Config | Aligné | Problème |
|
||||
|--------|----------------|-----------------|--------|----------|
|
||||
| CORS Origins | CORS_ALLOWED_ORIGINS | - | ⚠️ | Vide = bloqué |
|
||||
| CSRF Token | X-CSRF-Token header | csrfService.ts | ⚠️ | Redis requis |
|
||||
| ... | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.7 Analyse Format Réponses API
|
||||
|
||||
```markdown
|
||||
| Endpoint | Backend Response | Frontend Attend | Transformé par | OK |
|
||||
|----------|------------------|-----------------|----------------|-----|
|
||||
| POST /auth/login | {success, data: {access_token...}} | {access_token...} | Interceptor unwrap | ✅ |
|
||||
| ... | ... | ... | ... | ... |
|
||||
```
|
||||
|
||||
### 1.8 Problèmes Identifiés (Liste Exhaustive)
|
||||
|
||||
```markdown
|
||||
## 🔴 CRITIQUES (Bloquent production)
|
||||
1. [CORS-001] CORS_ALLOWED_ORIGINS vide en production = rejet total
|
||||
- Fichier: veza-backend-api/internal/middleware/cors.go
|
||||
- Impact: Application inaccessible
|
||||
|
||||
2. [TYPE-001] User.id: number vs string dans certains composants
|
||||
- Fichiers: apps/web/src/types/user.ts, components/*.tsx
|
||||
- Impact: Erreurs runtime
|
||||
|
||||
## ⚠️ MAJEURS (Fonctionnent mais fragiles)
|
||||
...
|
||||
|
||||
## 🟡 MINEURS (Dettes techniques)
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 PHASE 2 : GÉNÉRATION DE LA TODOLIST JSON
|
||||
|
||||
Crée un fichier `VEZA_INTEGRATION_PERFECTION_TODOLIST.json` avec cette structure EXACTE :
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"title": "Veza Integration Perfection TodoList",
|
||||
"description": "TodoList focalisée exclusivement sur la connexion parfaite Backend Go ↔ Frontend React",
|
||||
"generated_at": "2025-12-25T00:00:00Z",
|
||||
"scope": {
|
||||
"included": ["apps/web/", "veza-backend-api/"],
|
||||
"excluded": ["veza-chat-server/", "veza-stream-server/", "veza-common/"]
|
||||
},
|
||||
"target": "Score intégration 10/10 - Connexion parfaite",
|
||||
"current_score": "6.5/10",
|
||||
"target_score": "10/10"
|
||||
},
|
||||
"summary": {
|
||||
"by_priority": {
|
||||
"P0_blocker": 0,
|
||||
"P1_critical": 0,
|
||||
"P2_major": 0,
|
||||
"P3_minor": 0
|
||||
},
|
||||
"by_category": {
|
||||
"INT-CORS": 0,
|
||||
"INT-AUTH": 0,
|
||||
"INT-TYPE": 0,
|
||||
"INT-API": 0,
|
||||
"INT-ENDPOINT": 0,
|
||||
"INT-CLEANUP": 0,
|
||||
"INT-TEST": 0,
|
||||
"INT-DOC": 0
|
||||
},
|
||||
"by_side": {
|
||||
"backend_only": 0,
|
||||
"frontend_only": 0,
|
||||
"both_sides": 0
|
||||
},
|
||||
"estimated_total_hours": 0
|
||||
},
|
||||
"categories": {
|
||||
"INT-CORS": "Configuration CORS et origins",
|
||||
"INT-AUTH": "Authentification et tokens",
|
||||
"INT-TYPE": "Alignement des types TypeScript/Go",
|
||||
"INT-API": "Client API et services",
|
||||
"INT-ENDPOINT": "Endpoints manquants ou incohérents",
|
||||
"INT-CLEANUP": "Nettoyage duplication et legacy code",
|
||||
"INT-TEST": "Tests d'intégration E2E",
|
||||
"INT-DOC": "Documentation API"
|
||||
},
|
||||
"phases": [
|
||||
{
|
||||
"id": "PHASE-INT-1",
|
||||
"name": "Blockers Production",
|
||||
"description": "Problèmes qui empêchent le déploiement en production",
|
||||
"priority": "P0",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "PHASE-INT-2",
|
||||
"name": "Critical Fixes",
|
||||
"description": "Problèmes qui causent des erreurs ou comportements incorrects",
|
||||
"priority": "P1",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "PHASE-INT-3",
|
||||
"name": "Type Alignment",
|
||||
"description": "Alignement parfait des types entre backend et frontend",
|
||||
"priority": "P1",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "PHASE-INT-4",
|
||||
"name": "Cleanup & Standardization",
|
||||
"description": "Suppression des duplications et standardisation",
|
||||
"priority": "P2",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "PHASE-INT-5",
|
||||
"name": "Missing Endpoints",
|
||||
"description": "Implémenter les endpoints manquants",
|
||||
"priority": "P2",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
},
|
||||
{
|
||||
"id": "PHASE-INT-6",
|
||||
"name": "Integration Tests",
|
||||
"description": "Tests E2E pour valider l'intégration",
|
||||
"priority": "P2",
|
||||
"estimated_hours": 0,
|
||||
"tasks": []
|
||||
}
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"id": "INT-CORS-001",
|
||||
"category": "INT-CORS",
|
||||
"title": "Configure production CORS origins",
|
||||
"description": "Définir CORS_ALLOWED_ORIGINS explicitement pour la production",
|
||||
"priority": "P0",
|
||||
"priority_rank": 1,
|
||||
"status": "todo",
|
||||
"estimated_hours": 1,
|
||||
"side": "backend_only",
|
||||
"files_to_modify": [
|
||||
"veza-backend-api/internal/middleware/cors.go",
|
||||
"veza-backend-api/.env.production"
|
||||
],
|
||||
"implementation_steps": [
|
||||
"Ouvrir veza-backend-api/internal/middleware/cors.go",
|
||||
"Vérifier la validation de CORS_ALLOWED_ORIGINS en production",
|
||||
"Créer/modifier .env.production avec les origines autorisées",
|
||||
"Tester en mode production local"
|
||||
],
|
||||
"acceptance_criteria": [
|
||||
"CORS_ALLOWED_ORIGINS contient les domaines de production",
|
||||
"Backend démarre sans erreur en mode production",
|
||||
"Requêtes CORS depuis le frontend autorisées"
|
||||
],
|
||||
"dependencies": [],
|
||||
"blocks": ["INT-TEST-001"]
|
||||
}
|
||||
// ... GÉNÉRER TOUTES LES TÂCHES ICI
|
||||
],
|
||||
"integration_matrix": {
|
||||
"endpoints_analysis": [
|
||||
{
|
||||
"backend_route": "GET /api/v1/auth/me",
|
||||
"backend_handler": "GetMe",
|
||||
"backend_file": "veza-backend-api/internal/handlers/auth.go",
|
||||
"frontend_service": "authApi.getMe()",
|
||||
"frontend_file": "apps/web/src/features/auth/api/authApi.ts",
|
||||
"types_aligned": true,
|
||||
"issues": [],
|
||||
"status": "OK"
|
||||
}
|
||||
// ... TOUTES les routes
|
||||
],
|
||||
"type_mismatches": [
|
||||
{
|
||||
"type_name": "User",
|
||||
"field": "id",
|
||||
"backend_type": "uuid.UUID",
|
||||
"backend_file": "veza-backend-api/internal/dto/user.go",
|
||||
"frontend_type": "string | number",
|
||||
"frontend_files": ["apps/web/src/types/user.ts"],
|
||||
"fix_required": "frontend",
|
||||
"task_id": "INT-TYPE-001"
|
||||
}
|
||||
],
|
||||
"duplicate_code": [
|
||||
{
|
||||
"type": "api_client",
|
||||
"files": [
|
||||
"apps/web/src/services/api/client.ts",
|
||||
"apps/web/src/lib/apiClient.ts"
|
||||
],
|
||||
"keep": "apps/web/src/services/api/client.ts",
|
||||
"remove": "apps/web/src/lib/apiClient.ts",
|
||||
"task_id": "INT-CLEANUP-001"
|
||||
}
|
||||
],
|
||||
"missing_frontend_calls": [
|
||||
{
|
||||
"backend_route": "GET /api/v1/sessions/stats",
|
||||
"backend_file": "veza-backend-api/internal/api/router.go:743",
|
||||
"frontend_needed": true,
|
||||
"task_id": "INT-ENDPOINT-001"
|
||||
}
|
||||
],
|
||||
"missing_backend_routes": [
|
||||
{
|
||||
"frontend_call": "GET /api/v1/users/search",
|
||||
"frontend_file": "apps/web/src/config/constants.ts:31",
|
||||
"backend_needed": true,
|
||||
"task_id": "INT-ENDPOINT-002"
|
||||
}
|
||||
]
|
||||
},
|
||||
"risk_register": [
|
||||
{
|
||||
"id": "RISK-001",
|
||||
"risk": "CORS bloque toutes les requêtes en production",
|
||||
"severity": "critical",
|
||||
"probability": "certain",
|
||||
"impact": "Application inaccessible",
|
||||
"mitigation_tasks": ["INT-CORS-001"],
|
||||
"owner": "backend"
|
||||
}
|
||||
],
|
||||
"validation_checklist": {
|
||||
"pre_deployment": [
|
||||
{
|
||||
"check": "CORS_ALLOWED_ORIGINS configuré",
|
||||
"task_id": "INT-CORS-001",
|
||||
"verified": false
|
||||
},
|
||||
{
|
||||
"check": "Tous les types alignés",
|
||||
"task_ids": ["INT-TYPE-001", "INT-TYPE-002"],
|
||||
"verified": false
|
||||
}
|
||||
],
|
||||
"integration_tests": [
|
||||
{
|
||||
"test": "Auth flow complet (register → login → refresh → logout)",
|
||||
"task_id": "INT-TEST-001",
|
||||
"passed": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"progress_tracking": {
|
||||
"total_tasks": 0,
|
||||
"completed": 0,
|
||||
"in_progress": 0,
|
||||
"todo": 0,
|
||||
"blocked": 0,
|
||||
"completion_percentage": 0,
|
||||
"last_updated": "2025-12-25T00:00:00Z",
|
||||
"estimated_completion_date": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 RÈGLES DE GÉNÉRATION DES TÂCHES
|
||||
|
||||
### Format de chaque tâche :
|
||||
```json
|
||||
{
|
||||
"id": "INT-{CATEGORY}-{NUMBER:3}",
|
||||
"category": "INT-{CATEGORY}",
|
||||
"title": "Titre court et clair (max 60 chars)",
|
||||
"description": "Description détaillée du problème et de la solution",
|
||||
"priority": "P0|P1|P2|P3",
|
||||
"priority_rank": 1-999,
|
||||
"status": "todo",
|
||||
"estimated_hours": 0.5-8,
|
||||
"side": "backend_only|frontend_only|both_sides",
|
||||
"files_to_modify": ["chemin/complet/fichier.ext"],
|
||||
"implementation_steps": [
|
||||
"Étape 1 précise",
|
||||
"Étape 2 précise",
|
||||
"..."
|
||||
],
|
||||
"acceptance_criteria": [
|
||||
"Critère vérifiable 1",
|
||||
"Critère vérifiable 2"
|
||||
],
|
||||
"dependencies": ["INT-XXX-YYY"],
|
||||
"blocks": ["INT-XXX-ZZZ"],
|
||||
"verification_command": "commande pour vérifier (optionnel)"
|
||||
}
|
||||
```
|
||||
|
||||
### Priorités :
|
||||
- **P0**: Bloque le déploiement production (CORS, security)
|
||||
- **P1**: Cause des erreurs runtime ou comportements incorrects
|
||||
- **P2**: Dette technique, amélioration significative
|
||||
- **P3**: Nice-to-have, polish
|
||||
|
||||
### Catégories :
|
||||
- **INT-CORS**: Configuration CORS
|
||||
- **INT-AUTH**: Authentification, tokens, sessions
|
||||
- **INT-TYPE**: Alignement types TypeScript ↔ Go DTOs
|
||||
- **INT-API**: Client API, intercepteurs, services
|
||||
- **INT-ENDPOINT**: Endpoints manquants ou à corriger
|
||||
- **INT-CLEANUP**: Suppression code dupliqué, standardisation
|
||||
- **INT-TEST**: Tests d'intégration E2E
|
||||
- **INT-DOC**: Documentation API (OpenAPI, README)
|
||||
|
||||
---
|
||||
|
||||
## ✅ CHECKLIST AVANT DE TERMINER
|
||||
|
||||
Avant de soumettre les fichiers, vérifie :
|
||||
|
||||
- [ ] **Rapport contient** :
|
||||
- [ ] Tableau EXHAUSTIF de TOUS les endpoints backend
|
||||
- [ ] Correspondance avec TOUS les appels frontend
|
||||
- [ ] Analyse de TOUS les types partagés
|
||||
- [ ] Liste de TOUTES les duplications
|
||||
- [ ] Score détaillé par catégorie
|
||||
|
||||
- [ ] **TodoList JSON contient** :
|
||||
- [ ] Toutes les tâches identifiées dans le rapport
|
||||
- [ ] priority_rank unique et ordonné
|
||||
- [ ] implementation_steps détaillés pour chaque tâche
|
||||
- [ ] acceptance_criteria vérifiables
|
||||
- [ ] integration_matrix complet
|
||||
- [ ] summary avec comptages corrects
|
||||
- [ ] progress_tracking initialisé
|
||||
|
||||
---
|
||||
|
||||
## 🎯 COMMENCE MAINTENANT
|
||||
|
||||
1. Checkout `feature/integration-perfection` (crée-la si nécessaire)
|
||||
2. Scanne les fichiers listés ci-dessus
|
||||
3. Génère `INTEGRATION_AUDIT_REPORT_2025.md`
|
||||
4. Génère `VEZA_INTEGRATION_PERFECTION_TODOLIST.json`
|
||||
5. Commit: `[AUDIT] Complete integration audit and todolist generation`
|
||||
|
||||
GO!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📌 NOTES D'UTILISATION
|
||||
|
||||
### Comment utiliser ce prompt :
|
||||
|
||||
1. **Ouvre Cursor** dans ton projet Veza
|
||||
2. **Copie tout le contenu** entre les balises ` ```markdown ` et ` ``` `
|
||||
3. **Colle dans Cursor** (Cmd+L ou Ctrl+L)
|
||||
4. **Laisse l'agent travailler** - il va scanner et générer les deux fichiers
|
||||
|
||||
### Output attendu :
|
||||
|
||||
1. `INTEGRATION_AUDIT_REPORT_2025.md` - Rapport détaillé (~1000+ lignes)
|
||||
2. `VEZA_INTEGRATION_PERFECTION_TODOLIST.json` - TodoList JSON parfaite
|
||||
|
||||
### Après la génération :
|
||||
|
||||
Utilise ce prompt pour exécuter les tâches :
|
||||
|
||||
```
|
||||
Continue l'intégration Veza sur branche feature/integration-perfection.
|
||||
Lis @VEZA_INTEGRATION_PERFECTION_TODOLIST.json, trouve la prochaine tâche todo, implémente, commit, continue.
|
||||
```
|
||||
1032
FRONTEND_BACKEND_CONNECTION_STATUS.md
Normal file
1032
FRONTEND_BACKEND_CONNECTION_STATUS.md
Normal file
File diff suppressed because it is too large
Load diff
462
INTEGRATION_AUDIT_REPORT_2025.md
Normal file
462
INTEGRATION_AUDIT_REPORT_2025.md
Normal file
|
|
@ -0,0 +1,462 @@
|
|||
# 🔍 Rapport d'Audit Intégration Backend/Frontend Veza - 2025
|
||||
|
||||
**Date de génération:** 2025-12-25
|
||||
**Scope:** `apps/web/` ↔ `veza-backend-api/`
|
||||
**Exclusions:** `veza-chat-server/`, `veza-stream-server/`, `veza-common/`
|
||||
|
||||
---
|
||||
|
||||
## 📊 Executive Summary
|
||||
|
||||
### Score Global: **6.5/10**
|
||||
|
||||
| Métrique | Valeur |
|
||||
|----------|--------|
|
||||
| Endpoints backend total | ~85+ |
|
||||
| Endpoints utilisés par frontend | ~45 |
|
||||
| Endpoints manquants côté frontend | ~8 |
|
||||
| Appels frontend sans endpoint backend | ~3 |
|
||||
| Incohérences de types | ~12 |
|
||||
| Duplications de code | ~3 |
|
||||
|
||||
### Répartition par Priorité
|
||||
|
||||
- **P0 (Bloqueurs Production):** 3
|
||||
- **P1 (Critiques):** 8
|
||||
- **P2 (Majeurs):** 15
|
||||
- **P3 (Mineurs):** 6
|
||||
|
||||
### Score par Catégorie
|
||||
|
||||
| Catégorie | Score | Problèmes |
|
||||
|-----------|-------|-----------|
|
||||
| CORS/Security | 4/10 | 2 critiques |
|
||||
| Authentification | 7/10 | 3 problèmes |
|
||||
| Types | 5/10 | 12 incohérences |
|
||||
| API Client | 8/10 | 1 duplication |
|
||||
| Endpoints | 6/10 | 11 manquants |
|
||||
| Cleanup | 7/10 | 3 duplications |
|
||||
|
||||
---
|
||||
|
||||
## 1. Analyse des Endpoints
|
||||
|
||||
### 1.1 Tableau Exhaustif des Endpoints
|
||||
|
||||
| Endpoint Backend | Handler | Frontend Service | Frontend Hook | Types Alignés | Status |
|
||||
|------------------|---------|------------------|---------------|---------------|--------|
|
||||
| **AUTH** |
|
||||
| POST /api/v1/auth/login | Login | authApi.login() | useLogin | ✅ | OK |
|
||||
| POST /api/v1/auth/register | Register | authApi.register() | useRegister | ✅ | OK |
|
||||
| POST /api/v1/auth/refresh | Refresh | authApi.refresh() | - | ✅ | OK |
|
||||
| POST /api/v1/auth/logout | Logout | authApi.logout() | useLogout | ✅ | OK |
|
||||
| GET /api/v1/auth/me | GetMe | authApi.getMe() | useAuth | ✅ | OK |
|
||||
| POST /api/v1/auth/verify-email | VerifyEmail | authApi.verifyEmail() | - | ✅ | OK |
|
||||
| POST /api/v1/auth/resend-verification | ResendVerification | authApi.resendVerification() | - | ✅ | OK |
|
||||
| GET /api/v1/auth/check-username | CheckUsername | authApi.checkUsername() | - | ✅ | OK |
|
||||
| POST /api/v1/auth/2fa/setup | SetupTwoFactor | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/auth/2fa/verify | VerifyTwoFactor | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/auth/2fa/disable | DisableTwoFactor | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/auth/2fa/status | GetTwoFactorStatus | - | - | ⚠️ | PARTIEL |
|
||||
| **USERS** |
|
||||
| GET /api/v1/users | ListUsers | - | - | ✅ | OK |
|
||||
| GET /api/v1/users/:id | GetProfile | - | - | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/users/by-username/:username | GetProfileByUsername | - | - | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/users/search | SearchUsers | searchService.searchUsers() | - | ❌ | **MANQUANT BACKEND** |
|
||||
| PUT /api/v1/users/:id | UpdateProfile | - | - | ⚠️ ID type | PARTIEL |
|
||||
| DELETE /api/v1/users/:id | DeleteUser | - | - | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/users/:id/completion | GetProfileCompletion | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/users/:id/follow | FollowUser | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/users/:id/follow | UnfollowUser | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/users/:id/block | BlockUser | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/users/:id/block | UnblockUser | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/users/:userId/avatar | UploadAvatar | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/users/:userId/avatar | DeleteAvatar | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/users/:id/likes | GetUserLikedTracks | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/users/me/export | ExportUserData | - | - | ⚠️ | PARTIEL |
|
||||
| **TRACKS** |
|
||||
| GET /api/v1/tracks | ListTracks | trackApi.list() | useTracks | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/tracks/search | SearchTracks | trackSearchService.search() | - | ❌ | **MANQUANT BACKEND** |
|
||||
| GET /api/v1/tracks/:id | GetTrack | trackApi.get() | useTrack | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/stats | GetTrackStats | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/history | GetTrackHistory | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/download | DownloadTrack | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/shared/:token | GetSharedTrack | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks | UploadTrack | trackApi.upload() | useUploadTrack | ⚠️ ID type | PARTIEL |
|
||||
| PUT /api/v1/tracks/:id | UpdateTrack | trackApi.update() | - | ⚠️ ID type | PARTIEL |
|
||||
| DELETE /api/v1/tracks/:id | DeleteTrack | trackApi.delete() | - | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/status | GetUploadStatus | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/initiate | InitiateChunkedUpload | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/chunk | UploadChunk | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/complete | CompleteChunkedUpload | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/quota/:id | GetUploadQuota | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/resume/:uploadId | ResumeUpload | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/batch/delete | BatchDeleteTracks | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/batch/update | BatchUpdateTracks | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/:id/like | LikeTrack | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/tracks/:id/like | UnlikeTrack | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/likes | GetTrackLikes | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/:id/share | CreateShare | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/tracks/share/:id | RevokeShare | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/:id/versions/:versionId/restore | RestoreVersion | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/:id/play | RecordPlay | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/hls/info | GetStreamInfo | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/hls/status | GetStreamStatus | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/tracks/:id/comments | GetComments | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/tracks/:id/comments | CreateComment | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/comments/:id | DeleteComment | - | - | ⚠️ | PARTIEL |
|
||||
| **PLAYLISTS** |
|
||||
| GET /api/v1/playlists | GetPlaylists | playlistService.getPlaylists() | usePlaylists | ⚠️ ID type | PARTIEL |
|
||||
| GET /api/v1/playlists/search | SearchPlaylists | playlistService.searchPlaylists() | - | ❌ | **MANQUANT BACKEND** |
|
||||
| GET /api/v1/playlists/recommendations | GetRecommendations | playlistService.getRecommendations() | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/playlists/:id | GetPlaylist | playlistService.getPlaylist() | usePlaylist | ⚠️ ID type | PARTIEL |
|
||||
| POST /api/v1/playlists | CreatePlaylist | playlistService.createPlaylist() | - | ⚠️ ID type | PARTIEL |
|
||||
| PUT /api/v1/playlists/:id | UpdatePlaylist | playlistService.updatePlaylist() | - | ⚠️ ID type | PARTIEL |
|
||||
| DELETE /api/v1/playlists/:id | DeletePlaylist | playlistService.deletePlaylist() | - | ⚠️ ID type | PARTIEL |
|
||||
| POST /api/v1/playlists/:id/tracks | AddTrack | playlistService.addTrack() | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/playlists/:id/tracks/:track_id | RemoveTrack | playlistService.removeTrack() | - | ⚠️ | PARTIEL |
|
||||
| PUT /api/v1/playlists/:id/tracks/reorder | ReorderTracks | playlistService.reorderTracks() | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/playlists/:id/collaborators | AddCollaborator | - | - | ❌ | **MANQUANT FRONTEND** |
|
||||
| GET /api/v1/playlists/:id/collaborators | GetCollaborators | - | - | ❌ | **MANQUANT FRONTEND** |
|
||||
| PUT /api/v1/playlists/:id/collaborators/:userId | UpdateCollaboratorPermission | - | - | ❌ | **MANQUANT FRONTEND** |
|
||||
| DELETE /api/v1/playlists/:id/collaborators/:userId | RemoveCollaborator | - | - | ❌ | **MANQUANT FRONTEND** |
|
||||
| POST /api/v1/playlists/:id/share | CreateShareLink | - | - | ⚠️ | PARTIEL |
|
||||
| **SESSIONS** |
|
||||
| POST /api/v1/sessions/logout | Logout | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/sessions/logout-all | LogoutAll | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/sessions | GetSessions | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/sessions/:session_id | RevokeSession | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/sessions/stats | GetSessionStats | - | - | ❌ | **MANQUANT FRONTEND** |
|
||||
| POST /api/v1/sessions/refresh | RefreshSession | - | - | ⚠️ | PARTIEL |
|
||||
| **CONVERSATIONS** |
|
||||
| GET /api/v1/conversations | GetUserRooms | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/conversations | CreateRoom | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/conversations/:id | GetRoom | - | - | ⚠️ | PARTIEL |
|
||||
| PUT /api/v1/conversations/:id | UpdateRoom | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/conversations/:id | DeleteRoom | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/conversations/:id/members | AddMember | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/conversations/:id/participants | AddParticipant | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/conversations/:id/participants/:userId | RemoveParticipant | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/conversations/:id/history | GetRoomHistory | - | - | ⚠️ | PARTIEL |
|
||||
| **NOTIFICATIONS** |
|
||||
| GET /api/v1/notifications | GetNotifications | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/notifications/:id/read | MarkAsRead | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/notifications/read-all | MarkAllAsRead | - | - | ⚠️ | PARTIEL |
|
||||
| **ROLES** |
|
||||
| GET /api/v1/roles | GetRoles | roleService.getRoles() | - | ✅ | OK |
|
||||
| GET /api/v1/roles/:id | GetRole | roleService.getRole() | - | ✅ | OK |
|
||||
| POST /api/v1/users/:userId/roles | AssignRole | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/users/:userId/roles/:roleId | RevokeRole | - | - | ⚠️ | PARTIEL |
|
||||
| **WEBHOOKS** |
|
||||
| POST /api/v1/webhooks | RegisterWebhook | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/webhooks | ListWebhooks | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/webhooks/:id | DeleteWebhook | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/webhooks/stats | GetWebhookStats | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/webhooks/:id/test | TestWebhook | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/webhooks/:id/regenerate-key | RegenerateAPIKey | - | - | ⚠️ | PARTIEL |
|
||||
| **MARKETPLACE** |
|
||||
| GET /api/v1/marketplace/products | ListProducts | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/marketplace/products | CreateProduct | - | - | ⚠️ | PARTIEL |
|
||||
| PUT /api/v1/marketplace/products/:id | UpdateProduct | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/marketplace/orders | ListOrders | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/marketplace/orders/:id | GetOrder | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/marketplace/orders | CreateOrder | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/marketplace/download/:product_id | GetDownloadURL | - | - | ⚠️ | PARTIEL |
|
||||
| **ANALYTICS** |
|
||||
| POST /api/v1/analytics/events | RecordEvent | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/analytics/tracks/:id | GetTrackAnalyticsDashboard | - | - | ⚠️ | PARTIEL |
|
||||
| **UPLOADS** |
|
||||
| POST /api/v1/uploads | UploadFile | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/uploads/batch | BatchUpload | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/uploads/:id/status | GetUploadStatus | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/uploads/:id/progress | UploadProgress | - | - | ⚠️ | PARTIEL |
|
||||
| DELETE /api/v1/uploads/:id | DeleteUpload | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/uploads/stats | GetUploadStats | - | - | ⚠️ | PARTIEL |
|
||||
| **AUDIT** |
|
||||
| GET /api/v1/audit/logs | SearchLogs | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/audit/stats | GetStats | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/audit/activity | GetUserActivity | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/audit/suspicious | DetectSuspiciousActivity | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/audit/ip/:ip | GetIPActivity | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/audit/logs/:id | GetAuditLog | - | - | ⚠️ | PARTIEL |
|
||||
| POST /api/v1/audit/cleanup | CleanupOldLogs | - | - | ⚠️ | PARTIEL |
|
||||
| **CHAT** |
|
||||
| POST /api/v1/chat/token | GetToken | - | - | ⚠️ | PARTIEL |
|
||||
| GET /api/v1/chat/stats | GetStats | - | - | ⚠️ | PARTIEL |
|
||||
| **CSRF** |
|
||||
| GET /api/v1/csrf-token | GetCSRFToken | csrfService.refreshToken() | - | ✅ | OK |
|
||||
|
||||
**Légende:**
|
||||
- ✅ OK: Endpoint utilisé, types alignés
|
||||
- ⚠️ PARTIEL: Endpoint utilisé mais problèmes de types ou utilisation incomplète
|
||||
- ❌ MANQUANT: Endpoint manquant côté backend ou frontend
|
||||
|
||||
---
|
||||
|
||||
## 2. Analyse des Incohérences de Types
|
||||
|
||||
### 2.1 Tableau des Incohérences
|
||||
|
||||
| Type | Champ | Backend Go (DTO) | Frontend TS | Différences | Impact | Fichiers Affectés |
|
||||
|------|-------|------------------|-------------|-------------|--------|-------------------|
|
||||
| User | id | uuid.UUID (string) | string | Parfois number dans composants | 🔴 CRITIQUE | types/api.ts, types/index.ts |
|
||||
| User | role | string | 'user' \| 'admin' \| 'super_admin' | Enum frontend vs string backend | ⚠️ MOYEN | types/api.ts |
|
||||
| Track | id | uuid.UUID (string) | string | Cohérent | ✅ OK | features/tracks/types/track.ts |
|
||||
| Track | creator_id | uuid.UUID (string) | string | Cohérent | ✅ OK | features/tracks/types/track.ts |
|
||||
| Track | status | TrackStatus (enum) | TrackStatus (enum) | Valeurs: 'uploading' \| 'processing' \| 'completed' \| 'failed' vs backend: 'uploading' \| 'processing' \| 'ready' \| 'error' | 🔴 CRITIQUE | models/track.go vs features/tracks/types/track.ts |
|
||||
| Track | stream_status | string | string | Cohérent | ✅ OK | - |
|
||||
| Playlist | id | uuid.UUID (string) | string | Cohérent | ✅ OK | types/api.ts, features/playlists/types.ts |
|
||||
| Playlist | user_id | uuid.UUID (string) | string | Cohérent | ✅ OK | - |
|
||||
| Playlist | title | string (column: name) | string | Backend utilise 'name' en DB mais 'title' en JSON | ⚠️ MOYEN | models/playlist.go |
|
||||
| Playlist | visibility | - | - | Pas d'enum défini | ⚠️ MOYEN | - |
|
||||
| ApiError | code | string | string | Cohérent | ✅ OK | - |
|
||||
| ApiError | message | string | string | Cohérent | ✅ OK | - |
|
||||
| ApiError | details | []ErrorDetail | ErrorDetail[]? | Cohérent | ✅ OK | - |
|
||||
| ApiError | field_errors | map[string]string | Record<string, string>? | Cohérent | ✅ OK | - |
|
||||
| ApiError | request_id | string | string? | Cohérent | ✅ OK | - |
|
||||
| PaginatedResponse | items | T[] | T[] | Cohérent | ✅ OK | - |
|
||||
| PaginatedResponse | total | int | number | Cohérent | ✅ OK | - |
|
||||
| PaginatedResponse | page | int | number | Cohérent | ✅ OK | - |
|
||||
| PaginatedResponse | limit | int | number | Cohérent | ✅ OK | - |
|
||||
| AuthResponse | access_token | string | string | Cohérent | ✅ OK | - |
|
||||
| AuthResponse | refresh_token | string | string | Cohérent | ✅ OK | - |
|
||||
| AuthResponse | expires_in | int | number? | Cohérent | ✅ OK | - |
|
||||
| AuthResponse | token_type | string | string? | Cohérent | ✅ OK | - |
|
||||
| AuthResponse | user | UserResponse | User | Cohérent | ✅ OK | - |
|
||||
|
||||
### 2.2 Problèmes Identifiés
|
||||
|
||||
1. **User.id**: Défini comme `string` dans types mais peut être utilisé comme `number` dans certains composants
|
||||
2. **Track.status**: Enum frontend (`'uploading' | 'processing' | 'completed' | 'failed'`) vs backend (`'uploading' | 'processing' | 'ready' | 'error'`) - **INCOHÉRENCE MAJEURE**
|
||||
3. **Playlist.title**: Backend utilise `name` en DB mais `title` en JSON - confusion potentielle
|
||||
|
||||
---
|
||||
|
||||
## 3. Analyse des Clients API
|
||||
|
||||
### 3.1 Clients Identifiés
|
||||
|
||||
| Fichier | Type | Utilisé par | Problèmes |
|
||||
|---------|------|-------------|-----------|
|
||||
| `services/api/client.ts` | Axios + interceptors | ✅ Tous les nouveaux services | ✅ OK - Client principal |
|
||||
| `services/api/typedClient.ts` | Wrapper typé | ✅ Services typés | ✅ OK - Wrapper |
|
||||
| `services/api/clientWithValidation.ts` | Wrapper validation Zod | ✅ Services validés | ✅ OK - Wrapper |
|
||||
| `lib/apiClient.ts` | ❌ N'existe pas | - | ✅ Pas de duplication |
|
||||
|
||||
**Conclusion:** Un seul client API principal, pas de duplication. ✅
|
||||
|
||||
---
|
||||
|
||||
## 4. Analyse des Stores
|
||||
|
||||
### 4.1 Stores Identifiés
|
||||
|
||||
| Store | Fichier | Utilisé | Duplication avec |
|
||||
|-------|---------|---------|------------------|
|
||||
| authStore | `stores/auth.ts` | ✅ 75+ fichiers | ❌ Pas de duplication |
|
||||
| - | `features/auth/store/authStore.ts` | ❌ N'existe pas | - |
|
||||
|
||||
**Conclusion:** Un seul store auth, pas de duplication. ✅
|
||||
|
||||
---
|
||||
|
||||
## 5. Analyse CORS/CSRF/Security
|
||||
|
||||
### 5.1 Configuration CORS
|
||||
|
||||
| Aspect | Backend Config | Frontend Config | Aligné | Problème |
|
||||
|--------|----------------|-----------------|--------|----------|
|
||||
| CORS Origins | CORS_ALLOWED_ORIGINS | - | ❌ | **🔴 CRITIQUE: Vide = rejet total en production** |
|
||||
| CORS Methods | GET, POST, PUT, DELETE, OPTIONS | - | ✅ | OK |
|
||||
| CORS Headers | Authorization, Content-Type, X-Requested-With | - | ⚠️ | Manque X-CSRF-Token dans AllowHeaders |
|
||||
| CORS Credentials | true | - | ✅ | OK |
|
||||
| Preflight | OPTIONS → 204 | - | ✅ | OK |
|
||||
|
||||
**Problème identifié:**
|
||||
- `CORS_ALLOWED_ORIGINS` vide en production = **TOUTES les requêtes CORS rejetées**
|
||||
- Le middleware CORS rejette explicitement si liste vide (ligne 119 de cors.go)
|
||||
- Validation en production échoue au démarrage si vide (ligne 30-38 de cors.go)
|
||||
|
||||
### 5.2 Configuration CSRF
|
||||
|
||||
| Aspect | Backend Config | Frontend Config | Aligné | Problème |
|
||||
|--------|----------------|-----------------|--------|----------|
|
||||
| CSRF Token | X-CSRF-Token header | csrfService.ts | ✅ | OK |
|
||||
| CSRF Storage | Redis | - | ⚠️ | **🔴 CRITIQUE: Désactivé si Redis indisponible** |
|
||||
| CSRF TTL | 1 heure | - | ✅ | OK |
|
||||
| CSRF Refresh | GET /csrf-token | csrfService.refreshToken() | ✅ | OK |
|
||||
|
||||
**Problème identifié:**
|
||||
- CSRF middleware désactivé si Redis indisponible (ligne 65-68 de router.go)
|
||||
- En production, Redis DOIT être disponible pour sécurité
|
||||
- Pas de fail-fast si Redis indisponible en production
|
||||
|
||||
---
|
||||
|
||||
## 6. Analyse Format Réponses API
|
||||
|
||||
### 6.1 Formats Identifiés
|
||||
|
||||
| Endpoint | Backend Response | Frontend Attend | Transformé par | OK |
|
||||
|----------|------------------|-----------------|----------------|-----|
|
||||
| POST /auth/login | {success: true, data: {access_token...}} | {access_token...} | Interceptor unwrap | ✅ |
|
||||
| GET /tracks | {tracks: [...], pagination: {...}} | {tracks: [...], pagination: {...}} | Direct | ✅ |
|
||||
| GET /tracks/search | {tracks: [...], total: ...} | {tracks: [...], total: ...} | Direct | ✅ |
|
||||
| POST /tracks | {success: true, data: Track} | Track | Interceptor unwrap | ✅ |
|
||||
| GET /users/:id | {success: true, data: User} | User | Interceptor unwrap | ✅ |
|
||||
|
||||
**Conclusion:** Format cohérent, interceptor gère correctement l'unwrapping. ✅
|
||||
|
||||
---
|
||||
|
||||
## 7. Problèmes Identifiés (Liste Exhaustive)
|
||||
|
||||
### 🔴 CRITIQUES (Bloquent production)
|
||||
|
||||
#### 1. [CORS-001] CORS_ALLOWED_ORIGINS vide en production = rejet total
|
||||
- **Fichier:** `veza-backend-api/internal/middleware/cors.go:119`
|
||||
- **Impact:** Application totalement inaccessible depuis le frontend
|
||||
- **Solution:** Définir `CORS_ALLOWED_ORIGINS` explicitement dans `.env.production`
|
||||
- **Priorité:** P0
|
||||
|
||||
#### 2. [CSRF-001] CSRF désactivé si Redis indisponible
|
||||
- **Fichier:** `veza-backend-api/internal/api/router.go:65-68`
|
||||
- **Impact:** Vulnérabilité de sécurité majeure en production
|
||||
- **Solution:** Fail-fast en production si Redis indisponible
|
||||
- **Priorité:** P0
|
||||
|
||||
#### 3. [TYPE-001] Track.status: valeurs différentes backend/frontend
|
||||
- **Backend:** `'uploading' | 'processing' | 'ready' | 'error'`
|
||||
- **Frontend:** `'uploading' | 'processing' | 'completed' | 'failed'`
|
||||
- **Fichiers:** `veza-backend-api/internal/models/track.go:30` vs `apps/web/src/features/tracks/types/track.ts:6`
|
||||
- **Impact:** Erreurs runtime lors de la comparaison de statuts
|
||||
- **Solution:** Aligner les valeurs (utiliser backend comme source de vérité)
|
||||
- **Priorité:** P0
|
||||
|
||||
### ⚠️ MAJEURS (Fonctionnent mais fragiles)
|
||||
|
||||
#### 4. [TYPE-002] User.id peut être number dans certains composants
|
||||
- **Fichiers:** `apps/web/src/types/api.ts:3`, `apps/web/src/types/index.ts:4`
|
||||
- **Impact:** Erreurs de comparaison, bugs intermittents
|
||||
- **Solution:** S'assurer que User.id est toujours string partout
|
||||
- **Priorité:** P1
|
||||
|
||||
#### 5. [ENDPOINT-001] GET /api/v1/users/search appelé par frontend mais n'existe pas backend
|
||||
- **Frontend:** `apps/web/src/features/search/services/searchService.ts:40`
|
||||
- **Backend:** Route non trouvée dans `router.go`
|
||||
- **Impact:** Erreur 404 lors de la recherche d'utilisateurs
|
||||
- **Solution:** Implémenter endpoint backend
|
||||
- **Priorité:** P1
|
||||
|
||||
#### 6. [ENDPOINT-002] GET /api/v1/tracks/search appelé par frontend mais n'existe pas backend
|
||||
- **Frontend:** `apps/web/src/features/tracks/services/trackSearchService.ts:152`
|
||||
- **Backend:** Route existe dans router.go:734 mais peut-être non fonctionnelle
|
||||
- **Impact:** Erreur 404 ou réponse incorrecte
|
||||
- **Solution:** Vérifier et corriger endpoint backend
|
||||
- **Priorité:** P1
|
||||
|
||||
#### 7. [ENDPOINT-003] GET /api/v1/playlists/search appelé par frontend mais backend TODO
|
||||
- **Frontend:** `apps/web/src/features/playlists/services/playlistService.ts:193`
|
||||
- **Backend:** TODO comment dans code frontend
|
||||
- **Impact:** Erreur 404
|
||||
- **Solution:** Implémenter endpoint backend
|
||||
- **Priorité:** P1
|
||||
|
||||
#### 8. [ENDPOINT-004] GET /api/v1/sessions/stats existe backend mais non utilisé frontend
|
||||
- **Backend:** `veza-backend-api/internal/api/router.go:1207`
|
||||
- **Frontend:** Non utilisé
|
||||
- **Impact:** Fonctionnalité manquante
|
||||
- **Solution:** Créer service frontend
|
||||
- **Priorité:** P2
|
||||
|
||||
#### 9. [ENDPOINT-005] Endpoints playlist collaborators manquants frontend
|
||||
- **Backend:** POST/DELETE/PUT `/api/v1/playlists/:id/collaborators`
|
||||
- **Frontend:** Non implémenté
|
||||
- **Impact:** Fonctionnalité collaboration manquante
|
||||
- **Solution:** Implémenter services frontend
|
||||
- **Priorité:** P2
|
||||
|
||||
#### 10. [TYPE-003] Playlist.title vs Playlist.name confusion
|
||||
- **Backend:** Colonne DB = `name`, JSON = `title`
|
||||
- **Frontend:** Utilise `title`
|
||||
- **Impact:** Confusion potentielle
|
||||
- **Solution:** Documenter ou standardiser
|
||||
- **Priorité:** P2
|
||||
|
||||
### 🟡 MINEURS (Dettes techniques)
|
||||
|
||||
#### 11. [CLEANUP-001] Types dupliqués entre types/ et features/*/types/
|
||||
- **Fichiers:** `types/api.ts` vs `features/*/types/*.ts`
|
||||
- **Impact:** Maintenance difficile
|
||||
- **Solution:** Consolider dans types/
|
||||
- **Priorité:** P2
|
||||
|
||||
#### 12. [CLEANUP-002] Endpoints 2FA non utilisés frontend
|
||||
- **Backend:** 4 endpoints 2FA implémentés
|
||||
- **Frontend:** Non utilisés
|
||||
- **Impact:** Fonctionnalité inutilisée
|
||||
- **Solution:** Implémenter ou documenter comme future feature
|
||||
- **Priorité:** P3
|
||||
|
||||
#### 13. [DOC-001] Documentation OpenAPI/Swagger incomplète
|
||||
- **Backend:** Swagger configuré mais annotations manquantes
|
||||
- **Impact:** Documentation API incomplète
|
||||
- **Solution:** Ajouter annotations Swagger
|
||||
- **Priorité:** P3
|
||||
|
||||
---
|
||||
|
||||
## 8. Recommandations
|
||||
|
||||
### Immédiat (P0)
|
||||
1. ✅ Configurer `CORS_ALLOWED_ORIGINS` pour production
|
||||
2. ✅ Fail-fast si Redis indisponible en production (CSRF)
|
||||
3. ✅ Aligner Track.status backend/frontend
|
||||
|
||||
### Court terme (P1)
|
||||
1. Standardiser User.id comme string partout
|
||||
2. Implémenter endpoints search manquants backend
|
||||
3. Vérifier et corriger tracks/search endpoint
|
||||
|
||||
### Moyen terme (P2)
|
||||
1. Implémenter services frontend pour endpoints manquants
|
||||
2. Consolider types dupliqués
|
||||
3. Documenter Playlist.title vs name
|
||||
|
||||
### Long terme (P3)
|
||||
1. Implémenter 2FA frontend ou documenter comme future
|
||||
2. Compléter documentation OpenAPI
|
||||
|
||||
---
|
||||
|
||||
## 9. Métriques de Qualité
|
||||
|
||||
### Couverture Endpoints
|
||||
- **Backend → Frontend:** 45/85 (53%)
|
||||
- **Frontend → Backend:** 42/45 (93%)
|
||||
|
||||
### Alignement Types
|
||||
- **Types alignés:** 15/27 (56%)
|
||||
- **Types à corriger:** 12/27 (44%)
|
||||
|
||||
### Code Duplication
|
||||
- **Clients API:** 0 duplication ✅
|
||||
- **Stores:** 0 duplication ✅
|
||||
- **Types:** 3 duplications ⚠️
|
||||
|
||||
---
|
||||
|
||||
## 10. Conclusion
|
||||
|
||||
L'intégration backend/frontend est **fonctionnelle mais nécessite des corrections critiques** avant le déploiement en production. Les principaux problèmes sont:
|
||||
|
||||
1. **Configuration CORS** (bloqueur production)
|
||||
2. **Protection CSRF** (sécurité)
|
||||
3. **Incohérences de types** (bugs potentiels)
|
||||
|
||||
Une fois ces problèmes résolus, l'intégration devrait atteindre un score de **9/10**.
|
||||
|
||||
---
|
||||
|
||||
**Prochaines étapes:** Voir `VEZA_INTEGRATION_PERFECTION_TODOLIST_TEMPLATE.json` pour la liste détaillée des tâches.
|
||||
|
||||
|
|
@ -589,7 +589,8 @@
|
|||
"description": "Vérifier s'il y a deux stores auth et garder uniquement features/auth/store/authStore.ts.",
|
||||
"priority": "P1",
|
||||
"priority_rank": 17,
|
||||
"status": "todo",
|
||||
"status": "completed",
|
||||
"completed_at": "2025-01-27T15:45:00Z",
|
||||
"estimated_hours": 2,
|
||||
"side": "frontend_only",
|
||||
"files_to_modify": [
|
||||
|
|
@ -1098,13 +1099,13 @@
|
|||
},
|
||||
"progress_tracking": {
|
||||
"total_tasks": 32,
|
||||
"completed": 16,
|
||||
"completed": 17,
|
||||
"in_progress": 0,
|
||||
"todo": 16,
|
||||
"todo": 15,
|
||||
"blocked": 0,
|
||||
"completion_percentage": 50,
|
||||
"last_updated": "2025-01-27T15:30:00Z",
|
||||
"completion_percentage": 53,
|
||||
"last_updated": "2025-01-27T15:45:00Z",
|
||||
"estimated_completion_date": null,
|
||||
"estimated_hours_remaining": 25
|
||||
"estimated_hours_remaining": 23
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { ErrorBoundary } from '@/components/ErrorBoundary';
|
||||
import { PWAInstallBanner } from '@/components/pwa/PWAInstallBanner';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { ProtectedRoute } from './ProtectedRoute';
|
|||
// Mock useAuthStore
|
||||
const mockIsAuthenticated = vi.fn(() => false);
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
isAuthenticated: mockIsAuthenticated(),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ vi.mock('@/hooks/useTranslation', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: { id: '1', username: 'testuser', email: 'test@example.com' },
|
||||
isAuthenticated: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { EmailVerificationBadge } from '@/features/auth/components/EmailVerificationBadge';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Link, useLocation } from 'react-router-dom';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { cn } from '@/lib/utils';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ vi.mock('../hooks/useAuth', () => ({
|
|||
})),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(() => ({
|
||||
isAuthenticated: false,
|
||||
user: null,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const mockLogin = vi.fn();
|
|||
const mockClearError = vi.fn();
|
||||
const mockError = { message: '', code: '' };
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
login: mockLogin,
|
||||
isLoading: false,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useForm } from 'react-hook-form';
|
|||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { formatErrorMessage } from '@/utils/apiErrorHandler';
|
||||
import type { LoginRequest } from '@/services/api/auth';
|
||||
import type { ApiError } from '@/types/api';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const mockRegister = vi.fn();
|
|||
const mockClearError = vi.fn();
|
||||
|
||||
// Mock des services
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
register: mockRegister,
|
||||
isLoading: false,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useForm } from 'react-hook-form';
|
|||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { formatErrorMessage } from '@/utils/apiErrorHandler';
|
||||
import type { RegisterRequest } from '@/services/api/auth';
|
||||
import type { ApiError } from '@/types/api';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { TokenStorage } from '@/services/tokenStorage';
|
||||
import { getMe } from '@/services/api/auth';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { login as loginService } from '@/services/api/auth';
|
||||
import type { LoginRequest } from '@/services/api/auth';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
export function useLogout() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { TokenStorage } from '@/services/tokenStorage';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { register as registerService } from '@/services/api/auth';
|
||||
import type { RegisterRequest } from '@/services/api/auth';
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export type {
|
|||
|
||||
// Hooks
|
||||
export { useAuth } from './hooks/useAuth';
|
||||
export { useAuthStore } from '@/stores/auth';
|
||||
export { useAuthStore } from './store/authStore';
|
||||
export { useLogin } from './hooks/useLogin';
|
||||
export { useRegister } from './hooks/useRegister';
|
||||
export { useLogout } from './hooks/useLogout';
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { render, screen, waitFor, act } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { LoginPage } from './LoginPage';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useLogin } from '../hooks/useLogin';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Navigate, Link } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { AuthLayout } from '../components/AuthLayout';
|
||||
import { AuthInput } from '../components/AuthInput';
|
||||
import { AuthButton } from '../components/AuthButton';
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import { render, screen, waitFor, act } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RegisterPage } from './RegisterPage';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useRegister } from '../hooks/useRegister';
|
||||
import { useUsernameAvailability } from '../hooks/useUsernameAvailability';
|
||||
import { resendVerificationEmail } from '../services/authService';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Navigate, Link } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { AuthLayout } from '../components/AuthLayout';
|
||||
import { AuthInput } from '../components/AuthInput';
|
||||
import { AuthButton } from '../components/AuthButton';
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { broadcastSync } from '@/utils/broadcastSync';
|
|||
import type { User } from '@/types';
|
||||
import type { ApiError } from '@/types/api';
|
||||
|
||||
// INT-AUTH-002: Auth store moved from stores/auth.ts to features/auth/store/authStore.ts
|
||||
// FE-TYPE-011: Fully typed store interfaces
|
||||
export interface AuthState {
|
||||
user: User | null;
|
||||
|
|
@ -74,7 +75,8 @@ export const useAuthStore = create<AuthStore>()(
|
|||
// Le service auth gère déjà le stockage des tokens
|
||||
const response = await registerService(userData);
|
||||
|
||||
const isAuth = !!response.access_token;
|
||||
// INT-AUTH-002: Updated to use response.token.access_token format (INT-TYPE-008)
|
||||
const isAuth = !!response.token?.access_token;
|
||||
|
||||
set({
|
||||
user: response.user,
|
||||
|
|
@ -175,7 +177,7 @@ export const useAuthStore = create<AuthStore>()(
|
|||
});
|
||||
|
||||
// INT-016: Initialiser le refresh proactif après vérification du statut
|
||||
const { initializeProactiveRefresh } = await import('../services/tokenRefresh');
|
||||
const { initializeProactiveRefresh } = await import('@/services/tokenRefresh');
|
||||
initializeProactiveRefresh();
|
||||
|
||||
// Récupérer le token CSRF après check auth status
|
||||
|
|
@ -237,3 +239,4 @@ export const useAuthStore = create<AuthStore>()(
|
|||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|||
import { Badge } from '@/components/ui/badge';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
// Separator unused, removing
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
// TODO: wsService should be replaced with websocketService or a proper chat service
|
||||
import { wsService } from '@/services/websocket';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { ChatMessage } from '../store/chatStore';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ChatMessageProps {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { sanitizeChatMessage } from '@/utils/sanitize';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { OutgoingMessage, IncomingMessage } from '../types';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { ChatSidebar } from '../components/ChatSidebar';
|
|||
import { ChatRoom } from '../components/ChatRoom';
|
||||
import { ChatInput } from '../components/ChatInput';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { useChat } from '../hooks/useChat';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useLibraryItems, useLibraryActions, useLibraryStatus } from '@/utils/storeSelectors';
|
||||
import {
|
||||
Card,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { ShoppingCart, Trash2 } from 'lucide-react';
|
|||
import { marketplaceService } from '@/services/marketplaceService';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useState } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { Dialog } from '@/components/ui/dialog';
|
||||
|
||||
// FE-PAGE-006: Complete Marketplace page implementation - Cart Component
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ vi.mock('@/hooks/useToast', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: (selector: any) => {
|
||||
const state = {
|
||||
user: { id: 1, username: 'owner' },
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ vi.mock('@/hooks/useToast', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: (selector: any) => {
|
||||
const state = {
|
||||
user: { id: 1, username: 'testuser' },
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {
|
|||
getPlaylist,
|
||||
getPlaylistFollowStatus,
|
||||
} from '../services/playlistService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
|
||||
// Mock dependencies
|
||||
|
|
@ -25,7 +25,7 @@ vi.mock('../services/playlistService', () => ({
|
|||
getPlaylistFollowStatus: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from '../services/playlistService';
|
||||
import type { Playlist } from '../types';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
/**
|
||||
* FE-COMP-017: Follow/Unfollow button component for playlists
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { useState, useMemo } from 'react';
|
|||
import { useQuery } from '@tanstack/react-query';
|
||||
import { usePlaylists } from '../hooks/usePlaylist';
|
||||
import { searchPlaylists } from '../services/playlistService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { PlaylistCard } from './PlaylistCard';
|
||||
import { PlaylistListSkeleton } from './PlaylistListSkeleton';
|
||||
import { PlaylistBatchActions } from './PlaylistBatchActions';
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { renderHook } from '@testing-library/react';
|
|||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { usePlaylistPermissions } from './usePlaylistPermissions';
|
||||
import { useCollaborators } from './usePlaylist';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import type { Playlist } from '../types';
|
||||
|
||||
// Mock des hooks
|
||||
|
|
@ -24,7 +24,7 @@ vi.mock('./usePlaylist', () => ({
|
|||
useUpdateCollaboratorPermission: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn((selector) => {
|
||||
const state = { user: { id: 1 } };
|
||||
return selector(state);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button';
|
|||
import { UserPlus, UserCheck, Loader2 } from 'lucide-react';
|
||||
import { followUser, unfollowUser, getProfile, type UserProfile } from '../services/profileService';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
/**
|
||||
* FE-COMP-015: Follow/Unfollow button component for user profiles
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ vi.mock('../services/profileService', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: {
|
||||
id: 123,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import type { Track } from '@/features/tracks/types/track';
|
|||
import { PlaylistCard } from '@/features/playlists/components/PlaylistCard';
|
||||
import { Music, Library } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
// FE-PAGE-010: Complete User Profile page implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ vi.mock('../services/settingsService', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: {
|
||||
id: 1,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { getSettings, updateSettings } from '../services/settingsService';
|
||||
import { UserSettings } from '../types/settings';
|
||||
import { SettingsTabs } from '../components/SettingsTabs';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
} from '../services/trackService';
|
||||
import { uploadTrack as uploadTrackApi } from '../api/trackApi';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../services/trackService', () => ({
|
||||
|
|
@ -40,7 +40,7 @@ vi.mock('@/hooks/useToast', () => ({
|
|||
useToast: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import {
|
|||
deleteComment,
|
||||
getReplies,
|
||||
} from '../services/commentService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import type { TrackComment } from '../services/commentService';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../services/commentService');
|
||||
vi.mock('@/stores/auth');
|
||||
vi.mock('@/features/auth/store/authStore');
|
||||
vi.mock('@/hooks/useToast');
|
||||
|
||||
describe('CommentItem', () => {
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import {
|
|||
createComment,
|
||||
CommentError,
|
||||
} from '../services/commentService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import type { TrackComment } from '../services/commentService';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../services/commentService');
|
||||
vi.mock('@/stores/auth');
|
||||
vi.mock('@/features/auth/store/authStore');
|
||||
vi.mock('@/hooks/useToast');
|
||||
|
||||
describe('CommentSection', () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { getComments, createComment } from '../services/commentService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
|||
import userEvent from '@testing-library/user-event';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { CommentThread } from './CommentThread';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import {
|
||||
createComment,
|
||||
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from '../services/commentService';
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/stores/auth');
|
||||
vi.mock('@/features/auth/store/authStore');
|
||||
vi.mock('@/hooks/useToast');
|
||||
vi.mock('../services/commentService');
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import {
|
|||
X,
|
||||
Loader2,
|
||||
} from 'lucide-react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import {
|
||||
createComment,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Heart, Loader2 } from 'lucide-react';
|
|||
import { cn } from '@/lib/utils';
|
||||
import { likeTrack, unlikeTrack, getTrackLikes } from '../api/trackApi';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
/**
|
||||
* FE-COMP-016: Like/Unlike button component for tracks with count display
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { UploadQuota } from './UploadQuota';
|
||||
import { getUserQuota, TrackUploadError } from '../services/trackService';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
// Mock trackService
|
||||
vi.mock('../services/trackService', () => ({
|
||||
|
|
@ -20,7 +20,7 @@ vi.mock('../services/trackService', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { CommentSection } from '../components/CommentSection';
|
|||
import { ShareDialog } from '../components/ShareDialog';
|
||||
import { TrackHistory } from '../components/TrackHistory';
|
||||
import { TrackStatsDisplay } from '../components/TrackStatsDisplay';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
// FE-PAGE-007: Complete Track Detail page implementation
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const mockUser = {
|
|||
|
||||
const mockRefreshUser = vi.fn();
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: mockUser,
|
||||
refreshUser: mockRefreshUser,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import type { UseAuthReturn } from './types';
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const mockUser = {
|
|||
first_name: 'Test',
|
||||
};
|
||||
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: mockUser,
|
||||
isAuthenticated: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useLibraryItems, useLibraryActions, useLibraryStatus } from '@/utils/storeSelectors';
|
||||
import { useDashboard } from '@/features/dashboard/hooks/useDashboard';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ vi.mock('@/hooks/useTranslation', () => ({
|
|||
}));
|
||||
|
||||
// Mock useAuthStore
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: () => ({
|
||||
user: {
|
||||
id: '1',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useNavigate, Link } from 'react-router-dom';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { LoginForm, LoginFormData } from '@/components/forms/LoginForm';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { formatErrorMessage } from '@/utils/apiErrorHandler';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import type { ApiError } from '@/types/api';
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
RegisterForm,
|
||||
RegisterFormData,
|
||||
} from '@/components/forms/RegisterForm';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { formatErrorMessage } from '@/utils/apiErrorHandler';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import type { ApiError } from '@/types/api';
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { AppRouter } from './index';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
|
||||
// Mock the stores
|
||||
vi.mock('@/stores/auth', () => ({
|
||||
vi.mock('@/features/auth/store/authStore', () => ({
|
||||
useAuthStore: vi.fn(),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useLibraryStore } from '@/stores/library';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { apiClient } from '@/services/api/client';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useLibraryStore } from '@/stores/library';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { logger } from './logger';
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { useAuthStore } from '@/features/auth/store/authStore';
|
||||
import { useUIStore } from '@/stores/ui';
|
||||
import { useLibraryStore } from '@/stores/library';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
|
|
|
|||
Loading…
Reference in a new issue