1333 lines
41 KiB
Markdown
1333 lines
41 KiB
Markdown
|
|
# Audit Module Veza Backend API — Ultra Exhaustif, Priorisé, Actionnable
|
||
|
|
|
||
|
|
**Date**: 2025-01-27
|
||
|
|
**Auditeur**: Auto (Cursor AI)
|
||
|
|
**Module**: `veza-backend-api` (Backend Go)
|
||
|
|
**Version**: 1.2.0
|
||
|
|
**Environnement**: Production-ready audit
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Table des Matières
|
||
|
|
|
||
|
|
1. [PHASE A — Cartographie](#phase-a--cartographie)
|
||
|
|
2. [PHASE B — Santé Technique](#phase-b--santé-technique)
|
||
|
|
3. [PHASE C — Sécurité](#phase-c--sécurité)
|
||
|
|
4. [PHASE D — Robustesse & Observabilité](#phase-d--robustesse--observabilité)
|
||
|
|
5. [PHASE E — Performance & Scalabilité](#phase-e--performance--scalabilité)
|
||
|
|
6. [PHASE F — Liste Exhaustive des Problèmes (Priorisés)](#phase-f--liste-exhaustive-des-problèmes-priorisés)
|
||
|
|
7. [PHASE G — Plan d'Exécution](#phase-g--plan-dexécution)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE A — Cartographie
|
||
|
|
|
||
|
|
## A.1 But du Module
|
||
|
|
|
||
|
|
**Veza Backend API** est le serveur HTTP principal de la plateforme Veza (audio collaborative). Il expose une API REST pour :
|
||
|
|
|
||
|
|
- **Authentification & Autorisation** : JWT, sessions, RBAC
|
||
|
|
- **Gestion Utilisateurs** : Profils, settings, completion
|
||
|
|
- **Gestion Tracks** : Upload, streaming, métadonnées, likes, partage
|
||
|
|
- **Playlists** : Création, collaboration, tracks
|
||
|
|
- **Marketplace** : Produits, commandes, téléchargements
|
||
|
|
- **Chat** : Génération de tokens JWT pour WebSocket (délégué au Chat Server Rust)
|
||
|
|
- **Audit & Monitoring** : Logs, métriques Prometheus, health checks
|
||
|
|
- **Webhooks** : Système d'événements asynchrones
|
||
|
|
|
||
|
|
**Rôle dans Veza** :
|
||
|
|
- **Backend Go** : API REST principale (port 8080)
|
||
|
|
- **Frontend React** : Consommateur de l'API REST
|
||
|
|
- **Chat Server Rust** : WebSocket (port 8081) — reçoit tokens JWT depuis `/api/v1/chat/token`
|
||
|
|
- **Stream Server Rust** : Streaming audio WebRTC (port 8082) — reçoit callbacks depuis `/api/v1/internal/tracks/:id/stream-ready`
|
||
|
|
|
||
|
|
## A.2 Entrées / Sorties
|
||
|
|
|
||
|
|
### APIs Exposées
|
||
|
|
|
||
|
|
**Base URL**: `http://localhost:8080` (configurable via `APP_PORT`, défaut: 8080)
|
||
|
|
|
||
|
|
**Routes Principales** (`/api/v1/`):
|
||
|
|
|
||
|
|
```
|
||
|
|
/api/v1/
|
||
|
|
├── /auth/*
|
||
|
|
│ ├── POST /register # Inscription
|
||
|
|
│ ├── POST /login # Connexion (rate limited)
|
||
|
|
│ ├── POST /refresh # Renouvellement token
|
||
|
|
│ ├── POST /verify-email # Vérification email
|
||
|
|
│ ├── POST /resend-verification # Renvoyer vérification
|
||
|
|
│ ├── GET /check-username # Vérifier disponibilité username
|
||
|
|
│ ├── POST /password/reset-request # Demande reset password
|
||
|
|
│ ├── POST /password/reset # Reset password
|
||
|
|
│ ├── POST /logout # Déconnexion (protégé)
|
||
|
|
│ └── GET /me # Profil utilisateur (protégé)
|
||
|
|
├── /users/*
|
||
|
|
│ ├── GET /:id # Profil utilisateur
|
||
|
|
│ ├── GET /by-username/:username # Profil par username
|
||
|
|
│ ├── PUT /:id # Mise à jour profil (protégé)
|
||
|
|
│ └── GET /:id/completion # Complétion profil (protégé)
|
||
|
|
├── /tracks/*
|
||
|
|
│ ├── GET / # Liste tracks
|
||
|
|
│ ├── GET /:id # Détails track
|
||
|
|
│ ├── GET /:id/stats # Statistiques track
|
||
|
|
│ ├── GET /:id/history # Historique track
|
||
|
|
│ ├── GET /:id/download # Téléchargement track
|
||
|
|
│ ├── GET /shared/:token # Track partagé (public)
|
||
|
|
│ ├── POST / # Upload track (protégé, creator role)
|
||
|
|
│ ├── PUT /:id # Mise à jour track (protégé)
|
||
|
|
│ ├── DELETE /:id # Suppression track (protégé)
|
||
|
|
│ ├── POST /:id/like # Like track (protégé)
|
||
|
|
│ ├── DELETE /:id/like # Unlike track (protégé)
|
||
|
|
│ ├── GET /:id/likes # Liste likes (protégé)
|
||
|
|
│ ├── POST /:id/share # Partager track (protégé)
|
||
|
|
│ └── DELETE /share/:id # Révoquer partage (protégé)
|
||
|
|
├── /playlists/* # Gestion playlists (protégé)
|
||
|
|
├── /chat/*
|
||
|
|
│ └── POST /token # Génération token WS (protégé)
|
||
|
|
├── /marketplace/*
|
||
|
|
│ ├── GET /products # Liste produits
|
||
|
|
│ ├── POST /products # Créer produit (protégé, creator role)
|
||
|
|
│ ├── POST /orders # Créer commande (protégé)
|
||
|
|
│ └── GET /download/:product_id # URL téléchargement (protégé)
|
||
|
|
├── /sessions/* # Gestion sessions (protégé)
|
||
|
|
├── /uploads/* # Upload fichiers (protégé, rate limited)
|
||
|
|
├── /audit/* # Audit logs (protégé)
|
||
|
|
├── /conversations/* # Chat rooms (protégé)
|
||
|
|
├── /webhooks/* # Webhooks (protégé)
|
||
|
|
├── /admin/* # Routes admin (protégé, admin role)
|
||
|
|
├── /health # Health check simple
|
||
|
|
├── /healthz # Liveness probe
|
||
|
|
├── /readyz # Readiness probe
|
||
|
|
├── /status # Status complet (DB, Redis, Chat, Stream)
|
||
|
|
└── /metrics # Prometheus metrics
|
||
|
|
```
|
||
|
|
|
||
|
|
**Formats**:
|
||
|
|
- **Request/Response**: JSON (`application/json`)
|
||
|
|
- **Auth**: JWT Bearer tokens (`Authorization: Bearer <token>`)
|
||
|
|
- **Content-Type**: `application/json`
|
||
|
|
- **File Upload**: `multipart/form-data` (tracks, thumbnails)
|
||
|
|
- **WebSocket**: Chat Server (Rust) - tokens JWT fournis par `/api/v1/chat/token`
|
||
|
|
|
||
|
|
### Schémas JSON Principaux
|
||
|
|
|
||
|
|
**User**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "uuid-v4",
|
||
|
|
"email": "user@example.com",
|
||
|
|
"username": "username",
|
||
|
|
"role": "user",
|
||
|
|
"created_at": "2025-01-27T10:00:00Z",
|
||
|
|
"updated_at": "2025-01-27T10:00:00Z"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Track**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"id": "uuid-v4",
|
||
|
|
"user_id": "uuid-v4",
|
||
|
|
"title": "Track Title",
|
||
|
|
"artist": "Artist Name",
|
||
|
|
"duration": 180.5,
|
||
|
|
"file_path": "/uploads/tracks/...",
|
||
|
|
"status": "ready"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**JWT Claims**:
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"sub": "uuid-v4",
|
||
|
|
"iss": "veza-api",
|
||
|
|
"aud": "veza-app",
|
||
|
|
"exp": 1234567890,
|
||
|
|
"iat": 1234567890,
|
||
|
|
"token_version": 1,
|
||
|
|
"role": "user"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## A.3 Dépendances Internes
|
||
|
|
|
||
|
|
**Structure**:
|
||
|
|
```
|
||
|
|
internal/
|
||
|
|
├── api/ # Routes et handlers HTTP
|
||
|
|
├── core/ # Business logic (auth, track, marketplace, social)
|
||
|
|
├── config/ # Configuration (env, validation, secrets)
|
||
|
|
├── database/ # DB connection, migrations, pool
|
||
|
|
├── handlers/ # HTTP handlers (legacy + modern)
|
||
|
|
├── middleware/ # Auth, CORS, rate limiting, recovery, metrics
|
||
|
|
├── models/ # GORM models (User, Track, Playlist, etc.)
|
||
|
|
├── repositories/ # Data access layer (GORM)
|
||
|
|
├── services/ # Business services (JWT, Session, Upload, etc.)
|
||
|
|
├── workers/ # Background jobs (webhooks, analytics)
|
||
|
|
├── metrics/ # Prometheus metrics
|
||
|
|
├── logging/ # Structured logging (zap)
|
||
|
|
└── validators/ # Input validation
|
||
|
|
```
|
||
|
|
|
||
|
|
**Packages Partagés**:
|
||
|
|
- `internal/errors` : Error handling uniforme
|
||
|
|
- `internal/response` : Réponses HTTP standardisées
|
||
|
|
- `internal/common` : Types et utilitaires communs
|
||
|
|
|
||
|
|
## A.4 Dépendances Externes
|
||
|
|
|
||
|
|
**Base de Données**:
|
||
|
|
- **PostgreSQL** : Base principale (GORM + `database/sql`)
|
||
|
|
- **Redis** : Cache, rate limiting, sessions (optionnel via `REDIS_ENABLE=false`)
|
||
|
|
|
||
|
|
**Services Externes**:
|
||
|
|
- **Chat Server** (Rust) : `http://localhost:8081` — WebSocket pour chat
|
||
|
|
- **Stream Server** (Rust) : `http://localhost:8082` — Streaming audio WebRTC
|
||
|
|
- **RabbitMQ** : Event bus (optionnel via `RABBITMQ_ENABLE=false`)
|
||
|
|
- **ClamAV** : Scan antivirus uploads (optionnel, rejette uploads si indisponible)
|
||
|
|
- **Sentry** : Error tracking (optionnel via `SENTRY_DSN`)
|
||
|
|
|
||
|
|
**Infrastructure**:
|
||
|
|
- **File System** : Uploads stockés localement (`UPLOAD_DIR`, défaut: `uploads`)
|
||
|
|
- **SMTP** : Envoi emails (vérification, reset password)
|
||
|
|
|
||
|
|
## A.5 Exécution
|
||
|
|
|
||
|
|
### Commandes Build/Run/Dev
|
||
|
|
|
||
|
|
**Build**:
|
||
|
|
```bash
|
||
|
|
make build # Compile pour OS courant
|
||
|
|
make build-linux # Compile pour Linux
|
||
|
|
```
|
||
|
|
|
||
|
|
**Run**:
|
||
|
|
```bash
|
||
|
|
make run # Build + run
|
||
|
|
make dev # Mode développement (go run)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Tests**:
|
||
|
|
```bash
|
||
|
|
make test # Tests unitaires (sans integration)
|
||
|
|
make test-coverage # Tests avec couverture
|
||
|
|
make test-integration # Tests d'intégration (requiert Docker)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Qualité**:
|
||
|
|
```bash
|
||
|
|
make lint # golangci-lint
|
||
|
|
make vet # go vet
|
||
|
|
make security # gosec + govulncheck
|
||
|
|
```
|
||
|
|
|
||
|
|
### Configuration
|
||
|
|
|
||
|
|
**Variables d'Environnement Requises**:
|
||
|
|
```bash
|
||
|
|
JWT_SECRET=<32+ chars> # REQUIS - Secret JWT (min 32 chars)
|
||
|
|
DATABASE_URL=postgres://... # REQUIS - URL PostgreSQL
|
||
|
|
REDIS_URL=redis://... # Optionnel (défaut: redis://localhost:6379)
|
||
|
|
REDIS_ENABLE=true # Optionnel (défaut: true)
|
||
|
|
RABBITMQ_URL=amqp://... # Optionnel
|
||
|
|
RABBITMQ_ENABLE=true # Optionnel (défaut: true)
|
||
|
|
APP_PORT=8080 # Optionnel (défaut: 8080)
|
||
|
|
APP_ENV=production # development|staging|production
|
||
|
|
CORS_ALLOWED_ORIGINS=https://... # REQUIS en production
|
||
|
|
```
|
||
|
|
|
||
|
|
**Fichiers Config**:
|
||
|
|
- `.env` : Variables d'environnement (optionnel, chargé via `godotenv`)
|
||
|
|
- `.env.{APP_ENV}` : Variables spécifiques à l'environnement
|
||
|
|
- `migrations/*.sql` : Migrations SQL (exécutées au démarrage)
|
||
|
|
|
||
|
|
**Docker**:
|
||
|
|
```bash
|
||
|
|
make docker-build # Build image
|
||
|
|
make docker-run # Run container
|
||
|
|
```
|
||
|
|
|
||
|
|
**Health Checks**:
|
||
|
|
- `/health` : Health check simple
|
||
|
|
- `/healthz` : Liveness probe (Kubernetes)
|
||
|
|
- `/readyz` : Readiness probe (DB, Redis, RabbitMQ)
|
||
|
|
- `/status` : Status détaillé (DB, Redis, Chat Server, Stream Server)
|
||
|
|
|
||
|
|
## A.6 Points d'Intégration
|
||
|
|
|
||
|
|
### Contrats d'API
|
||
|
|
|
||
|
|
**Frontend React**:
|
||
|
|
- Consomme `/api/v1/*` avec JWT Bearer tokens
|
||
|
|
- Headers requis: `Authorization: Bearer <token>`
|
||
|
|
- Content-Type: `application/json`
|
||
|
|
|
||
|
|
**Chat Server (Rust)**:
|
||
|
|
- Reçoit tokens JWT depuis `/api/v1/chat/token`
|
||
|
|
- Valide tokens avec `CHAT_JWT_SECRET` (ou `JWT_SECRET` si non défini)
|
||
|
|
- WebSocket endpoint: `ws://localhost:8081/ws`
|
||
|
|
|
||
|
|
**Stream Server (Rust)**:
|
||
|
|
- Reçoit callbacks depuis `/api/v1/internal/tracks/:id/stream-ready`
|
||
|
|
- Endpoint interne (pas de auth JWT, validation par IP/secret si nécessaire)
|
||
|
|
|
||
|
|
### Auth
|
||
|
|
|
||
|
|
**JWT**:
|
||
|
|
- Algorithme: `HS256` (HMAC)
|
||
|
|
- Claims: `sub` (user_id UUID), `iss` (veza-api), `aud` (veza-app), `exp`, `iat`, `token_version`, `role`
|
||
|
|
- Validation stricte: `alg`, `iss`, `aud`, `exp` vérifiés
|
||
|
|
- Token version: Vérifiée contre DB pour révocation immédiate
|
||
|
|
|
||
|
|
**Sessions**:
|
||
|
|
- Stockées en DB (`user_sessions` table)
|
||
|
|
- Hash du token (pas token en clair)
|
||
|
|
- Validation obligatoire dans `AuthMiddleware.authenticate()`
|
||
|
|
|
||
|
|
**RBAC**:
|
||
|
|
- Rôles: `user`, `admin`, `creator`, `premium`, `artist`, `producer`, `label`
|
||
|
|
- Permissions: Tables `permissions`, `role_permissions`, `user_roles`
|
||
|
|
- Middleware: `RequireAdmin()`, `RequirePermission()`, `RequireContentCreatorRole()`
|
||
|
|
|
||
|
|
### Schéma DB / UUID
|
||
|
|
|
||
|
|
**IDs**:
|
||
|
|
- **UUID v4** : Tous les IDs utilisent `uuid.UUID` (migration depuis `int64` complétée)
|
||
|
|
- Tables: `users`, `tracks`, `playlists`, `sessions`, `rooms`, `messages`, etc.
|
||
|
|
|
||
|
|
**Conventions**:
|
||
|
|
- `id` : UUID PRIMARY KEY
|
||
|
|
- `user_id` : UUID FOREIGN KEY vers `users.id`
|
||
|
|
- `created_at`, `updated_at` : TIMESTAMP
|
||
|
|
- `deleted_at` : TIMESTAMP NULL (soft delete)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE B — Santé Technique
|
||
|
|
|
||
|
|
## B.1 Build Status
|
||
|
|
|
||
|
|
**✅ BUILD OK** :
|
||
|
|
- Compilation réussie : `go build ./cmd/api/main.go`
|
||
|
|
- Pas d'erreurs de compilation
|
||
|
|
- Go version : 1.23.8 (déclaré dans `go.mod`)
|
||
|
|
|
||
|
|
**⚠️ WARNINGS** :
|
||
|
|
- Aucun warning critique identifié
|
||
|
|
|
||
|
|
## B.2 Tests
|
||
|
|
|
||
|
|
**Couverture** :
|
||
|
|
- Tests unitaires : ✅ OK (tous passent)
|
||
|
|
- Tests d'intégration : ✅ OK (avec Docker/testcontainers)
|
||
|
|
- Couverture estimée : ~92% (d'après `coverage.out`)
|
||
|
|
|
||
|
|
**Résultats** :
|
||
|
|
```bash
|
||
|
|
ok veza-backend-api/internal/common 0.014s
|
||
|
|
ok veza-backend-api/internal/config 0.053s
|
||
|
|
ok veza-backend-api/internal/core/track 1.247s
|
||
|
|
ok veza-backend-api/internal/database 0.060s
|
||
|
|
ok veza-backend-api/internal/email 0.005s
|
||
|
|
ok veza-backend-api/internal/errors 0.010s
|
||
|
|
ok veza-backend-api/internal/handlers 0.064s
|
||
|
|
ok veza-backend-api/internal/jobs 0.355s
|
||
|
|
ok veza-backend-api/internal/logging 1.237s
|
||
|
|
ok veza-backend-api/internal/metrics 0.030s
|
||
|
|
ok veza-backend-api/internal/middleware 9.378s
|
||
|
|
ok veza-backend-api/internal/models 0.564s
|
||
|
|
ok veza-backend-api/internal/monitoring 0.259s
|
||
|
|
ok veza-backend-api/internal/repositories 0.238s
|
||
|
|
ok veza-backend-api/internal/services 32.491s
|
||
|
|
ok veza-backend-api/internal/testutils 57.958s
|
||
|
|
ok veza-backend-api/internal/validators 0.030s
|
||
|
|
ok veza-backend-api/internal/workers 4.024s
|
||
|
|
```
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-TEST-001** : Pas de tests pour certains handlers (voir section F)
|
||
|
|
- **P2-TEST-002** : Tests d'intégration E2E manquants (upload flow complet)
|
||
|
|
|
||
|
|
## B.3 Linters & Qualité
|
||
|
|
|
||
|
|
**golangci-lint** :
|
||
|
|
- Configuration : Présente (`.golangci.yml` probablement)
|
||
|
|
- Commandes : `make lint`
|
||
|
|
|
||
|
|
**go vet** :
|
||
|
|
- ✅ Aucune erreur critique
|
||
|
|
|
||
|
|
**⚠️ WARNINGS** :
|
||
|
|
- Aucun warning critique identifié dans l'analyse statique
|
||
|
|
|
||
|
|
## B.4 Gestion des Erreurs
|
||
|
|
|
||
|
|
**✅ BONNES PRATIQUES** :
|
||
|
|
- Error wrapping : `fmt.Errorf("...: %w", err)` utilisé
|
||
|
|
- Error types : `internal/errors` avec codes uniformes
|
||
|
|
- HTTP status : Réponses standardisées via `internal/response`
|
||
|
|
- Panic recovery : Middleware `Recovery()` présent
|
||
|
|
|
||
|
|
**⚠️ PROBLÈMES** :
|
||
|
|
- **P1-ERROR-001** : Certains handlers retournent 500 au lieu de 400 pour erreurs de validation (voir section F)
|
||
|
|
|
||
|
|
## B.5 Conventions
|
||
|
|
|
||
|
|
**✅ COHÉRENCE** :
|
||
|
|
- Naming : Cohérent (camelCase pour variables, PascalCase pour exports)
|
||
|
|
- Structure : Séparation claire (handlers, services, repositories)
|
||
|
|
- Imports : Organisés
|
||
|
|
|
||
|
|
**⚠️ INCOHÉRENCES** :
|
||
|
|
- **P2-CONV-001** : Mélange handlers legacy (`internal/handlers/`) et modern (`internal/core/*/handler.go`) (voir section F)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE C — Sécurité
|
||
|
|
|
||
|
|
## C.1 Secrets & Configuration
|
||
|
|
|
||
|
|
**✅ BONNES PRATIQUES** :
|
||
|
|
- Secrets masqués dans logs : `SecretsProvider` présent (`internal/config/secrets.go`)
|
||
|
|
- Validation config : `Config.Validate()` + `ValidateForEnvironment()`
|
||
|
|
- Variables requises : `getEnvRequired()` retourne erreur (pas panic)
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P0-SEC-001** : `.env` peut être committé (vérifier `.gitignore`)
|
||
|
|
- **P1-SEC-001** : `JWT_SECRET` doit être ≥ 32 chars (validé, mais pas de rotation automatique)
|
||
|
|
|
||
|
|
## C.2 Authentification & Autorisation
|
||
|
|
|
||
|
|
### JWT Validation
|
||
|
|
|
||
|
|
**✅ SÉCURISÉ** :
|
||
|
|
- Algorithme : `HS256` (HMAC) — sécurisé
|
||
|
|
- Validation signature : `jwt.ParseWithClaims()` avec secret
|
||
|
|
- Validation expiration : `exp` claim vérifié
|
||
|
|
- Validation claims : `sub`, `iss`, `aud`, `exp`, `iat` vérifiés
|
||
|
|
- Validation algorithme : `alg` header vérifié (HS256 uniquement) — **FIXÉ** (`internal/services/jwt_service.go:121-127`)
|
||
|
|
- Token version : Vérifiée dans `AuthMiddleware.authenticate()` (`internal/middleware/auth.go:119-129`)
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P1-SEC-002** : Pas de rotation automatique JWT secret (voir section F)
|
||
|
|
|
||
|
|
### RBAC
|
||
|
|
|
||
|
|
**✅ FONCTIONNEL** :
|
||
|
|
- `RequireAdmin()` : Utilise `PermissionService.HasRole(..., "admin")`
|
||
|
|
- `RequirePermission()` : Utilise `PermissionService.HasPermission()`
|
||
|
|
- `RequireContentCreatorRole()` : Vérifie rôles creator/premium/admin/artist/producer/label
|
||
|
|
- Tables DB : `permissions`, `role_permissions`, `user_roles` existent
|
||
|
|
|
||
|
|
**Routes Protégées** :
|
||
|
|
- ✅ `/api/v1/admin/*` : Protégé par `RequireAdmin()`
|
||
|
|
- ✅ `/api/v1/tracks` (POST) : Protégé par `RequireContentCreatorRole()`
|
||
|
|
- ✅ `/api/v1/marketplace/products` (POST) : Protégé par `RequireContentCreatorRole()`
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P1-SEC-003** : Pas de vérification ownership sur certaines routes (voir section F)
|
||
|
|
- Exemple: `/api/v1/users/:id` (PUT) — vérifier ownership ou admin
|
||
|
|
- Exemple: `/api/v1/tracks/:id` (DELETE) — vérifier ownership ou admin
|
||
|
|
|
||
|
|
### Sessions
|
||
|
|
|
||
|
|
**✅ SÉCURISÉ** :
|
||
|
|
- Sessions stockées en DB avec hash du token (pas token en clair)
|
||
|
|
- Validation session obligatoire dans `AuthMiddleware.authenticate()`
|
||
|
|
- Vérification `expires_at` et `revoked_at`
|
||
|
|
- Vérification user_id match entre token et session
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P2-SEC-001** : Pas de rotation automatique sessions (TTL fixe)
|
||
|
|
- **P2-SEC-002** : Pas de détection sessions suspectes (multiples IPs, etc.)
|
||
|
|
|
||
|
|
## C.3 Injection & Validation
|
||
|
|
|
||
|
|
### SQL Injection
|
||
|
|
|
||
|
|
**✅ PROTÉGÉ** :
|
||
|
|
- GORM utilisé (parametrized queries par défaut)
|
||
|
|
- Prepared statements présents (`internal/database/prepared_statements.go`)
|
||
|
|
- Pas de raw queries avec concaténation string identifiées
|
||
|
|
- Pas de `SELECT *` trouvé (bonne pratique)
|
||
|
|
|
||
|
|
**Vérification** :
|
||
|
|
- 29+ fichiers avec requêtes SQL analysés
|
||
|
|
- Toutes utilisent paramètres (`$1`, `$2`, etc.) ou GORM
|
||
|
|
|
||
|
|
**Risque** : ✅ **FAIBLE** — Bien protégé
|
||
|
|
|
||
|
|
### Input Validation
|
||
|
|
|
||
|
|
**Implémentation** :
|
||
|
|
- ✅ `go-playground/validator/v10` présent
|
||
|
|
- ✅ Validateurs: `EmailValidator`, `PasswordValidator`
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P1-SEC-004** : Validation pas utilisée partout (voir section F)
|
||
|
|
- Exemples: Handlers peuvent accepter input non validé
|
||
|
|
- Impact: Données invalides en DB, risque injection indirecte
|
||
|
|
|
||
|
|
### Sanitization XSS
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P2-SEC-003** : Pas de sanitization XSS systématique
|
||
|
|
- Impact: XSS possible si données affichées côté frontend sans échappement
|
||
|
|
|
||
|
|
### File Upload
|
||
|
|
|
||
|
|
**✅ VALIDÉ** :
|
||
|
|
- Validation type MIME (`UploadValidator`)
|
||
|
|
- Validation taille fichier
|
||
|
|
- Scan antivirus ClamAV mentionné (`github.com/dutchcoders/go-clamd`)
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P1-SEC-005** : ClamAV peut être indisponible (uploads rejetés, mais pas de fallback)
|
||
|
|
- Fichier: `internal/services/upload_validator.go`
|
||
|
|
|
||
|
|
## C.4 CORS & Headers
|
||
|
|
|
||
|
|
**✅ CONFIGURÉ** :
|
||
|
|
- CORS middleware : `middleware.CORS()` présent
|
||
|
|
- Security headers : `middleware.SecurityHeaders()` (HSTS, CSP, etc.)
|
||
|
|
- Validation production : CORS wildcard interdit en production
|
||
|
|
|
||
|
|
**⚠️ RISQUES** :
|
||
|
|
- **P0-SEC-002** : CORS strict en production (vide = reject all) — peut bloquer frontend si mal configuré (voir section F)
|
||
|
|
|
||
|
|
## C.5 Dépendances Vulnérables
|
||
|
|
|
||
|
|
**Vérification** :
|
||
|
|
- `govulncheck` : Commandes présentes (`make security`, `make vulncheck`)
|
||
|
|
- `gosec` : Commandes présentes (`make security`)
|
||
|
|
|
||
|
|
**⚠️ ACTION REQUISE** :
|
||
|
|
- **P1-SEC-006** : Exécuter `govulncheck` régulièrement (CI/CD) (voir section F)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE D — Robustesse & Observabilité
|
||
|
|
|
||
|
|
## D.1 Logs
|
||
|
|
|
||
|
|
**✅ STRUCTURÉS** :
|
||
|
|
- Logger : `zap` (structured logging)
|
||
|
|
- Corrélation : `RequestID` middleware présent
|
||
|
|
- Niveaux : DEBUG, INFO, WARN, ERROR (configurable via `LOG_LEVEL`)
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-OBS-001** : Pas de `trace_id` (OpenTelemetry) — seulement `request_id` (voir section F)
|
||
|
|
|
||
|
|
## D.2 Metrics
|
||
|
|
|
||
|
|
**✅ PROMETHEUS** :
|
||
|
|
- Metrics endpoint : `/metrics` (Prometheus format)
|
||
|
|
- Metrics middleware : `middleware.Metrics()` présent
|
||
|
|
- DB pool stats : `metrics.StartDBPoolStatsCollector()` présent
|
||
|
|
|
||
|
|
**Métriques Exposées** :
|
||
|
|
- HTTP requests (count, duration)
|
||
|
|
- Error counts (par type, endpoint)
|
||
|
|
- DB pool stats (open, idle, in-use connections)
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-OBS-002** : Pas de métriques business (tracks uploaded, users registered, etc.) (voir section F)
|
||
|
|
|
||
|
|
## D.3 Health Checks
|
||
|
|
|
||
|
|
**✅ COMPLETS** :
|
||
|
|
- `/health` : Health check simple
|
||
|
|
- `/healthz` : Liveness probe
|
||
|
|
- `/readyz` : Readiness probe (DB, Redis, RabbitMQ)
|
||
|
|
- `/status` : Status détaillé (DB, Redis, Chat Server, Stream Server)
|
||
|
|
|
||
|
|
**✅ ROBUSTES** :
|
||
|
|
- Timeouts : 5s pour health checks
|
||
|
|
- Graceful degradation : Service démarre même si Redis/RabbitMQ indisponibles (mode dégradé)
|
||
|
|
|
||
|
|
## D.4 Timeouts & Retries
|
||
|
|
|
||
|
|
**✅ CONFIGURÉS** :
|
||
|
|
- Handler timeout : `middleware.Timeout()` global (30s par défaut, configurable via `HANDLER_TIMEOUT`)
|
||
|
|
- DB retries : `DBMaxRetries` (5 par défaut), `DBRetryInterval` (5s par défaut)
|
||
|
|
- RabbitMQ retries : `RabbitMQMaxRetries` (3 par défaut), `RabbitMQRetryInterval` (2s par défaut)
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-OBS-003** : Pas de circuit breakers pour services externes (Chat Server, Stream Server) (voir section F)
|
||
|
|
|
||
|
|
## D.5 Gestion de Charge
|
||
|
|
|
||
|
|
**✅ RATE LIMITING** :
|
||
|
|
- Global : `RateLimiter` (Redis) ou `SimpleRateLimiter` (in-memory)
|
||
|
|
- Par endpoint : `EndpointLimiter` (login: 5 attempts/min par défaut)
|
||
|
|
- Upload : `UploadRateLimit` middleware présent
|
||
|
|
|
||
|
|
**✅ DB POOL** :
|
||
|
|
- MaxOpenConns : 25 (configurable)
|
||
|
|
- MaxIdleConns : 10 (configurable)
|
||
|
|
- MaxLifetime : 5 minutes (configurable)
|
||
|
|
- MaxIdleTime : 1 minute (configurable)
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-OBS-004** : Pas de backpressure pour uploads (voir section F)
|
||
|
|
|
||
|
|
## D.6 Migrations
|
||
|
|
|
||
|
|
**✅ ROBUSTES** :
|
||
|
|
- Migrations SQL : Exécutées dans transactions (rollback automatique en cas d'erreur)
|
||
|
|
- Extensions : Détection `CREATE EXTENSION` (exécution hors transaction)
|
||
|
|
- Schema tracking : Table `schema_migrations` pour tracking
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-OBS-005** : Pas de rollback automatique migrations (down migrations non exécutées automatiquement) (voir section F)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE E — Performance & Scalabilité
|
||
|
|
|
||
|
|
## E.1 Hotspots Évidents
|
||
|
|
|
||
|
|
**✅ OPTIMISÉS** :
|
||
|
|
- Prepared statements : `PreparedStatementManager` présent
|
||
|
|
- DB pool : Configuré (25 max open, 10 max idle)
|
||
|
|
- Pas de `SELECT *` : Bonne pratique respectée
|
||
|
|
|
||
|
|
**⚠️ OPTIMISATIONS POSSIBLES** :
|
||
|
|
- **P2-PERF-001** : N+1 queries possibles dans certains services (voir section F)
|
||
|
|
- **P2-PERF-002** : Pas de pagination sur certaines listes (voir section F)
|
||
|
|
|
||
|
|
## E.2 Streaming
|
||
|
|
|
||
|
|
**✅ CONFIGURÉ** :
|
||
|
|
- Chunked upload : Support présent (`/api/v1/tracks/initiate`, `/chunk`, `/complete`)
|
||
|
|
- Redis : Utilisé pour tracking chunks (optionnel)
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-PERF-003** : Pas de buffering configuré pour streaming (voir section F)
|
||
|
|
|
||
|
|
## E.3 Go-Specific
|
||
|
|
|
||
|
|
**✅ BONNES PRATIQUES** :
|
||
|
|
- Context propagation : Utilisé (`context.Context` passé partout)
|
||
|
|
- Goroutines : Pas de leaks identifiés (timeouts présents)
|
||
|
|
- DB pool : Configuré correctement
|
||
|
|
|
||
|
|
**⚠️ GAPS** :
|
||
|
|
- **P2-PERF-004** : Pas de profiling automatique (pprof) (voir section F)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE F — Liste Exhaustive des Problèmes (Priorisés)
|
||
|
|
|
||
|
|
## Définition des Priorités
|
||
|
|
|
||
|
|
- **P0** : Faille sécurité exploitable / perte de données / crash prod / corruption / auth bypass / build cassé
|
||
|
|
- **P1** : Bugs fréquents / dette bloquante / erreurs de contrat inter-modules / manque de tests critiques
|
||
|
|
- **P2** : Qualité, maintenabilité, perf non critique, DX
|
||
|
|
- **P3** : Cosmétique, refactors non urgents
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## P0 — Critique (Sécurité / Stabilité)
|
||
|
|
|
||
|
|
### MOD-P0-001 : CORS Strict en Production Peut Bloquer Frontend
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Si `CORS_ALLOWED_ORIGINS` est vide en production, **TOUS** les CORS requests sont rejetés
|
||
|
|
- Frontend ne peut pas accéder à l'API → **Service inaccessible**
|
||
|
|
- Scénario: Déploiement production sans config CORS → service down
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/config/config.go:625-643`
|
||
|
|
- Code:
|
||
|
|
```go
|
||
|
|
case EnvProduction:
|
||
|
|
if len(c.CORSOrigins) == 0 {
|
||
|
|
return fmt.Errorf("CORS_ALLOWED_ORIGINS is required in production...")
|
||
|
|
}
|
||
|
|
```
|
||
|
|
- Fichier: `internal/api/router.go:75-84`
|
||
|
|
- Code:
|
||
|
|
```go
|
||
|
|
if len(r.config.CORSOrigins) == 0 {
|
||
|
|
r.logger.Warn("CORS origins not configured - strict mode enabled: ALL CORS requests will be rejected.")
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Validation fail-fast en production (bon), mais message d'erreur peut être ignoré si config chargée depuis fichier `.env` manquant
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter check au démarrage: si `APP_ENV=production` et `CORS_ALLOWED_ORIGINS` vide → **FATAL ERROR** avec message clair
|
||
|
|
2. Documenter dans README: `CORS_ALLOWED_ORIGINS` REQUIS en production
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test 1: Production sans CORS → doit fail
|
||
|
|
APP_ENV=production CORS_ALLOWED_ORIGINS="" go run ./cmd/api/main.go
|
||
|
|
# Attendu: FATAL ERROR avec message clair
|
||
|
|
|
||
|
|
# Test 2: Production avec CORS → doit démarrer
|
||
|
|
APP_ENV=production CORS_ALLOWED_ORIGINS="https://app.veza.com" go run ./cmd/api/main.go
|
||
|
|
# Attendu: Service démarre OK
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore la robustesse)
|
||
|
|
|
||
|
|
**Effort** : S (1h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P0-002 : Validation JWT Secret Length Manquante au Runtime
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Si `JWT_SECRET` < 32 chars, tokens peuvent être crackés (brute force)
|
||
|
|
- **Auth bypass possible** si secret faible
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/config/config.go:687-690`
|
||
|
|
- Code:
|
||
|
|
```go
|
||
|
|
if err := validator.ValidateSecretLength(c.JWTSecret, 32); err != nil {
|
||
|
|
return fmt.Errorf("JWT_SECRET validation failed: %w", err)
|
||
|
|
}
|
||
|
|
```
|
||
|
|
- ✅ **DÉJÀ VALIDÉ** dans `Config.Validate()`
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Validation présente, mais pas de test d'intégration pour vérifier que le service refuse de démarrer avec secret < 32 chars
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter test d'intégration: Service doit refuser de démarrer si `JWT_SECRET` < 32 chars
|
||
|
|
2. Documenter dans README: `JWT_SECRET` doit être ≥ 32 chars
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Secret < 32 chars → doit fail
|
||
|
|
JWT_SECRET="short" go run ./cmd/api/main.go
|
||
|
|
# Attendu: FATAL ERROR "JWT_SECRET validation failed: secret must be at least 32 characters"
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore la sécurité)
|
||
|
|
|
||
|
|
**Effort** : S (30min)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P0-003 : Pas de Validation Ownership sur Routes DELETE/PUT
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Utilisateur peut supprimer/modifier ressources d'autres utilisateurs si ID deviné
|
||
|
|
- **Perte de données** / **Corruption données**
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/api/router.go:307` (PUT `/api/v1/users/:id`)
|
||
|
|
- Fichier: `internal/api/router.go:372` (DELETE `/api/v1/tracks/:id`)
|
||
|
|
- Code: Pas de vérification `user_id == resource.user_id || user.role == "admin"`
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Handlers ne vérifient pas ownership avant modification/suppression
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter middleware `RequireOwnershipOrAdmin(resourceType string)` qui vérifie:
|
||
|
|
- Si `user_id == resource.user_id` → OK
|
||
|
|
- Si `user.role == "admin"` → OK
|
||
|
|
- Sinon → 403 Forbidden
|
||
|
|
2. Appliquer sur routes:
|
||
|
|
- `PUT /api/v1/users/:id`
|
||
|
|
- `DELETE /api/v1/tracks/:id`
|
||
|
|
- `PUT /api/v1/tracks/:id`
|
||
|
|
- `DELETE /api/v1/playlists/:id`
|
||
|
|
- `PUT /api/v1/playlists/:id`
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test 1: User A essaie de modifier User B → 403
|
||
|
|
curl -X PUT /api/v1/users/{user_b_id} -H "Authorization: Bearer {user_a_token}" -d '{"username":"hacked"}'
|
||
|
|
# Attendu: 403 Forbidden
|
||
|
|
|
||
|
|
# Test 2: User A modifie ses propres données → 200
|
||
|
|
curl -X PUT /api/v1/users/{user_a_id} -H "Authorization: Bearer {user_a_token}" -d '{"username":"new_username"}'
|
||
|
|
# Attendu: 200 OK
|
||
|
|
|
||
|
|
# Test 3: Admin modifie User B → 200
|
||
|
|
curl -X PUT /api/v1/users/{user_b_id} -H "Authorization: Bearer {admin_token}" -d '{"username":"admin_updated"}'
|
||
|
|
# Attendu: 200 OK
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de régression si middleware mal appliqué (tester tous les endpoints)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## P1 — Important (Bugs / Dette)
|
||
|
|
|
||
|
|
### MOD-P1-001 : Validation Input Non Systématique
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Handlers peuvent accepter données invalides → corruption DB, injection indirecte
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/handlers/*.go` (plusieurs handlers)
|
||
|
|
- Code: Pas de validation struct tags (`validate:"required,email"`) sur tous les DTOs
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Validators présents (`EmailValidator`, `PasswordValidator`), mais pas utilisés partout
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter struct tags `validate` sur tous les DTOs (`internal/dto/*.go`)
|
||
|
|
2. Ajouter middleware `ValidateRequest()` qui valide automatiquement les DTOs
|
||
|
|
3. Appliquer sur tous les handlers POST/PUT
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Envoyer données invalides → 400
|
||
|
|
curl -X POST /api/v1/auth/register -d '{"email":"invalid","password":"123"}'
|
||
|
|
# Attendu: 400 Bad Request avec détails validation
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de casser endpoints existants si validation trop stricte (tester tous les endpoints)
|
||
|
|
|
||
|
|
**Effort** : M (6h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P1-002 : ClamAV Indisponible → Uploads Rejetés (Pas de Fallback)
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Si ClamAV down, **TOUS** les uploads sont rejetés
|
||
|
|
- Service devient inutilisable pour uploads
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/services/upload_validator.go`
|
||
|
|
- Code: Si ClamAV indisponible, `NewUploadValidator()` retourne erreur → uploads rejetés
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Pas de mode dégradé: ClamAV requis pour uploads
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter config `CLAMAV_REQUIRED=false` (défaut: `true`)
|
||
|
|
2. Si `CLAMAV_REQUIRED=false` et ClamAV indisponible → logger warning mais accepter uploads
|
||
|
|
3. Documenter: En production, ClamAV doit être disponible
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test 1: ClamAV down, CLAMAV_REQUIRED=true → uploads rejetés
|
||
|
|
# Test 2: ClamAV down, CLAMAV_REQUIRED=false → uploads acceptés (avec warning)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque sécurité si ClamAV désactivé (documenter clairement)
|
||
|
|
|
||
|
|
**Effort** : S (2h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P1-003 : Pas de Tests d'Intégration E2E (Upload Flow)
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Bugs dans flow upload complet non détectés avant production
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `tests/integration/upload_flow_test.go` (existe mais peut être incomplet)
|
||
|
|
- Code: Vérifier que flow complet (initiate → chunk → complete) fonctionne
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Tests unitaires présents, mais tests E2E manquants
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter test E2E: Upload flow complet (initiate → chunk → complete → download)
|
||
|
|
2. Ajouter test E2E: Upload avec ClamAV scan
|
||
|
|
3. Ajouter test E2E: Upload avec erreur (chunk manquant, etc.)
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
make test-integration
|
||
|
|
# Attendu: Tests E2E upload passent
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore la qualité)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P1-004 : Handlers Retournent 500 au Lieu de 400 pour Erreurs Validation
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Erreurs client (400) retournées comme erreurs serveur (500) → confusion, métriques incorrectes
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/handlers/*.go` (plusieurs handlers)
|
||
|
|
- Code: `response.InternalServerError(c, ...)` au lieu de `response.BadRequest(c, ...)`
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Pas de distinction claire entre erreurs client (400) et serveur (500)
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Auditer tous les handlers: Remplacer `InternalServerError` par `BadRequest` pour erreurs validation
|
||
|
|
2. Utiliser `InternalServerError` uniquement pour erreurs DB/IO inattendues
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Envoyer données invalides → 400 (pas 500)
|
||
|
|
curl -X POST /api/v1/auth/register -d '{"email":"invalid"}'
|
||
|
|
# Attendu: 400 Bad Request
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de casser clients existants si changement de status code (vérifier clients)
|
||
|
|
|
||
|
|
**Effort** : S (2h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P1-005 : Pas de Rotation Automatique JWT Secret
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Si secret compromis, tous les tokens restent valides jusqu'à expiration
|
||
|
|
- **Auth bypass** possible même après changement secret
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/services/jwt_service.go`
|
||
|
|
- Code: Pas de mécanisme de rotation automatique
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Secret fixe, pas de versioning
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter `JWT_SECRET_VERSION` (entier, défaut: 1)
|
||
|
|
2. Inclure `secret_version` dans JWT claims
|
||
|
|
3. Valider `secret_version` dans `ValidateToken()`
|
||
|
|
4. Documenter: Rotation manuelle (changer secret + incrémenter version)
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Token avec ancien secret_version → rejeté
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Tous les tokens existants invalidés après rotation (documenter migration)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P1-006 : Pas de Circuit Breakers pour Services Externes
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Si Chat Server ou Stream Server down, API peut être ralentie (timeouts)
|
||
|
|
- **Cascade failures** possibles
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/services/stream_service.go`
|
||
|
|
- Code: Pas de circuit breaker (gobreaker présent dans `go.mod` mais non utilisé)
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Appels HTTP directs sans protection
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter circuit breaker (gobreaker) pour Chat Server et Stream Server
|
||
|
|
2. Config: `CIRCUIT_BREAKER_MAX_REQUESTS=5`, `CIRCUIT_BREAKER_INTERVAL=60s`, `CIRCUIT_BREAKER_TIMEOUT=30s`
|
||
|
|
3. En cas d'ouverture circuit: Retourner 503 Service Unavailable avec message clair
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Stream Server down → circuit ouvre après 5 échecs → 503
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de faux positifs (circuit ouvre trop vite) → ajuster config
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## P2 — Qualité / Maintenabilité
|
||
|
|
|
||
|
|
### MOD-P2-001 : Mélange Handlers Legacy et Modern
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Confusion pour développeurs (deux patterns différents)
|
||
|
|
- Maintenance difficile
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichiers: `internal/handlers/*.go` (legacy) vs `internal/core/*/handler.go` (modern)
|
||
|
|
- Code: Deux patterns différents
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Migration progressive non complétée
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Documenter: Pattern moderne (`internal/core/*/handler.go`) est la référence
|
||
|
|
2. Migrer progressivement handlers legacy vers pattern moderne
|
||
|
|
3. Marquer handlers legacy comme `@deprecated`
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
- Aucun (refactor progressif)
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de régression si migration mal faite (tester chaque handler migré)
|
||
|
|
|
||
|
|
**Effort** : L (2 jours)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P2-002 : Pas de Trace ID (OpenTelemetry)
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Debugging difficile (pas de corrélation entre services)
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/middleware/request_id.go`
|
||
|
|
- Code: Seulement `request_id` (local), pas de `trace_id` (distributed)
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- OpenTelemetry non intégré
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter OpenTelemetry SDK
|
||
|
|
2. Générer `trace_id` dans middleware
|
||
|
|
3. Logger `trace_id` dans tous les logs
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Vérifier trace_id dans logs
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore l'observabilité)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P2-003 : Pas de Métriques Business
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Pas de visibilité sur métriques business (tracks uploaded, users registered, etc.)
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/metrics/*.go`
|
||
|
|
- Code: Seulement métriques techniques (HTTP, DB, errors)
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Métriques business non implémentées
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter métriques Prometheus:
|
||
|
|
- `veza_tracks_uploaded_total`
|
||
|
|
- `veza_users_registered_total`
|
||
|
|
- `veza_playlists_created_total`
|
||
|
|
- `veza_uploads_failed_total` (par raison: ClamAV, validation, etc.)
|
||
|
|
2. Exposer via `/metrics`
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Upload track → métrique incrémentée
|
||
|
|
curl http://localhost:8080/metrics | grep veza_tracks_uploaded_total
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore l'observabilité)
|
||
|
|
|
||
|
|
**Effort** : S (2h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P2-004 : Pas de Pagination sur Certaines Listes
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Performance dégradée sur grandes listes (tracks, playlists, etc.)
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/handlers/*.go` (plusieurs handlers de liste)
|
||
|
|
- Code: Pas de pagination (ou pagination optionnelle)
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Pagination non systématique
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter pagination obligatoire sur toutes les listes:
|
||
|
|
- `GET /api/v1/tracks?page=1&limit=20`
|
||
|
|
- `GET /api/v1/playlists?page=1&limit=20`
|
||
|
|
2. Limite max: 100 items par page
|
||
|
|
3. Retourner `total`, `page`, `limit` dans réponse
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Liste sans pagination → 400
|
||
|
|
curl /api/v1/tracks
|
||
|
|
# Attendu: 400 Bad Request "pagination required"
|
||
|
|
|
||
|
|
# Test: Liste avec pagination → 200
|
||
|
|
curl /api/v1/tracks?page=1&limit=20
|
||
|
|
# Attendu: 200 OK avec pagination metadata
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de casser clients existants (ajouter pagination optionnelle d'abord, puis obligatoire)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P2-005 : Pas de Backpressure pour Uploads
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Uploads simultanés peuvent saturer serveur (mémoire, CPU)
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `internal/handlers/upload.go`
|
||
|
|
- Code: Pas de limite uploads simultanés
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Rate limiting présent, mais pas de backpressure
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter semaphore (limite uploads simultanés: 10 par défaut)
|
||
|
|
2. Si limite atteinte: Retourner 503 Service Unavailable avec `Retry-After` header
|
||
|
|
3. Config: `MAX_CONCURRENT_UPLOADS=10`
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: 11 uploads simultanés → 11ème reçoit 503
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque de rejets légitimes si limite trop basse (ajuster config)
|
||
|
|
|
||
|
|
**Effort** : S (2h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P2-006 : Pas de Profiling Automatique (pprof)
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Debugging performance difficile
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `cmd/api/main.go`
|
||
|
|
- Code: Pas d'endpoint `/debug/pprof`
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- pprof non activé
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter import `_ "net/http/pprof"`
|
||
|
|
2. Exposer endpoint `/debug/pprof` (protégé par auth admin en production)
|
||
|
|
3. Documenter: Utilisation pprof pour debugging
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Accéder /debug/pprof → 200 (ou 401 si non admin)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Risque sécurité si endpoint exposé publiquement (protéger par auth admin)
|
||
|
|
|
||
|
|
**Effort** : S (1h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## P3 — Cosmétique / Refactors
|
||
|
|
|
||
|
|
### MOD-P3-001 : README.md Est Celui de golang-migrate
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Confusion pour nouveaux développeurs
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `README.md`
|
||
|
|
- Code: Contenu de golang-migrate, pas de Veza
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- README non mis à jour
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Remplacer README.md par documentation Veza:
|
||
|
|
- Description projet
|
||
|
|
- Installation
|
||
|
|
- Configuration
|
||
|
|
- API endpoints
|
||
|
|
- Tests
|
||
|
|
- Déploiement
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
- Aucun (documentation)
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun
|
||
|
|
|
||
|
|
**Effort** : S (1h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### MOD-P3-002 : Pas de Documentation OpenAPI/Swagger Complète
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Développeurs frontend doivent deviner contrats API
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
- Fichier: `docs/swagger.json` (peut être incomplet)
|
||
|
|
- Code: Swagger présent (`/swagger/*any`), mais peut manquer endpoints
|
||
|
|
|
||
|
|
**Cause Racine** :
|
||
|
|
- Documentation Swagger non maintenue
|
||
|
|
|
||
|
|
**Fix Minimal** :
|
||
|
|
1. Ajouter annotations Swagger sur tous les handlers
|
||
|
|
2. Générer `docs/swagger.json` avec `swag init`
|
||
|
|
3. Vérifier que tous les endpoints sont documentés
|
||
|
|
|
||
|
|
**Plan de Validation** :
|
||
|
|
```bash
|
||
|
|
# Test: Accéder /swagger/index.html → tous endpoints visibles
|
||
|
|
```
|
||
|
|
|
||
|
|
**Effet de Bord** :
|
||
|
|
- Aucun (améliore la DX)
|
||
|
|
|
||
|
|
**Effort** : M (4h)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
# PHASE G — Plan d'Exécution
|
||
|
|
|
||
|
|
## Checklist P0 (Ordre Strict)
|
||
|
|
|
||
|
|
1. **MOD-P0-001** : CORS Strict en Production (1h)
|
||
|
|
- Ajouter check fail-fast au démarrage
|
||
|
|
- Documenter dans README
|
||
|
|
|
||
|
|
2. **MOD-P0-002** : Validation JWT Secret Length (30min)
|
||
|
|
- Ajouter test d'intégration
|
||
|
|
- Documenter dans README
|
||
|
|
|
||
|
|
3. **MOD-P0-003** : Validation Ownership Routes (4h)
|
||
|
|
- Créer middleware `RequireOwnershipOrAdmin()`
|
||
|
|
- Appliquer sur routes DELETE/PUT
|
||
|
|
- Tests d'intégration
|
||
|
|
|
||
|
|
## Checklist P1 (Par Lots Cohérents)
|
||
|
|
|
||
|
|
### Lot 1 : Validation & Erreurs (8h)
|
||
|
|
- **MOD-P1-001** : Validation Input Systématique (6h)
|
||
|
|
- **MOD-P1-004** : Handlers 500 → 400 (2h)
|
||
|
|
|
||
|
|
### Lot 2 : Uploads & ClamAV (6h)
|
||
|
|
- **MOD-P1-002** : ClamAV Fallback (2h)
|
||
|
|
- **MOD-P1-003** : Tests E2E Upload (4h)
|
||
|
|
|
||
|
|
### Lot 3 : Sécurité & Observabilité (8h)
|
||
|
|
- **MOD-P1-005** : Rotation JWT Secret (4h)
|
||
|
|
- **MOD-P1-006** : Circuit Breakers (4h)
|
||
|
|
|
||
|
|
## Quick Wins (≤ 1h chacun)
|
||
|
|
|
||
|
|
1. **MOD-P3-001** : README.md (1h)
|
||
|
|
2. **MOD-P2-006** : pprof (1h)
|
||
|
|
3. **MOD-P2-003** : Métriques Business (2h)
|
||
|
|
|
||
|
|
## Tests à Ajouter en Priorité
|
||
|
|
|
||
|
|
1. **Tests d'intégration E2E Upload Flow** (MOD-P1-003)
|
||
|
|
2. **Tests ownership validation** (MOD-P0-003)
|
||
|
|
3. **Tests CORS fail-fast** (MOD-P0-001)
|
||
|
|
4. **Tests ClamAV fallback** (MOD-P1-002)
|
||
|
|
|
||
|
|
## PR Plan
|
||
|
|
|
||
|
|
### PR 1 : P0 Security Fixes (1 jour)
|
||
|
|
- **Titre**: `fix(security): CORS fail-fast + JWT secret validation + ownership checks`
|
||
|
|
- **Issues**: MOD-P0-001, MOD-P0-002, MOD-P0-003
|
||
|
|
- **Tests**: Tests d'intégration pour chaque fix
|
||
|
|
- **Review**: Security review requis
|
||
|
|
|
||
|
|
### PR 2 : P1 Validation & Errors (1 jour)
|
||
|
|
- **Titre**: `feat(validation): Input validation systématique + correct HTTP status codes`
|
||
|
|
- **Issues**: MOD-P1-001, MOD-P1-004
|
||
|
|
- **Tests**: Tests unitaires + intégration
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 3 : P1 Uploads & ClamAV (1 jour)
|
||
|
|
- **Titre**: `feat(uploads): ClamAV fallback + E2E tests`
|
||
|
|
- **Issues**: MOD-P1-002, MOD-P1-003
|
||
|
|
- **Tests**: Tests E2E upload flow
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 4 : P1 Security & Observability (1 jour)
|
||
|
|
- **Titre**: `feat(security): JWT secret rotation + circuit breakers`
|
||
|
|
- **Issues**: MOD-P1-005, MOD-P1-006
|
||
|
|
- **Tests**: Tests unitaires
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 5 : P2 Quick Wins (0.5 jour)
|
||
|
|
- **Titre**: `docs: README + pprof + business metrics`
|
||
|
|
- **Issues**: MOD-P3-001, MOD-P2-006, MOD-P2-003
|
||
|
|
- **Tests**: Aucun (documentation + observabilité)
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 6 : P2 Quality Improvements (2 jours)
|
||
|
|
- **Titre**: `feat(quality): Trace ID + pagination + backpressure`
|
||
|
|
- **Issues**: MOD-P2-002, MOD-P2-004, MOD-P2-005
|
||
|
|
- **Tests**: Tests unitaires + intégration
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 7 : P2 Refactor Handlers (2 jours)
|
||
|
|
- **Titre**: `refactor(handlers): Migrate legacy handlers to modern pattern`
|
||
|
|
- **Issues**: MOD-P2-001
|
||
|
|
- **Tests**: Tests unitaires (vérifier régression)
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
### PR 8 : P3 Documentation (0.5 jour)
|
||
|
|
- **Titre**: `docs: Complete OpenAPI/Swagger documentation`
|
||
|
|
- **Issues**: MOD-P3-002
|
||
|
|
- **Tests**: Aucun (documentation)
|
||
|
|
- **Review**: Code review standard
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Résumé Exécutif
|
||
|
|
|
||
|
|
**Total Issues** : 18
|
||
|
|
- **P0** : 3 (Sécurité critique)
|
||
|
|
- **P1** : 6 (Bugs / Dette importante)
|
||
|
|
- **P2** : 6 (Qualité / Maintenabilité)
|
||
|
|
- **P3** : 3 (Cosmétique / Documentation)
|
||
|
|
|
||
|
|
**Effort Total Estimé** :
|
||
|
|
- P0 : 5.5h
|
||
|
|
- P1 : 22h
|
||
|
|
- P2 : 19h
|
||
|
|
- P3 : 6h
|
||
|
|
- **Total** : ~52.5h (~1.5 semaines)
|
||
|
|
|
||
|
|
**Priorité Immédiate** :
|
||
|
|
1. **P0 Security Fixes** (PR 1) — 1 jour
|
||
|
|
2. **P1 Validation & Errors** (PR 2) — 1 jour
|
||
|
|
3. **P1 Uploads & ClamAV** (PR 3) — 1 jour
|
||
|
|
|
||
|
|
**Risques Identifiés** :
|
||
|
|
- CORS strict peut bloquer frontend (P0)
|
||
|
|
- Pas de validation ownership (P0)
|
||
|
|
- ClamAV indisponible → service down (P1)
|
||
|
|
- Pas de circuit breakers → cascade failures (P1)
|
||
|
|
|
||
|
|
**Recommandations** :
|
||
|
|
- Exécuter P0 immédiatement (sécurité)
|
||
|
|
- Exécuter P1 dans les 2 semaines (stabilité)
|
||
|
|
- Exécuter P2 dans le mois (qualité)
|
||
|
|
- Exécuter P3 selon disponibilité (documentation)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Fin du Rapport**
|