# 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 oĂč 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 { 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 { 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 { 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)> { 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 | null | undefined; ``` **Avoid any**: ```typescript // ❌ Bad: any (loses type safety) function processData(data: any) { return data.value; } // ✅ Good: Generic function processData(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 = | { status: 'success'; data: T } | { status: 'error'; error: string }; function handleResponse(response: ApiResponse) { 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 { 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 = ({ track, onPlay, className }) => { const [isLiked, setIsLiked] = useState(false); const handleLike = useCallback(() => { setIsLiked(!isLiked); // API call... }, [isLiked]); return (

{track.title}

); }; ``` ### 6.2 Hooks **Use Hooks Correctly**: ```tsx // ✅ Good: Hooks at top level function UserProfile({ userId }: { userId: string }) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetchUser(userId).then(setUser).finally(() => setLoading(false)); }, [userId]); if (loading) return ; if (!user) return
User not found
; return
{user.name}
; } // ❌ Bad: Conditional hooks function UserProfile({ userId }: { userId: string }) { if (!userId) return null; const [user, setUser] = useState(null); // ❌ Conditional hook // ... } ``` **Custom Hooks**: ```tsx // ✅ Good: Extract reusable logic function useUser(userId: string) { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(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 ; if (error) return ; if (!user) return
User not found
; return
{user.name}
; } ``` **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 (
{sortedTracks.map(track => ( ))}
); } ``` ### 6.3 State Management **Local State** (useState): ```tsx function Counter() { const [count, setCount] = useState(0); return (

Count: {count}

); } ``` **Global State** (Zustand): ```tsx import { create } from 'zustand'; interface UserStore { user: User | null; setUser: (user: User) => void; logout: () => void; } export const useUserStore = create((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 (
{user ? ( <> {user.name} ) : ( Login )}
); } ``` **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 ; if (error) return ; if (!track) return
Track not found
; return (

{track.title}

); } ``` ### 6.4 Component Composition **Avoid Prop Drilling**: ```tsx // ❌ Bad: Prop drilling function App() { const [user, setUser] = useState(null); return ; } function Layout({ user, setUser }: { user: User | null; setUser: (user: User) => void }) { return
; } function Header({ user, setUser }: { user: User | null; setUser: (user: User) => void }) { return ; } // ✅ Good: Context or global state function App() { return ; } function Header() { const user = useUserStore((state) => state.user); return ; } ``` **Compound Components**: ```tsx // ✅ Good: Compound pattern interface CardProps { children: React.ReactNode; } export const Card = ({ children }: CardProps) => { return
{children}
; }; Card.Header = ({ children }: CardProps) => { return
{children}
; }; Card.Body = ({ children }: CardProps) => { return
{children}
; }; Card.Footer = ({ children }: CardProps) => { return
{children}
; }; // Usage Title Content Actions ``` ## 7. CSS/TAILWIND STANDARDS ### 7.1 Tailwind Utilities **Prefer Tailwind Utilities**: ```tsx // ✅ Good: Tailwind utilities

Title

// ❌ Bad: Inline styles
{/* ... */}
``` **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 ( ); }; ``` ### 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 ``` ():