34 KiB
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
- TOUJOURS consulter ce document avant de commencer une nouvelle tâche
- TOUJOURS vérifier qu'aucun pattern d'erreur ne sera introduit
- TOUJOURS documenter tout nouveau pattern découvert
- 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 :
// ❌ 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
cd veza-backend-api
go list -f '{{join .DepsErrors "\n"}}' ./... | grep -i "cycle"
Étape 2 : Créer package de types partagés
// ✅ 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
// ✅ 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 graphpour visualiser les dépendances - Définir les interfaces dans
internal/types/ouinternal/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 :
// ❌ 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
*stringversstring(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)
// ✅ 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)
// ✅ 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 :
stringou*stringpour 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 vetpour 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 :
// ❌ 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
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 :
// ✅ 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 :
// ✅ 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 tidypour 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 :
// ❌ ERREUR
import "github.com/crewjam/saml/samlsp"
// Error: no required module provides package github.com/crewjam/saml/samlsp
Solution Standard
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 tidyré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 :
// ❌ 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 vetpour 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 :
// ❌ 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_ISSUERetJWT_AUDIENCEabsentes ou incohérentes
Solution Standard
// ✅ 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
issetaudlors de chaque parsing JWT - Centraliser la configuration JWT dans un seul package (
internal/auth/config.go) - Vérifier la cohérence des variables
JWT_ISSUERetJWT_AUDIENCEau 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 :
// ❌ 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
// ✅ 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 :
// ❌ 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.Contextpour signaler l'annulation - Pas de
sync.WaitGrouppour attendre la fin des goroutines au shutdown
Solution Standard
// ✅ 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.Contextpour l'annulation - Utiliser
sync.WaitGrouppour le graceful shutdown - Utiliser
selectavecctx.Done()dans les boucles - Monitorer le nombre de goroutines en production (
runtime.NumGoroutine()) - Tests avec
goleakpour 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 :
// ❌ 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
MaxPageSizepartagée - Confiance implicite dans les paramètres du client
Solution Standard
// ✅ 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
MaxPageSizecomme constante partagée (ex.internal/api/pagination.go) - Valider et borner
limitdans tous les endpoints paginés - Valider que
offsetest ≥ 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 :
// ❌ 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
// ✅ 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
RespondWithAppErrorpour 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 :
// ❌ 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
// ✅ 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-checkavant 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 :
// ❌ ERREUR - src/features/playlists/components/PlaylistList.tsx
<div className="playlist-list">
{playlists.map(p => <Card>)} // ← Pas de </Card> ni </div>
Solution Standard
// ✅ 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 --noEmitdevrait 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 :
// ❌ ERREUR - vite.config.ts
build: {
terserOptions: {
compress: {
drop_console: true, // Type incompatibilité
}
}
}
Solution Standard
Option A - Utiliser esbuild (recommandé) :
// ✅ SOLUTION A
build: {
minify: 'esbuild', // Plus moderne, plus rapide
// Pas besoin de terserOptions
}
Option B - Corriger terserOptions :
// ✅ 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 :
// ❌ ERREUR
const user: User = { // Type User non défini
id: '123',
name: 'John'
}
Solution Standard
// ✅ 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: truedanstsconfig.json - Éviter
any(utiliserunknownsi 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 :
// ❌ ERREUR
const user = getUser(); // Variable déclarée mais non utilisée
console.log('Hello');
Solution Standard
Option A - Supprimer la variable :
// ✅ SOLUTION A
// const user = getUser(); ← Supprimé
console.log('Hello');
Option B - Préfixer avec underscore :
// ✅ 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 -- --fixpour 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 :
// ❌ ERREUR
console.log('Debug info'); // no-console rule
Solution Standard
Option A - Supprimer en production :
// ✅ SOLUTION A
if (process.env.NODE_ENV === 'development') {
console.log('Debug info');
}
Option B - Utiliser un logger :
// ✅ SOLUTION B
import { logger } from '@/utils/logger';
logger.debug('Debug info'); // Logger gère l'environnement
Checklist de Prévention
- Ne pas utiliser
console.logen 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 :
// ❌ ERREUR
function processData(data: any) { // any interdit
return data.value;
}
Solution Standard
// ✅ 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(utiliserunknownsi nécessaire) - Typer toutes les fonctions et variables
- Utiliser
strict: truedanstsconfig.json - ESLint devrait bloquer
anyexplicit
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 :
// ❌ ERREUR
function getUser(id: string) { // Type de retour manquant
return { id, name: 'John' };
}
Solution Standard
// ✅ 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 :
// ❌ 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
// ✅ 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
beforeEachsi 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 :
// ❌ WARNING
Warning: An update to Component inside a test was not wrapped in act(...).
Solution Standard
// ✅ 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/reactgèreact()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 :
// ❌ ERREUR
TypeError: realWebSocket.addEventListener is not a function
Solution Standard
// ✅ 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 :
// ❌ ERREUR - API changée
expect(result).toEqual({ success: true });
// API retourne maintenant: { status: 'success', data: {...} }
Solution Standard
// ✅ 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
// ✅ 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
--coveragepour 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
dotenvpour 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.ymlavant 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
# 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-importavec 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 vetetgolangci-lint - Tests unitaires pour chaque fonction
- Valider JWT issuer/audience dans la config et au parsing
- Propager
c.Request.Context()dans tous les handlers (jamaiscontext.Background()) - Toute goroutine reçoit un
context.Contextet un mécanisme d'arrêt - Pagination bornée par
MaxPageSizesur tous les endpoints - Utiliser exclusivement
RespondWithAppError(jamaisgin.H{"error": ...})
Frontend TypeScript/React
- Linter en temps réel activé
- TypeScript strict mode activé
- Tous les tags JSX fermés
- Pas de
anytypes - Pas de
console.logen 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
- Identifier le pattern récurrent
- Documenter dans ce fichier avec le format standard
- Mettre à jour les statistiques
- Ajouter à la checklist de prévention appropriée
- 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É