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

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

  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 :

// ❌ 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 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


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 *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)

// ✅ 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 : 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


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 tidy pour nettoyer les dépendances
  • Vérifier avec go build ./... après chaque modification

Références


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 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 :

// ❌ 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 :

// ❌ 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

// ✅ 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 :

// ❌ 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.Context pour signaler l'annulation
  • Pas de sync.WaitGroup pour 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.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 :

// ❌ 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

// ✅ 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 :

// ❌ 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 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 :

// ❌ 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-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 :

// ❌ 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 --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 :

// ❌ 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: 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 :

// ❌ 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 -- --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 :

// ❌ 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.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 :

// ❌ 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 (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 :

// ❌ 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 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 :

// ❌ 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/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 :

// ❌ 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 --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

# 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É