1401 lines
34 KiB
Markdown
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É**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|