2265 lines
70 KiB
Markdown
2265 lines
70 KiB
Markdown
# ORIGIN_MASTER_ARCHITECTURE.md
|
|
|
|
## 📋 RÉSUMÉ EXÉCUTIF
|
|
|
|
Ce document définit l'architecture technique de la plateforme Veza (Talas), une plateforme audio open source pour musiciens indépendants. Il constitue la source de vérité pour toutes les décisions architecturales. L'architecture cible une plateforme audio combinant streaming, marketplace, social et éducation avec une capacité de 100,000+ utilisateurs concurrents. Cette architecture intègre des contraintes éthiques explicites : pas de tracking comportemental, pas d'IA/ML, pas de blockchain, pas de gamification addictive. Les métriques servent le créateur, pas la plateforme.
|
|
|
|
## 🎯 OBJECTIFS
|
|
|
|
### Objectif Principal
|
|
Définir une architecture microservices scalable, sécurisée et performante, alignée sur des principes éthiques documentés et auditables, capable de supporter les modules métier avec des SLA de 99.9% uptime et <100ms latency.
|
|
|
|
### Objectifs Secondaires
|
|
- Assurer la cohérence architecturale sur 24 mois de développement
|
|
- Documenter toutes les décisions architecturales (ADR)
|
|
- Établir les standards de communication inter-services (REST)
|
|
- Définir les patterns de sécurité, performance et observabilité
|
|
- Garantir l'auditabilité complète du code et des algorithmes (open source)
|
|
|
|
## 📖 TABLE DES MATIÈRES
|
|
|
|
1. [Principes d'Architecture Éthique](#1-principes-darchitecture-éthique)
|
|
2. [Vue d'Ensemble Architecturale](#2-vue-densemble-architecturale)
|
|
3. [Architecture des Services](#3-architecture-des-services)
|
|
4. [Découverte Éthique (remplacement ML)](#4-découverte-éthique-remplacement-ml)
|
|
5. [Infrastructure et Déploiement](#5-infrastructure-et-déploiement)
|
|
6. [Flux de Données](#6-flux-de-données)
|
|
7. [Sécurité](#7-sécurité)
|
|
8. [Performance et Scalabilité](#8-performance-et-scalabilité)
|
|
9. [Observabilité](#9-observabilité)
|
|
10. [Décisions Architecturales (ADR)](#10-décisions-architecturales-adr)
|
|
11. [Conventions de Nommage](#11-conventions-de-nommage)
|
|
12. [Structure des Répertoires](#12-structure-des-répertoires)
|
|
13. [Exclusions et Raisons Éthiques](#13-exclusions-et-raisons-éthiques)
|
|
|
|
## 🔒 RÈGLES IMMUABLES
|
|
|
|
Les décisions suivantes sont **ABSOLUES et NON NÉGOCIABLES** :
|
|
|
|
1. **Backend API Principal**: Go 1.23+ uniquement (stabilité, performance, typage fort)
|
|
2. **Chat Server**: Go 1.23+ (WebSocket, cohérence stack, performance suffisante)
|
|
3. **Stream Server**: Rust 1.75+ uniquement (sécurité mémoire, performance critique audio)
|
|
4. **Frontend**: React 18+ avec TypeScript 5.3+ strict mode (pas de JavaScript pur)
|
|
5. **Base de Données Principale**: PostgreSQL 15+ (ACID, relations, performance)
|
|
6. **Recherche**: Elasticsearch (fulltext, pas de ML)
|
|
7. **Cache**: Redis 7+ (in-memory, pub/sub, sessions)
|
|
8. **Communication Services**: REST uniquement (inter-service et clients externes)
|
|
9. **Message Queue**: RabbitMQ 3.12+ pour événements asynchrones
|
|
10. **Paiements**: Hyperswitch (agrégateur open source, pas de vendor lock-in Stripe)
|
|
11. **Container Runtime**: Docker 24+ (standardisation, portabilité)
|
|
12. **API Gateway**: Traefik 2.10+ (moderne, cloud-native, labels)
|
|
13. **Monitoring**: Prometheus + Grafana + Loki (standard industrie)
|
|
14. **Pas d'IA/ML** : aucun pipeline d'intelligence artificielle ou machine learning
|
|
15. **Pas de blockchain/Web3** : aucun smart contract, NFT, IPFS, crypto
|
|
16. **Pas de gamification addictive** : pas de XP, niveaux, leaderboards
|
|
|
|
## 1. PRINCIPES D'ARCHITECTURE ÉTHIQUE
|
|
|
|
Ces principes sont des contraintes architecturales. Ils contraignent les choix techniques au même titre que les exigences de performance ou de sécurité.
|
|
|
|
### 1.1 Pas de tracking comportemental
|
|
|
|
Aucune collecte de données d'usage à des fins de profilage, ciblage publicitaire ou revente. Les analytics collectées servent exclusivement le créateur (nombre d'écoutes, provenance géographique agrégée) et sont accessibles à l'artiste via son dashboard. Aucune donnée comportementale n'alimente un algorithme de recommandation.
|
|
|
|
### 1.2 Métriques au service du créateur, pas de la plateforme
|
|
|
|
Les compteurs d'écoutes, les statistiques de téléchargement et les revenus marketplace sont exposés aux créateurs. La plateforme ne calcule pas de métriques d'engagement destinées à optimiser la rétention (temps passé, taux de scroll, boucles de notification).
|
|
|
|
### 1.3 Données minimales et justifiées
|
|
|
|
Chaque donnée collectée est documentée avec sa finalité. Si la finalité disparaît, la donnée est supprimée. Le schéma de base de données ne contient pas de colonnes "pour plus tard". Les données personnelles sont soumises aux principes de minimisation RGPD.
|
|
|
|
### 1.4 Algorithmes documentés et auditables
|
|
|
|
Tout algorithme de tri, classement ou découverte est documenté dans le code et dans la documentation. Les règles de classement (recherche, découverte, trending) sont déterministes et reproductibles. Pas de boîte noire.
|
|
|
|
### 1.5 Open source auditable
|
|
|
|
Le code source est publié sous licence open source. Toute personne peut vérifier que les principes éthiques sont respectés dans l'implémentation. Les dépendances sont auditées (Snyk/Dependabot).
|
|
|
|
## 2. VUE D'ENSEMBLE ARCHITECTURALE
|
|
|
|
### 2.1 Architecture Globale
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Frontend Layer"
|
|
WEB[Web App React]
|
|
MOBILE[Mobile Apps RN]
|
|
DESKTOP[Desktop Electron]
|
|
end
|
|
|
|
subgraph "API Gateway Layer"
|
|
TRAEFIK[Traefik API Gateway]
|
|
LB[Load Balancer]
|
|
end
|
|
|
|
subgraph "Backend Services"
|
|
API[API Backend Go]
|
|
CHAT[Chat Server Go]
|
|
STREAM[Stream Server Rust]
|
|
WORKER[Background Workers]
|
|
end
|
|
|
|
subgraph "Data Layer"
|
|
PG[(PostgreSQL)]
|
|
REDIS[(Redis Cluster)]
|
|
S3[(Object Storage S3)]
|
|
ES[(Elasticsearch)]
|
|
end
|
|
|
|
subgraph "Message Layer"
|
|
RABBITMQ[RabbitMQ]
|
|
end
|
|
|
|
subgraph "External Services"
|
|
HYPERSWITCH[Hyperswitch Payments]
|
|
SENDGRID[SendGrid Email]
|
|
CDN[CloudFront CDN]
|
|
end
|
|
|
|
WEB --> TRAEFIK
|
|
MOBILE --> TRAEFIK
|
|
DESKTOP --> TRAEFIK
|
|
|
|
TRAEFIK --> API
|
|
TRAEFIK --> CHAT
|
|
TRAEFIK --> STREAM
|
|
|
|
API --> PG
|
|
API --> REDIS
|
|
API --> S3
|
|
API --> RABBITMQ
|
|
API --> HYPERSWITCH
|
|
API --> SENDGRID
|
|
|
|
CHAT --> PG
|
|
CHAT --> REDIS
|
|
CHAT --> RABBITMQ
|
|
|
|
STREAM --> PG
|
|
STREAM --> REDIS
|
|
STREAM --> S3
|
|
STREAM --> CDN
|
|
|
|
WORKER --> RABBITMQ
|
|
WORKER --> PG
|
|
WORKER --> S3
|
|
|
|
API --> ES
|
|
ES -.-> PG
|
|
```
|
|
|
|
### 2.2 Patterns Architecturaux
|
|
|
|
#### 2.2.1 Clean Architecture (Hexagonal)
|
|
Tous les services suivent le pattern Clean Architecture avec séparation stricte en couches:
|
|
|
|
```
|
|
src/
|
|
├── domain/ # Entités métier, règles business (indépendant)
|
|
│ ├── entities/ # User, Track, Playlist, etc.
|
|
│ ├── value_objects/ # Email, Money, Duration, etc.
|
|
│ └── interfaces/ # Ports (abstractions)
|
|
├── application/ # Cas d'usage, services applicatifs
|
|
│ ├── use_cases/ # CreateUser, UploadTrack, etc.
|
|
│ ├── services/ # AuthService, PaymentService, etc.
|
|
│ └── dto/ # Data Transfer Objects
|
|
├── infrastructure/ # Implémentations techniques
|
|
│ ├── persistence/ # Repositories PostgreSQL
|
|
│ ├── cache/ # Redis adapters
|
|
│ ├── messaging/ # RabbitMQ publishers/consumers
|
|
│ ├── storage/ # S3 file storage
|
|
│ └── external/ # Hyperswitch, SendGrid, etc.
|
|
└── interfaces/ # Adapters externes
|
|
├── http/ # REST handlers (Gin)
|
|
└── websocket/ # WebSocket handlers
|
|
```
|
|
|
|
**Règle de Dépendance**: Les dépendances pointent TOUJOURS vers l'intérieur
|
|
- `interfaces` → `application` → `domain`
|
|
- `infrastructure` → `application` → `domain`
|
|
- `domain` ne dépend de RIEN (pure business logic)
|
|
|
|
#### 2.2.2 Domain-Driven Design (DDD)
|
|
|
|
##### Bounded Contexts (18 Domaines)
|
|
|
|
1. **Authentication & Security** (`auth`)
|
|
- Aggregates: User, Session, MFAConfig
|
|
- Events: UserRegistered, UserLoggedIn, PasswordChanged
|
|
|
|
2. **User Profiles** (`profiles`)
|
|
- Aggregates: UserProfile, Badge
|
|
- Events: ProfileUpdated, BadgeEarned
|
|
|
|
3. **File Management** (`files`)
|
|
- Aggregates: File, Upload, Metadata
|
|
- Events: FileUploaded, FileProcessed, FileDeleted
|
|
|
|
4. **Audio Streaming** (`streaming`)
|
|
- Aggregates: Track, Playlist, Queue
|
|
- Events: TrackPlayed, PlaylistCreated, QueueUpdated
|
|
|
|
5. **Chat & Messaging** (`chat`)
|
|
- Aggregates: Conversation, Message, Room
|
|
- Events: MessageSent, RoomCreated, UserJoinedRoom
|
|
|
|
6. **Social & Community** (`social`)
|
|
- Aggregates: Follow, Post, Comment, Like
|
|
- Events: UserFollowed, PostCreated, CommentAdded
|
|
|
|
7. **Marketplace** (`marketplace`)
|
|
- Aggregates: Product, License, Order
|
|
- Events: ProductListed, OrderPlaced, PaymentProcessed
|
|
|
|
8. **Education** (`education`)
|
|
- Aggregates: Course, Lesson, Enrollment
|
|
- Events: CourseCreated, EnrollmentStarted, LessonCompleted
|
|
|
|
9. **Hardware Management** (`hardware`)
|
|
- Aggregates: Equipment, Warranty, Maintenance
|
|
- Events: EquipmentAdded, WarrantyExpiring
|
|
|
|
10. **Cloud Storage** (`cloud`)
|
|
- Aggregates: CloudAccount, SyncJob, Backup
|
|
- Events: BackupCompleted, SyncFailed
|
|
|
|
11. **Search & Discovery** (`search`)
|
|
- Aggregates: SearchQuery, SearchResult, CuratedPlaylist
|
|
- Events: SearchPerformed, PlaylistCurated
|
|
- Note: découverte par règles, curation humaine et graphe social (pas de ML)
|
|
|
|
12. **Analytics** (`analytics`)
|
|
- Aggregates: Metric, Report, Dashboard
|
|
- Events: MetricRecorded, ReportGenerated
|
|
- Note: métriques au service du créateur uniquement
|
|
|
|
13. **Administration** (`admin`)
|
|
- Aggregates: AdminUser, ModeratorAction, SystemConfig
|
|
- Events: UserBanned, ContentRemoved
|
|
|
|
14. **UI/UX** (`ui`)
|
|
- Aggregates: Theme, Layout, Preference
|
|
- Events: ThemeChanged, LayoutCustomized
|
|
|
|
15. **Live Streaming** (`live`)
|
|
- Aggregates: LiveStream, StreamSession, Viewer
|
|
- Events: StreamStarted, ViewerJoined
|
|
|
|
16. **Collaboration** (`collab`)
|
|
- Aggregates: Project, Version, Contributor
|
|
- Events: ProjectCreated, VersionCommitted
|
|
|
|
17. **External Integrations** (`integrations`)
|
|
- Aggregates: Integration, Connection, Sync
|
|
- Events: IntegrationConnected, SyncCompleted
|
|
|
|
18. **Mobile/Desktop Apps** (`native`)
|
|
- Aggregates: Device, AppSession, Notification
|
|
- Events: DeviceRegistered, NotificationSent
|
|
|
|
#### 2.2.3 Event-Driven Architecture
|
|
|
|
```mermaid
|
|
graph LR
|
|
SERVICE_A[Service A] -->|Publish Event| RABBITMQ[RabbitMQ Exchange]
|
|
RABBITMQ -->|Route| QUEUE_B[Queue B]
|
|
RABBITMQ -->|Route| QUEUE_C[Queue C]
|
|
QUEUE_B --> SERVICE_B[Service B Subscribe]
|
|
QUEUE_C --> SERVICE_C[Service C Subscribe]
|
|
|
|
SERVICE_B -->|Store| EVENT_STORE[(Event Store)]
|
|
SERVICE_C -->|Store| EVENT_STORE
|
|
```
|
|
|
|
**Event Naming Convention**: `{Domain}.{Entity}.{Action}.{Version}`
|
|
- Examples: `auth.user.registered.v1`, `marketplace.order.paid.v1`
|
|
|
|
**Event Structure** (JSON):
|
|
```json
|
|
{
|
|
"event_id": "uuid-v4",
|
|
"event_type": "auth.user.registered.v1",
|
|
"aggregate_id": "user-123",
|
|
"aggregate_type": "User",
|
|
"timestamp": "2025-11-02T10:30:00Z",
|
|
"version": 1,
|
|
"data": {
|
|
"user_id": "123",
|
|
"email": "user@example.com",
|
|
"username": "johndoe"
|
|
},
|
|
"metadata": {
|
|
"correlation_id": "request-456",
|
|
"causation_id": "command-789",
|
|
"user_agent": "Mozilla/5.0..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### 2.2.4 CQRS (Command Query Responsibility Segregation)
|
|
|
|
**Séparation stricte Write/Read**:
|
|
|
|
```
|
|
Commands (Write) Queries (Read)
|
|
↓ ↑
|
|
Write Model Read Model
|
|
↓ ↑
|
|
PostgreSQL (Master) Redis + Elasticsearch
|
|
```
|
|
|
|
**Command Example** (Go):
|
|
```go
|
|
type CreateUserCommand struct {
|
|
CommandID string
|
|
Username string
|
|
Email string
|
|
Password string
|
|
FirstName string
|
|
LastName string
|
|
}
|
|
|
|
type CreateUserHandler struct {
|
|
repo UserRepository
|
|
bus EventBus
|
|
}
|
|
|
|
func (h *CreateUserHandler) Handle(ctx context.Context, cmd CreateUserCommand) error {
|
|
// 1. Validate
|
|
if err := cmd.Validate(); err != nil {
|
|
return ErrInvalidCommand
|
|
}
|
|
|
|
// 2. Create aggregate
|
|
user, err := domain.NewUser(cmd.Username, cmd.Email, cmd.Password)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 3. Persist
|
|
if err := h.repo.Save(ctx, user); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 4. Publish events
|
|
for _, event := range user.UncommittedEvents() {
|
|
h.bus.Publish(ctx, event)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
```
|
|
|
|
**Query Example** (Go):
|
|
```go
|
|
type GetUserQuery struct {
|
|
UserID string
|
|
}
|
|
|
|
type GetUserQueryHandler struct {
|
|
cache *redis.Client
|
|
search *elasticsearch.Client
|
|
}
|
|
|
|
func (h *GetUserQueryHandler) Handle(ctx context.Context, q GetUserQuery) (*UserDTO, error) {
|
|
// 1. Try cache first
|
|
cached, err := h.cache.Get(ctx, "user:"+q.UserID).Result()
|
|
if err == nil {
|
|
return unmarshal(cached)
|
|
}
|
|
|
|
// 2. Query read model
|
|
user, err := h.search.Get(ctx, "users", q.UserID)
|
|
if err != nil {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
|
|
// 3. Cache for next time
|
|
h.cache.Set(ctx, "user:"+q.UserID, user, 5*time.Minute)
|
|
|
|
return toDTO(user), nil
|
|
}
|
|
```
|
|
|
|
## 3. ARCHITECTURE DES SERVICES
|
|
|
|
### 3.1 Backend API (Go)
|
|
|
|
**Repository**: `/veza-backend-api`
|
|
**Port**: `8080`
|
|
**Protocol**: HTTP/2 (REST)
|
|
**Language**: Go 1.23+
|
|
**Framework**: Gin 1.9+
|
|
|
|
#### 3.1.1 Responsabilités
|
|
|
|
- Authentification/Autorisation (JWT RS256, OAuth2, 2FA)
|
|
- Gestion utilisateurs, profils, rôles
|
|
- API REST pour clients web/mobile et communication inter-services
|
|
- Business logic core
|
|
- Orchestration des workflows
|
|
- Gestion des transactions
|
|
- API publique documentée (OpenAPI)
|
|
|
|
#### 3.1.2 Endpoints Principaux
|
|
|
|
**Base URL**: `https://api.veza.app/v1`
|
|
|
|
| Groupe | Endpoints | Méthodes | Auth Required |
|
|
|--------|-----------|----------|---------------|
|
|
| **Auth** | `/auth/*` | POST | Partial |
|
|
| - Register | `/auth/register` | POST | No |
|
|
| - Login | `/auth/login` | POST | No |
|
|
| - Logout | `/auth/logout` | POST | Yes |
|
|
| - Refresh | `/auth/refresh` | POST | Yes (Refresh Token) |
|
|
| - 2FA Setup | `/auth/2fa/setup` | POST | Yes |
|
|
| - 2FA Verify | `/auth/2fa/verify` | POST | Yes |
|
|
| - Password Reset | `/auth/password/reset` | POST | No |
|
|
| **Users** | `/users/*` | GET, PUT, DELETE | Yes |
|
|
| - Get Profile | `/users/{id}` | GET | Yes |
|
|
| - Update Profile | `/users/{id}` | PUT | Yes |
|
|
| - Delete Account | `/users/{id}` | DELETE | Yes |
|
|
| - Upload Avatar | `/users/{id}/avatar` | POST | Yes |
|
|
| **Tracks** | `/tracks/*` | GET, POST, PUT, DELETE | Partial |
|
|
| - List Tracks | `/tracks` | GET | No |
|
|
| - Get Track | `/tracks/{id}` | GET | No |
|
|
| - Upload Track | `/tracks` | POST | Yes |
|
|
| - Update Metadata | `/tracks/{id}` | PUT | Yes (Owner) |
|
|
| - Delete Track | `/tracks/{id}` | DELETE | Yes (Owner) |
|
|
| **Playlists** | `/playlists/*` | GET, POST, PUT, DELETE | Partial |
|
|
| **Marketplace** | `/marketplace/*` | GET, POST | Partial |
|
|
| **Search** | `/search/*` | GET | No |
|
|
| **Admin** | `/admin/*` | ALL | Yes (Admin Role) |
|
|
|
|
#### 3.1.3 Structure Interne
|
|
|
|
```
|
|
veza-backend-api/
|
|
├── cmd/
|
|
│ └── api/
|
|
│ └── main.go # Entry point
|
|
├── internal/
|
|
│ ├── domain/ # Domain layer (pure business)
|
|
│ │ ├── user/
|
|
│ │ │ ├── user.go # User aggregate
|
|
│ │ │ ├── repository.go # User repository interface
|
|
│ │ │ └── events.go # Domain events
|
|
│ │ ├── track/
|
|
│ │ ├── playlist/
|
|
│ │ └── shared/
|
|
│ │ ├── errors.go
|
|
│ │ └── value_objects.go
|
|
│ ├── application/ # Application layer
|
|
│ │ ├── commands/
|
|
│ │ │ ├── create_user.go
|
|
│ │ │ └── upload_track.go
|
|
│ │ ├── queries/
|
|
│ │ │ ├── get_user.go
|
|
│ │ │ └── search_tracks.go
|
|
│ │ └── services/
|
|
│ │ ├── auth_service.go
|
|
│ │ ├── payment_service.go
|
|
│ │ └── notification_service.go
|
|
│ ├── infrastructure/ # Infrastructure layer
|
|
│ │ ├── persistence/
|
|
│ │ │ ├── postgres/
|
|
│ │ │ │ ├── user_repository.go
|
|
│ │ │ │ └── migrations/
|
|
│ │ │ └── redis/
|
|
│ │ │ └── cache_repository.go
|
|
│ │ ├── messaging/
|
|
│ │ │ └── rabbitmq/
|
|
│ │ │ ├── publisher.go
|
|
│ │ │ └── consumer.go
|
|
│ │ ├── storage/
|
|
│ │ │ └── s3/
|
|
│ │ │ └── file_storage.go
|
|
│ │ └── external/
|
|
│ │ ├── hyperswitch/
|
|
│ │ └── sendgrid/
|
|
│ └── interfaces/ # Interfaces layer
|
|
│ └── http/
|
|
│ ├── handlers/
|
|
│ │ ├── auth_handler.go
|
|
│ │ └── user_handler.go
|
|
│ ├── middleware/
|
|
│ │ ├── auth.go
|
|
│ │ ├── rate_limit.go
|
|
│ │ └── cors.go
|
|
│ └── routes.go
|
|
├── pkg/ # Public packages
|
|
│ ├── logger/
|
|
│ ├── validator/
|
|
│ └── jwt/
|
|
├── migrations/ # Database migrations
|
|
│ ├── 001_create_users.sql
|
|
│ └── 002_create_tracks.sql
|
|
├── go.mod
|
|
└── go.sum
|
|
```
|
|
|
|
#### 3.1.4 Technologies & Dépendances
|
|
|
|
```go
|
|
// go.mod (exact versions LOCKED)
|
|
module veza-backend-api
|
|
|
|
go 1.23.8
|
|
|
|
require (
|
|
github.com/gin-gonic/gin v1.9.1 // HTTP framework
|
|
github.com/google/uuid v1.6.0 // UUID generation
|
|
github.com/golang-jwt/jwt/v5 v5.3.0 // JWT tokens (RS256)
|
|
github.com/lib/pq v1.10.9 // PostgreSQL driver
|
|
gorm.io/gorm v1.25.5 // ORM
|
|
gorm.io/driver/postgres v1.5.4 // GORM PostgreSQL
|
|
github.com/redis/go-redis/v9 v9.16.0 // Redis client
|
|
github.com/rabbitmq/amqp091-go v1.9.0 // RabbitMQ
|
|
github.com/aws/aws-sdk-go-v2 v1.24.0 // AWS S3
|
|
github.com/olivere/elastic/v7 v7.0.32 // Elasticsearch client
|
|
go.uber.org/zap v1.27.0 // Structured logging
|
|
github.com/prometheus/client_golang v1.18.0 // Metrics
|
|
github.com/spf13/viper v1.18.2 // Configuration
|
|
golang.org/x/crypto v0.41.0 // Bcrypt, argon2
|
|
)
|
|
```
|
|
|
|
> **Note paiements** : les paiements transitent via Hyperswitch (agrégateur open source). Le SDK Go Hyperswitch est intégré via son API REST. Pas de dépendance directe à un PSP unique (Stripe, Adyen, etc.).
|
|
|
|
### 3.2 Chat Server (Go)
|
|
|
|
**Repository**: `/veza-chat-server`
|
|
**Port**: `8081`
|
|
**Protocol**: WebSocket (WS/WSS)
|
|
**Language**: Go 1.23+
|
|
**Framework**: Gin 1.9+ (HTTP), gorilla/websocket
|
|
|
|
#### 3.2.1 Responsabilités
|
|
|
|
- Chat temps réel (WebSocket)
|
|
- Messagerie 1-to-1 et groupes
|
|
- Rooms publiques/privées
|
|
- Notifications push
|
|
- Présence utilisateurs (online/offline)
|
|
- Message history et recherche
|
|
- File sharing dans chat
|
|
- Reactions et threads
|
|
|
|
#### 3.2.2 Architecture WebSocket
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant WSServer
|
|
participant RoomManager
|
|
participant MessageStore
|
|
participant RabbitMQ
|
|
|
|
Client->>WSServer: WebSocket Upgrade
|
|
WSServer->>Client: 101 Switching Protocols
|
|
Client->>WSServer: Auth Token
|
|
WSServer->>RoomManager: Register Connection
|
|
|
|
Client->>WSServer: Send Message
|
|
WSServer->>MessageStore: Store Message
|
|
MessageStore->>RabbitMQ: Publish Event
|
|
WSServer->>RoomManager: Broadcast to Room
|
|
RoomManager->>Client: Deliver Message
|
|
```
|
|
|
|
#### 3.2.3 Message Protocol
|
|
|
|
**WebSocket Message Format** (JSON):
|
|
```json
|
|
{
|
|
"type": "message",
|
|
"action": "send",
|
|
"data": {
|
|
"room_id": "room-123",
|
|
"content": "Hello World!",
|
|
"message_type": "text",
|
|
"reply_to": null,
|
|
"metadata": {}
|
|
},
|
|
"request_id": "req-456",
|
|
"timestamp": "2025-11-02T10:30:00Z"
|
|
}
|
|
```
|
|
|
|
**Server Response**:
|
|
```json
|
|
{
|
|
"type": "message",
|
|
"action": "received",
|
|
"data": {
|
|
"message_id": "msg-789",
|
|
"room_id": "room-123",
|
|
"sender_id": "user-123",
|
|
"content": "Hello World!",
|
|
"created_at": "2025-11-02T10:30:00Z"
|
|
},
|
|
"request_id": "req-456"
|
|
}
|
|
```
|
|
|
|
#### 3.2.4 Structure Interne
|
|
|
|
```
|
|
veza-chat-server/
|
|
├── cmd/
|
|
│ └── chat/
|
|
│ └── main.go # Entry point
|
|
├── internal/
|
|
│ ├── domain/
|
|
│ │ ├── message.go # Message aggregate
|
|
│ │ ├── room.go # Room aggregate
|
|
│ │ └── events.go # Domain events
|
|
│ ├── application/
|
|
│ │ ├── chat_service.go # Chat service
|
|
│ │ └── presence_service.go # Presence tracking
|
|
│ ├── infrastructure/
|
|
│ │ ├── persistence/
|
|
│ │ │ └── postgres/
|
|
│ │ │ ├── message_repository.go
|
|
│ │ │ └── room_repository.go
|
|
│ │ ├── cache/
|
|
│ │ │ └── redis_presence.go # Redis presence + pub/sub
|
|
│ │ └── messaging/
|
|
│ │ └── rabbitmq/
|
|
│ │ ├── publisher.go
|
|
│ │ └── consumer.go
|
|
│ └── interfaces/
|
|
│ ├── http/
|
|
│ │ ├── handlers/
|
|
│ │ │ └── chat_handler.go
|
|
│ │ └── routes.go
|
|
│ └── websocket/
|
|
│ ├── hub.go # Connection hub (goroutines)
|
|
│ ├── client.go # WebSocket client handler
|
|
│ └── protocol.go # Message protocol
|
|
├── migrations/
|
|
│ ├── 001_create_rooms.sql
|
|
│ └── 002_create_messages.sql
|
|
├── go.mod
|
|
└── go.sum
|
|
```
|
|
|
|
#### 3.2.5 Technologies & Dépendances
|
|
|
|
```go
|
|
// go.mod
|
|
module veza-chat-server
|
|
|
|
go 1.23.8
|
|
|
|
require (
|
|
github.com/gin-gonic/gin v1.9.1 // HTTP framework
|
|
github.com/gorilla/websocket v1.5.1 // WebSocket
|
|
github.com/google/uuid v1.6.0 // UUID generation
|
|
github.com/golang-jwt/jwt/v5 v5.3.0 // JWT validation (RS256)
|
|
github.com/lib/pq v1.10.9 // PostgreSQL driver
|
|
gorm.io/gorm v1.25.5 // ORM
|
|
gorm.io/driver/postgres v1.5.4 // GORM PostgreSQL
|
|
github.com/redis/go-redis/v9 v9.16.0 // Redis (presence, pub/sub)
|
|
github.com/rabbitmq/amqp091-go v1.9.0 // RabbitMQ
|
|
go.uber.org/zap v1.27.0 // Structured logging
|
|
github.com/prometheus/client_golang v1.18.0 // Metrics
|
|
github.com/spf13/viper v1.18.2 // Configuration
|
|
)
|
|
```
|
|
|
|
### 3.3 Stream Server (Rust)
|
|
|
|
**Repository**: `/veza-stream-server`
|
|
**Port**: `8082`
|
|
**Protocol**: HTTP/2, HLS
|
|
**Language**: Rust 1.75+
|
|
**Framework**: Axum 0.7+, Tokio 1.0+
|
|
|
|
#### 3.3.1 Responsabilités
|
|
|
|
- Streaming audio haute performance
|
|
- Transcoding multi-format (MP3, FLAC, AAC, OGG)
|
|
- Adaptive bitrate streaming (HLS)
|
|
- Audio processing (normalization, EQ)
|
|
- Waveform generation
|
|
- CDN integration
|
|
- Live streaming support
|
|
- Low-latency playback (<50ms)
|
|
|
|
#### 3.3.2 Streaming Pipeline
|
|
|
|
```mermaid
|
|
graph LR
|
|
UPLOAD[File Upload] --> VALIDATE[Validation]
|
|
VALIDATE --> TRANSCODE[Transcoding]
|
|
TRANSCODE --> NORMALIZE[Audio Normalization]
|
|
NORMALIZE --> WAVEFORM[Waveform Generation]
|
|
WAVEFORM --> SEGMENTS[HLS Segmentation]
|
|
SEGMENTS --> CDN[CDN Upload]
|
|
CDN --> READY[Ready to Stream]
|
|
```
|
|
|
|
#### 3.3.3 Supported Formats
|
|
|
|
| Input Formats | Output Formats | Bitrates | Sample Rates |
|
|
|---------------|----------------|----------|--------------|
|
|
| WAV | MP3 | 128, 192, 256, 320 kbps | 44.1, 48 kHz |
|
|
| FLAC | AAC | 128, 192, 256, 320 kbps | 44.1, 48, 96 kHz |
|
|
| MP3 | OGG Vorbis | 128, 192, 256, 320 kbps | 44.1, 48 kHz |
|
|
| M4A | FLAC | Lossless | 44.1, 48, 96, 192 kHz |
|
|
| AIFF | OPUS | 64, 96, 128, 192 kbps | 48 kHz |
|
|
|
|
#### 3.3.4 HLS Streaming
|
|
|
|
**Playlist Structure** (.m3u8):
|
|
```
|
|
#EXTM3U
|
|
#EXT-X-VERSION:3
|
|
#EXT-X-TARGETDURATION:10
|
|
#EXT-X-MEDIA-SEQUENCE:0
|
|
#EXTINF:10.0,
|
|
segment0.ts
|
|
#EXTINF:10.0,
|
|
segment1.ts
|
|
#EXTINF:10.0,
|
|
segment2.ts
|
|
#EXT-X-ENDLIST
|
|
```
|
|
|
|
**Adaptive Bitrate**:
|
|
```
|
|
#EXTM3U
|
|
#EXT-X-STREAM-INF:BANDWIDTH=128000,RESOLUTION=0x0
|
|
stream_128k.m3u8
|
|
#EXT-X-STREAM-INF:BANDWIDTH=192000,RESOLUTION=0x0
|
|
stream_192k.m3u8
|
|
#EXT-X-STREAM-INF:BANDWIDTH=320000,RESOLUTION=0x0
|
|
stream_320k.m3u8
|
|
```
|
|
|
|
#### 3.3.5 Technologies & Dépendances
|
|
|
|
```toml
|
|
[dependencies]
|
|
# Async runtime
|
|
tokio = { version = "1.0", features = ["full"] }
|
|
axum = { version = "0.7", features = ["macros", "multipart"] }
|
|
|
|
# Audio processing
|
|
symphonia = { version = "0.5", features = ["all"] }
|
|
hound = "3.5" # WAV
|
|
minimp3 = "0.5" # MP3 decoder
|
|
rubato = "0.15" # Resampling
|
|
|
|
# FFT and signal processing
|
|
rustfft = "6.2"
|
|
dasp = "0.11"
|
|
|
|
# Streaming protocols
|
|
m3u8-rs = "5.0" # HLS playlists
|
|
|
|
# Database
|
|
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-rustls", "uuid", "chrono"] }
|
|
redis = { version = "0.25", features = ["tokio-comp", "connection-manager"] }
|
|
|
|
# Storage
|
|
reqwest = { version = "0.11", features = ["json", "stream"] }
|
|
|
|
# Compression
|
|
brotli = "3.4"
|
|
lz4_flex = "0.11"
|
|
|
|
# Utilities
|
|
uuid = { version = "1.6", features = ["v4", "serde"] }
|
|
chrono = { version = "0.4", features = ["serde"] }
|
|
bytes = "1.5"
|
|
```
|
|
|
|
### 3.4 Frontend Web (React)
|
|
|
|
**Repository**: `/apps/web`
|
|
**Port**: `5176` (dev), `443` (prod)
|
|
**Protocol**: HTTPS
|
|
**Language**: TypeScript 5.3+
|
|
**Framework**: React 18+, Vite 7+
|
|
|
|
#### 3.4.1 Responsabilités
|
|
|
|
- Interface utilisateur web
|
|
- State management (Zustand)
|
|
- API client (Axios + React Query)
|
|
- WebSocket client (chat, notifications)
|
|
- Audio player UI
|
|
- Forms avec validation (React Hook Form + Zod)
|
|
- Internationalisation (i18next)
|
|
- Responsive design (Tailwind CSS)
|
|
- Progressive Web App (PWA)
|
|
|
|
#### 3.4.2 Architecture Frontend
|
|
|
|
```
|
|
apps/web/
|
|
├── public/
|
|
│ ├── manifest.json
|
|
│ └── service-worker.js
|
|
├── src/
|
|
│ ├── main.tsx # Entry point
|
|
│ ├── App.tsx # Root component
|
|
│ ├── features/ # Feature-based organization
|
|
│ │ ├── auth/
|
|
│ │ │ ├── components/
|
|
│ │ │ │ ├── LoginForm.tsx
|
|
│ │ │ │ └── RegisterForm.tsx
|
|
│ │ │ ├── hooks/
|
|
│ │ │ │ └── useAuth.ts
|
|
│ │ │ ├── services/
|
|
│ │ │ │ └── authService.ts
|
|
│ │ │ └── types.ts
|
|
│ │ ├── player/
|
|
│ │ ├── chat/
|
|
│ │ ├── marketplace/
|
|
│ │ └── dashboard/
|
|
│ ├── components/ # Shared components
|
|
│ │ ├── ui/ # Base UI components
|
|
│ │ │ ├── Button.tsx
|
|
│ │ │ ├── Input.tsx
|
|
│ │ │ └── Card.tsx
|
|
│ │ └── layout/
|
|
│ │ ├── Header.tsx
|
|
│ │ ├── Sidebar.tsx
|
|
│ │ └── Footer.tsx
|
|
│ ├── lib/ # Utilities
|
|
│ │ ├── api.ts # API client
|
|
│ │ ├── websocket.ts # WebSocket client
|
|
│ │ └── utils.ts
|
|
│ ├── stores/ # Zustand stores
|
|
│ │ ├── authStore.ts
|
|
│ │ ├── playerStore.ts
|
|
│ │ └── chatStore.ts
|
|
│ ├── hooks/ # Custom hooks
|
|
│ │ ├── useApi.ts
|
|
│ │ └── useWebSocket.ts
|
|
│ ├── types/ # TypeScript types
|
|
│ │ └── index.ts
|
|
│ ├── i18n/ # Translations
|
|
│ │ ├── en.json
|
|
│ │ ├── fr.json
|
|
│ │ └── i18n.ts
|
|
│ └── styles/
|
|
│ └── globals.css
|
|
├── package.json
|
|
├── tsconfig.json
|
|
├── vite.config.ts
|
|
└── tailwind.config.js
|
|
```
|
|
|
|
#### 3.4.3 Technologies & Dépendances
|
|
|
|
```json
|
|
{
|
|
"dependencies": {
|
|
"react": "^18.2.0",
|
|
"react-dom": "^18.2.0",
|
|
"react-router-dom": "^6.22.0",
|
|
"@tanstack/react-query": "^5.17.0",
|
|
"axios": "^1.6.7",
|
|
"zustand": "^4.5.0",
|
|
"react-hook-form": "^7.49.3",
|
|
"zod": "^3.25.76",
|
|
"@hookform/resolvers": "^3.3.4",
|
|
"i18next": "^25.5.2",
|
|
"react-i18next": "^15.7.3",
|
|
"lucide-react": "^0.321.0",
|
|
"tailwind-merge": "^2.2.1",
|
|
"clsx": "^2.1.0"
|
|
},
|
|
"devDependencies": {
|
|
"@vitejs/plugin-react": "^4.2.1",
|
|
"typescript": "^5.3.3",
|
|
"vite": "^7.1.5",
|
|
"tailwindcss": "^4.0.0",
|
|
"eslint": "^9.0.0",
|
|
"prettier": "^3.2.5",
|
|
"vitest": "^3.2.4",
|
|
"@playwright/test": "^1.41.2"
|
|
}
|
|
}
|
|
```
|
|
|
|
## 4. DÉCOUVERTE ÉTHIQUE (REMPLACEMENT ML)
|
|
|
|
L'architecture de découverte de Veza remplace les systèmes de recommandation ML par des mécanismes transparents, documentés et auditables.
|
|
|
|
### 4.1 Découverte par règles (genres/tags déclarés par l'artiste)
|
|
|
|
Les artistes déclarent eux-mêmes les genres, sous-genres et tags de leurs morceaux. La découverte s'appuie sur ces métadonnées déclaratives. L'algorithme de matching est déterministe : un utilisateur qui filtre "jazz" obtient les morceaux tagués "jazz", triés par date de publication ou popularité (nombre d'écoutes).
|
|
|
|
```
|
|
Requête utilisateur → Filtres (genre, tags, date) → Elasticsearch query → Résultats triés
|
|
```
|
|
|
|
Aucun profil utilisateur n'influence les résultats. Deux utilisateurs avec la même requête obtiennent les mêmes résultats.
|
|
|
|
### 4.2 Curation humaine
|
|
|
|
Les playlists de découverte sont créées et maintenues par des humains (équipe éditoriale, artistes invités, communauté). La plateforme ne génère pas automatiquement de playlists "pour vous" basées sur un profil comportemental.
|
|
|
|
Les playlists curées sont stockées en base PostgreSQL avec attribution claire du curateur.
|
|
|
|
### 4.3 Découverte par graphe social
|
|
|
|
Un utilisateur découvre de la musique via les artistes et utilisateurs qu'il suit. Le flux de découverte social est chronologique (pas d'algorithme de tri par "pertinence"). Les nouvelles publications des comptes suivis apparaissent dans un feed chronologique simple.
|
|
|
|
```
|
|
Feed social = SELECT tracks FROM follows WHERE follower_id = :user_id ORDER BY created_at DESC
|
|
```
|
|
|
|
### 4.4 Recherche fulltext (Elasticsearch)
|
|
|
|
La recherche utilise Elasticsearch pour l'indexation fulltext des titres, artistes, descriptions et tags. Pas de ML, pas de "did you mean" basé sur le comportement utilisateur.
|
|
|
|
```mermaid
|
|
graph LR
|
|
USER[Utilisateur] -->|Recherche texte| API[API Go]
|
|
API -->|Query| ES[Elasticsearch]
|
|
ES -->|Résultats| API
|
|
API -->|JSON| USER
|
|
|
|
TRACK_CREATED[Track créée] -->|Event| WORKER[Worker]
|
|
WORKER -->|Index| ES
|
|
```
|
|
|
|
**Champs indexés** : titre, artiste, description, genre, tags, album.
|
|
**Tri par défaut** : pertinence Elasticsearch (TF-IDF/BM25), puis date.
|
|
**Filtres** : genre, tags, durée, date de publication, licence.
|
|
|
|
### 4.5 Trending (algorithme documenté)
|
|
|
|
Le classement "trending" est basé sur une formule documentée et auditable :
|
|
|
|
```
|
|
score = nombre_écoutes_7_jours * decay_factor(age_publication)
|
|
```
|
|
|
|
La formule est publiée dans le code source et dans la documentation. Aucun facteur opaque n'intervient.
|
|
|
|
## 5. INFRASTRUCTURE ET DÉPLOIEMENT
|
|
|
|
### 5.1 Architecture de Déploiement
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Production Environment"
|
|
subgraph "Edge Layer"
|
|
CF[CloudFlare CDN]
|
|
WAF[Web Application Firewall]
|
|
end
|
|
|
|
subgraph "Load Balancing"
|
|
NGINX[NGINX Load Balancer]
|
|
end
|
|
|
|
subgraph "Application Layer"
|
|
API1[API Server 1]
|
|
API2[API Server 2]
|
|
API3[API Server 3]
|
|
CHAT1[Chat Server 1]
|
|
CHAT2[Chat Server 2]
|
|
STREAM1[Stream Server 1]
|
|
STREAM2[Stream Server 2]
|
|
end
|
|
|
|
subgraph "Data Layer"
|
|
PG_PRIMARY[(PostgreSQL Primary)]
|
|
PG_REPLICA1[(PostgreSQL Replica 1)]
|
|
PG_REPLICA2[(PostgreSQL Replica 2)]
|
|
REDIS_CLUSTER[(Redis Cluster)]
|
|
end
|
|
|
|
subgraph "Storage Layer"
|
|
S3[S3 Object Storage]
|
|
CDN_ORIGIN[CDN Origin]
|
|
end
|
|
end
|
|
|
|
CF --> WAF
|
|
WAF --> NGINX
|
|
|
|
NGINX --> API1
|
|
NGINX --> API2
|
|
NGINX --> API3
|
|
NGINX --> CHAT1
|
|
NGINX --> CHAT2
|
|
NGINX --> STREAM1
|
|
NGINX --> STREAM2
|
|
|
|
API1 --> PG_PRIMARY
|
|
API2 --> PG_PRIMARY
|
|
API3 --> PG_PRIMARY
|
|
|
|
API1 --> REDIS_CLUSTER
|
|
CHAT1 --> REDIS_CLUSTER
|
|
STREAM1 --> REDIS_CLUSTER
|
|
|
|
PG_PRIMARY --> PG_REPLICA1
|
|
PG_PRIMARY --> PG_REPLICA2
|
|
|
|
STREAM1 --> S3
|
|
S3 --> CDN_ORIGIN
|
|
CDN_ORIGIN --> CF
|
|
```
|
|
|
|
### 5.2 Environnements
|
|
|
|
| Environnement | URL | Purpose | Data |
|
|
|---------------|-----|---------|------|
|
|
| **Development** | `http://localhost:*` | Local dev | Fixtures |
|
|
| **Staging** | `https://staging.veza.app` | Pre-prod testing | Anonymized prod |
|
|
| **Production** | `https://veza.app` | Live users | Production |
|
|
|
|
### 5.3 Docker Compose (Development)
|
|
|
|
```yaml
|
|
# docker-compose.yml
|
|
version: '3.8'
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:15-alpine
|
|
environment:
|
|
POSTGRES_DB: veza_db
|
|
POSTGRES_USER: veza
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
ports:
|
|
- "5432:5432"
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U veza"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
ports:
|
|
- "6379:6379"
|
|
volumes:
|
|
- redis_data:/data
|
|
command: redis-server --appendonly yes
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
rabbitmq:
|
|
image: rabbitmq:3.12-management-alpine
|
|
ports:
|
|
- "5672:5672"
|
|
- "15672:15672"
|
|
environment:
|
|
RABBITMQ_DEFAULT_USER: veza
|
|
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
|
|
volumes:
|
|
- rabbitmq_data:/var/lib/rabbitmq
|
|
healthcheck:
|
|
test: ["CMD", "rabbitmq-diagnostics", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
backend-api:
|
|
build:
|
|
context: ./veza-backend-api
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "8080:8080"
|
|
environment:
|
|
DATABASE_URL: postgres://veza:${DB_PASSWORD}@postgres:5432/veza_db
|
|
REDIS_URL: redis://redis:6379
|
|
RABBITMQ_URL: amqp://veza:${RABBITMQ_PASSWORD}@rabbitmq:5672/
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
HYPERSWITCH_URL: ${HYPERSWITCH_URL}
|
|
HYPERSWITCH_API_KEY: ${HYPERSWITCH_API_KEY}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
rabbitmq:
|
|
condition: service_healthy
|
|
|
|
chat-server:
|
|
build:
|
|
context: ./veza-chat-server
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "8081:8081"
|
|
environment:
|
|
DATABASE_URL: postgres://veza:${DB_PASSWORD}@postgres:5432/veza_db
|
|
REDIS_URL: redis://redis:6379
|
|
RABBITMQ_URL: amqp://veza:${RABBITMQ_PASSWORD}@rabbitmq:5672/
|
|
JWT_SECRET: ${JWT_SECRET}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
|
|
stream-server:
|
|
build:
|
|
context: ./veza-stream-server
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "8082:8082"
|
|
environment:
|
|
DATABASE_URL: postgres://veza:${DB_PASSWORD}@postgres:5432/veza_db
|
|
REDIS_URL: redis://redis:6379
|
|
S3_ENDPOINT: ${S3_ENDPOINT}
|
|
S3_BUCKET: ${S3_BUCKET}
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
|
|
frontend:
|
|
build:
|
|
context: ./apps/web
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "5176:80"
|
|
environment:
|
|
VITE_API_URL: http://backend-api:8080
|
|
VITE_WS_URL: ws://chat-server:8081
|
|
VITE_STREAM_URL: http://stream-server:8082
|
|
|
|
volumes:
|
|
postgres_data:
|
|
redis_data:
|
|
rabbitmq_data:
|
|
```
|
|
|
|
### 5.4 Ports et Protocoles
|
|
|
|
| Service | Port | Protocol | Access |
|
|
|---------|------|----------|--------|
|
|
| Backend API | 8080 | HTTP/2 (REST) | Public |
|
|
| Chat Server | 8081 | HTTP, WebSocket | Public |
|
|
| Stream Server | 8082 | HTTP/2, HLS | Public |
|
|
| PostgreSQL | 5432 | TCP | Internal |
|
|
| Redis | 6379 | TCP | Internal |
|
|
| RabbitMQ | 5672 | AMQP | Internal |
|
|
| RabbitMQ Management | 15672 | HTTP | Internal |
|
|
| Prometheus | 9090 | HTTP | Internal |
|
|
| Grafana | 3000 | HTTP | Internal |
|
|
| Traefik Dashboard | 8888 | HTTP | Internal |
|
|
|
|
## 6. FLUX DE DONNÉES
|
|
|
|
### 6.1 Flux d'Authentification
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Frontend
|
|
participant API
|
|
participant PostgreSQL
|
|
participant Redis
|
|
|
|
User->>Frontend: Enter credentials
|
|
Frontend->>API: POST /auth/login
|
|
API->>PostgreSQL: Validate credentials
|
|
PostgreSQL-->>API: User found
|
|
API->>API: Generate JWT
|
|
API->>Redis: Store session
|
|
API-->>Frontend: JWT + Refresh Token
|
|
Frontend->>Frontend: Store tokens (httpOnly cookie)
|
|
Frontend->>API: GET /users/me (with JWT)
|
|
API->>Redis: Validate JWT
|
|
Redis-->>API: Session valid
|
|
API-->>Frontend: User profile
|
|
```
|
|
|
|
### 6.2 Flux d'Upload de Track
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant User
|
|
participant Frontend
|
|
participant API
|
|
participant StreamServer
|
|
participant S3
|
|
participant RabbitMQ
|
|
participant Worker
|
|
participant PostgreSQL
|
|
|
|
User->>Frontend: Select audio file
|
|
Frontend->>API: POST /tracks/upload (multipart)
|
|
API->>API: Validate file (type, size)
|
|
API->>S3: Upload raw file
|
|
S3-->>API: File URL
|
|
API->>PostgreSQL: Create track record (status: processing)
|
|
API->>RabbitMQ: Publish TrackUploaded event
|
|
API-->>Frontend: Track ID, status
|
|
|
|
RabbitMQ->>Worker: Consume TrackUploaded event
|
|
Worker->>S3: Download raw file
|
|
Worker->>StreamServer: POST /transcode
|
|
StreamServer->>StreamServer: Transcode to multiple formats
|
|
StreamServer->>StreamServer: Generate waveform
|
|
StreamServer->>S3: Upload processed files
|
|
StreamServer-->>Worker: Processing complete
|
|
Worker->>PostgreSQL: Update track (status: ready)
|
|
Worker->>RabbitMQ: Publish TrackProcessed event
|
|
RabbitMQ->>API: Consume TrackProcessed event
|
|
API->>Frontend: WebSocket notification
|
|
Frontend->>User: Track ready!
|
|
```
|
|
|
|
### 6.3 Flux de Chat Temps Réel
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant UserA
|
|
participant FrontendA
|
|
participant ChatServer
|
|
participant Redis
|
|
participant PostgreSQL
|
|
participant RabbitMQ
|
|
participant FrontendB
|
|
participant UserB
|
|
|
|
FrontendA->>ChatServer: WebSocket connect
|
|
ChatServer->>Redis: Register connection
|
|
FrontendB->>ChatServer: WebSocket connect
|
|
ChatServer->>Redis: Register connection
|
|
|
|
UserA->>FrontendA: Type message
|
|
FrontendA->>ChatServer: Send message
|
|
ChatServer->>PostgreSQL: Store message
|
|
ChatServer->>Redis: Cache message
|
|
ChatServer->>RabbitMQ: Publish MessageSent event
|
|
ChatServer->>FrontendB: Deliver message (WebSocket)
|
|
FrontendB->>UserB: Display message
|
|
```
|
|
|
|
## 7. SÉCURITÉ
|
|
|
|
### 7.1 Authentication & Authorization
|
|
|
|
#### 7.1.1 JWT Structure
|
|
|
|
```json
|
|
{
|
|
"header": {
|
|
"alg": "RS256",
|
|
"typ": "JWT"
|
|
},
|
|
"payload": {
|
|
"sub": "user-123",
|
|
"email": "user@example.com",
|
|
"roles": ["user", "creator"],
|
|
"permissions": ["track:create", "track:read"],
|
|
"iat": 1730550000,
|
|
"exp": 1730553600,
|
|
"jti": "token-uuid"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Algorithme de signature** : RS256 (asymétrique). Migration depuis HS256 planifiée.
|
|
|
|
**Token Lifetime** :
|
|
- Access Token: 15 minutes
|
|
- Refresh Token: 30 days
|
|
- Remember Me Token: 90 days
|
|
|
|
#### 7.1.2 RBAC (Role-Based Access Control)
|
|
|
|
**Roles Hierarchy**:
|
|
```
|
|
admin (all permissions)
|
|
↓
|
|
moderator (moderation permissions)
|
|
↓
|
|
creator (content creation permissions)
|
|
↓
|
|
premium_user (premium features)
|
|
↓
|
|
user (basic permissions)
|
|
↓
|
|
guest (read-only)
|
|
```
|
|
|
|
**Permissions Matrix**:
|
|
|
|
| Resource | guest | user | creator | premium | moderator | admin |
|
|
|----------|-------|------|---------|---------|-----------|-------|
|
|
| Track Read | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
| Track Create | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
| Track Delete Own | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
| Track Delete Any | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
|
| User Ban | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
|
|
| System Config | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
|
|
|
|
### 7.2 Data Encryption
|
|
|
|
**At Rest**:
|
|
- Database: AES-256-GCM (PostgreSQL pgcrypto)
|
|
- Files: AES-256-CBC (S3 SSE-KMS)
|
|
- Backups: AES-256-GCM
|
|
|
|
**In Transit**:
|
|
- TLS 1.3 minimum
|
|
- Cipher suites: TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256
|
|
- Certificate: Let's Encrypt + automatic renewal
|
|
|
|
### 7.3 Security Headers
|
|
|
|
```
|
|
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
|
|
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'
|
|
X-Frame-Options: DENY
|
|
X-Content-Type-Options: nosniff
|
|
X-XSS-Protection: 1; mode=block
|
|
Referrer-Policy: strict-origin-when-cross-origin
|
|
Permissions-Policy: geolocation=(), microphone=(), camera=()
|
|
```
|
|
|
|
### 7.4 Rate Limiting
|
|
|
|
| Endpoint | Rate Limit | Window | Burst |
|
|
|----------|------------|--------|-------|
|
|
| `/auth/login` | 5 requests | 15 min | 2 |
|
|
| `/auth/register` | 3 requests | 1 hour | 1 |
|
|
| `/api/v1/*` (authenticated) | 1000 requests | 1 min | 100 |
|
|
| `/api/v1/*` (guest) | 100 requests | 1 min | 20 |
|
|
| WebSocket connections | 10 connections | 1 min | 2 |
|
|
|
|
## 8. PERFORMANCE ET SCALABILITÉ
|
|
|
|
### 8.1 Performance Targets
|
|
|
|
| Metric | Target | Measurement |
|
|
|--------|--------|-------------|
|
|
| API Response Time (p95) | < 100ms | Prometheus |
|
|
| API Response Time (p99) | < 200ms | Prometheus |
|
|
| WebSocket Latency | < 50ms | Custom metrics |
|
|
| Database Query Time (p95) | < 10ms | pgStatements |
|
|
| Page Load Time (FCP) | < 1.5s | Lighthouse |
|
|
| Page Load Time (LCP) | < 2.5s | Lighthouse |
|
|
| Time to Interactive (TTI) | < 3.5s | Lighthouse |
|
|
| Audio Playback Start | < 500ms | Custom metrics |
|
|
|
|
### 8.2 Scalability Targets
|
|
|
|
| Resource | Target | Strategy |
|
|
|----------|--------|----------|
|
|
| Concurrent Users | 100,000+ | Horizontal scaling |
|
|
| Audio Streams | 10,000+ | CDN + adaptive bitrate |
|
|
| WebSocket Connections | 50,000+ | Multi-instance + Redis pub/sub |
|
|
| Database Connections | 1,000+ | Connection pooling (pgBouncer) |
|
|
| Messages/sec | 100,000+ | Queue sharding |
|
|
| File Uploads/min | 1,000+ | Background workers |
|
|
|
|
### 8.3 Caching Strategy
|
|
|
|
**Cache Layers**:
|
|
|
|
1. **Browser Cache** (Service Worker):
|
|
- Static assets: 1 year
|
|
- API responses: 5 minutes
|
|
- Waveforms: 1 hour
|
|
|
|
2. **CDN Cache** (CloudFlare):
|
|
- Audio files: 7 days
|
|
- Images: 30 days
|
|
- Static JS/CSS: 1 year
|
|
|
|
3. **Redis Cache**:
|
|
- User sessions: 30 days
|
|
- User profiles: 1 hour
|
|
- Track metadata: 15 minutes
|
|
- Search results: 5 minutes
|
|
|
|
4. **Application Cache** (in-memory):
|
|
- Configuration: Until restart
|
|
- Feature flags: 1 minute
|
|
- JWT public keys: 1 hour
|
|
|
|
**Cache Invalidation**:
|
|
- Write-through: Update DB + cache simultaneously
|
|
- Cache-aside: Read from cache, fallback to DB
|
|
- Event-driven: Invalidate on domain events
|
|
|
|
### 8.4 Database Optimization
|
|
|
|
**Indexes** (top 10 critical):
|
|
```sql
|
|
-- Users
|
|
CREATE INDEX idx_users_email ON users(email);
|
|
CREATE INDEX idx_users_username ON users(username);
|
|
CREATE INDEX idx_users_created_at ON users(created_at DESC);
|
|
|
|
-- Tracks
|
|
CREATE INDEX idx_tracks_creator_id ON tracks(creator_id);
|
|
CREATE INDEX idx_tracks_genre ON tracks(genre);
|
|
CREATE INDEX idx_tracks_created_at ON tracks(created_at DESC);
|
|
|
|
-- Messages
|
|
CREATE INDEX idx_messages_room_id_created_at ON messages(room_id, created_at DESC);
|
|
CREATE INDEX idx_messages_sender_id ON messages(sender_id);
|
|
|
|
-- Search
|
|
CREATE INDEX idx_tracks_search ON tracks USING GIN(to_tsvector('english', title || ' ' || artist));
|
|
CREATE INDEX idx_users_search ON users USING GIN(to_tsvector('english', username || ' ' || display_name));
|
|
```
|
|
|
|
**Partitioning**:
|
|
```sql
|
|
-- Messages table partitioned by month
|
|
CREATE TABLE messages_2025_01 PARTITION OF messages
|
|
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
|
|
|
|
-- Analytics events partitioned by day
|
|
CREATE TABLE analytics_events_2025_01_01 PARTITION OF analytics_events
|
|
FOR VALUES FROM ('2025-01-01') TO ('2025-01-02');
|
|
```
|
|
|
|
**Connection Pooling** (pgBouncer):
|
|
```ini
|
|
[databases]
|
|
veza_db = host=postgres port=5432 dbname=veza_db
|
|
|
|
[pgbouncer]
|
|
pool_mode = transaction
|
|
max_client_conn = 1000
|
|
default_pool_size = 25
|
|
reserve_pool_size = 5
|
|
reserve_pool_timeout = 3
|
|
```
|
|
|
|
## 9. OBSERVABILITÉ
|
|
|
|
### 9.1 Logging
|
|
|
|
**Log Levels**:
|
|
- `TRACE`: Very detailed (disabled in production)
|
|
- `DEBUG`: Detailed debugging information
|
|
- `INFO`: General informational messages
|
|
- `WARN`: Warning messages
|
|
- `ERROR`: Error messages
|
|
- `FATAL`: Critical errors (application crash)
|
|
|
|
**Log Format** (JSON):
|
|
```json
|
|
{
|
|
"timestamp": "2025-11-02T10:30:00.123Z",
|
|
"level": "INFO",
|
|
"service": "backend-api",
|
|
"trace_id": "abc123",
|
|
"span_id": "def456",
|
|
"message": "User logged in successfully",
|
|
"user_id": "user-123",
|
|
"ip": "192.168.1.100",
|
|
"duration_ms": 45
|
|
}
|
|
```
|
|
|
|
**Centralized Logging** (Loki):
|
|
```yaml
|
|
# promtail-config.yaml
|
|
server:
|
|
http_listen_port: 9080
|
|
|
|
clients:
|
|
- url: http://loki:3100/loki/api/v1/push
|
|
|
|
scrape_configs:
|
|
- job_name: docker
|
|
docker_sd_configs:
|
|
- host: unix:///var/run/docker.sock
|
|
relabel_configs:
|
|
- source_labels: ['__meta_docker_container_name']
|
|
target_label: 'container'
|
|
```
|
|
|
|
### 9.2 Metrics (Prometheus)
|
|
|
|
**Application Metrics**:
|
|
```go
|
|
// Go (backend-api)
|
|
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"},
|
|
)
|
|
|
|
activeWebSocketConnections = prometheus.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "websocket_connections_active",
|
|
Help: "Number of active WebSocket connections",
|
|
},
|
|
)
|
|
)
|
|
```
|
|
|
|
**Infrastructure Metrics**:
|
|
- CPU usage per service
|
|
- Memory usage per service
|
|
- Disk I/O
|
|
- Network I/O
|
|
- Database connections
|
|
- Cache hit/miss ratio
|
|
|
|
### 9.3 Tracing (Jaeger)
|
|
|
|
**Distributed Tracing**:
|
|
```go
|
|
import "go.opentelemetry.io/otel"
|
|
|
|
func CreateUser(ctx context.Context, input CreateUserInput) error {
|
|
ctx, span := otel.Tracer("backend-api").Start(ctx, "CreateUser")
|
|
defer span.End()
|
|
|
|
span.SetAttributes(
|
|
attribute.String("user.username", input.Username),
|
|
attribute.String("user.email", input.Email),
|
|
)
|
|
|
|
// Business logic...
|
|
|
|
if err != nil {
|
|
span.RecordError(err)
|
|
span.SetStatus(codes.Error, err.Error())
|
|
return err
|
|
}
|
|
|
|
span.SetStatus(codes.Ok, "User created successfully")
|
|
return nil
|
|
}
|
|
```
|
|
|
|
### 9.4 Alerting
|
|
|
|
**Alert Rules** (Prometheus Alertmanager):
|
|
```yaml
|
|
groups:
|
|
- name: veza_alerts
|
|
interval: 30s
|
|
rules:
|
|
# High error rate
|
|
- alert: HighErrorRate
|
|
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
|
|
for: 5m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "High error rate detected"
|
|
description: "Error rate is {{ $value | humanizePercentage }}"
|
|
|
|
# High response time
|
|
- alert: HighResponseTime
|
|
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
|
|
for: 5m
|
|
labels:
|
|
severity: warning
|
|
annotations:
|
|
summary: "High response time (p95)"
|
|
description: "Response time p95 is {{ $value }}s"
|
|
|
|
# Database connection pool exhausted
|
|
- alert: DatabasePoolExhausted
|
|
expr: pg_stat_database_numbackends / pg_settings_max_connections > 0.9
|
|
for: 2m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "Database connection pool nearly exhausted"
|
|
description: "Connection usage is {{ $value | humanizePercentage }}"
|
|
|
|
# Service down
|
|
- alert: ServiceDown
|
|
expr: up{job="backend-api"} == 0
|
|
for: 1m
|
|
labels:
|
|
severity: critical
|
|
annotations:
|
|
summary: "Backend API is down"
|
|
description: "Backend API has been down for more than 1 minute"
|
|
```
|
|
|
|
## 10. DÉCISIONS ARCHITECTURALES (ADR)
|
|
|
|
### ADR-001: Choix de Go pour le Backend API
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Besoin d'un langage performant, typé, avec bonne concurrence pour API REST haute charge.
|
|
**Décision**: Utiliser Go 1.23+ avec framework Gin.
|
|
**Conséquences**:
|
|
- ✅ Compilation rapide, binaire unique
|
|
- ✅ Goroutines pour concurrence
|
|
- ✅ Typage fort, pas de runtime errors
|
|
- ✅ Excellent pour microservices
|
|
- ❌ Verbosité du code (error handling)
|
|
- ❌ Écosystème moins riche que Node.js
|
|
|
|
**Alternatives rejetées**:
|
|
- **Node.js**: Single-threaded, performance inférieure
|
|
- **Python**: GIL, performance médiocre pour API haute charge
|
|
- **Java**: Trop lourd, démarrage lent, complexité
|
|
|
|
### ADR-002: Choix de Go pour le Chat Server
|
|
|
|
**Date**: 2025-01-01 (révisé 2026-03-04)
|
|
**Statut**: Accepted (révisé)
|
|
**Contexte**: Le chat nécessite des WebSocket performantes mais pas la performance critique du streaming audio. Rust était initialement prévu pour tous les services temps réel, mais la complexité de développement et de maintenance n'est pas justifiée pour le chat.
|
|
**Décision**: Utiliser Go 1.23+ avec gorilla/websocket pour le Chat Server. Rust reste pour le Stream Server uniquement.
|
|
**Conséquences**:
|
|
- ✅ Cohérence stack avec le Backend API (Go + Go)
|
|
- ✅ Goroutines suffisantes pour les WebSocket chat
|
|
- ✅ Recrutement et maintenance plus simples
|
|
- ✅ Temps de compilation rapide
|
|
- ❌ GC pauses possibles (acceptable pour le chat, non critique)
|
|
|
|
**Alternatives rejetées**:
|
|
- **Rust (Axum)**: surengineering pour le chat, complexité de développement excessive
|
|
- **Node.js**: single-threaded, performance inférieure
|
|
|
|
### ADR-002b: Choix de Rust pour le Stream Server
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Le streaming audio nécessite une performance native pour le transcoding, le traitement audio et le HLS.
|
|
**Décision**: Utiliser Rust 1.75+ avec Axum + Tokio pour le Stream Server uniquement.
|
|
**Conséquences**:
|
|
- ✅ Zero-cost abstractions pour le traitement audio
|
|
- ✅ Sécurité mémoire garantie
|
|
- ✅ Performance native (C/C++ level)
|
|
- ❌ Courbe d'apprentissage raide
|
|
- ❌ Temps de compilation long
|
|
|
|
### ADR-003: Choix de PostgreSQL comme Base Principale
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Besoin ACID, relations complexes, performance.
|
|
**Décision**: PostgreSQL 15+ comme base principale.
|
|
**Conséquences**:
|
|
- ✅ ACID complet
|
|
- ✅ Relations complexes (foreign keys, joins)
|
|
- ✅ Full-text search intégré
|
|
- ✅ JSON/JSONB pour flexibilité
|
|
- ✅ Extensions (pgcrypto, pg_trgm, etc.)
|
|
- ❌ Scaling horizontal complexe
|
|
|
|
**Alternatives rejetées**:
|
|
- **MySQL**: Moins de fonctionnalités avancées
|
|
- **MongoDB**: Pas ACID, relations difficiles
|
|
- **CockroachDB**: Trop jeune, écosystème limité
|
|
|
|
### ADR-004: Architecture Microservices Modulaire
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Nombreuses features réparties sur 18 domaines métier, équipe multiple, scalabilité.
|
|
**Décision**: Architecture microservices avec 3 services principaux (API, Chat, Stream).
|
|
**Conséquences**:
|
|
- ✅ Scalabilité indépendante
|
|
- ✅ Technologies différentes par service
|
|
- ✅ Isolation des pannes
|
|
- ✅ Déploiements indépendants
|
|
- ❌ Complexité opérationnelle
|
|
- ❌ Transactions distribuées complexes
|
|
|
|
**Alternatives rejetées**:
|
|
- **Monolithe**: Pas scalable, déploiements risqués
|
|
- **Serverless**: Vendor lock-in, cold starts
|
|
- **Microservices complets** (20+ services): Trop complexe au démarrage
|
|
|
|
### ADR-005: REST pour Communication Inter-Services
|
|
|
|
**Date**: 2025-01-01 (révisé 2026-03-04)
|
|
**Statut**: Accepted (révisé)
|
|
**Contexte**: Avec 3 services (API, Chat, Stream), la complexité de gRPC (protobuf, code generation, debugging) n'est pas justifiée. REST est suffisant et simplifie le développement, le debugging et l'observabilité.
|
|
**Décision**: REST (JSON over HTTP/2) pour toutes les communications : inter-services et clients externes.
|
|
**Conséquences**:
|
|
- ✅ Simplicité de développement et debugging
|
|
- ✅ Outillage universel (curl, Postman, navigateur)
|
|
- ✅ OpenAPI pour documentation et génération de clients
|
|
- ✅ Un seul protocole à maîtriser
|
|
- ❌ Overhead JSON vs protobuf (acceptable pour 3 services)
|
|
|
|
**Alternatives rejetées**:
|
|
- **gRPC**: surengineering pour 3 services, debugging difficile
|
|
- **GraphQL**: trop complexe pour inter-service
|
|
- **Message Queue pure**: latence, complexité
|
|
|
|
### ADR-006: Redis pour Cache et Sessions
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Besoin cache in-memory ultra-rapide + pub/sub.
|
|
**Décision**: Redis 7+ Cluster.
|
|
**Conséquences**:
|
|
- ✅ Performance exceptionnelle (<1ms)
|
|
- ✅ Pub/sub intégré
|
|
- ✅ Structures de données riches
|
|
- ✅ Cluster mode (scaling horizontal)
|
|
- ❌ Volatilité (RAM)
|
|
- ❌ Coût (RAM expensive)
|
|
|
|
**Alternatives rejetées**:
|
|
- **Memcached**: Moins de fonctionnalités
|
|
- **In-memory applicatif**: Pas partagé entre instances
|
|
- **Hazelcast**: Trop complexe, Java-centric
|
|
|
|
### ADR-007: RabbitMQ pour Message Queue
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Événements asynchrones, découplage services.
|
|
**Décision**: RabbitMQ 3.12+ avec AMQP.
|
|
**Conséquences**:
|
|
- ✅ Mature, stable
|
|
- ✅ Routing flexible (exchanges, queues)
|
|
- ✅ Garanties de livraison
|
|
- ✅ Management UI
|
|
- ❌ Throughput inférieur à Kafka
|
|
- ❌ Persistence moins optimale que Kafka
|
|
|
|
**Alternatives rejetées**:
|
|
- **Kafka**: Over-engineering pour début, complexité
|
|
- **AWS SQS**: Vendor lock-in
|
|
- **NATS**: Moins mature pour persistence
|
|
|
|
### ADR-008: React avec TypeScript pour Frontend
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: UI complexe, typage strict, écosystème riche.
|
|
**Décision**: React 18+ avec TypeScript 5.3+ strict.
|
|
**Conséquences**:
|
|
- ✅ Écosystème immense
|
|
- ✅ Typage strict (moins d'erreurs runtime)
|
|
- ✅ Performance (Concurrent Mode)
|
|
- ✅ Communauté énorme
|
|
- ❌ Bundle size important
|
|
- ❌ Complexité state management
|
|
|
|
**Alternatives rejetées**:
|
|
- **Vue.js**: Écosystème plus petit
|
|
- **Svelte**: Moins mature, écosystème limité
|
|
- **Angular**: Trop lourd, opinionated
|
|
|
|
### ADR-009: Vite comme Build Tool Frontend
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Build rapide, HMR performant.
|
|
**Décision**: Vite 7+ au lieu de Webpack.
|
|
**Conséquences**:
|
|
- ✅ Build ultra-rapide (ESBuild)
|
|
- ✅ HMR instantané
|
|
- ✅ Configuration simple
|
|
- ✅ Support natif TypeScript
|
|
- ❌ Écosystème moins mature que Webpack
|
|
|
|
**Alternatives rejetées**:
|
|
- **Webpack**: Lent, configuration complexe
|
|
- **Parcel**: Moins performant que Vite
|
|
- **Rollup**: Moins de fonctionnalités DX
|
|
|
|
### ADR-010: Docker pour Conteneurisation
|
|
|
|
**Date**: 2025-01-01
|
|
**Statut**: Accepted
|
|
**Contexte**: Déploiement consistant multi-environnements.
|
|
**Décision**: Docker 24+ avec multi-stage builds.
|
|
**Conséquences**:
|
|
- ✅ Portabilité totale
|
|
- ✅ Isolation
|
|
- ✅ Écosystème mature
|
|
- ✅ CI/CD intégré
|
|
- ❌ Overhead léger (performance)
|
|
- ❌ Sécurité (root privileges)
|
|
|
|
**Alternatives rejetées**:
|
|
- **VMs**: Trop lourd, lent
|
|
- **Bare metal**: Pas portable
|
|
- **Podman**: Moins mature
|
|
|
|
### ADR-011: Hyperswitch pour les Paiements
|
|
|
|
**Date**: 2026-03-04
|
|
**Statut**: Accepted
|
|
**Contexte**: Le projet nécessite un système de paiement pour la marketplace (vente de licences, beats, services). Un vendor lock-in sur un seul PSP (Stripe) limite la flexibilité et augmente les coûts.
|
|
**Décision**: Utiliser Hyperswitch, agrégateur de paiement open source, comme couche d'abstraction au-dessus des PSP.
|
|
**Conséquences**:
|
|
- ✅ Multi-PSP (Stripe, Adyen, PayPal, etc.) sans changement de code
|
|
- ✅ Open source, auditable
|
|
- ✅ Pas de vendor lock-in
|
|
- ✅ Smart routing entre PSP
|
|
- ❌ Hébergement et maintenance de l'instance Hyperswitch
|
|
- ❌ Moins de documentation que l'intégration Stripe directe
|
|
|
|
**Alternatives rejetées**:
|
|
- **Stripe direct**: vendor lock-in, commissions non négociables
|
|
- **Développement interne**: trop risqué pour la conformité PCI-DSS
|
|
|
|
### ADR-012: Elasticsearch pour la Recherche (pas de ML)
|
|
|
|
**Date**: 2026-03-04
|
|
**Statut**: Accepted
|
|
**Contexte**: La recherche et la découverte de contenu doivent être transparentes et auditables. Les systèmes de recommandation ML sont des boîtes noires incompatibles avec les principes éthiques du projet.
|
|
**Décision**: Utiliser Elasticsearch pour la recherche fulltext avec des algorithmes déterministes (BM25). La découverte repose sur des règles, la curation humaine et le graphe social.
|
|
**Conséquences**:
|
|
- ✅ Algorithme de scoring transparent et documenté
|
|
- ✅ Résultats reproductibles et auditables
|
|
- ✅ Pas de profilage utilisateur
|
|
- ✅ Infrastructure mature et éprouvée
|
|
- ❌ Pas de personnalisation automatique (choix éthique assumé)
|
|
|
|
**Alternatives rejetées**:
|
|
- **Algolia**: propriétaire, boîte noire
|
|
- **ML/embeddings**: incompatible avec les principes éthiques
|
|
- **PostgreSQL GIN seul**: performance insuffisante à grande échelle
|
|
|
|
## 11. CONVENTIONS DE NOMMAGE
|
|
|
|
### 11.1 Base de Données
|
|
|
|
**Tables**: snake_case, pluriel
|
|
```sql
|
|
users
|
|
tracks
|
|
playlists
|
|
playlist_tracks
|
|
```
|
|
|
|
**Colonnes**: snake_case
|
|
```sql
|
|
user_id
|
|
created_at
|
|
updated_at
|
|
first_name
|
|
```
|
|
|
|
**Indexes**: `idx_{table}_{column(s)}`
|
|
```sql
|
|
idx_users_email
|
|
idx_tracks_creator_id_created_at
|
|
```
|
|
|
|
**Foreign Keys**: `fk_{source_table}_{target_table}`
|
|
```sql
|
|
fk_playlist_tracks_playlists
|
|
fk_playlist_tracks_tracks
|
|
```
|
|
|
|
### 11.2 Backend Go
|
|
|
|
**Packages**: lowercase, singular
|
|
```go
|
|
domain
|
|
application
|
|
infrastructure
|
|
```
|
|
|
|
**Structs**: PascalCase
|
|
```go
|
|
type User struct { }
|
|
type CreateUserCommand struct { }
|
|
```
|
|
|
|
**Functions/Methods**: PascalCase (public), camelCase (private)
|
|
```go
|
|
func CreateUser() { } // Public
|
|
func validateEmail() { } // Private
|
|
```
|
|
|
|
**Variables**: camelCase
|
|
```go
|
|
var userRepository UserRepository
|
|
var maxConnections int
|
|
```
|
|
|
|
**Constants**: PascalCase ou SCREAMING_SNAKE_CASE
|
|
```go
|
|
const MaxRetries = 3
|
|
const DEFAULT_TIMEOUT = 30 * time.Second
|
|
```
|
|
|
|
**Interfaces**: PascalCase, suffix `-er` si applicable
|
|
```go
|
|
type UserRepository interface { }
|
|
type Logger interface { }
|
|
type Validator interface { }
|
|
```
|
|
|
|
### 11.3 Rust
|
|
|
|
**Modules**: snake_case
|
|
```rust
|
|
mod websocket;
|
|
mod message_store;
|
|
```
|
|
|
|
**Structs/Enums**: PascalCase
|
|
```rust
|
|
struct Message { }
|
|
enum MessageType { }
|
|
```
|
|
|
|
**Functions**: snake_case
|
|
```rust
|
|
fn send_message() { }
|
|
fn validate_token() { }
|
|
```
|
|
|
|
**Constants**: SCREAMING_SNAKE_CASE
|
|
```rust
|
|
const MAX_MESSAGE_SIZE: usize = 1024;
|
|
```
|
|
|
|
**Traits**: PascalCase
|
|
```rust
|
|
trait MessageStore { }
|
|
trait Authenticator { }
|
|
```
|
|
|
|
### 11.4 TypeScript/React
|
|
|
|
**Files**: PascalCase (components), camelCase (utilities)
|
|
```
|
|
LoginForm.tsx
|
|
Button.tsx
|
|
utils.ts
|
|
api.ts
|
|
```
|
|
|
|
**Components**: PascalCase
|
|
```tsx
|
|
function LoginForm() { }
|
|
const Button: React.FC = () => { }
|
|
```
|
|
|
|
**Functions**: camelCase
|
|
```ts
|
|
function fetchUsers() { }
|
|
const handleSubmit = () => { }
|
|
```
|
|
|
|
**Types/Interfaces**: PascalCase
|
|
```ts
|
|
interface User { }
|
|
type CreateUserInput = { }
|
|
```
|
|
|
|
**Enums**: PascalCase
|
|
```ts
|
|
enum UserRole { }
|
|
```
|
|
|
|
**Constants**: SCREAMING_SNAKE_CASE
|
|
```ts
|
|
const API_BASE_URL = "https://api.veza.app";
|
|
```
|
|
|
|
### 11.5 API REST
|
|
|
|
**Endpoints**: kebab-case, pluriel pour ressources
|
|
```
|
|
GET /api/v1/users
|
|
POST /api/v1/users
|
|
GET /api/v1/users/{id}
|
|
PUT /api/v1/users/{id}
|
|
DELETE /api/v1/users/{id}
|
|
POST /api/v1/users/{id}/avatar
|
|
GET /api/v1/users/{id}/playlists
|
|
```
|
|
|
|
**Query Params**: snake_case
|
|
```
|
|
GET /api/v1/tracks?genre=rock&sort_by=created_at&order=desc
|
|
```
|
|
|
|
**JSON Fields**: camelCase
|
|
```json
|
|
{
|
|
"userId": "123",
|
|
"firstName": "John",
|
|
"createdAt": "2025-11-02T10:30:00Z"
|
|
}
|
|
```
|
|
|
|
### 11.6 Events
|
|
|
|
**Event Names**: `{domain}.{entity}.{action}.{version}`
|
|
```
|
|
auth.user.registered.v1
|
|
marketplace.order.paid.v1
|
|
chat.message.sent.v1
|
|
```
|
|
|
|
**Event Fields**: camelCase (JSON)
|
|
```json
|
|
{
|
|
"eventId": "evt-123",
|
|
"eventType": "auth.user.registered.v1",
|
|
"aggregateId": "user-123"
|
|
}
|
|
```
|
|
|
|
## 12. STRUCTURE DES RÉPERTOIRES
|
|
|
|
```
|
|
veza-full-stack/
|
|
├── .github/ # GitHub Actions CI/CD
|
|
│ └── workflows/
|
|
│ ├── backend-ci.yml
|
|
│ ├── chat-ci.yml
|
|
│ ├── stream-ci.yml
|
|
│ └── frontend-ci.yml
|
|
├── ansible/ # Ansible deployment
|
|
│ ├── inventory/
|
|
│ ├── playbooks/
|
|
│ └── roles/
|
|
├── apps/ # Applications frontend
|
|
│ ├── web/ # React web app
|
|
│ ├── mobile/ # React Native mobile
|
|
│ └── desktop/ # Electron desktop
|
|
├── config/ # Configurations centralisées
|
|
│ ├── docker/
|
|
│ ├── prometheus/
|
|
│ ├── grafana/
|
|
│ └── nginx/
|
|
├── docs/ # Documentation
|
|
│ ├── ORIGIN/ # ⭐ Documents ORIGIN (immuables)
|
|
│ │ ├── ORIGIN_MASTER_ARCHITECTURE.md
|
|
│ │ ├── ORIGIN_DEVELOPMENT_PHASES.md
|
|
│ │ ├── ORIGIN_FEATURES_REGISTRY.md
|
|
│ │ └── ... (15 documents)
|
|
│ ├── architecture/
|
|
│ ├── api/
|
|
│ └── guides/
|
|
├── features/ # Feature flags & contracts
|
|
│ └── core-contracts/
|
|
├── fixtures/ # Test data & fixtures
|
|
│ ├── scenarios/
|
|
│ └── services/
|
|
├── scripts/ # Utility scripts
|
|
│ ├── start-veza.sh
|
|
│ ├── stop-veza.sh
|
|
│ └── test-veza.sh
|
|
├── veza-backend-api/ # ⭐ Backend API (Go)
|
|
│ ├── cmd/
|
|
│ │ └── api/
|
|
│ │ └── main.go
|
|
│ ├── internal/
|
|
│ │ ├── domain/
|
|
│ │ ├── application/
|
|
│ │ ├── infrastructure/
|
|
│ │ └── interfaces/
|
|
│ ├── pkg/
|
|
│ ├── migrations/
|
|
│ ├── go.mod
|
|
│ └── Dockerfile
|
|
├── veza-chat-server/ # ⭐ Chat Server (Go)
|
|
│ ├── cmd/
|
|
│ │ └── chat/
|
|
│ │ └── main.go
|
|
│ ├── internal/
|
|
│ │ ├── domain/
|
|
│ │ ├── application/
|
|
│ │ ├── infrastructure/
|
|
│ │ └── interfaces/
|
|
│ ├── migrations/
|
|
│ ├── go.mod
|
|
│ └── Dockerfile
|
|
├── veza-stream-server/ # ⭐ Stream Server (Rust)
|
|
│ ├── src/
|
|
│ │ ├── main.rs
|
|
│ │ ├── audio/
|
|
│ │ └── streaming/
|
|
│ ├── Cargo.toml
|
|
│ └── Dockerfile
|
|
├── docker-compose.yml # Development environment
|
|
├── docker-compose.production.yml # Production environment
|
|
├── Makefile # Build automation
|
|
├── .env.example # Environment variables template
|
|
└── README.md # Project README
|
|
```
|
|
|
|
## 13. EXCLUSIONS ET RAISONS ÉTHIQUES
|
|
|
|
Ce qui suit a été explicitement exclu de l'architecture Veza. Chaque exclusion est une décision architecturale permanente, pas un report.
|
|
|
|
### 13.1 IA / Machine Learning
|
|
|
|
| Composant exclu | Raison |
|
|
|-----------------|--------|
|
|
| Mastering automatique (IA) | L'artiste maîtrise son processus créatif. Un mastering IA impose une esthétique normalisée. |
|
|
| Séparation de stems (IA) | Nécessite des modèles ML opaques. Risque de faciliter le plagiat non consenti. |
|
|
| Détection de genre automatique | Les artistes déclarent eux-mêmes leurs genres. La classification automatique impose des catégories réductrices. |
|
|
| Recommandations ML | Les algorithmes de recommandation ML créent des bulles de filtre et optimisent l'engagement, pas la découverte. |
|
|
| Content ID (fingerprinting ML) | Systèmes opaques avec un historique de faux positifs nuisibles aux artistes indépendants. |
|
|
| Transcription automatique | Dépendance à des modèles propriétaires (Whisper, etc.) sans garantie de précision. |
|
|
|
|
### 13.2 Blockchain / Web3 / Crypto
|
|
|
|
| Composant exclu | Raison |
|
|
|-----------------|--------|
|
|
| NFT / tokens | Spéculation financière incompatible avec le soutien aux créateurs. Impact environnemental. |
|
|
| Smart contracts | Complexité inutile pour la gestion de droits. Le droit d'auteur existe déjà. |
|
|
| IPFS / stockage décentralisé | Performance insuffisante pour le streaming audio. Complexité opérationnelle disproportionnée. |
|
|
| Crypto-paiements | Volatilité, blanchiment, pas de protection consommateur. Les artistes ont besoin de revenus stables. |
|
|
| DAO / gouvernance blockchain | Les décisions de gouvernance sont prises par la communauté via des mécanismes classiques (votes, forums). |
|
|
|
|
### 13.3 Gamification addictive
|
|
|
|
| Composant exclu | Raison |
|
|
|-----------------|--------|
|
|
| Système XP / points | Transforme l'écoute musicale en compétition. Optimise le temps passé, pas la satisfaction. |
|
|
| Niveaux utilisateur | Crée une hiérarchie artificielle entre utilisateurs. |
|
|
| Leaderboards / classements | Encourage la quantité au détriment de la qualité. Favorise les comportements de farming. |
|
|
| Streaks / séries | Mécanisme de rétention manipulatoire (FOMO). |
|
|
| Badges de complétion | Acceptable uniquement pour les parcours éducatifs (sans pression sociale). |
|
|
|
|
### 13.4 Autres exclusions techniques
|
|
|
|
| Composant exclu | Raison |
|
|
|-----------------|--------|
|
|
| WebRTC | Code mort, hors scope définitif. Le streaming audio fonctionne via HLS. |
|
|
| gRPC inter-services | Surengineering pour 3 services. REST est suffisant et plus simple à débugger. |
|
|
| Kafka | RabbitMQ est suffisant pour le volume actuel et projeté. |
|
|
| DRM | Incompatible avec la philosophie open source et la confiance envers les artistes. |
|
|
|
|
## ✅ CHECKLIST DE VALIDATION
|
|
|
|
### Architecture
|
|
- [ ] Tous les services sont définis avec ports et protocoles
|
|
- [ ] Les flux de données sont documentés avec diagrammes
|
|
- [ ] Les bounded contexts DDD sont clairement délimités (18 domaines, pas d'IA/Web3/Gamification)
|
|
- [ ] Les patterns architecturaux sont explicites (Clean, CQRS, Event-Driven)
|
|
- [ ] Les décisions architecturales (ADR) sont documentées avec justifications
|
|
- [ ] Les principes éthiques sont documentés comme contraintes architecturales
|
|
- [ ] Les exclusions sont documentées avec leurs raisons
|
|
|
|
### Sécurité
|
|
- [ ] Authentification JWT avec refresh tokens
|
|
- [ ] Autorisation RBAC avec matrice de permissions
|
|
- [ ] Chiffrement at-rest et in-transit défini
|
|
- [ ] Rate limiting configuré par endpoint
|
|
- [ ] Security headers complets
|
|
|
|
### Performance
|
|
- [ ] Targets de performance définies (latence, throughput)
|
|
- [ ] Stratégie de caching multi-niveaux
|
|
- [ ] Optimisations base de données (indexes, partitioning)
|
|
- [ ] Connection pooling configuré
|
|
- [ ] CDN pour assets statiques et audio
|
|
|
|
### Observabilité
|
|
- [ ] Logging structuré (JSON) centralisé (Loki)
|
|
- [ ] Métriques Prometheus pour tous les services
|
|
- [ ] Distributed tracing (Jaeger/OpenTelemetry)
|
|
- [ ] Alerting rules définies (Alertmanager)
|
|
- [ ] Dashboards Grafana
|
|
|
|
### Infrastructure
|
|
- [ ] Docker Compose pour développement
|
|
- [ ] Kubernetes ready (futurs déploiements)
|
|
- [ ] CI/CD pipelines GitHub Actions
|
|
- [ ] Déploiement Ansible automatisé
|
|
- [ ] Environnements (dev, staging, prod) définis
|
|
|
|
## 📊 MÉTRIQUES DE SUCCÈS
|
|
|
|
### Technique
|
|
- **Code Quality**: Coverage > 80%, SonarQube Quality Gate A
|
|
- **Performance API**: p95 < 100ms, p99 < 200ms
|
|
- **Performance Frontend**: Lighthouse Score > 90
|
|
- **Uptime**: > 99.9% (SLA)
|
|
- **Security**: Zero vulnerabilities critiques (Snyk/Dependabot)
|
|
|
|
### Business
|
|
- **Concurrent Users**: 100,000+ supportés
|
|
- **Audio Streams**: 10,000+ simultanés
|
|
- **WebSocket Connections**: 50,000+ simultanées
|
|
- **Messages/sec**: 100,000+
|
|
- **Database Queries**: p95 < 10ms
|
|
|
|
### DevOps
|
|
- **Deploy Time**: < 10 minutes (zero-downtime)
|
|
- **Rollback Time**: < 5 minutes
|
|
- **Build Time**: < 5 minutes (CI)
|
|
- **MTTR** (Mean Time To Recovery): < 15 minutes
|
|
- **Change Failure Rate**: < 5%
|
|
|
|
## 🔄 HISTORIQUE DES VERSIONS
|
|
|
|
| Version | Date | Changements |
|
|
|---------|------|-------------|
|
|
| 1.0.0 | 2025-11-02 | Version initiale - Architecture complète définitive |
|
|
| 2.0.0 | 2026-03-04 | Révision éthique - Suppression IA/ML, Web3/NFT, gamification addictive. Chat Server migré de Rust à Go. gRPC remplacé par REST. Stripe remplacé par Hyperswitch. Ajout principes d'architecture éthique, découverte éthique, exclusions documentées. JWT HS256 → RS256. |
|
|
|
|
---
|
|
|
|
## ⚠️ AVERTISSEMENT
|
|
|
|
**CE DOCUMENT EST LA SOURCE DE VÉRITÉ ARCHITECTURALE**
|
|
|
|
Toute modification de ce document doit suivre le processus de Change Management formel :
|
|
|
|
1. **Proposition** : créer une RFC (Request For Comments) avec justification détaillée
|
|
2. **Vérification éthique** : confirmer que la modification respecte les principes d'architecture éthique (section 1)
|
|
3. **Review** : review par l'équipe technique
|
|
4. **Approval** : approbation requise
|
|
5. **Documentation** : mettre à jour ADR avec nouvelle décision
|
|
6. **Communication** : communiquer à toute l'équipe
|
|
7. **Implémentation** : planifier la migration si nécessaire
|
|
|
|
**Raisons acceptables de modification** :
|
|
- Vulnérabilité de sécurité critique découverte
|
|
- Technologie devenue obsolète (end-of-life)
|
|
- Performance dégradée non récupérable
|
|
- Changement réglementaire (RGPD, etc.)
|
|
- Renforcement des principes éthiques
|
|
|
|
**Raisons NON acceptables** :
|
|
- "On préfère technologie X"
|
|
- "C'est plus à la mode"
|
|
- "J'ai vu sur Hacker News..."
|
|
- "Mon ancien projet utilisait Y"
|
|
- Réintroduction d'IA/ML, blockchain, ou gamification addictive
|
|
|
|
**Alignement éthique** : ce document intègre les principes éthiques comme contraintes architecturales permanentes. Les exclusions documentées en section 13 ne sont pas des reports mais des décisions définitives. Toute proposition de réintroduction d'un composant exclu est rejetée par défaut.
|
|
|
|
---
|
|
|
|
**Document créé par** : Architecture Team
|
|
**Date de création** : 2025-11-02
|
|
**Dernière révision** : 2026-03-04 (révision éthique v2.0.0)
|
|
**Propriétaire** : CTO / Lead Architect
|
|
|
|
**Statut** : ✅ **RÉVISÉ ET VERROUILLÉ — ALIGNÉ ÉTHIQUE**
|
|
|