veza/veza-docs/vision/domains/backend/implementation-guidelines.md

714 lines
16 KiB
Markdown
Raw Normal View History

---
id: "implementation-guidelines"
title: "🔧 GUIDELINES D'IMPLÉMENTATION - VEZA BACKEND"
sidebar_label: "🔧 GUIDELINES D'IMPLÉMENTATION - VEZA BACKEND"
---
> NOTE: Cette page décrit la CIBLE (but visé).
# 🔧 GUIDELINES D'IMPLÉMENTATION - VEZA BACKEND
## 📋 CONVENTIONS DE DÉVELOPPEMENT
### 1. **Structure de Code**
#### Go (Backend API)
```
veza-backend-api/
├── cmd/ # Points d'entrée
│ ├── server/ # Serveur principal
│ └── production-server/ # Serveur production
├── internal/ # Code privé
│ ├── domain/ # Entités et règles métier
│ │ ├── entities/ # Entités du domaine
│ │ ├── repositories/ # Interfaces des repositories
│ │ └── services/ # Services du domaine
│ ├── application/ # Cas d'usage
│ │ ├── commands/ # Commandes CQRS
│ │ ├── queries/ # Requêtes CQRS
│ │ └── handlers/ # Gestionnaires
│ ├── infrastructure/ # Implémentations techniques
│ │ ├── database/ # PostgreSQL
│ │ ├── cache/ # Redis
│ │ ├── messaging/ # NATS/Kafka
│ │ └── external/ # APIs externes
│ └── interfaces/ # Controllers, présentateurs
│ ├── http/ # Handlers HTTP
│ ├── grpc/ # gRPC services
│ └── websocket/ # WebSocket handlers
├── pkg/ # Code public réutilisable
├── proto/ # Définitions protobuf
├── docs/ # Documentation
├── scripts/ # Scripts utilitaires
├── tests/ # Tests d'intégration
├── go.mod
├── go.sum
└── Dockerfile
```
#### Rust (Chat/Stream Server)
```
veza-chat-server/
├── src/
│ ├── core/ # Logique métier
│ ├── hub/ # WebSocket hub
│ ├── auth/ # Authentification
│ ├── cache/ # Cache Redis
│ ├── database/ # Base de données
│ ├── monitoring/ # Métriques et logs
│ └── main.rs
├── proto/ # Définitions protobuf
├── migrations/ # Migrations SQL
├── scripts/ # Scripts utilitaires
├── Cargo.toml
└── Dockerfile
```
### 2. **Conventions de Nommage**
#### Go
```go
// Packages : lowercase, single word
package user
// Types : PascalCase
type UserService struct {}
// Méthodes : PascalCase
func (s *UserService) CreateUser() {}
// Variables : camelCase
var userID int64
// Constantes : PascalCase
const MaxRetries = 3
// Interfaces : PascalCase + "er"
type UserRepository interface {}
// Erreurs : camelCase
var ErrUserNotFound = errors.New("user not found")
```
#### Rust
```rust
// Modules : snake_case
mod user_service;
// Types : PascalCase
struct UserService {}
// Fonctions : snake_case
fn create_user() -> Result<User, Error> {}
// Variables : snake_case
let user_id: i64 = 123;
// Constantes : SCREAMING_SNAKE_CASE
const MAX_RETRIES: u32 = 3;
// Traits : PascalCase
trait UserRepository {}
// Erreurs : PascalCase
#[derive(Debug, thiserror::Error)]
pub enum UserError {
#[error("User not found")]
NotFound,
}
```
### 3. **Standards de Code**
#### Go
```go
// Imports organisés
import (
// Standard library
"context"
"time"
// Third party
"github.com/gin-gonic/gin"
"github.com/go-redis/redis/v8"
// Internal
"github.com/okinrev/veza-web-app/internal/domain/entities"
"github.com/okinrev/veza-web-app/internal/infrastructure/database"
)
// Documentation des fonctions
// CreateUser crée un nouvel utilisateur avec validation
func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*entities.User, error) {
// Validation
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("invalid request: %w", err)
}
// Logique métier
user, err := entities.NewUser(req.Username, req.Email, req.Password)
if err != nil {
return nil, fmt.Errorf("failed to create user: %w", err)
}
// Persistence
if err := s.repo.Create(ctx, user); err != nil {
return nil, fmt.Errorf("failed to save user: %w", err)
}
return user, nil
}
```
#### Rust
```rust
// Documentation des fonctions
/// Crée un nouvel utilisateur avec validation
pub async fn create_user(
&self,
req: CreateUserRequest,
) -> Result<User, UserError> {
// Validation
req.validate()?;
// Logique métier
let user = User::new(req.username, req.email, req.password)?;
// Persistence
self.repo.create(&user).await?;
Ok(user)
}
// Gestion d'erreurs avec thiserror
#[derive(Debug, thiserror::Error)]
pub enum UserError {
#[error("Invalid request: {0}")]
ValidationError(String),
#[error("Database error: {0}")]
DatabaseError(#[from] sqlx::Error),
#[error("User not found")]
NotFound,
}
```
## 🧪 TESTS
### 1. **Tests Unitaires**
#### Go
```go
// user_service_test.go
func TestUserService_CreateUser(t *testing.T) {
// Arrange
mockRepo := &MockUserRepository{}
service := NewUserService(mockRepo)
req := CreateUserRequest{
Username: "testuser",
Email: "test@example.com",
Password: "SecurePass123!",
}
// Act
user, err := service.CreateUser(context.Background(), req)
// Assert
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, req.Username, user.Username)
assert.Equal(t, req.Email, user.Email)
}
```
#### Rust
```rust
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_create_user() {
// Arrange
let mock_repo = MockUserRepository::new();
let service = UserService::new(mock_repo);
let req = CreateUserRequest {
username: "testuser".to_string(),
email: "test@example.com".to_string(),
password: "SecurePass123!".to_string(),
};
// Act
let result = service.create_user(req).await;
// Assert
assert!(result.is_ok());
let user = result.unwrap();
assert_eq!(user.username, "testuser");
}
}
```
### 2. **Tests d'Intégration**
```go
// integration_test.go
func TestUserAPI_Integration(t *testing.T) {
// Setup
db := setupTestDatabase(t)
defer cleanupTestDatabase(t, db)
router := setupTestRouter(t, db)
// Test
req := CreateUserRequest{
Username: "integrationuser",
Email: "integration@example.com",
Password: "SecurePass123!",
}
body, _ := json.Marshal(req)
resp := httptest.NewRecorder()
request := httptest.NewRequest("POST", "/api/v1/users", bytes.NewBuffer(body))
router.ServeHTTP(resp, request)
assert.Equal(t, http.StatusCreated, resp.Code)
}
```
### 3. **Tests de Performance**
```go
// benchmark_test.go
func BenchmarkUserService_CreateUser(b *testing.B) {
service := setupBenchmarkService(b)
b.ResetTimer()
for i := 0; i < b.N; i++ {
req := CreateUserRequest{
Username: fmt.Sprintf("user%d", i),
Email: fmt.Sprintf("user%d@example.com", i),
Password: "SecurePass123!",
}
_, err := service.CreateUser(context.Background(), req)
if err != nil {
b.Fatal(err)
}
}
}
```
## 🔒 SÉCURITÉ
### 1. **Validation des Entrées**
```go
// validation.go
type CreateUserRequest struct {
Username string `json:"username" validate:"required,min=3,max=50,alphanum"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,containsany=!@#$%^&*"`
}
func (r *CreateUserRequest) Validate() error {
validate := validator.New()
return validate.Struct(r)
}
```
### 2. **Authentification JWT**
```go
// middleware/auth.go
func AuthMiddleware(jwtSecret string) gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "token required"})
c.Abort()
return
}
// Remove "Bearer " prefix
token = strings.TrimPrefix(token, "Bearer ")
claims, err := utils.VerifyToken(token, jwtSecret)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
c.Abort()
return
}
c.Set("user_id", claims.UserID)
c.Set("username", claims.Username)
c.Set("role", claims.Role)
c.Next()
}
}
```
### 3. **Rate Limiting**
```go
// middleware/rate_limiter.go
func RateLimiter(limit int, window time.Duration) gin.HandlerFunc {
limiter := rate.NewLimiter(rate.Every(window/time.Duration(limit)), limit)
return func(c *gin.Context) {
if !limiter.Allow() {
c.JSON(http.StatusTooManyRequests, gin.H{"error": "rate limit exceeded"})
c.Abort()
return
}
c.Next()
}
}
```
## 📊 MONITORING
### 1. **Métriques Prometheus**
```go
// monitoring/metrics.go
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "endpoint", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: prometheus.DefBuckets,
},
[]string{"method", "endpoint"},
)
)
func MetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start).Seconds()
status := strconv.Itoa(c.Writer.Status())
httpRequestsTotal.WithLabelValues(c.Request.Method, c.FullPath(), status).Inc()
httpRequestDuration.WithLabelValues(c.Request.Method, c.FullPath()).Observe(duration)
}
}
```
### 2. **Logging Structuré**
```go
// utils/logger.go
func SetupLogger(level string) *zap.Logger {
config := zap.NewProductionConfig()
config.Level = zap.NewAtomicLevelAt(getLogLevel(level))
logger, err := config.Build()
if err != nil {
log.Fatal("failed to build logger:", err)
}
return logger
}
func LogRequest(c *gin.Context, logger *zap.Logger) {
logger.Info("HTTP request",
zap.String("method", c.Request.Method),
zap.String("path", c.Request.URL.Path),
zap.String("ip", c.ClientIP()),
zap.String("user_agent", c.Request.UserAgent()),
zap.Int("status", c.Writer.Status()),
zap.Duration("duration", time.Since(c.GetTime("start_time"))),
)
}
```
## 🚀 WORKFLOW PR
### 1. **Création de Branche**
```bash
# Convention de nommage
git checkout -b feat/user-service-tests
git checkout -b refactor/clean-architecture
git checkout -b fix/auth-middleware-bug
git checkout -b docs/api-documentation
```
### 2. **Développement**
```bash
# Commits atomiques (≤150 LOC)
git add .
git commit -m "feat: add user service unit tests
- Add tests for CreateUser method
- Add tests for ValidateUser method
- Add mock repository for testing
- Achieve 95% test coverage
Closes #123"
```
### 3. **Tests Locaux**
```bash
# Go
go test -v ./...
go test -cover ./...
go vet ./...
golangci-lint run
# Rust
cargo test
cargo clippy
cargo fmt --check
```
### 4. **Pull Request**
```markdown
## 🎯 Description
Ajout de tests unitaires complets pour le UserService avec 95% de couverture.
## 🔧 Changements
- [x] Tests unitaires pour CreateUser
- [x] Tests unitaires pour ValidateUser
- [x] Mock repository pour isolation
- [x] Configuration coverage reporting
## 🧪 Tests
- [x] Tests unitaires passent
- [x] Tests d'intégration passent
- [x] Couverture > 90%
- [x] Linting OK
## 📊 Métriques
- Couverture : 95% (+65%)
- Complexité cyclomatique : 8 (-2)
- Duplication : 2% (-3%)
## 🔗 Issues
Closes #123
Relates to #456
## ✅ Checklist
- [ ] Code review effectuée
- [ ] Tests passent
- [ ] Documentation mise à jour
- [ ] Breaking changes documentées
- [ ] Performance testé
- [ ] Sécurité vérifiée
```
### 5. **Code Review**
#### Critères de Review
- ✅ Code lisible et maintenable
- ✅ Tests complets et pertinents
- ✅ Documentation à jour
- ✅ Performance acceptable
- ✅ Sécurité respectée
- ✅ Conventions respectées
#### Template de Review
```markdown
## 👀 Code Review
### ✅ Points Positifs
- Tests bien structurés
- Documentation claire
- Respect des conventions
### ⚠️ Points d'Amélioration
- [ ] Ajouter test pour cas d'erreur
- [ ] Optimiser requête SQL
- [ ] Ajouter validation supplémentaire
### 🚨 Problèmes Critiques
- [ ] Gestion d'erreur manquante ligne 45
- [ ] Race condition possible ligne 78
### 📝 Suggestions
- Utiliser context.WithTimeout pour la DB
- Ajouter métrique pour les erreurs
- Considérer circuit breaker pattern
## 🎯 Décision
- [ ] ✅ Approuvé
- [ ] ⚠️ Approuvé avec modifications
- [ ] ❌ Rejeté
```
## 📚 DOCUMENTATION
### 1. **Documentation API**
```go
// @Summary Créer un utilisateur
// @Description Crée un nouvel utilisateur avec validation
// @Tags users
// @Accept json
// @Produce json
// @Param user body CreateUserRequest true "Données utilisateur"
// @Success 201 {object} User
// @Failure 400 {object} ErrorResponse
// @Failure 409 {object} ErrorResponse
// @Router /api/v1/users [post]
func (h *UserHandler) CreateUser(c *gin.Context) {
// Implementation
}
```
### 2. **README de Service**
```markdown
# User Service
## 🎯 Description
Service de gestion des utilisateurs avec authentification et profils.
## 🏗️ Architecture
- Domain Layer : Entités User, UserRepository
- Application Layer : UserService, CreateUserCommand
- Infrastructure Layer : PostgreSQL, Redis
- Interface Layer : HTTP handlers, gRPC
## 🚀 Démarrage
```bash
go run cmd/server/main.go
```
## 🧪 Tests
```bash
go test -v ./internal/domain/services
go test -cover ./...
```
## 📊 Métriques
- Latence moyenne : 15ms
- Throughput : 1000 req/s
- Couverture tests : 95%
```
## 🔄 CI/CD
### 1. **GitHub Actions**
```yaml
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.23'
- name: Run tests
run: |
go test -v -cover ./...
go vet ./...
golangci-lint run
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.out
build:
needs: test
runs-on: ubuntu-latest
steps:
- name: Build Docker image
run: |
docker build -t veza-backend-api .
- name: Security scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'veza-backend-api:latest'
format: 'sarif'
output: 'trivy-results.sarif'
```
### 2. **Docker**
```dockerfile
# Dockerfile
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
COPY --from=builder /app/config.example.env .env
EXPOSE 8080
CMD ["./main"]
```
## 🎯 BONNES PRATIQUES
### 1. **Performance**
- Utiliser des goroutines pour les opérations I/O
- Implémenter du caching (Redis)
- Optimiser les requêtes SQL
- Utiliser des pools de connexions
### 2. **Sécurité**
- Valider toutes les entrées
- Utiliser HTTPS en production
- Implémenter rate limiting
- Logger les événements de sécurité
### 3. **Maintenabilité**
- Code lisible et documenté
- Tests complets
- Séparation des responsabilités
- Injection de dépendances
### 4. **Observabilité**
- Logging structuré
- Métriques Prometheus
- Distributed tracing
- Health checks
---
*Guidelines créées par le Lead Backend Engineer & Refactor Bot*
*Prochaine étape : Implémentation de la Phase 1 - Foundation*