veza/veza-docs/ORIGIN/ORIGIN_ERROR_PATTERNS.md
2026-03-05 19:22:31 +01:00

1401 lines
34 KiB
Markdown

# ORIGIN_ERROR_PATTERNS.md
## 📋 RÉSUMÉ EXÉCUTIF
Ce document catalogue **TOUS** les patterns d'erreurs identifiés dans le projet Veza pendant la Phase 0 (Error Resolution). Chaque pattern inclut la cause racine, la solution standard, et une checklist de prévention pour éviter sa réapparition dans les futures implémentations.
**Dernière mise à jour** : 2026-03-04
**Statut** : ✅ Document de référence officiel
**Version** : 2.0.0
---
## 🔒 RÈGLES IMMUABLES
1. **TOUJOURS consulter ce document** avant de commencer une nouvelle tâche
2. **TOUJOURS vérifier** qu'aucun pattern d'erreur ne sera introduit
3. **TOUJOURS documenter** tout nouveau pattern découvert
4. **JAMAIS contourner** une erreur sans la corriger définitivement
---
## 📊 STATISTIQUES DES PATTERNS
| Catégorie | Patterns | Fréquence | Priorité |
|-----------|----------|-----------|----------|
| **Backend Go** | 10 | Haute | P0-P1 |
| **Frontend TypeScript** | 8 | Très Haute | P0-P2 |
| **Tests** | 6 | Haute | P1-P2 |
| **Configuration** | 3 | Moyenne | P0-P1 |
| **Lint/Format** | 4 | Haute | P2 |
**Total** : 31 patterns documentés
---
## 1. BACKEND GO - PATTERNS D'ERREURS
### PAT-001: Import Cycles (Circular Dependencies)
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Import cyclique détecté entre packages Go, empêchant la compilation.
**Pattern typique** :
```
package A imports package B
package B imports package C
package C imports package A ← CYCLE DÉTECTÉ
```
**Exemple réel** :
```go
// ❌ ERREUR
// internal/services/user_service.go
package services
import "veza-backend-api/internal/handlers" // Import handlers
// internal/handlers/user_handlers.go
package handlers
import "veza-backend-api/internal/services" // Import services → CYCLE!
```
#### Cause Racine
- Dépendances circulaires entre couches (handlers → services → handlers)
- Types partagés définis dans le mauvais package
- Interfaces définies dans les packages qui les utilisent
#### Solution Standard
**Étape 1** : Identifier le cycle
```bash
cd veza-backend-api
go list -f '{{join .DepsErrors "\n"}}' ./... | grep -i "cycle"
```
**Étape 2** : Créer package de types partagés
```go
// ✅ SOLUTION - Créer internal/types/interfaces.go
package types
// Interfaces définies dans package neutre
type UserRepository interface {
Create(user *User) error
FindByID(id uuid.UUID) (*User, error)
}
type UserService interface {
CreateUser(req *CreateUserRequest) (*User, error)
}
```
**Étape 3** : Refactorer les packages
```go
// ✅ internal/services/user_service.go
package services
import "veza-backend-api/internal/types" // Import types seulement
type UserService struct {
repo types.UserRepository // Dépend de l'interface
}
// ✅ internal/handlers/user_handlers.go
package handlers
import "veza-backend-api/internal/types" // Import types seulement
func CreateUser(c *gin.Context) {
service := types.UserService // Utilise l'interface
}
```
#### Checklist de Prévention
- [ ] Vérifier qu'aucun import cycle ne sera créé avant d'ajouter un import
- [ ] Utiliser `go mod graph` pour visualiser les dépendances
- [ ] Définir les interfaces dans `internal/types/` ou `internal/interfaces/`
- [ ] Services ne doivent JAMAIS importer handlers
- [ ] Handlers ne doivent JAMAIS importer services directement
- [ ] Utiliser dependency injection via interfaces
#### Références
- **Documentation Go** : https://golang.org/ref/spec#Import_declarations
- **Best Practices** : Clean Architecture, Dependency Inversion Principle
---
### PAT-002: Type Mismatches (string vs *string)
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Incohérence entre types `string` et `*string` (nullable) causant des erreurs de compilation.
**Exemple réel** :
```go
// ❌ ERREUR - internal/models/responses.go
type User struct {
FirstName string `json:"first_name"` // string (non-nullable)
}
func (ur *UserResponse) FromUser(user *User) {
if user.FirstName != nil { // ❌ ERREUR: string ne peut pas être nil
ur.FirstName = *user.FirstName // ❌ ERREUR: déréférencement impossible
}
}
```
#### Cause Racine
- Migration partielle de `*string` vers `string` (ou vice versa)
- Manque de cohérence dans la définition des modèles
- Changement de stratégie nullable/non-nullable non appliqué partout
#### Solution Standard
**Option A : Utiliser string (non-nullable)**
```go
// ✅ SOLUTION A
type User struct {
FirstName string `json:"first_name,omitempty"` // string, jamais nil
}
func (ur *UserResponse) FromUser(user *User) {
if user.FirstName != "" { // ✅ Vérifier string vide
ur.FirstName = user.FirstName // ✅ Pas de déréférencement
}
}
```
**Option B : Utiliser *string (nullable)**
```go
// ✅ SOLUTION B
type User struct {
FirstName *string `json:"first_name,omitempty"` // *string, peut être nil
}
func (ur *UserResponse) FromUser(user *User) {
if user.FirstName != nil { // ✅ Vérifier nil
ur.FirstName = *user.FirstName // ✅ Déréférencement correct
}
}
```
**Recommandation** : Utiliser `string` avec valeur vide `""` pour les champs optionnels (plus simple, moins de pointeurs).
#### Checklist de Prévention
- [ ] Décider une stratégie cohérente : `string` ou `*string` pour champs optionnels
- [ ] Documenter la décision dans `ORIGIN_CODE_STANDARDS.md`
- [ ] Vérifier la cohérence des types avant de modifier un modèle
- [ ] Utiliser `go vet` pour détecter les incohérences
- [ ] Tests unitaires pour valider le comportement nullable/non-nullable
#### Références
- **Go Best Practices** : https://go.dev/doc/effective_go#pointers_vs_values
---
### PAT-003: Missing Packages (Packages Not in std)
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Import de packages qui n'existent pas ou ne sont pas dans le module.
**Exemple réel** :
```go
// ❌ ERREUR
import "veza-backend-api/internal/api/search" // Package n'existe pas
import "veza-backend-api/internal/mocks" // Package n'existe pas
```
#### Cause Racine
- Packages référencés mais jamais créés
- Imports non nettoyés après refactoring
- Packages déplacés/renommés sans mise à jour des imports
#### Solution Standard
**Étape 1** : Identifier les packages manquants
```bash
cd veza-backend-api
go build ./... 2>&1 | grep "is not in std"
```
**Étape 2** : Pour chaque package manquant, décider :
- **Option A** : Créer le package (si nécessaire pour la tâche)
- **Option B** : Retirer l'import (si non utilisé)
- **Option C** : Créer un stub minimal (si nécessaire pour compilation)
**Option A - Créer le package** :
```go
// ✅ Créer internal/api/search/handler.go
package search
import "github.com/gin-gonic/gin"
func SearchHandler(c *gin.Context) {
// Stub minimal pour permettre compilation
c.JSON(200, gin.H{"message": "Search endpoint - TODO: implement"})
}
```
**Option B - Retirer l'import** :
```go
// ✅ Retirer l'import non utilisé
// import "veza-backend-api/internal/api/search" ← SUPPRIMÉ
```
#### Checklist de Prévention
- [ ] Vérifier que tous les packages importés existent avant commit
- [ ] Nettoyer les imports non utilisés avec `goimports -w .`
- [ ] Créer les packages nécessaires AVANT de les importer
- [ ] Utiliser `go mod tidy` pour nettoyer les dépendances
- [ ] Vérifier avec `go build ./...` après chaque modification
#### Références
- **Go Modules** : https://go.dev/ref/mod
---
### PAT-004: Missing Dependencies (go.mod)
**Catégorie** : CAT-03 (Dépendances)
**Priorité** : P0 (Critique)
**Fréquence** : Basse
**Découvert** : 2025-11-09
#### Description
Dépendance Go manquante dans `go.mod`.
**Exemple réel** :
```go
// ❌ ERREUR
import "github.com/crewjam/saml/samlsp"
// Error: no required module provides package github.com/crewjam/saml/samlsp
```
#### Solution Standard
```bash
cd veza-backend-api
go get github.com/crewjam/saml/samlsp
go mod tidy
```
#### Checklist de Prévention
- [ ] Vérifier que toutes les dépendances sont dans `go.mod`
- [ ] Utiliser `go mod tidy` régulièrement
- [ ] Documenter les nouvelles dépendances dans `ORIGIN_TECHNICAL_STACK.md`
---
### PAT-005: Undefined Types/Variables
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Basse
**Découvert** : 2025-11-09
#### Description
Utilisation de types ou variables non définis.
**Exemple réel** :
```go
// ❌ ERREUR
// internal/database/chat_repository.go
var db *DB // Type DB non défini
```
#### Solution Standard
- Vérifier que le type existe dans le package ou un package importé
- Importer le package contenant le type
- Créer le type si nécessaire
#### Checklist de Prévention
- [ ] Vérifier que tous les types utilisés sont définis
- [ ] Utiliser `go vet` pour détecter les problèmes
- [ ] IDE (VS Code/GoLand) devrait signaler les erreurs en temps réel
---
### PAT-024: JWT Issuer/Audience Mismatch
**Catégorie** : CAT-02 (Configuration)
**Priorité** : P0 (Critique)
**Fréquence** : Moyenne
**Découvert** : 2026-03-04 (Audit)
#### Description
Le token JWT est rejeté car l'issuer (`iss`) ou l'audience (`aud`) ne correspond pas à la configuration attendue par le service de validation. Cela provoque des erreurs d'authentification silencieuses ou des 401 intermittents.
**Exemple réel** :
```go
// ❌ ERREUR - issuer codé en dur, différent entre services
func ValidateToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("JWT_SECRET")), nil
})
// Pas de vérification de iss/aud → token accepté même si émis par un autre service
}
```
#### Cause Racine
- Issuer/audience non validés lors du parsing JWT
- Configuration différente entre le service d'émission et le service de validation
- Variables d'environnement `JWT_ISSUER` et `JWT_AUDIENCE` absentes ou incohérentes
#### Solution Standard
```go
// ✅ SOLUTION - Valider issuer et audience explicitement
func ValidateToken(tokenString string) (*Claims, error) {
expectedIssuer := config.GetJWTIssuer()
expectedAudience := config.GetJWTAudience()
token, err := jwt.ParseWithClaims(tokenString, &Claims{},
func(token *jwt.Token) (interface{}, error) {
return []byte(config.GetJWTSecret()), nil
},
jwt.WithIssuer(expectedIssuer),
jwt.WithAudience(expectedAudience),
)
if err != nil {
return nil, fmt.Errorf("token validation failed: %w", err)
}
return token.Claims.(*Claims), nil
}
```
#### Checklist de Prévention
- [ ] Valider `iss` et `aud` lors de chaque parsing JWT
- [ ] Centraliser la configuration JWT dans un seul package (`internal/auth/config.go`)
- [ ] Vérifier la cohérence des variables `JWT_ISSUER` et `JWT_AUDIENCE` au démarrage
- [ ] Tests unitaires couvrant les cas de mismatch issuer/audience
- [ ] Documenter la configuration JWT dans `.env.example`
---
### PAT-025: Context Propagation Manquante
**Catégorie** : CAT-04 (Runtime)
**Priorité** : P1 (Haute)
**Fréquence** : Haute
**Découvert** : 2026-03-04 (Audit)
#### Description
Utilisation de `context.Background()` ou `context.TODO()` dans les handlers HTTP au lieu de propager le contexte de la requête (`c.Request.Context()`). Cela empêche la propagation des deadlines, l'annulation des requêtes, et le tracing distribué.
**Exemple réel** :
```go
// ❌ ERREUR - context.Background() utilisé dans un handler
func (h *TrackHandler) GetTrack(c *gin.Context) {
track, err := h.trackService.GetByID(context.Background(), trackID)
// Le context de la requête HTTP est ignoré
}
```
#### Cause Racine
- Habitude de passer `context.Background()` par facilité
- Manque de convention de propagation du contexte
- Absence de linter rule pour détecter ce pattern
#### Solution Standard
```go
// ✅ SOLUTION - Propager le contexte de la requête
func (h *TrackHandler) GetTrack(c *gin.Context) {
ctx := c.Request.Context()
track, err := h.trackService.GetByID(ctx, trackID)
}
```
#### Checklist de Prévention
- [ ] Toujours utiliser `c.Request.Context()` dans les handlers Gin
- [ ] Ajouter une règle golangci-lint (contextcheck) pour détecter `context.Background()` dans les handlers
- [ ] Propager le contexte dans toute la chaîne service → repository → database
- [ ] Code review systématique sur l'usage du contexte
- [ ] Grep régulier : `grep -rn "context.Background()" internal/handlers/`
---
### PAT-026: Goroutine Leak Patterns
**Catégorie** : CAT-04 (Runtime)
**Priorité** : P1 (Haute)
**Fréquence** : Moyenne
**Découvert** : 2026-03-04 (Audit)
#### Description
Goroutines lancées sans mécanisme d'arrêt (context, done channel, WaitGroup), provoquant des fuites de goroutines qui consomment de la mémoire et des ressources indéfiniment.
**Exemple réel** :
```go
// ❌ ERREUR - goroutine sans mécanisme d'arrêt
func (s *StreamService) StartProcessing() {
go func() {
for {
s.processQueue()
time.Sleep(5 * time.Second)
}
}()
}
```
#### Cause Racine
- Goroutines lancées avec `go func()` sans condition d'arrêt
- Absence de `context.Context` pour signaler l'annulation
- Pas de `sync.WaitGroup` pour attendre la fin des goroutines au shutdown
#### Solution Standard
```go
// ✅ SOLUTION - Goroutine avec contexte et WaitGroup
func (s *StreamService) StartProcessing(ctx context.Context, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
defer wg.Done()
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
s.processQueue(ctx)
}
}
}()
}
```
#### Checklist de Prévention
- [ ] Toute goroutine doit recevoir un `context.Context` pour l'annulation
- [ ] Utiliser `sync.WaitGroup` pour le graceful shutdown
- [ ] Utiliser `select` avec `ctx.Done()` dans les boucles
- [ ] Monitorer le nombre de goroutines en production (`runtime.NumGoroutine()`)
- [ ] Tests avec `goleak` pour détecter les fuites de goroutines
---
### PAT-027: Pagination Sans Limite Max
**Catégorie** : CAT-04 (Runtime)
**Priorité** : P1 (Haute)
**Fréquence** : Moyenne
**Découvert** : 2026-03-04 (Audit)
#### Description
Les endpoints paginés acceptent des valeurs `limit` arbitrairement grandes sans borne supérieure, permettant à un client de demander des millions d'enregistrements en une seule requête (risque de DoS, OOM).
**Exemple réel** :
```go
// ❌ ERREUR - pas de limite max
func (h *TrackHandler) ListTracks(c *gin.Context) {
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
// limit peut valoir 999999999 → charge mémoire excessive
tracks, err := h.trackService.List(ctx, limit, offset)
}
```
#### Cause Racine
- Validation insuffisante des paramètres de pagination
- Absence de constante `MaxPageSize` partagée
- Confiance implicite dans les paramètres du client
#### Solution Standard
```go
// ✅ SOLUTION - Valider et borner les paramètres de pagination
const (
DefaultPageSize = 20
MaxPageSize = 100
)
func parsePagination(c *gin.Context) (limit, offset int) {
limit, _ = strconv.Atoi(c.DefaultQuery("limit", strconv.Itoa(DefaultPageSize)))
offset, _ = strconv.Atoi(c.DefaultQuery("offset", "0"))
if limit <= 0 {
limit = DefaultPageSize
}
if limit > MaxPageSize {
limit = MaxPageSize
}
if offset < 0 {
offset = 0
}
return limit, offset
}
```
#### Checklist de Prévention
- [ ] Définir `MaxPageSize` comme constante partagée (ex. `internal/api/pagination.go`)
- [ ] Valider et borner `limit` dans tous les endpoints paginés
- [ ] Valider que `offset` est ≥ 0
- [ ] Tests unitaires pour les cas limites (limit=0, limit=-1, limit=999999)
- [ ] Documenter les limites de pagination dans l'API specification
---
### PAT-028: Error Handling Inconsistant (gin.H vs RespondWithAppError)
**Catégorie** : CAT-04 (Runtime)
**Priorité** : P1 (Haute)
**Fréquence** : Haute
**Découvert** : 2026-03-04 (Audit)
#### Description
Mélange de deux patterns de réponse d'erreur dans les handlers : `gin.H{"error": ...}` (format ad hoc) et `RespondWithAppError()` (format standardisé). Cela crée des réponses d'erreur inconsistantes côté client, compliquant le parsing et le traitement des erreurs frontend.
**Exemple réel** :
```go
// ❌ ERREUR - Mélange de formats dans le même handler
func (h *TrackHandler) CreateTrack(c *gin.Context) {
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()}) // Format ad hoc
return
}
track, err := h.service.Create(ctx, &req)
if err != nil {
RespondWithAppError(c, err) // Format standardisé
return
}
}
```
#### Cause Racine
- Migration partielle vers `RespondWithAppError`
- Pas de convention imposée par linter
- Copier-coller de code ancien utilisant `gin.H`
#### Solution Standard
```go
// ✅ SOLUTION - Utiliser exclusivement RespondWithAppError
func (h *TrackHandler) CreateTrack(c *gin.Context) {
if err := c.ShouldBindJSON(&req); err != nil {
RespondWithAppError(c, apperrors.NewValidationError("invalid request body", err))
return
}
track, err := h.service.Create(ctx, &req)
if err != nil {
RespondWithAppError(c, err)
return
}
c.JSON(http.StatusCreated, track)
}
```
#### Checklist de Prévention
- [ ] Utiliser exclusivement `RespondWithAppError` pour toutes les réponses d'erreur
- [ ] Grep régulier : `grep -rn 'gin.H{"error"' internal/handlers/` → doit retourner 0 résultat
- [ ] Envelopper les erreurs de validation dans `apperrors.NewValidationError()`
- [ ] Code review systématique sur le format des réponses d'erreur
- [ ] Documenter le format standardisé dans `ORIGIN_API_SPECIFICATION.md`
---
## 2. FRONTEND TYPESCRIPT/REACT - PATTERNS D'ERREURS
### PAT-006: Syntax Errors - Unterminated Regex
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Regex non terminée dans les tests, causant une erreur de syntaxe.
**Exemple réel** :
```typescript
// ❌ ERREUR - src/features/auth/hooks/useOAuthCallback.test.ts
expect(mockNavigate).toHaveBeenCalledWith('/dashboard/ // ← Guillemet manquant
```
#### Cause Racine
- Copier-coller incomplet
- Erreur de frappe
- Éditeur qui n'a pas signalé l'erreur
#### Solution Standard
```typescript
// ✅ FIX
expect(mockNavigate).toHaveBeenCalledWith('/dashboard'); // Guillemet fermant ajouté
```
#### Checklist de Prévention
- [ ] Utiliser un linter en temps réel (ESLint dans VS Code)
- [ ] Vérifier la syntaxe avant de sauvegarder
- [ ] Utiliser `npm run type-check` avant commit
- [ ] Pre-commit hook devrait bloquer les erreurs de syntaxe
---
### PAT-007: Syntax Errors - Unclosed JSX Tags
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P0 (Critique)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Balises JSX non fermées, causant des erreurs de compilation.
**Exemple réel** :
```typescript
// ❌ ERREUR - src/features/playlists/components/PlaylistList.tsx
<div className="playlist-list">
{playlists.map(p => <Card>)} // ← Pas de </Card> ni </div>
```
#### Solution Standard
```typescript
// ✅ FIX
<div className="playlist-list">
{playlists.map(p => <Card key={p.id} />)} // Self-closing tag
</div> // Tag fermant ajouté
```
#### Checklist de Prévention
- [ ] Utiliser Prettier pour formater automatiquement
- [ ] Vérifier que tous les tags JSX sont fermés
- [ ] Utiliser l'extension React dans VS Code
- [ ] `tsc --noEmit` devrait détecter ces erreurs
---
### PAT-008: Configuration Errors - vite.config.ts Type Issues
**Catégorie** : CAT-02 (Configuration)
**Priorité** : P0 (Critique)
**Fréquence** : Basse
**Découvert** : 2025-11-09
#### Description
Incompatibilité de types dans la configuration Vite.
**Exemple réel** :
```typescript
// ❌ ERREUR - vite.config.ts
build: {
terserOptions: {
compress: {
drop_console: true, // Type incompatibilité
}
}
}
```
#### Solution Standard
**Option A - Utiliser esbuild (recommandé)** :
```typescript
// ✅ SOLUTION A
build: {
minify: 'esbuild', // Plus moderne, plus rapide
// Pas besoin de terserOptions
}
```
**Option B - Corriger terserOptions** :
```typescript
// ✅ SOLUTION B
build: {
minify: 'terser',
terserOptions: {
compress: {
drop_console: process.env.NODE_ENV === 'production',
},
} as any, // Type assertion si nécessaire
}
```
#### Checklist de Prévention
- [ ] Utiliser esbuild au lieu de terser (plus moderne)
- [ ] Vérifier la compatibilité des types avec `tsc --noEmit`
- [ ] Consulter la documentation Vite pour les types corrects
- [ ] Tester le build après modification de la config
---
### PAT-009: Type Errors - Missing Type Definitions
**Catégorie** : CAT-01 (Compilation)
**Priorité** : P1 (Haute)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Types TypeScript manquants ou incorrects.
**Exemple réel** :
```typescript
// ❌ ERREUR
const user: User = { // Type User non défini
id: '123',
name: 'John'
}
```
#### Solution Standard
```typescript
// ✅ FIX - Définir le type
interface User {
id: string;
name: string;
}
const user: User = {
id: '123',
name: 'John'
}
```
#### Checklist de Prévention
- [ ] Toujours définir les types avant utilisation
- [ ] Utiliser `strict: true` dans `tsconfig.json`
- [ ] Éviter `any` (utiliser `unknown` si nécessaire)
- [ ] Vérifier avec `tsc --noEmit --strict`
---
### PAT-010: Lint Errors - Unused Variables
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Très Haute
**Découvert** : 2025-11-09
#### Description
Variables déclarées mais jamais utilisées.
**Exemple réel** :
```typescript
// ❌ ERREUR
const user = getUser(); // Variable déclarée mais non utilisée
console.log('Hello');
```
#### Solution Standard
**Option A - Supprimer la variable** :
```typescript
// ✅ SOLUTION A
// const user = getUser(); ← Supprimé
console.log('Hello');
```
**Option B - Préfixer avec underscore** :
```typescript
// ✅ SOLUTION B - Si la variable sera utilisée plus tard
const _user = getUser(); // Préfixe _ indique intentionnellement non utilisé
console.log('Hello');
```
#### Checklist de Prévention
- [ ] Supprimer les variables non utilisées
- [ ] Utiliser `npm run lint -- --fix` pour auto-fix
- [ ] Configurer ESLint pour signaler en temps réel
- [ ] Pre-commit hook devrait bloquer les erreurs lint
---
### PAT-011: Lint Errors - Console Statements
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Utilisation de `console.log` en production (interdit par lint rules).
**Exemple réel** :
```typescript
// ❌ ERREUR
console.log('Debug info'); // no-console rule
```
#### Solution Standard
**Option A - Supprimer en production** :
```typescript
// ✅ SOLUTION A
if (process.env.NODE_ENV === 'development') {
console.log('Debug info');
}
```
**Option B - Utiliser un logger** :
```typescript
// ✅ SOLUTION B
import { logger } from '@/utils/logger';
logger.debug('Debug info'); // Logger gère l'environnement
```
#### Checklist de Prévention
- [ ] Ne pas utiliser `console.log` en production
- [ ] Utiliser un logger configuré
- [ ] ESLint devrait bloquer `console.*` en production
- [ ] Vite supprime automatiquement les console en build production
---
### PAT-012: Lint Errors - Any Types
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Utilisation de `any` au lieu de types spécifiques.
**Exemple réel** :
```typescript
// ❌ ERREUR
function processData(data: any) { // any interdit
return data.value;
}
```
#### Solution Standard
```typescript
// ✅ FIX - Typer correctement
interface Data {
value: string;
}
function processData(data: Data) {
return data.value;
}
// OU utiliser unknown si le type est vraiment inconnu
function processData(data: unknown) {
if (typeof data === 'object' && data !== null && 'value' in data) {
return (data as { value: string }).value;
}
throw new Error('Invalid data');
}
```
#### Checklist de Prévention
- [ ] Éviter `any` (utiliser `unknown` si nécessaire)
- [ ] Typer toutes les fonctions et variables
- [ ] Utiliser `strict: true` dans `tsconfig.json`
- [ ] ESLint devrait bloquer `any` explicit
---
### PAT-013: Missing Return Types
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Fonctions sans type de retour explicite.
**Exemple réel** :
```typescript
// ❌ ERREUR
function getUser(id: string) { // Type de retour manquant
return { id, name: 'John' };
}
```
#### Solution Standard
```typescript
// ✅ FIX
interface User {
id: string;
name: string;
}
function getUser(id: string): User { // Type de retour explicite
return { id, name: 'John' };
}
```
#### Checklist de Prévention
- [ ] Toujours typer le retour des fonctions
- [ ] Utiliser `@typescript-eslint/explicit-function-return-type`
- [ ] TypeScript peut inférer, mais explicite est mieux
---
## 3. TESTS - PATTERNS D'ERREURS
### PAT-014: Test Failures - Missing Mocks
**Catégorie** : CAT-05 (Tests)
**Priorité** : P1 (Haute)
**Fréquence** : Très Haute
**Découvert** : 2025-11-09
#### Description
Tests échouent car les mocks ne sont pas configurés.
**Exemple réel** :
```typescript
// ❌ ERREUR
it('should fetch user', async () => {
const user = await userService.getUser('123'); // userService non mocké
expect(user).toBeDefined();
});
// Error: Cannot read property 'data' of undefined
```
#### Solution Standard
```typescript
// ✅ FIX
import { vi } from 'vitest';
vi.mock('@/services/user', () => ({
userService: {
getUser: vi.fn().mockResolvedValue({ id: '123', name: 'John' })
}
}));
it('should fetch user', async () => {
const user = await userService.getUser('123');
expect(user).toBeDefined();
});
```
#### Checklist de Prévention
- [ ] Toujours mocker les dépendances externes
- [ ] Utiliser `vi.mock()` pour les modules
- [ ] Configurer les mocks dans `beforeEach` si réutilisés
- [ ] Vérifier que les mocks correspondent aux vrais services
---
### PAT-015: Test Failures - React act() Warnings
**Catégorie** : CAT-05 (Tests)
**Priorité** : P2 (Moyenne)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Avertissements React `act()` dans les tests.
**Exemple réel** :
```typescript
// ❌ WARNING
Warning: An update to Component inside a test was not wrapped in act(...).
```
#### Solution Standard
```typescript
// ✅ FIX
import { act, render, screen } from '@testing-library/react';
it('should update state', async () => {
render(<Component />);
await act(async () => {
fireEvent.click(screen.getByRole('button'));
await waitFor(() => {
expect(screen.getByText('Updated')).toBeInTheDocument();
});
});
});
```
#### Checklist de Prévention
- [ ] Utiliser `act()` pour les mises à jour d'état
- [ ] Utiliser `waitFor()` pour les mises à jour asynchrones
- [ ] `@testing-library/react` gère `act()` automatiquement dans la plupart des cas
- [ ] Vérifier les warnings dans les logs de tests
---
### PAT-016: Test Failures - WebSocket Mocking Issues
**Catégorie** : CAT-05 (Tests)
**Priorité** : P1 (Haute)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Problèmes de mock WebSocket dans les tests.
**Exemple réel** :
```typescript
// ❌ ERREUR
TypeError: realWebSocket.addEventListener is not a function
```
#### Solution Standard
```typescript
// ✅ FIX - Mocker WebSocket globalement
global.WebSocket = class MockWebSocket {
addEventListener = vi.fn();
removeEventListener = vi.fn();
send = vi.fn();
close = vi.fn();
readyState = WebSocket.OPEN;
} as any;
```
#### Checklist de Prévention
- [ ] Mocker WebSocket dans `setupTests.ts`
- [ ] Utiliser une bibliothèque de mock WebSocket si nécessaire
- [ ] Tester les connexions WebSocket séparément
---
### PAT-017: Test Failures - Outdated Assertions
**Catégorie** : CAT-05 (Tests)
**Priorité** : P1 (Haute)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Assertions de tests obsolètes après changement d'API.
**Exemple réel** :
```typescript
// ❌ ERREUR - API changée
expect(result).toEqual({ success: true });
// API retourne maintenant: { status: 'success', data: {...} }
```
#### Solution Standard
```typescript
// ✅ FIX - Adapter aux nouveaux contracts
expect(result).toEqual({
status: 'success',
data: expect.objectContaining({
id: expect.any(String),
name: expect.any(String),
})
});
```
#### Checklist de Prévention
- [ ] Mettre à jour les tests lors de changement d'API
- [ ] Utiliser des matchers flexibles (`expect.objectContaining`)
- [ ] Contract testing pour valider les APIs
- [ ] Snapshot testing pour détecter les changements
---
### PAT-018: Test Failures - Missing Test Data
**Catégorie** : CAT-05 (Tests)
**Priorité** : P1 (Haute)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Tests échouent car les données de test sont manquantes.
#### Solution Standard
```typescript
// ✅ FIX - Créer fixtures
// tests/fixtures/users.ts
export const testUsers = {
normalUser: {
id: 'user-123',
email: 'user@example.com',
name: 'Test User',
},
};
// test
import { testUsers } from '@/tests/fixtures/users';
it('should work', () => {
const user = testUsers.normalUser;
// ...
});
```
#### Checklist de Prévention
- [ ] Créer des fixtures réutilisables
- [ ] Centraliser les données de test
- [ ] Utiliser des factories pour générer des données
---
### PAT-019: Test Coverage Below Threshold
**Catégorie** : CAT-05 (Tests)
**Priorité** : P1 (Haute)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Couverture de tests en dessous du seuil de 80%.
#### Solution Standard
- Identifier le code non testé
- Écrire des tests pour les branches manquantes
- Utiliser `--coverage` pour voir les détails
#### Checklist de Prévention
- [ ] Maintenir coverage ≥ 80%
- [ ] CI/CD devrait bloquer si coverage < 80%
- [ ] Écrire les tests en même temps que le code (TDD)
---
## 4. CONFIGURATION - PATTERNS D'ERREURS
### PAT-020: Missing Environment Variables
**Catégorie** : CAT-02 (Configuration)
**Priorité** : P0 (Critique)
**Fréquence** : Basse
**Découvert** : 2025-11-09
#### Description
Variables d'environnement manquantes.
#### Solution Standard
- Documenter toutes les variables requises dans `.env.example`
- Valider les variables au démarrage
- Utiliser des valeurs par défaut si approprié
#### Checklist de Prévention
- [ ] Documenter toutes les variables dans `.env.example`
- [ ] Valider les variables au démarrage
- [ ] Utiliser `dotenv` pour charger les variables
---
### PAT-021: Docker Configuration Errors
**Catégorie** : CAT-06 (Docker)
**Priorité** : P0 (Critique)
**Fréquence** : Basse
**Découvert** : 2025-11-09
#### Description
Erreurs de syntaxe YAML dans `docker-compose.yml`.
#### Solution Standard
- Valider la syntaxe YAML avec `docker-compose config`
- Vérifier l'indentation (espaces, pas tabs)
- Utiliser un validateur YAML
#### Checklist de Prévention
- [ ] Valider `docker-compose.yml` avant commit
- [ ] Utiliser 2 espaces pour l'indentation
- [ ] Vérifier les guillemets et caractères spéciaux
---
## 5. LINT/FORMAT - PATTERNS D'ERREURS
### PAT-022: Code Formatting Issues
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Haute
**Découvert** : 2025-11-09
#### Description
Code non formaté selon les standards.
#### Solution Standard
```bash
# Auto-fix avec Prettier
npm run format
# Auto-fix avec ESLint
npm run lint -- --fix
```
#### Checklist de Prévention
- [ ] Utiliser Prettier pour formater automatiquement
- [ ] Pre-commit hook devrait formater avant commit
- [ ] Configurer l'éditeur pour formater à la sauvegarde
---
### PAT-023: Import Order Issues
**Catégorie** : CAT-07 (Lint/Format)
**Priorité** : P2 (Moyenne)
**Fréquence** : Moyenne
**Découvert** : 2025-11-09
#### Description
Imports non triés selon les règles.
#### Solution Standard
- Utiliser `eslint-plugin-import` avec règle de tri
- Auto-fix avec `npm run lint -- --fix`
#### Checklist de Prévention
- [ ] Configurer ESLint pour trier les imports
- [ ] Auto-fix devrait corriger automatiquement
---
## 📊 RÉSUMÉ DES CHECKLISTS PAR CATÉGORIE
### Backend Go
- [ ] Vérifier import cycles avant d'ajouter un import
- [ ] Maintenir cohérence string vs *string
- [ ] Vérifier que tous les packages importés existent
- [ ] Utiliser `go vet` et `golangci-lint`
- [ ] Tests unitaires pour chaque fonction
- [ ] Valider JWT issuer/audience dans la config et au parsing
- [ ] Propager `c.Request.Context()` dans tous les handlers (jamais `context.Background()`)
- [ ] Toute goroutine reçoit un `context.Context` et un mécanisme d'arrêt
- [ ] Pagination bornée par `MaxPageSize` sur tous les endpoints
- [ ] Utiliser exclusivement `RespondWithAppError` (jamais `gin.H{"error": ...}`)
### Frontend TypeScript/React
- [ ] Linter en temps réel activé
- [ ] TypeScript strict mode activé
- [ ] Tous les tags JSX fermés
- [ ] Pas de `any` types
- [ ] Pas de `console.log` en production
- [ ] Prettier configuré
### Tests
- [ ] Mocks configurés pour toutes les dépendances
- [ ] Coverage 80%
- [ ] Tests passent avant commit
- [ ] Fixtures réutilisables
### Configuration
- [ ] Variables d'environnement documentées
- [ ] docker-compose.yml validé
- [ ] vite.config.ts types corrects
---
## 🔄 MAINTENANCE
### Ajouter un Nouveau Pattern
1. Identifier le pattern récurrent
2. Documenter dans ce fichier avec le format standard
3. Mettre à jour les statistiques
4. Ajouter à la checklist de prévention appropriée
5. Mettre à jour `ORIGIN_ERROR_PREVENTION_GUIDE.md`
### Révision
- **Fréquence** : Mensuelle
- **Responsable** : Lead Engineers
- **Processus** : Analyser les nouvelles erreurs, documenter les patterns
---
**Dernière mise à jour** : 2026-03-04
**Version** : 2.0.0
**Statut** : **APPROUVÉ ET VERROUILLÉ**