316 lines
10 KiB
Markdown
316 lines
10 KiB
Markdown
|
|
# 🔍 AUDIT TECHNIQUE POST-REMÉDIATION — VEZA BACKEND API
|
||
|
|
|
||
|
|
**Date**: 2025-12-12
|
||
|
|
**Contexte**: Module remédié (P0/P1 traités) — Identification des blocages résiduels pour production
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## A. ÉTAT GLOBAL DU MODULE
|
||
|
|
|
||
|
|
### Verdict
|
||
|
|
|
||
|
|
**Module prêt avec réserves** — Les correctifs P0/P1 ont considérablement amélioré la stabilité et la sécurité. Cependant, **3 problèmes P1-résiduels** et plusieurs **P2-stability** doivent être traités avant une mise en production confiante.
|
||
|
|
|
||
|
|
**Points forts** :
|
||
|
|
- ✅ Sécurité critique (CORS, ownership, validation) : **SOLIDE**
|
||
|
|
- ✅ Robustesse de base (timeout, readiness) : **ACCEPTABLE**
|
||
|
|
- ✅ Tests critiques (ownership, validation) : **COUVERTS**
|
||
|
|
|
||
|
|
**Points faibles** :
|
||
|
|
- ⚠️ **Incohérences architecturales** : Patterns d'erreur divergents
|
||
|
|
- ⚠️ **Résilience externe** : Pas de retry/circuit breaker sur dépendances
|
||
|
|
- ⚠️ **Observabilité limitée** : Métriques DB pool non exposées
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## B. PROBLÈMES RESTANTS
|
||
|
|
|
||
|
|
### 🔴 P1-RESIDUAL (Bloquant production)
|
||
|
|
|
||
|
|
#### P1-RES-001 : Incohérence patterns de réponse d'erreur
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Deux patterns d'erreur coexistent sans standardisation :
|
||
|
|
- `TrackHandler` utilise `response.BadRequest()`, `response.NotFound()`, `response.Success()` (package `internal/response`)
|
||
|
|
- `ProfileHandler` utilise `RespondWithAppError()`, `RespondSuccess()` (package `handlers`)
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Réponses API incohérentes selon l'endpoint
|
||
|
|
- Difficulté de maintenance et debugging
|
||
|
|
- Risque de confusion pour les clients API
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
```go
|
||
|
|
// internal/core/track/handler.go:113
|
||
|
|
response.BadRequest(c, "no file provided")
|
||
|
|
|
||
|
|
// internal/handlers/profile_handler.go:52
|
||
|
|
RespondWithAppError(c, apperrors.New(apperrors.ErrCodeValidation, "invalid user id"))
|
||
|
|
```
|
||
|
|
|
||
|
|
**Recommandation MINIMALE** :
|
||
|
|
1. Standardiser sur UN pattern (recommandé : `RespondWithAppError` + `RespondSuccess` du package `handlers`)
|
||
|
|
2. Migrer `TrackHandler` vers le pattern standardisé
|
||
|
|
3. Créer un helper centralisé si nécessaire
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/core/track/handler.go` (19 occurrences de `response.*`)
|
||
|
|
- `internal/handlers/profile_handler.go` (utilise déjà le pattern standard)
|
||
|
|
- `internal/response/response.go` (package à déprécier ou aligner)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P1-RES-002 : Absence de retry sur appels Stream Server
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Les appels HTTP vers Stream Server n'ont pas de mécanisme de retry. Un échec réseau temporaire provoque une perte de jobs de transcodage.
|
||
|
|
|
||
|
|
**Note** : `WebhookService` a déjà un retry implémenté (3 tentatives avec backoff exponentiel).
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Perte de jobs de transcodage si Stream Server temporairement indisponible
|
||
|
|
- Pas de résilience face aux pannes partielles du Stream Server
|
||
|
|
- État incohérent si le job est créé mais le Stream Server ne le reçoit pas
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
```go
|
||
|
|
// internal/services/stream_service.go:55
|
||
|
|
resp, err := s.client.Do(req)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to send request: %w", err) // Pas de retry
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Recommandation MINIMALE** :
|
||
|
|
1. Ajouter retry avec backoff exponentiel (3 tentatives, max 30s) similaire à `WebhookService`
|
||
|
|
2. Utiliser `context.WithTimeout` pour limiter le temps total
|
||
|
|
3. Logger les échecs après retries épuisés
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/services/stream_service.go`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P1-RES-003 : c.MustGet() sans protection explicite
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Utilisation extensive de `c.MustGet("user_id")` qui peut `panic` si la clé n'existe pas. Bien que le middleware auth devrait toujours définir cette clé, une erreur de configuration ou un handler mal isolé peut provoquer un crash.
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Panic possible si middleware auth non appliqué
|
||
|
|
- Pas de message d'erreur clair pour debugging
|
||
|
|
- Risque de crash en production
|
||
|
|
|
||
|
|
**Preuve** :
|
||
|
|
```go
|
||
|
|
// internal/core/track/handler.go:105 (et 18 autres occurrences)
|
||
|
|
userID := c.MustGet("user_id").(uuid.UUID) // Peut panic
|
||
|
|
```
|
||
|
|
|
||
|
|
**Recommandation MINIMALE** :
|
||
|
|
1. Créer un helper `GetUserID(c *gin.Context) (uuid.UUID, error)` qui retourne une erreur au lieu de panic
|
||
|
|
2. Remplacer progressivement `c.MustGet()` par ce helper
|
||
|
|
3. Ou au minimum : wrapper avec `recover()` dans un middleware de récupération (déjà présent mais pas idéal)
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/core/track/handler.go` (19 occurrences)
|
||
|
|
- `internal/handlers/profile_handler.go` (utilise déjà `c.Get()` avec vérification)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 🟠 P2-STABILITY (À traiter avant montée en charge)
|
||
|
|
|
||
|
|
#### P2-STAB-001 : Pas de circuit breaker sur dépendances externes
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Aucun circuit breaker implémenté pour protéger contre les dépendances lentes/indisponibles (Stream Server, Chat Server, Webhooks).
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Service peut être surchargé si dépendance lente
|
||
|
|
- Pas de dégradation gracieuse
|
||
|
|
- Timeouts peuvent s'accumuler
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
Implémenter un circuit breaker simple (ex: `github.com/sony/gobreaker`) pour :
|
||
|
|
- Stream Server calls
|
||
|
|
- Webhook deliveries
|
||
|
|
- Chat Server health checks
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/services/stream_service.go`
|
||
|
|
- `internal/services/webhook_service.go`
|
||
|
|
- `internal/handlers/status_handler.go`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P2-STAB-002 : Pool stats DB non exposés dans métriques
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Les statistiques du pool de connexions DB (`MaxOpenConns`, `OpenConns`, `InUse`, `Idle`) ne sont pas exposées dans les métriques Prometheus/health.
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Impossible de diagnostiquer les problèmes de connexion en production
|
||
|
|
- Pas de visibilité sur l'utilisation du pool
|
||
|
|
- Difficulté à dimensionner correctement
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
Exposer les stats via :
|
||
|
|
- Endpoint `/metrics` (Prometheus)
|
||
|
|
- Endpoint `/health` (champ `database.pool_stats`)
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/database/database.go` (fonction `GetPoolStats` existe déjà)
|
||
|
|
- `internal/handlers/health.go`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P2-STAB-003 : Migrations sans rollback global
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Chaque migration est transactionnelle (rollback si échec), mais si une migration échoue, les migrations précédentes restent appliquées. Pas de mécanisme de rollback global.
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- DB peut être dans un état partiellement migré
|
||
|
|
- Récupération manuelle nécessaire
|
||
|
|
- Risque en production lors de déploiements
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
- Documenter la procédure de rollback manuel
|
||
|
|
- Ajouter un script de vérification d'intégrité post-migration
|
||
|
|
- (Optionnel) Implémenter un système de versioning de schéma avec rollback
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/database/database.go` (fonction `Initialize()`)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P2-STAB-004 : Fichiers backup non nettoyés
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Dossiers `.backup-pre-uuid-migration/` présents dans le codebase (migration UUID complétée).
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Confusion pour les développeurs
|
||
|
|
- Risque d'utilisation accidentelle d'ancien code
|
||
|
|
- Pollution du codebase
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
Supprimer les dossiers backup après vérification qu'ils ne sont plus référencés.
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/handlers/.backup-pre-uuid-migration/`
|
||
|
|
- `internal/services/.backup-pre-uuid-migration/`
|
||
|
|
- `internal/models/.backup-pre-uuid-migration/`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 🟡 P3-CLEANUP (Acceptable avant prod)
|
||
|
|
|
||
|
|
#### P3-CLEAN-001 : TODOs restants dans le code
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Quelques TODOs/FIXMEs présents :
|
||
|
|
- `internal/core/track/handler.go:227` : "TODO(P2-GO-004): trackUploadService attend int64"
|
||
|
|
- `internal/core/track/service.go:225` : "TODO(P2-GO-018): Enqueue job pour traitement asynchrone"
|
||
|
|
- `internal/services/track_history_service.go:74` : "FIXME: models.TrackHistory needs UUID too"
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Dette technique mineure
|
||
|
|
- Pas de blocage fonctionnel
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
Documenter ces TODOs et planifier leur traitement post-MVP.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P3-CLEAN-002 : Pas de versioning API
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Toutes les routes sont `/api/v1/*` mais pas de mécanisme de versioning pour breaking changes futurs.
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Difficulté à introduire des breaking changes
|
||
|
|
- Pas de support multi-versions
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
- Documenter la stratégie de versioning
|
||
|
|
- Préparer l'infrastructure pour `/api/v2/*` si nécessaire
|
||
|
|
- (Non-bloquant pour MVP)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### P3-CLEAN-003 : Tests manquants pour certains handlers
|
||
|
|
|
||
|
|
**Description** :
|
||
|
|
Certains handlers n'ont pas de tests unitaires complets (ex: `ChatHandler` a des `panic("not implemented")` dans les tests).
|
||
|
|
|
||
|
|
**Impact** :
|
||
|
|
- Couverture de tests incomplète
|
||
|
|
- Risque de régression silencieuse
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
- Compléter les tests manquants progressivement
|
||
|
|
- Prioriser les handlers critiques (auth, uploads, tracks)
|
||
|
|
|
||
|
|
**Fichiers concernés** :
|
||
|
|
- `internal/handlers/chat_handler_test.go`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## C. DÉCISION FINALE
|
||
|
|
|
||
|
|
### Verdict
|
||
|
|
|
||
|
|
**"Module prêt avec réserves"**
|
||
|
|
|
||
|
|
### Justification
|
||
|
|
|
||
|
|
**Points positifs** :
|
||
|
|
- ✅ Sécurité critique solide (P0/P1 traités)
|
||
|
|
- ✅ Tests critiques présents (ownership, validation)
|
||
|
|
- ✅ Robustesse de base acceptable (timeout, readiness)
|
||
|
|
|
||
|
|
**Blocages résiduels** :
|
||
|
|
- 🔴 **P1-RES-001** : Incohérence patterns erreur (bloquant pour cohérence API)
|
||
|
|
- 🔴 **P1-RES-002** : Pas de retry Stream Server (bloquant pour résilience)
|
||
|
|
- 🔴 **P1-RES-003** : `c.MustGet()` non protégé (bloquant pour stabilité)
|
||
|
|
|
||
|
|
**Recommandation** :
|
||
|
|
1. **Corriger les 3 P1-RES** avant production (estimation : 1-2 jours)
|
||
|
|
2. **Traiter les P2-STAB prioritaires** (circuit breaker, pool stats) avant montée en charge
|
||
|
|
3. **P3-CLEAN** peut être traité post-MVP
|
||
|
|
|
||
|
|
### Plan d'action minimal
|
||
|
|
|
||
|
|
**Phase 1 (Blocant prod)** :
|
||
|
|
1. Standardiser patterns d'erreur (P1-RES-001) — 4h
|
||
|
|
2. Ajouter retry Stream Server (P1-RES-002) — 2h (réutiliser pattern WebhookService)
|
||
|
|
3. Protéger `c.MustGet()` (P1-RES-003) — 2h
|
||
|
|
|
||
|
|
**Phase 2 (Avant montée en charge)** :
|
||
|
|
4. Circuit breaker dépendances (P2-STAB-001) — 4h
|
||
|
|
5. Exposer pool stats DB (P2-STAB-002) — 2h
|
||
|
|
6. Nettoyer fichiers backup (P2-STAB-004) — 30min
|
||
|
|
|
||
|
|
**Total estimé** : ~14h de travail
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## D. RÉSUMÉ EXÉCUTIF
|
||
|
|
|
||
|
|
| Catégorie | État | Blocages |
|
||
|
|
|-----------|------|----------|
|
||
|
|
| **Sécurité** | ✅ Solide | 0 |
|
||
|
|
| **Robustesse** | ⚠️ Acceptable | 3 P1-RES |
|
||
|
|
| **Observabilité** | ⚠️ Limité | 1 P2-STAB |
|
||
|
|
| **Tests** | ✅ Couvert (critiques) | 0 |
|
||
|
|
| **Dette technique** | 🟡 Mineure | 0 |
|
||
|
|
|
||
|
|
**Conclusion** : Module **prêt pour phase CI/CD** après correction des 3 P1-RES (estimation 1-2 jours).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Auditeur** : AI Assistant
|
||
|
|
**Date** : 2025-12-12
|
||
|
|
**Version** : Post-remédiation P0/P1
|