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

2086 lines
49 KiB
Markdown

# ORIGIN_CODE_STANDARDS.md
## 📋 RÉSUMÉ EXÉCUTIF
Ce document définit les standards de code complets et définitifs pour la plateforme Veza. Il couvre les conventions de code, architectures, patterns, et anti-patterns pour Go (backend), Rust (services temps réel), TypeScript/React (frontend), CSS/Tailwind, Git, et documentation. Ces standards garantissent la maintenabilité, lisibilité, performance, et cohérence du code pendant 24 mois.
## 🎯 OBJECTIFS
### Objectif Principal
Établir des standards de code stricts et immuables qui garantissent la qualité, maintenabilité, et cohérence du codebase pendant 24 mois avec une équipe de 10+ développeurs.
### Objectifs Secondaires
- Réduire la dette technique (< 5% du temps de développement)
- Faciliter l'onboarding (< 1 semaine pour nouveaux développeurs)
- Garantir la lisibilité (code self-documenting)
- Optimiser les performances (hot paths identifiés)
- Standardiser le style (linters, formatters automatiques)
## 📖 TABLE DES MATIÈRES
1. [General Principles](#1-general-principles)
2. [Standards éthiques du code](#2-standards-éthiques-du-code)
3. [Go Standards (Backend)](#3-go-standards-backend)
4. [Rust Standards (Services)](#4-rust-standards-services)
5. [TypeScript Standards (Frontend)](#5-typescript-standards-frontend)
6. [React Standards](#6-react-standards)
7. [CSS/Tailwind Standards](#7-csstailwind-standards)
8. [Git Standards](#8-git-standards)
9. [Documentation Standards](#9-documentation-standards)
10. [Code Review Process](#10-code-review-process)
11. [Refactoring Guidelines](#11-refactoring-guidelines)
12. [Anti-Patterns Library](#12-anti-patterns-library)
## 🔒 RÈGLES IMMUABLES
1. **Formatters OBLIGATOIRES**: gofmt (Go), rustfmt (Rust), Prettier (TS/React)
2. **Linters OBLIGATOIRES**: golangci-lint (Go), clippy (Rust), ESLint (TS)
3. **Tests OBLIGATOIRES** pour toute nouvelle feature (coverage 80%)
4. **Code review OBLIGATOIRE** (2 approbations minimum)
5. **Naming conventions STRICTES** (camelCase/PascalCase/snake_case selon langage)
6. **Documentation OBLIGATOIRE** pour fonctions publiques
7. **Error handling COMPLET** (pas de panic/unwrap en production)
8. **Magic numbers INTERDITS** (utiliser constantes nommées)
9. **Code mort INTERDIT** (suppression immédiate)
10. **Complexity limit**: Fonctions max 50 lignes, cyclomatic complexity < 10
## 1. GENERAL PRINCIPLES
### 1.1 SOLID Principles
**Single Responsibility Principle** (SRP):
```go
// ❌ Bad: UserService does too much
type UserService struct{}
func (s *UserService) CreateUser() {}
func (s *UserService) SendEmail() {}
func (s *UserService) ProcessPayment() {}
// ✅ Good: Separate services
type UserService struct{}
func (s *UserService) CreateUser() {}
type EmailService struct{}
func (s *EmailService) SendEmail() {}
type PaymentService struct{}
func (s *PaymentService) ProcessPayment() {}
```
**Open/Closed Principle** (OCP):
```go
// ✅ Good: Open for extension, closed for modification
type NotificationSender interface {
Send(message string) error
}
type EmailNotification struct{}
func (e *EmailNotification) Send(message string) error { /* ... */ }
type SMSNotification struct{}
func (s *SMSNotification) Send(message string) error { /* ... */ }
// Add new notification types without modifying existing code
type PushNotification struct{}
func (p *PushNotification) Send(message string) error { /* ... */ }
```
**Liskov Substitution Principle** (LSP):
```go
// ✅ Good: Subtypes can replace base types
type Storage interface {
Save(data []byte) error
Load() ([]byte, error)
}
type S3Storage struct{}
func (s *S3Storage) Save(data []byte) error { /* ... */ }
func (s *S3Storage) Load() ([]byte, error) { /* ... */ }
type LocalStorage struct{}
func (l *LocalStorage) Save(data []byte) error { /* ... */ }
func (l *LocalStorage) Load() ([]byte, error) { /* ... */ }
// Can swap implementations
var storage Storage = &S3Storage{} // or &LocalStorage{}
```
**Interface Segregation Principle** (ISP):
```go
// ❌ Bad: Fat interface
type Worker interface {
Work()
Eat()
Sleep()
Code()
}
// ✅ Good: Segregated interfaces
type Workable interface {
Work()
}
type Eatable interface {
Eat()
}
type Sleepable interface {
Sleep()
}
type Codeable interface {
Code()
}
```
**Dependency Inversion Principle** (DIP):
```go
// ❌ Bad: High-level module depends on low-level module
type UserService struct {
repo *PostgresUserRepository // Concrete dependency
}
// ✅ Good: Both depend on abstraction
type UserRepository interface {
Create(user *User) error
FindByID(id uuid.UUID) (*User, error)
}
type UserService struct {
repo UserRepository // Abstract dependency
}
// Implementations
type PostgresUserRepository struct{}
type MongoUserRepository struct{}
```
### 1.2 DRY (Don't Repeat Yourself)
**Extract Common Logic**:
```go
// ❌ Bad: Duplication
func CreateUser(req CreateUserRequest) error {
if req.Email == "" {
return errors.New("email required")
}
if !isValidEmail(req.Email) {
return errors.New("invalid email")
}
// ... create user
}
func UpdateUser(req UpdateUserRequest) error {
if req.Email == "" {
return errors.New("email required")
}
if !isValidEmail(req.Email) {
return errors.New("invalid email")
}
// ... update user
}
// ✅ Good: Extract validation
func validateEmail(email string) error {
if email == "" {
return errors.New("email required")
}
if !isValidEmail(email) {
return errors.New("invalid email")
}
return nil
}
func CreateUser(req CreateUserRequest) error {
if err := validateEmail(req.Email); err != nil {
return err
}
// ... create user
}
```
### 1.3 KISS (Keep It Simple, Stupid)
**Favor Simplicity**:
```go
// ❌ Bad: Overengineered
func IsEven(n int) bool {
return n & 1 == 0
}
// ✅ Good: Simple and readable
func IsEven(n int) bool {
return n % 2 == 0
}
```
### 1.4 YAGNI (You Aren't Gonna Need It)
**Don't Add Features Until Needed**:
```go
// ❌ Bad: Premature generalization
type Cache interface {
Get(key string) (interface{}, error)
Set(key string, value interface{}) error
Delete(key string) error
GetMulti(keys []string) ([]interface{}, error) // Not needed yet
SetMulti(map[string]interface{}) error // Not needed yet
Flush() error // Not needed yet
GetStats() CacheStats // Not needed yet
}
// ✅ Good: Start simple, add when needed
type Cache interface {
Get(key string) (interface{}, error)
Set(key string, value interface{}) error
Delete(key string) error
}
```
## 2. STANDARDS ÉTHIQUES DU CODE
### 2.1 Tracking et consentement
**Aucun tracking côté client sans consentement explicite de l'utilisateur.**
Toute collecte de données comportementales (analytics, événements, métriques d'usage) doit être conditionnée à un opt-in explicite. Le consentement ne doit jamais être présumé.
```typescript
// ❌ Interdit : tracking silencieux
useEffect(() => {
analytics.track('page_view', { page: location.pathname });
}, [location]);
// ✅ Obligatoire : vérifier le consentement
useEffect(() => {
if (userConsent.analytics) {
analytics.track('page_view', { page: location.pathname });
}
}, [location, userConsent.analytics]);
```
### 2.2 Algorithmes d'exposition de contenu
Tout algorithme influençant la visibilité ou le classement du contenu (feed, recherche, suggestions) **doit être documenté et justifiable**. La documentation doit inclure :
- Les critères de classement et leur pondération
- L'objectif produit visé (ex : diversité, fraîcheur, pertinence)
- Les biais potentiels identifiés et les mesures de mitigation
Aucun algorithme opaque n'est autorisé. Les créateurs doivent pouvoir comprendre pourquoi leur contenu est ou n'est pas mis en avant.
### 2.3 Collecte de métriques
**Chaque métrique collectée doit avoir une justification produit documentée.** La collecte préventive ("au cas on en aurait besoin") est interdite.
```go
// ❌ Interdit : collecte préventive sans justification
type TrackEvent struct {
TrackID uuid.UUID
UserID uuid.UUID
ScrollDepth float64 // Pourquoi ?
MouseMovement []Point // Pourquoi ?
TimeOnPage int // Pourquoi ?
DeviceGyro []float64 // Pourquoi ?
}
// ✅ Obligatoire : chaque champ justifié
type TrackPlayEvent struct {
TrackID uuid.UUID // Identifier le contenu joué
ListenTimeMs int64 // Calculer les royalties (seuil 30s)
Completed bool // Taux de complétion pour le créateur
}
```
### 2.4 Scoring, ranking et diversité
Toute fonction de scoring ou de ranking **doit inclure des tests de non-régression sur la diversité**. Ces tests vérifient que les résultats ne concentrent pas la visibilité sur un sous-ensemble disproportionné de créateurs.
```go
func TestSearchRanking_Diversity(t *testing.T) {
results := searchService.Search(ctx, "electronic music", SearchParams{Limit: 50})
creatorIDs := make(map[uuid.UUID]bool)
for _, r := range results {
creatorIDs[r.CreatorID] = true
}
// Les 50 premiers résultats doivent provenir d'au moins 10 créateurs distincts
assert.GreaterOrEqual(t, len(creatorIDs), 10,
"Les résultats de recherche doivent refléter une diversité minimale de créateurs")
}
```
## 3. GO STANDARDS (BACKEND)
### 3.1 Project Structure (Clean Architecture)
```
veza-backend-api/
├── cmd/
│ └── api/
│ └── main.go # Entry point
├── internal/
│ ├── api/ # HTTP handlers (Delivery layer)
│ │ └── handlers/
│ │ ├── user_handlers.go
│ │ ├── track_handlers.go
│ │ └── auth_handlers.go
│ ├── core/ # Business logic (Use Cases)
│ │ ├── services/
│ │ │ ├── user_service.go
│ │ │ └── track_service.go
│ │ └── domain/ # Entities
│ │ ├── user.go
│ │ └── track.go
│ ├── repository/ # Data access (Repository pattern)
│ │ ├── interfaces.go
│ │ ├── user_repository.go
│ │ └── track_repository.go
│ ├── infrastructure/ # External dependencies
│ │ ├── database/
│ │ │ └── postgres.go
│ │ ├── cache/
│ │ │ └── redis.go
│ │ └── storage/
│ │ └── s3.go
│ ├── middleware/ # HTTP middleware
│ │ ├── auth.go
│ │ ├── cors.go
│ │ └── logging.go
│ └── config/ # Configuration
│ └── config.go
├── pkg/ # Public packages (reusable)
│ ├── logger/
│ └── validator/
├── migrations/ # Database migrations
├── tests/
│ ├── unit/
│ └── integration/
├── go.mod
└── go.sum
```
### 3.2 Naming Conventions
**Variables**: camelCase
```go
var userName string
var userCount int
```
**Constants**: PascalCase or SCREAMING_SNAKE_CASE (for exported)
```go
const MaxRetries = 3
const DEFAULT_TIMEOUT = 30 * time.Second
```
**Functions**: PascalCase (exported), camelCase (unexported)
```go
// Exported
func CreateUser(req *CreateUserRequest) (*User, error) {}
// Unexported
func validateEmail(email string) error {}
```
**Types**: PascalCase
```go
type UserService struct {}
type CreateUserRequest struct {}
```
**Interfaces**: -er suffix (if single method)
```go
type Reader interface {
Read(p []byte) (n int, err error)
}
type UserRepository interface { // Multi-method, no -er suffix
Create(user *User) error
FindByID(id uuid.UUID) (*User, error)
}
```
### 3.3 Error Handling
**Always Check Errors**:
```go
// ❌ Bad: Ignoring error
user, _ := repo.FindByID(id)
// ✅ Good: Check and handle
user, err := repo.FindByID(id)
if err != nil {
return nil, fmt.Errorf("failed to find user: %w", err)
}
```
**Wrap Errors with Context**:
```go
import "fmt"
func CreateUser(req *CreateUserRequest) error {
if err := validateEmail(req.Email); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := repo.Create(user); err != nil {
return fmt.Errorf("failed to create user in database: %w", err)
}
return nil
}
```
**Custom Error Types** (when needed):
```go
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation error: %s - %s", e.Field, e.Message)
}
// Usage
if req.Email == "" {
return &ValidationError{Field: "email", Message: "required"}
}
```
**Don't Panic in Production**:
```go
// ❌ Bad: Panic for recoverable errors
if err != nil {
panic(err)
}
// ✅ Good: Return error
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
// ⚠️ OK: Panic only for programmer errors (init, config)
func init() {
if os.Getenv("DATABASE_URL") == "" {
panic("DATABASE_URL environment variable not set")
}
}
```
### 3.4 Function Design
**Keep Functions Small** (< 50 lines):
```go
// ❌ Bad: Too long
func CreateUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "invalid request"})
return
}
if req.Email == "" {
c.JSON(400, gin.H{"error": "email required"})
return
}
if !isValidEmail(req.Email) {
c.JSON(400, gin.H{"error": "invalid email"})
return
}
existingUser, _ := repo.FindByEmail(req.Email)
if existingUser != nil {
c.JSON(409, gin.H{"error": "email already exists"})
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 12)
if err != nil {
c.JSON(500, gin.H{"error": "internal error"})
return
}
user := &User{
ID: uuid.New(),
Email: req.Email,
PasswordHash: string(hash),
CreatedAt: time.Now(),
}
if err := repo.Create(user); err != nil {
c.JSON(500, gin.H{"error": "failed to create user"})
return
}
c.JSON(201, user)
}
// ✅ Good: Extract to service layer
func CreateUser(c *gin.Context) {
var req CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, ErrorResponse{Code: 2000, Message: "Invalid request"})
return
}
user, err := userService.CreateUser(c.Request.Context(), &req)
if err != nil {
handleError(c, err)
return
}
c.JSON(201, user)
}
// Business logic in service
func (s *UserService) CreateUser(ctx context.Context, req *CreateUserRequest) (*User, error) {
if err := s.validateCreateRequest(req); err != nil {
return nil, err
}
if err := s.checkEmailExists(req.Email); err != nil {
return nil, err
}
user := s.buildUser(req)
if err := s.repo.Create(ctx, user); err != nil {
return nil, fmt.Errorf("failed to create user: %w", err)
}
return user, nil
}
```
**Single Return Type** (prefer):
```go
// ❌ Bad: Multiple return patterns
func FindUser(id uuid.UUID) (*User, error) {
user, err := repo.FindByID(id)
if err == sql.ErrNoRows {
return nil, nil // nil user, nil error
}
if err != nil {
return nil, err // nil user, error
}
return user, nil // user, nil error
}
// ✅ Good: Consistent return pattern
func FindUser(id uuid.UUID) (*User, error) {
user, err := repo.FindByID(id)
if err == sql.ErrNoRows {
return nil, ErrUserNotFound
}
if err != nil {
return nil, fmt.Errorf("failed to find user: %w", err)
}
return user, nil
}
```
### 3.5 Concurrency
**Use Context for Cancellation**:
```go
func ProcessTask(ctx context.Context, taskID uuid.UUID) error {
select {
case <-ctx.Done():
return ctx.Err() // Cancelled or timed out
case <-time.After(1 * time.Second):
// Continue processing
}
// ... do work
return nil
}
// Usage with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := ProcessTask(ctx, taskID); err != nil {
log.Error("Task failed", zap.Error(err))
}
```
**Goroutine Patterns**:
```go
// ✅ Good: Worker pool
func ProcessTracks(tracks []*Track) error {
const numWorkers = 10
jobs := make(chan *Track, len(tracks))
results := make(chan error, len(tracks))
// Start workers
for w := 0; w < numWorkers; w++ {
go func() {
for track := range jobs {
results <- processTrack(track)
}
}()
}
// Send jobs
for _, track := range tracks {
jobs <- track
}
close(jobs)
// Collect results
for i := 0; i < len(tracks); i++ {
if err := <-results; err != nil {
return err
}
}
return nil
}
```
**Avoid Goroutine Leaks**:
```go
// ❌ Bad: Goroutine leak (no way to stop)
func StartWorker() {
go func() {
for {
doWork()
time.Sleep(1 * time.Second)
}
}()
}
// ✅ Good: Cancellable goroutine
func StartWorker(ctx context.Context) {
go func() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return // Exit goroutine
case <-ticker.C:
doWork()
}
}
}()
}
```
### 3.6 Testing
**Table-Driven Tests**:
```go
func TestIsValidEmail(t *testing.T) {
tests := []struct {
name string
email string
want bool
}{
{"valid email", "user@example.com", true},
{"missing @", "userexample.com", false},
{"missing domain", "user@", false},
{"empty", "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsValidEmail(tt.email)
if got != tt.want {
t.Errorf("IsValidEmail(%q) = %v, want %v", tt.email, got, tt.want)
}
})
}
}
```
**Use testify/assert**:
```go
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateUser(t *testing.T) {
user, err := CreateUser(&CreateUserRequest{
Email: "test@example.com",
})
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, "test@example.com", user.Email)
}
```
**Mock Dependencies**:
```go
// Interface
type UserRepository interface {
Create(user *User) error
}
// Mock implementation (using testify/mock)
type MockUserRepository struct {
mock.Mock
}
func (m *MockUserRepository) Create(user *User) error {
args := m.Called(user)
return args.Error(0)
}
// Test with mock
func TestUserService_CreateUser(t *testing.T) {
mockRepo := new(MockUserRepository)
mockRepo.On("Create", mock.Anything).Return(nil)
service := NewUserService(mockRepo)
user, err := service.CreateUser(&CreateUserRequest{
Email: "test@example.com",
})
assert.NoError(t, err)
assert.NotNil(t, user)
mockRepo.AssertExpectations(t)
}
```
### 3.7 API Standards
#### Pagination obligatoire
Toute route retournant une liste **doit** accepter les paramètres `limit` et `offset` et imposer une limite maximale de **100 éléments**.
```go
const (
DefaultPageSize = 20
MaxPageSize = 100
)
func sanitizePagination(limit, offset int) (int, int) {
if limit <= 0 || limit > MaxPageSize {
limit = DefaultPageSize
}
if offset < 0 {
offset = 0
}
return limit, offset
}
// ❌ Interdit : liste sans pagination
func (h *TrackHandler) ListTracks(c *gin.Context) {
tracks, _ := h.service.ListAll(c.Request.Context())
c.JSON(200, tracks)
}
// ✅ Obligatoire : pagination bornée
func (h *TrackHandler) ListTracks(c *gin.Context) {
limit, offset := sanitizePagination(
c.GetInt("limit"),
c.GetInt("offset"),
)
tracks, total, err := h.service.List(c.Request.Context(), limit, offset)
if err != nil {
RespondWithAppError(c, err)
return
}
c.JSON(200, PaginatedResponse{Data: tracks, Total: total, Limit: limit, Offset: offset})
}
```
#### Propagation du contexte
**Interdit** d'utiliser `context.Background()` dans les handlers ou les services. Le contexte de la requête HTTP doit être propagé à toutes les couches.
```go
// ❌ Interdit : context.Background() dans un handler/service
func (s *TrackService) GetTrack(id uuid.UUID) (*Track, error) {
return s.repo.FindByID(context.Background(), id)
}
// ✅ Obligatoire : propager le contexte de la requête
func (s *TrackService) GetTrack(ctx context.Context, id uuid.UUID) (*Track, error) {
return s.repo.FindByID(ctx, id)
}
```
#### Gestion des erreurs standardisée
Tous les handlers **doivent** utiliser `RespondWithAppError` pour les réponses d'erreur. Les réponses `gin.H{"error": ...}` ad hoc sont interdites.
```go
// ❌ Interdit : réponses d'erreur ad hoc
func (h *TrackHandler) GetTrack(c *gin.Context) {
track, err := h.service.GetTrack(c.Request.Context(), id)
if err != nil {
c.JSON(500, gin.H{"error": "internal error"})
return
}
c.JSON(200, track)
}
// ✅ Obligatoire : RespondWithAppError
func (h *TrackHandler) GetTrack(c *gin.Context) {
track, err := h.service.GetTrack(c.Request.Context(), id)
if err != nil {
RespondWithAppError(c, err)
return
}
c.JSON(200, track)
}
```
## 4. RUST STANDARDS (SERVICES)
### 4.1 Project Structure
```
veza-chat-server/
├── src/
│ ├── main.rs # Entry point
│ ├── lib.rs # Library root
│ ├── handlers/ # WebSocket handlers
│ │ ├── mod.rs
│ │ ├── message.rs
│ │ └── presence.rs
│ ├── services/ # Business logic
│ │ ├── mod.rs
│ │ ├── message_service.rs
│ │ └── auth_service.rs
│ ├── repository/ # Data access
│ │ ├── mod.rs
│ │ └── message_repository.rs
│ ├── models/ # Data models
│ │ ├── mod.rs
│ │ ├── message.rs
│ │ └── room.rs
│ ├── utils/ # Utilities
│ │ ├── mod.rs
│ │ └── jwt.rs
│ └── config.rs # Configuration
├── migrations/ # SQLx migrations
├── tests/
│ ├── integration/
│ └── unit/
├── Cargo.toml
└── Cargo.lock
```
### 4.2 Naming Conventions
**Variables/Functions**: snake_case
```rust
let user_name = "John";
fn create_user() {}
```
**Types/Traits**: PascalCase
```rust
struct UserService;
trait Repository {}
```
**Constants**: SCREAMING_SNAKE_CASE
```rust
const MAX_CONNECTIONS: usize = 10000;
```
**Lifetimes**: short, lowercase
```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {}
```
### 4.3 Error Handling
**Use Result Type**:
```rust
use anyhow::{Result, Context};
fn create_user(email: &str) -> Result<User> {
if email.is_empty() {
return Err(anyhow!("Email is required"));
}
let user = User::new(email)
.context("Failed to create user")?;
Ok(user)
}
```
**Custom Error Types** (with thiserror):
```rust
use thiserror::Error;
#[derive(Error, Debug)]
pub enum UserError {
#[error("User not found: {0}")]
NotFound(Uuid),
#[error("Email already exists: {0}")]
EmailExists(String),
#[error("Validation failed: {0}")]
Validation(String),
#[error(transparent)]
Database(#[from] sqlx::Error),
}
// Usage
fn find_user(id: Uuid) -> Result<User, UserError> {
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
.fetch_one(&pool)
.await
.map_err(|_| UserError::NotFound(id))?;
Ok(user)
}
```
**Avoid unwrap/expect in Production**:
```rust
// ❌ Bad: unwrap can panic
let user = find_user(id).unwrap();
// ✅ Good: Handle error
let user = find_user(id)
.context("Failed to find user")?;
// ⚠️ OK: expect for programmer errors (init)
let config = Config::from_env()
.expect("CONFIG environment variables missing");
```
### 4.4 Ownership & Borrowing
**Prefer Borrowing**:
```rust
// ❌ Bad: Takes ownership (can't use afterwards)
fn process_user(user: User) {
println!("{}", user.name);
}
let user = User::new("John");
process_user(user);
// user is moved, can't use here
// ✅ Good: Borrows (can still use)
fn process_user(user: &User) {
println!("{}", user.name);
}
let user = User::new("John");
process_user(&user);
// user still usable here
```
**Clone When Necessary**:
```rust
// ✅ Clone for thread safety
let user = user.clone();
tokio::spawn(async move {
process_user(user).await;
});
```
### 4.5 Async/Await
**Use async/await for IO**:
```rust
use tokio;
async fn fetch_user(id: Uuid) -> Result<User> {
let user = sqlx::query_as!(
User,
"SELECT * FROM users WHERE id = $1",
id
)
.fetch_one(&pool)
.await?;
Ok(user)
}
#[tokio::main]
async fn main() -> Result<()> {
let user = fetch_user(uuid).await?;
println!("{:?}", user);
Ok(())
}
```
**Concurrent Operations**:
```rust
use tokio::try_join;
async fn fetch_user_data(user_id: Uuid) -> Result<(User, Vec<Track>)> {
let user_future = fetch_user(user_id);
let tracks_future = fetch_user_tracks(user_id);
// Run concurrently
let (user, tracks) = try_join!(user_future, tracks_future)?;
Ok((user, tracks))
}
```
### 4.6 Testing
**Unit Tests**:
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_user_creation() {
let user = User::new("test@example.com");
assert_eq!(user.email, "test@example.com");
}
#[tokio::test]
async fn test_fetch_user() {
let pool = setup_test_db().await;
let user = fetch_user(test_uuid, &pool).await.unwrap();
assert_eq!(user.email, "test@example.com");
}
}
```
**Property-Based Testing** (proptest):
```rust
use proptest::prelude::*;
proptest! {
#[test]
fn test_email_validation(email in "[a-z]+@[a-z]+\\.[a-z]+") {
assert!(is_valid_email(&email));
}
}
```
## 5. TYPESCRIPT STANDARDS (FRONTEND)
### 5.1 TypeScript Configuration
**tsconfig.json** (strict mode):
```json
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"skipLibCheck": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
```
### 5.2 Type Definitions
**Prefer Interfaces over Types** (for objects):
```typescript
// ✅ Good: Interface (can be extended)
interface User {
id: string;
email: string;
name: string;
}
interface AdminUser extends User {
permissions: string[];
}
// ⚠️ Type (use for unions, intersections)
type UserRole = 'user' | 'creator' | 'admin';
type Optional<T> = T | null | undefined;
```
**Avoid any**:
```typescript
// ❌ Bad: any (loses type safety)
function processData(data: any) {
return data.value;
}
// ✅ Good: Generic
function processData<T>(data: T): T {
return data;
}
// ✅ Good: unknown (safe any)
function processJSON(json: string): unknown {
return JSON.parse(json);
}
const data = processJSON('{"value": 42}');
// Must type-check before using
if (typeof data === 'object' && data !== null && 'value' in data) {
console.log(data.value);
}
```
**Discriminated Unions**:
```typescript
type ApiResponse<T> =
| { status: 'success'; data: T }
| { status: 'error'; error: string };
function handleResponse<T>(response: ApiResponse<T>) {
if (response.status === 'success') {
// TypeScript knows response.data exists
console.log(response.data);
} else {
// TypeScript knows response.error exists
console.error(response.error);
}
}
```
### 5.3 Function Types
**Type Function Parameters and Returns**:
```typescript
// ✅ Good: Typed
function calculateTotal(
price: number,
quantity: number,
discount?: number
): number {
const subtotal = price * quantity;
return discount ? subtotal * (1 - discount) : subtotal;
}
// ✅ Good: Arrow function
const calculateTotal = (
price: number,
quantity: number,
discount = 0
): number => {
const subtotal = price * quantity;
return subtotal * (1 - discount);
};
```
**Async Functions**:
```typescript
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error('Failed to fetch user');
}
return response.json();
}
```
### 5.4 Null Safety
**Use Optional Chaining**:
```typescript
// ❌ Bad: Verbose null checks
const city = user && user.profile && user.profile.location && user.profile.location.city;
// ✅ Good: Optional chaining
const city = user?.profile?.location?.city;
```
**Use Nullish Coalescing**:
```typescript
// ❌ Bad: || can give unexpected results (0, '', false treated as falsy)
const port = process.env.PORT || 3000; // Problem if PORT=0
// ✅ Good: ?? only for null/undefined
const port = process.env.PORT ?? 3000;
```
### 5.5 Enums vs Union Types
**Prefer String Unions** (more type-safe):
```typescript
// ✅ Good: String union (can't assign invalid values)
type UserRole = 'user' | 'creator' | 'premium' | 'moderator' | 'admin';
const role: UserRole = 'user'; // ✅
const invalidRole: UserRole = 'guest'; // ❌ Compile error
// ⚠️ Enum (runtime overhead, can assign numbers)
enum UserRole {
User = 'user',
Creator = 'creator',
Admin = 'admin',
}
```
## 6. REACT STANDARDS
### 6.1 Component Structure
**Functional Components** (prefer over class):
```tsx
// ✅ Good: Functional component with TypeScript
interface TrackCardProps {
track: Track;
onPlay: (trackId: string) => void;
className?: string;
}
export const TrackCard: React.FC<TrackCardProps> = ({
track,
onPlay,
className
}) => {
const [isLiked, setIsLiked] = useState(false);
const handleLike = useCallback(() => {
setIsLiked(!isLiked);
// API call...
}, [isLiked]);
return (
<div className={cn('track-card', className)}>
<h3>{track.title}</h3>
<button onClick={() => onPlay(track.id)}>Play</button>
<button onClick={handleLike}>
{isLiked ? '❤️' : '🤍'}
</button>
</div>
);
};
```
### 6.2 Hooks
**Use Hooks Correctly**:
```tsx
// ✅ Good: Hooks at top level
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUser(userId).then(setUser).finally(() => setLoading(false));
}, [userId]);
if (loading) return <Spinner />;
if (!user) return <div>User not found</div>;
return <div>{user.name}</div>;
}
// ❌ Bad: Conditional hooks
function UserProfile({ userId }: { userId: string }) {
if (!userId) return null;
const [user, setUser] = useState<User | null>(null); // ❌ Conditional hook
// ...
}
```
**Custom Hooks**:
```tsx
// ✅ Good: Extract reusable logic
function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
setLoading(true);
fetchUser(userId)
.then(setUser)
.catch(setError)
.finally(() => setLoading(false));
}, [userId]);
return { user, loading, error };
}
// Usage
function UserProfile({ userId }: { userId: string }) {
const { user, loading, error } = useUser(userId);
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!user) return <div>User not found</div>;
return <div>{user.name}</div>;
}
```
**useMemo and useCallback**:
```tsx
// ✅ Good: Memoize expensive computations
function TrackList({ tracks }: { tracks: Track[] }) {
const sortedTracks = useMemo(() => {
return [...tracks].sort((a, b) => b.playCount - a.playCount);
}, [tracks]);
const handlePlay = useCallback((trackId: string) => {
playTrack(trackId);
}, []);
return (
<div>
{sortedTracks.map(track => (
<TrackCard key={track.id} track={track} onPlay={handlePlay} />
))}
</div>
);
}
```
### 6.3 State Management
**Local State** (useState):
```tsx
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
```
**Global State** (Zustand):
```tsx
import { create } from 'zustand';
interface UserStore {
user: User | null;
setUser: (user: User) => void;
logout: () => void;
}
export const useUserStore = create<UserStore>((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null }),
}));
// Usage
function Header() {
const user = useUserStore((state) => state.user);
const logout = useUserStore((state) => state.logout);
return (
<header>
{user ? (
<>
<span>{user.name}</span>
<button onClick={logout}>Logout</button>
</>
) : (
<a href="/login">Login</a>
)}
</header>
);
}
```
**Server State** (React Query):
```tsx
import { useQuery, useMutation } from '@tanstack/react-query';
function useTrack(trackId: string) {
return useQuery({
queryKey: ['track', trackId],
queryFn: () => fetchTrack(trackId),
});
}
function useLikeTrack() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (trackId: string) => likeTrack(trackId),
onSuccess: (data, trackId) => {
// Invalidate cache
queryClient.invalidateQueries({ queryKey: ['track', trackId] });
},
});
}
// Usage
function TrackPage({ trackId }: { trackId: string }) {
const { data: track, isLoading, error } = useTrack(trackId);
const likeMutation = useLikeTrack();
if (isLoading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!track) return <div>Track not found</div>;
return (
<div>
<h1>{track.title}</h1>
<button
onClick={() => likeMutation.mutate(track.id)}
disabled={likeMutation.isPending}
>
Like
</button>
</div>
);
}
```
### 6.4 Component Composition
**Avoid Prop Drilling**:
```tsx
// ❌ Bad: Prop drilling
function App() {
const [user, setUser] = useState<User | null>(null);
return <Layout user={user} setUser={setUser} />;
}
function Layout({ user, setUser }: { user: User | null; setUser: (user: User) => void }) {
return <Header user={user} setUser={setUser} />;
}
function Header({ user, setUser }: { user: User | null; setUser: (user: User) => void }) {
return <UserMenu user={user} setUser={setUser} />;
}
// ✅ Good: Context or global state
function App() {
return <Layout />;
}
function Header() {
const user = useUserStore((state) => state.user);
return <UserMenu />;
}
```
**Compound Components**:
```tsx
// ✅ Good: Compound pattern
interface CardProps {
children: React.ReactNode;
}
export const Card = ({ children }: CardProps) => {
return <div className="card">{children}</div>;
};
Card.Header = ({ children }: CardProps) => {
return <div className="card-header">{children}</div>;
};
Card.Body = ({ children }: CardProps) => {
return <div className="card-body">{children}</div>;
};
Card.Footer = ({ children }: CardProps) => {
return <div className="card-footer">{children}</div>;
};
// Usage
<Card>
<Card.Header>Title</Card.Header>
<Card.Body>Content</Card.Body>
<Card.Footer>Actions</Card.Footer>
</Card>
```
## 7. CSS/TAILWIND STANDARDS
### 7.1 Tailwind Utilities
**Prefer Tailwind Utilities**:
```tsx
// ✅ Good: Tailwind utilities
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow-md">
<h2 className="text-xl font-bold text-gray-900">Title</h2>
<button className="px-4 py-2 text-white bg-blue-600 rounded hover:bg-blue-700">
Action
</button>
</div>
// ❌ Bad: Inline styles
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '16px',
backgroundColor: 'white',
borderRadius: '8px',
boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
}}>
{/* ... */}
</div>
```
**Use cn() Helper** (for conditional classes):
```tsx
import { cn } from '@/lib/utils';
interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
children: React.ReactNode;
}
export const Button = ({
variant = 'primary',
size = 'md',
disabled = false,
children
}: ButtonProps) => {
return (
<button
className={cn(
'rounded font-semibold transition-colors',
{
'bg-blue-600 text-white hover:bg-blue-700': variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
},
{
'px-2 py-1 text-sm': size === 'sm',
'px-4 py-2 text-base': size === 'md',
'px-6 py-3 text-lg': size === 'lg',
},
{
'opacity-50 cursor-not-allowed': disabled,
}
)}
disabled={disabled}
>
{children}
</button>
);
};
```
### 7.2 Custom Components (Extract Reusable)
**@apply for Component Classes**:
```css
/* components.css */
@layer components {
.btn {
@apply px-4 py-2 rounded font-semibold transition-colors;
}
.btn-primary {
@apply bg-blue-600 text-white hover:bg-blue-700;
}
.btn-secondary {
@apply bg-gray-200 text-gray-900 hover:bg-gray-300;
}
.card {
@apply p-4 bg-white rounded-lg shadow-md;
}
}
```
## 8. GIT STANDARDS
### 8.1 Commit Messages
**Format**: Conventional Commits
```
<type>(<scope>): <subject>
<body>
<footer>
```
**Types**:
```
feat: New feature
fix: Bug fix
docs: Documentation changes
style: Code style (formatting, no logic change)
refactor: Code refactoring (no feature/bug change)
perf: Performance improvements
test: Add/update tests
chore: Build process, dependencies, tooling
```
**Examples**:
```bash
# Good commit messages
git commit -m "feat(auth): add two-factor authentication"
git commit -m "fix(api): resolve rate limiting bug on login endpoint"
git commit -m "refactor(user): extract validation logic to separate service"
git commit -m "docs(readme): update installation instructions"
# Bad commit messages
git commit -m "fix bug"
git commit -m "WIP"
git commit -m "update"
```
### 8.2 Branch Naming
**Format**: `<type>/<ticket>-<description>`
```
feature/VEZ-123-user-authentication
bugfix/VEZ-456-fix-login-error
hotfix/VEZ-789-critical-security-patch
refactor/VEZ-012-extract-user-service
docs/VEZ-345-api-documentation
```
### 8.3 Pull Request Template
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing completed
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] No new warnings
```
## 9. DOCUMENTATION STANDARDS
### 9.1 Code Comments
**Go (godoc)**:
```go
// CreateUser creates a new user in the system.
// It validates the request, checks for duplicate emails,
// hashes the password, and stores the user in the database.
//
// Returns the created user and nil error on success.
// Returns nil and error if validation fails or database error occurs.
func CreateUser(req *CreateUserRequest) (*User, error) {
// Validation
if err := validateCreateRequest(req); err != nil {
return nil, fmt.Errorf("validation failed: %w", err)
}
// ... implementation
}
```
**Rust (rustdoc)**:
```rust
/// Creates a new user in the system.
///
/// # Arguments
///
/// * `email` - The user's email address
/// * `password` - The user's plain-text password (will be hashed)
///
/// # Returns
///
/// Returns `Ok(User)` on success, or `Err(UserError)` if:
/// - Email is invalid
/// - Email already exists
/// - Database error occurs
///
/// # Examples
///
/// ```
/// let user = create_user("test@example.com", "SecurePass123").await?;
/// assert_eq!(user.email, "test@example.com");
/// ```
pub async fn create_user(email: &str, password: &str) -> Result<User, UserError> {
// Implementation...
}
```
**TypeScript (JSDoc)**:
```typescript
/**
* Fetches a user by ID from the API.
*
* @param userId - The UUID of the user to fetch
* @returns A Promise that resolves to the User object
* @throws {Error} If the user is not found or API request fails
*
* @example
* ```typescript
* const user = await fetchUser('550e8400-e29b-41d4-a716-446655440000');
* console.log(user.name);
* ```
*/
export async function fetchUser(userId: string): Promise<User> {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error('Failed to fetch user');
}
return response.json();
}
```
### 9.2 README Files
**Every Module/Package Needs README.md**:
```markdown
# User Service
User management service for Veza platform.
## Features
- User registration with email verification
- Password authentication with bcrypt
- JWT token generation
- Two-factor authentication (TOTP)
## Usage
```go
import "veza/internal/services"
userService := services.NewUserService(db, redis)
user, err := userService.CreateUser(&CreateUserRequest{
Email: "test@example.com",
Password: "SecurePass123",
})
```
## Testing
```bash
go test ./... -v
```
## Dependencies
- GORM (database ORM)
- bcrypt (password hashing)
- jwt-go (JWT tokens)
```
### 9.3 Architecture Decision Records (ADR)
Toute décision architecturale significative **doit** être documentée sous forme d'ADR dans le dossier `docs/adr/`.
**Format obligatoire** :
```markdown
# ADR-NNN: Titre de la décision
## Statut
Accepté | Proposé | Déprécié | Remplacé par ADR-XXX
## Contexte
Quel est le problème ou la situation qui motive cette décision ?
## Décision
Quelle est la décision prise ?
## Raison
Pourquoi cette décision a-t-elle été choisie ?
## Alternatives rejetées
Quelles autres options ont été envisagées et pourquoi ont-elles été écartées ?
## Conséquences
Quels sont les effets positifs et négatifs de cette décision ?
## Impact éthique
(Obligatoire si pertinent) Quel est l'impact sur la vie privée des utilisateurs,
l'équité de traitement des créateurs, ou la transparence de la plateforme ?
```
**Règles** :
- Chaque ADR est **immuable** une fois accepté (on crée un nouvel ADR pour le remplacer)
- La section **Impact éthique** est obligatoire dès que la décision touche aux données utilisateurs, aux algorithmes de classement, ou à la collecte de métriques
- Les ADR sont numérotés séquentiellement (`ADR-001`, `ADR-002`, ...)
- Un ADR doit être créé **avant** l'implémentation, pas après
## 10. CODE REVIEW PROCESS
### 10.1 Review Checklist
**Reviewer Must Check**:
- [ ] Code follows style guidelines (linters pass)
- [ ] Tests are included and pass
- [ ] Documentation is updated
- [ ] No security vulnerabilities (SQL injection, XSS, etc.)
- [ ] Error handling is complete
- [ ] Performance is acceptable (no N+1 queries, etc.)
- [ ] Breaking changes are documented
### 10.2 Review Comments
**Constructive Feedback**:
```
✅ Good:
"Consider extracting this logic into a separate function for better testability:
func validateEmail(email string) error { ... }"
❌ Bad:
"This code is terrible."
```
**Approval Process**:
- 2 approvals required (1 from senior engineer)
- All comments resolved
- CI/CD passes
## 11. REFACTORING GUIDELINES
### 11.1 When to Refactor
**Triggers**:
- Duplicated code (DRY violation)
- Functions > 50 lines
- Cyclomatic complexity > 10
- Test coverage < 80%
- Code smells (magic numbers, deep nesting)
**Boy Scout Rule**: Leave code cleaner than you found it
### 11.2 Refactoring Techniques
**Extract Method**:
```go
// Before
func ProcessOrder(order *Order) error {
// Validate order (20 lines)
// ...
// Calculate total (15 lines)
// ...
// Process payment (25 lines)
// ...
}
// After
func ProcessOrder(order *Order) error {
if err := validateOrder(order); err != nil {
return err
}
total := calculateTotal(order)
if err := processPayment(order, total); err != nil {
return err
}
return nil
}
```
## 12. ANTI-PATTERNS LIBRARY
### 12.1 God Object
**Problem**: One class/module does everything
**Solution**: Split into smaller, focused modules (SRP)
### 12.2 Spaghetti Code
**Problem**: Tangled, unstructured code
**Solution**: Use clear architecture (Clean Architecture, layered)
### 12.3 Magic Numbers
**Problem**: Unexplained literal values
```go
// ❌ Bad
if user.Age > 18 && user.Age < 65 {
// ...
}
// ✅ Good
const (
MinimumAdultAge = 18
RetirementAge = 65
)
if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
// ...
}
```
### 12.4 Premature Optimization
**Problem**: Optimizing before identifying bottlenecks
**Solution**: Profile first, then optimize
## 13. ERROR PREVENTION
### 13.1 Pre-Flight Checks (OBLIGATOIRE)
**Avant de commencer TOUTE nouvelle tâche** :
- [ ] Exécuter `./scripts/pre-flight-check.sh`
- [ ] Vérifier qu'aucune erreur P0/P1 existe
- [ ] Tests existants passent
- [ ] Linter clean
- [ ] Code à jour avec `main`
**Référence complète** : `docs/ORIGIN/ORIGIN_ERROR_PREVENTION_GUIDE.md`
### 13.2 Templates de Code (OBLIGATOIRE)
**Utiliser les templates validés** pour créer de nouveaux fichiers :
- Backend Go : `dev-environment/templates/backend-*.template.go`
- Frontend React : `dev-environment/templates/frontend-*.template.tsx`
- Rust : `dev-environment/templates/rust-*.template.rs`
**NE JAMAIS créer un fichier sans utiliser un template** (sauf exception approuvée).
### 13.3 Patterns Sûrs
**Backend Go** :
- Interfaces dans `internal/types/` ou `internal/interfaces/`
- Services dépendent uniquement d'interfaces
- Handlers dépendent uniquement d'interfaces
- Types cohérents (toujours `string` OU toujours `*string`)
**Frontend TypeScript/React** :
- Types explicites pour toutes les fonctions
- Self-closing tags JSX (`<Component />`)
- ✅ Mocks configurés pour tous les tests
- ✅ Logger au lieu de `console.log`
**Référence** : `docs/ORIGIN/ORIGIN_ERROR_PATTERNS.md` pour tous les patterns.
### 13.4 Quality Gates
**Pre-Commit** (Husky) :
- Formatage automatique
- Linter (zero errors)
- Tests unitaires rapides
- Type checking
**Pre-Merge** (GitHub Actions) :
- Architecture validation (import cycles)
- Type safety
- Test coverage ≥ 80%
- Linter validation
- Build validation
**Si un gate échoue** : Corriger l'erreur, NE PAS contourner.
### 13.5 Documentation des Erreurs
**Si une nouvelle erreur est découverte** :
1. Documenter dans `docs/ORIGIN/ORIGIN_ERROR_PATTERNS.md`
2. Ajouter la solution standard
3. Mettre à jour les checklists de prévention
4. Communiquer à l'équipe
---
## ✅ CHECKLIST DE VALIDATION
### Code Quality
- [ ] Formatters run (gofmt, rustfmt, Prettier)
- [ ] Linters pass (golangci-lint, clippy, ESLint)
- [ ] Tests written (coverage ≥ 80%)
- [ ] Documentation updated (README, comments)
### Error Prevention
- [ ] Pre-flight check exécuté et passé
- [ ] Template utilisé pour nouveau fichier
- [ ] Patterns sûrs suivis
- [ ] Aucun anti-pattern introduit
### Architecture
- [ ] Clean Architecture followed
- [ ] SOLID principles respected
- [ ] Dependencies injected
- [ ] Separation of concerns
- [ ] No import cycles
### Performance
- [ ] No N+1 queries
- [ ] Expensive operations optimized
- [ ] Caching considered
- [ ] Bundle size acceptable (frontend)
### Security
- [ ] Input validated
- [ ] Errors handled
- [ ] Secrets not committed
- [ ] SQL injection prevented
## 📊 MÉTRIQUES DE SUCCÈS
### Code Quality Metrics
- **Cyclomatic Complexity**: < 10 per function
- **Function Length**: < 50 lines
- **Test Coverage**: 80%
- **Code Duplication**: < 3%
- **Linter Warnings**: 0
## 🔄 HISTORIQUE DES VERSIONS
| Version | Date | Changements |
|---------|------|-------------|
| 2.0.0 | 2026-03-04 | Révision éthique ajout standards éthiques du code, ADR, standards API (pagination, contexte, erreurs) |
| 1.0.0 | 2025-11-02 | Version initiale - Standards complets |
---
## ⚠️ AVERTISSEMENT
**CES STANDARDS SONT IMMUABLES**
Les standards de code définis ici sont **OBLIGATOIRES**. Toute dérogation nécessite:
1. **RFC Code Standards Exception** avec justification
2. **Approbation Lead Engineer**
3. **Documentation de l'exception**
**Le non-respect des standards bloque la merge de la PR.**
---
**Document créé par**: Engineering Team
**Date de création**: 2025-11-02
**Dernière révision**: 2026-03-04 (v2.0.0 révision éthique)
**Prochaine révision**: Annuelle
**Propriétaire**: Lead Engineers (Go, Rust, Frontend)
**Statut**: **APPROUVÉ ET VERROUILLÉ**