v0.9.1
This commit is contained in:
parent
ecf8d73e55
commit
2df921abd5
57 changed files with 9520 additions and 1679 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -98,6 +98,10 @@ docker-data/
|
|||
docker/haproxy/certs/*.key
|
||||
docker/haproxy/certs/*.pem
|
||||
|
||||
# JWT RSA keys (v0.9.1 RS256 migration — NEVER commit)
|
||||
jwt-private.pem
|
||||
jwt-public.pem
|
||||
|
||||
veza-backend-api/main
|
||||
veza-backend-api/api
|
||||
veza-backend-api/migrate_tool
|
||||
|
|
|
|||
913
AUDIT_TECHNIQUE_VEZA_2026-03-04.md
Normal file
913
AUDIT_TECHNIQUE_VEZA_2026-03-04.md
Normal file
|
|
@ -0,0 +1,913 @@
|
|||
# AUDIT TECHNIQUE — VEZA MONOREPO
|
||||
|
||||
| Champ | Valeur |
|
||||
|-------|--------|
|
||||
| **Date** | 2026-03-04 |
|
||||
| **Auditeur** | Claude (Architecte IA) — Audit indépendant pour due diligence |
|
||||
| **Version analysée** | v1.0.2 (commit `a007f4c7`, 2026-03-03) |
|
||||
| **Périmètre** | Backend Go, Stream Server Rust, Frontend React, Infrastructure |
|
||||
| **Méthodologie** | Analyse statique exhaustive du code source, 6 passes |
|
||||
| **Classification** | Confidentiel — Usage interne |
|
||||
|
||||
---
|
||||
|
||||
## EXECUTIVE SUMMARY
|
||||
|
||||
### Verdict global
|
||||
|
||||
Veza est un projet techniquement **ambitieux et structurellement solide** pour un projet de cette taille, mais qui présente des **risques critiques** empêchant un déploiement production immédiat sans correction. Le codebase totalise **~610K LOC** réparties sur 3 langages (Go, Rust, TypeScript), ce qui est considérable et soulève des questions de maintenabilité pour une petite équipe.
|
||||
|
||||
### Recommandation : GO CONDITIONNEL
|
||||
|
||||
Le projet peut être lancé en production **après correction des 6 vulnérabilités critiques identifiées** (estimé 2-3 semaines). Le socle architectural est sain, les bonnes pratiques de sécurité sont globalement respectées, et l'infrastructure de déploiement (Docker, CI/CD, blue-green) est mature.
|
||||
|
||||
### Top 5 des risques
|
||||
|
||||
| # | Risque | Gravité | Impact |
|
||||
|---|--------|---------|--------|
|
||||
| 1 | **340+ `unwrap()`/`expect()` dans le stream server Rust** — crash en production sous charge | Critique | Indisponibilité du streaming audio |
|
||||
| 2 | **Secret JWT par défaut dans `veza-common`** — fallback exploitable si env var manquante | Critique | Compromission de tous les tokens |
|
||||
| 3 | **Webhook worker non enregistré dans le shutdown manager** — fuite de goroutine | Elevée | Perte de webhooks au redéploiement |
|
||||
| 4 | **Incohérence politique mot de passe** frontend (8 chars) vs backend (12 chars) | Moyenne | UX dégradée, faux sentiment de sécurité |
|
||||
| 5 | **~500 LOC de code WebRTC mort** avec dépendance commentée | Moyenne | Dette technique, confusion |
|
||||
|
||||
### Top 5 des forces
|
||||
|
||||
| # | Force | Preuve |
|
||||
|---|-------|--------|
|
||||
| 1 | **Architecture backend propre** — séparation handler → service → repository | `veza-backend-api/internal/` |
|
||||
| 2 | **Sécurité auth solide** — httpOnly cookies, JWT HS256, bcrypt cost 12, rate limiting multi-couche | `middleware/auth.go`, `security_headers.go` |
|
||||
| 3 | **CI/CD mature** — 14 workflows GitHub Actions couvrant govulncheck, cargo audit, npm audit, E2E | `.github/workflows/` |
|
||||
| 4 | **Storybook-first** — 300 stories avec MSW, couverture des états (loading, error, empty) | `apps/web/src/**/*.stories.tsx` |
|
||||
| 5 | **Infrastructure production-ready** — blue-green HAProxy, health checks, resource limits, monitoring | `docker-compose.prod.yml` |
|
||||
|
||||
### Scorecard rapide
|
||||
|
||||
| Dimension | Score |
|
||||
|-----------|-------|
|
||||
| Architecture | 7/10 |
|
||||
| Maintenabilité | 5/10 |
|
||||
| Sécurité | 7/10 |
|
||||
| Scalabilité | 5/10 |
|
||||
| Testabilité | 7/10 |
|
||||
| Opérabilité | 7/10 |
|
||||
| Vélocité dev | 4/10 |
|
||||
| Maturité produit | 6/10 |
|
||||
|
||||
---
|
||||
|
||||
## 1. CARTOGRAPHIE GLOBALE
|
||||
|
||||
### 1.1 Stack réelle
|
||||
|
||||
| Élément | Version / Détail | Statut |
|
||||
|---------|-----------------|--------|
|
||||
| **Go** | 1.24.0 (`go.mod`) | Courant (released Feb 2025) |
|
||||
| **Rust** | edition 2021, stable (pas de `rust-toolchain.toml`) | Courant |
|
||||
| **Node.js** | 20 (CI `setup-node`), pas de `.nvmrc`/`.node-version` | LTS courant |
|
||||
| **TypeScript** | 5.9.3 | Courant |
|
||||
| **React** | ^18.2.0 | Stable (React 19 disponible mais non adopté) |
|
||||
| **Vite** | ^7.1.5 | Courant |
|
||||
| **Gin** | 1.11.0 | Courant |
|
||||
| **GORM** | 1.30.0 | Courant |
|
||||
| **Axum** | 0.8 | Courant |
|
||||
| **SQLx** | 0.8 | Courant |
|
||||
| **PostgreSQL** | 16-alpine | Courant |
|
||||
| **Redis** | 7-alpine | Courant |
|
||||
| **RabbitMQ** | 3-management-alpine | Courant |
|
||||
| **Hyperswitch** | 2025.01.21.0-standalone | ~1 an de retard |
|
||||
| **HAProxy** | 2.8-alpine | Courant LTS |
|
||||
| **Prometheus** | (Rust) 0.14 / (Go) client_golang 1.22.0 | Courant |
|
||||
| **JWT** | golang-jwt/v5 5.3.0 (Go) / jsonwebtoken 10 (Rust) | Courant |
|
||||
| **Bcrypt** | golang.org/x/crypto (Go) / bcrypt 0.17 (Rust) | Courant |
|
||||
| **Stripe** | stripe-go/v82 82.5.1 (backup/fallback) | Courant |
|
||||
| **AWS SDK** | aws-sdk-go-v2 1.41.0 | Courant |
|
||||
| **HLS** | FFmpeg (externe) + m3u8-rs 5.0 + hls.js 1.6.14 (frontend) | Réel |
|
||||
| **WebRTC** | Code présent mais `webrtc = "0.7"` commenté dans Cargo.toml | **Non fonctionnel** |
|
||||
| **WebSocket** | coder/websocket 1.8.14 (Go) / tokio-tungstenite 0.21 (Rust) | Fonctionnel |
|
||||
| **Storybook** | 8.6.15 | Courant |
|
||||
| **MSW** | 2.11.2 | Courant |
|
||||
| **Playwright** | 1.58.2 | Courant |
|
||||
| **Vitest** | 3.2.4 | Courant |
|
||||
| **Tailwind CSS** | ^4.0.0 | Courant |
|
||||
| **Sentry** | sentry-go 0.40.0 (backend) / @sentry/react ^10.32.1 | Courant |
|
||||
| **ClamAV** | clamav/clamav:latest | Intégré pour scan antivirus uploads |
|
||||
|
||||
**Constat** : Les dépendances sont globalement à jour. Seul Hyperswitch (~1 an de retard) mérite une mise à jour. Pas de dépendances abandonnées identifiées.
|
||||
|
||||
### 1.2 Organisation du monorepo
|
||||
|
||||
**Outil de gestion** : npm workspaces + Turborepo (`turbo.json`). Configuration minimale — 3 tâches (build, test, lint) avec dépendances `^build`. Pas de cache remote configuré.
|
||||
|
||||
| Répertoire | Rôle réel | Fichiers | LOC | Couplage |
|
||||
|-----------|-----------|----------|-----|----------|
|
||||
| `veza-backend-api/` | API REST Go (Gin, GORM, JWT) — coeur métier | 778 .go | ~188K | PostgreSQL, Redis, RabbitMQ, S3 |
|
||||
| `veza-stream-server/` | Serveur streaming Rust (Axum, HLS, FFmpeg) | 138 .rs | ~103K | PostgreSQL, Redis, RabbitMQ |
|
||||
| `veza-common/` | Bibliothèque Rust partagée (auth, config, types) | 53 .rs | ~4.3K | Utilisé par stream-server uniquement |
|
||||
| `apps/web/` | Frontend React SPA (Vite, Zustand, TanStack Query) | 1887 .ts/.tsx | ~211K | API backend via Axios, WebSocket |
|
||||
| `packages/design-system/` | Package partagé design system | ~10 | ~500 | Utilisé par apps/web |
|
||||
| `fixtures/` | Fixtures de test (npm package) | ~20 | ~1K | Cross-service test data |
|
||||
| `config/` | Configs déploiement (HAProxy, Prometheus, Grafana, Caddy, SSL) | ~30 | ~2K | Infrastructure |
|
||||
| `k8s/` | Manifestes Kubernetes (10+ sous-dossiers) | ~40 yaml | ~3K | Non déployé (templates) |
|
||||
| `docs/` | Documentation projet (285 fichiers .md) | 285 | ~15K | Référence |
|
||||
| `loadtests/` | Tests de charge k6 (backend, stream, chat) | ~15 | ~2K | Backend, Stream |
|
||||
| `.github/workflows/` | CI/CD (14 workflows) | 14 | ~600 | Tous services |
|
||||
| `proto/` | Définitions Protocol Buffers | ~5 | ~200 | Stream server (gRPC) |
|
||||
| `scripts/` | Scripts utilitaires (déploiement, dev, monitoring) | ~25 | ~1.5K | Tous services |
|
||||
| `make/` | Modules Makefile (config, dev, build, test, services) | 11 | ~800 | Orchestration |
|
||||
|
||||
**Total estimé** : ~319K LOC de code source (hors node_modules, target, dist, docs).
|
||||
|
||||
#### Packages orphelins et fantômes
|
||||
|
||||
| Répertoire | Statut | Détail |
|
||||
|-----------|--------|--------|
|
||||
| `chat_exports/` | Orphelin | 15 fichiers, artefacts de chat export. Aucune référence dans le code. |
|
||||
| `sub_task_agents/` | Orphelin | 15 fichiers de documentation IA. Aucun code exécutable. |
|
||||
| `tmt/` | Orphelin | 18 fichiers de config test management. Pas d'intégration CI. |
|
||||
| `full_veza_audit_data/` | Orphelin | 7 fichiers de données d'audit passé. |
|
||||
| `veza-docs/` | Partiellement orphelin | Site Docusaurus non intégré dans les workflows CI. |
|
||||
| `k8s/chat-server/` | Fantôme | Manifestes pour `veza-chat-server` supprimé en v0.502. Image Docker inexistante. |
|
||||
| `Makefile.old` | Mort | Ancien Makefile remplacé par `make/*.mk`. |
|
||||
|
||||
**Duplications cross-packages** : Les types d'authentification sont définis séparément dans Go (`internal/services/jwt_service.go`), Rust (`veza-common/src/auth.rs`), et TypeScript (`src/types/generated/api.ts`). Le TypeScript est généré depuis l'OpenAPI spec, mais Go et Rust sont indépendants — source d'incohérences (cf. mismatch issuer/audience Section 4).
|
||||
|
||||
**Dépendances circulaires** : Aucune détectée. Le flux de dépendances est unidirectionnel : `veza-common` -> `veza-stream-server` ; `apps/web` -> API backend (HTTP).
|
||||
|
||||
### 1.3 Dépendances critiques
|
||||
|
||||
| Service | Deps directes | Vulnérabilités CI | Deps > 2 ans sans release |
|
||||
|---------|--------------|-------------------|---------------------------|
|
||||
| Go backend | 45 directes + 116 indirectes = 161 | `govulncheck` en CI — 0 identifié | Aucune |
|
||||
| Rust stream | ~78 directes | `cargo audit` en CI — 0 identifié | `dotenv 0.15` (last: 2020, remplacé par `dotenvy`) |
|
||||
| Frontend | 35 deps + 37 devDeps = 72 | `npm audit --audit-level=critical` en CI | Aucune |
|
||||
|
||||
**Dépendance préoccupante** : `dotenv 0.15` dans le stream server Rust est maintenu par un nouveau mainteneur mais la version 0.15 date de 2020. Recommandation : migrer vers `dotenvy`.
|
||||
|
||||
### 1.4 Schéma des flux
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph client [Client Browser]
|
||||
ReactApp["React SPA<br/>Vite + HLS.js"]
|
||||
end
|
||||
|
||||
subgraph proxy [Reverse Proxy]
|
||||
HAProxy["HAProxy 2.8<br/>Blue-Green"]
|
||||
end
|
||||
|
||||
subgraph backend [Backend API - Go]
|
||||
GinRouter["Gin Router<br/>Middleware Chain"]
|
||||
AuthSvc["Auth Service<br/>JWT HS256"]
|
||||
TrackSvc["Track Service"]
|
||||
MarketSvc["Marketplace Service"]
|
||||
SocialSvc["Social Service"]
|
||||
ChatWS["Chat WebSocket<br/>Hub Pattern"]
|
||||
UploadSvc["Upload Service<br/>ClamAV Scan"]
|
||||
end
|
||||
|
||||
subgraph stream [Stream Server - Rust]
|
||||
AxumRouter["Axum Router"]
|
||||
HLSGen["HLS Generator<br/>FFmpeg"]
|
||||
TranscodeEng["Transcoding Engine"]
|
||||
StreamWS["Stream WebSocket"]
|
||||
end
|
||||
|
||||
subgraph data [Data Layer]
|
||||
PostgreSQL["PostgreSQL 16"]
|
||||
Redis["Redis 7"]
|
||||
RabbitMQ["RabbitMQ 3"]
|
||||
MinIO["MinIO / S3"]
|
||||
ClamAV["ClamAV"]
|
||||
end
|
||||
|
||||
subgraph payments [Payment]
|
||||
Hyperswitch["Hyperswitch Router"]
|
||||
HyperswitchDB["Hyperswitch PostgreSQL"]
|
||||
end
|
||||
|
||||
ReactApp -->|"HTTPS"| HAProxy
|
||||
HAProxy -->|"/api/v1/*"| GinRouter
|
||||
HAProxy -->|"/stream/*"| AxumRouter
|
||||
|
||||
GinRouter --> AuthSvc
|
||||
GinRouter --> TrackSvc
|
||||
GinRouter --> MarketSvc
|
||||
GinRouter --> SocialSvc
|
||||
GinRouter --> ChatWS
|
||||
GinRouter --> UploadSvc
|
||||
|
||||
UploadSvc --> ClamAV
|
||||
UploadSvc --> MinIO
|
||||
TrackSvc --> PostgreSQL
|
||||
MarketSvc --> Hyperswitch
|
||||
Hyperswitch --> HyperswitchDB
|
||||
|
||||
AuthSvc --> PostgreSQL
|
||||
AuthSvc --> Redis
|
||||
ChatWS --> Redis
|
||||
|
||||
AxumRouter --> HLSGen
|
||||
AxumRouter --> TranscodeEng
|
||||
AxumRouter --> StreamWS
|
||||
HLSGen --> MinIO
|
||||
|
||||
GinRouter --> RabbitMQ
|
||||
AxumRouter --> RabbitMQ
|
||||
|
||||
GinRouter --> PostgreSQL
|
||||
AxumRouter --> PostgreSQL
|
||||
AxumRouter --> Redis
|
||||
```
|
||||
|
||||
#### Flux critiques — Points de défaillance
|
||||
|
||||
**1. Auth Flow** (Register -> Login -> JWT -> Refresh)
|
||||
- SPOF : PostgreSQL (stockage users/sessions)
|
||||
- Timeouts : Configurés (middleware timeout global)
|
||||
- Retry : Refresh token automatique côté frontend (intercepteur Axios)
|
||||
- Fallback : Rate limiting en mémoire si Redis down
|
||||
- Race condition : Token refresh concurrent — géré par mutex dans le frontend interceptor
|
||||
|
||||
**2. Upload Flow** (Frontend -> API -> ClamAV -> S3)
|
||||
- SPOF : ClamAV (scan antivirus), MinIO/S3 (stockage)
|
||||
- Timeouts : `exec.CommandContext` avec context pour FFmpeg
|
||||
- Retry : Chunked upload avec resume (`/tracks/resume/:uploadId`)
|
||||
- Fallback : `CLAMAV_REQUIRED=false` permet de bypasser le scan en dev
|
||||
- Race condition : Upload concurrent du même fichier — ID unique par upload
|
||||
|
||||
**3. Playback Flow** (Frontend -> Stream Server -> HLS -> Player)
|
||||
- SPOF : Stream server Rust (single instance en dev), FFmpeg
|
||||
- Timeouts : Non explicitement configurés pour le stream server
|
||||
- Retry : hls.js gère les retries nativement
|
||||
- Fallback : Dev mode renvoie des segments factices
|
||||
- **RISQUE** : JWT issuer/audience mismatch entre Go et Rust (cf. Section 4)
|
||||
|
||||
**4. Payment Flow** (Frontend -> API -> Hyperswitch -> Webhook)
|
||||
- SPOF : Hyperswitch (payment router)
|
||||
- Timeouts : HTTP client avec timeout configuré
|
||||
- Retry : Webhook delivery avec retry intégré
|
||||
- Fallback : `HYPERSWITCH_ENABLED=false` désactive les paiements
|
||||
- Idempotence : Webhook signature HMAC-SHA512 vérifiée
|
||||
|
||||
**5. Chat Flow** (Frontend -> WebSocket -> Go Hub -> Redis PubSub)
|
||||
- SPOF : Redis (PubSub, présence)
|
||||
- Timeouts : WebSocket ping/pong configuré
|
||||
- Retry : Reconnection automatique côté frontend
|
||||
- Fallback : Chat fonctionne sans Redis (mode dégradé, pas de cross-instance)
|
||||
- Race condition : Messages concurrents gérés par le Hub pattern
|
||||
|
||||
---
|
||||
|
||||
## 2. CE QUE LE PRODUIT PERMET RÉELLEMENT
|
||||
|
||||
### 2.1 Classification des features
|
||||
|
||||
#### Fonctionnelles (flux complet front + back + DB + tests)
|
||||
|
||||
| Feature | Backend | Frontend | Tests | Preuve |
|
||||
|---------|---------|----------|-------|--------|
|
||||
| Auth (register, login, JWT, refresh, logout) | Routes + services + middleware | Login/Register pages + authStore | 306 test files Go, E2E Playwright | `routes_core.go`, `auth.go`, `jwt_service.go` |
|
||||
| 2FA (TOTP) | Setup/Verify/Disable handlers | 2FA settings UI | Unit tests | `two_factor_handler.go`, `two_factor_service.go` |
|
||||
| OAuth (Google, GitHub, Discord, Spotify) | PKCE, circuit breaker | OAuth buttons + callback | Service tests | `oauth_service.go` |
|
||||
| User profiles | CRUD, avatar, social links, follow/block | Profile pages + components | Tests | `routes_users.go`, `user_service.go` |
|
||||
| Upload audio | Chunked upload, ClamAV scan, S3 storage | Upload components + progress | Handler tests | `upload.go`, `upload_validator.go` |
|
||||
| CRUD Tracks | Create, read, update, delete, batch ops | Track list/detail pages | Tests + E2E | `routes_tracks.go`, `track/service.go` |
|
||||
| Playlists | CRUD, collaborators, share links, ordering | Playlist pages + drag-drop | Tests + E2E | `routes_playlists.go`, `playlist_service.go` |
|
||||
| Chat WebSocket | Hub pattern, Redis PubSub, presence | Chat page + real-time messages | Tests | `websocket/chat/`, `routes_chat` in `router.go` |
|
||||
| Dashboard | Stats, analytics | Dashboard page + charts (Recharts) | Tests | `dashboard_handler.go` |
|
||||
| Search | Full-text (pg_trgm), suggestions | Search page + filters | Tests | `track_search_service.go` |
|
||||
| Social (posts, feed, groups, follows) | CRUD + feed algorithm | Social pages + components | Tests | `routes_social.go`, `social/service.go` |
|
||||
| Marketplace (products, orders, payments) | Hyperswitch integration | Product listing + checkout | Tests | `routes_marketplace.go`, `marketplace/service.go` |
|
||||
| Notifications | Push + in-app | Notification center | Tests | `notification_handler.go` |
|
||||
| Webhooks | Delivery, signature, retry | Webhook management UI | Tests | `routes_webhooks.go`, `webhook_service.go` |
|
||||
| Gear/Inventory | CRUD gear items + images | Gear pages | Tests | `gear_handler.go` |
|
||||
| Analytics | Playback analytics, aggregation | Analytics dashboard | Tests | `playback_analytics_handler.go` |
|
||||
| Admin (reports, maintenance, flags, transfers) | Admin routes + RBAC | Admin pages | Tests | `routes_core.go` admin section |
|
||||
| Sessions management | CRUD, logout-all, stats | Sessions settings page | Tests | `session_service.go` |
|
||||
|
||||
#### Partiellement implémentées
|
||||
|
||||
| Feature | Statut | Détail |
|
||||
|---------|--------|--------|
|
||||
| HLS Streaming | Backend OK, stream server real FFmpeg | Frontend hls.js intégré, mais JWT mismatch Go/Rust empêche l'auth | `streaming/hls.rs`, `auth/mod.rs` |
|
||||
| Live Streaming | Routes backend + stream server | Frontend pages existent, dépend du stream server | `routes_core.go`, `live_stream` handlers |
|
||||
| Cloud Storage | Backend CRUD + S3 | Frontend pages + share links | Opérationnel mais feature flag masquée | `cloud_handler.go` |
|
||||
| GDPR Export | Backend async export | Frontend trigger + download | Long-running avec `context.Background()` | `gdpr_export.go` |
|
||||
|
||||
#### Fantômes (déclarées mais non fonctionnelles)
|
||||
|
||||
| Feature | Déclarée où | Réalité |
|
||||
|---------|------------|---------|
|
||||
| WebRTC Audio Calls | `FEATURE_STATUS.md` "WebRTC Beta" | Code Rust (~500 LOC) mais dépendance `webrtc = "0.7"` commentée. Signaling seulement, aucun média P2P. |
|
||||
| 2FA SMS | Planifié v0.104 | Aucun code SMS trouvé |
|
||||
| Passkeys/WebAuthn | Planifié v0.104 | Aucun code trouvé |
|
||||
| Electron Desktop | Mentionné dans les règles | Aucun code Electron trouvé, `.gitignore` only |
|
||||
|
||||
#### Code mort
|
||||
|
||||
| Élément | LOC estimé | Détail |
|
||||
|---------|-----------|--------|
|
||||
| `veza-stream-server/src/streaming/webrtc.rs` + `webrtc/config.rs` | ~500 | WebRTC sans dépendance native, jamais appelable |
|
||||
| `veza-stream-server/src/soundcloud/` (5 fichiers) | ~4000 | Discovery, playback, creator, management, social — module "SoundCloud-like" mais aucune route ne l'expose |
|
||||
| `k8s/chat-server/` | ~100 yaml | Manifestes pour service supprimé en v0.502 |
|
||||
| `Makefile.old` | ~200 | Ancien Makefile remplacé |
|
||||
| `chat_exports/`, `sub_task_agents/`, `tmt/`, `full_veza_audit_data/` | ~500 | Artefacts orphelins |
|
||||
| `internal/features/features.go` | 3 | Stub vide, feature flags implémentées ailleurs |
|
||||
|
||||
**Total code mort estimé** : ~5300 LOC
|
||||
|
||||
### 2.2 Incohérences produit/code
|
||||
|
||||
| Incohérence | Détail | Impact |
|
||||
|-------------|--------|--------|
|
||||
| **Version annoncée vs réelle** | Le prompt mentionne "v0.402 Phase 4 Commerce". Le code est v1.0.2. | Le projet a significativement avancé depuis le contexte du prompt. |
|
||||
| **JWT issuer/audience mismatch** | Go backend émet `iss: veza-api, aud: veza-app`. Stream server Rust attend `iss: veza-platform, aud: veza-services`. | Les tokens émis par le backend échoueront la validation dans le stream server. HLS auth cassé. |
|
||||
| **Password policy frontend vs backend** | Frontend valide 8 chars minimum. Backend rejette < 12 chars. | UX confuse : le formulaire accepte, le serveur rejette. |
|
||||
| **Feature flags runtime** | `internal/features/features.go` est un stub vide. Les feature flags sont en DB via `admin/feature-flags`. | Le stub crée de la confusion ; un développeur pourrait l'importer par erreur. |
|
||||
| **`onCreateProduct` no-op** | `routeConfig.tsx` : `onCreateProduct={() => {}}` dans le seller dashboard. | Le bouton "créer produit" depuis le seller dashboard ne fait rien. |
|
||||
|
||||
---
|
||||
|
||||
## 3. VALIDATION FONCTIONNELLE APPROFONDIE
|
||||
|
||||
### 3.1 Couverture de tests
|
||||
|
||||
| Service | Fichiers test | Fichiers code | Ratio | Couverture CI |
|
||||
|---------|--------------|---------------|-------|---------------|
|
||||
| Go backend | 306 `*_test.go` | 472 `.go` (non-test) | 0.65 | `go test ./...` en CI |
|
||||
| Rust stream | ~90 `#[test]` fonctions | 138 `.rs` | inline | `cargo test` en CI |
|
||||
| Frontend unit | 273 `.test.ts/.tsx` | 1614 `.ts/.tsx` (non-test) | 0.17 | `vitest --run` en CI |
|
||||
| Frontend stories | 300 `.stories.tsx` | ~1200 composants | 0.25 | Storybook build + audit en CI |
|
||||
| Frontend E2E | 26 `.spec.ts` | - | - | Playwright avec backend réel |
|
||||
|
||||
**Seuils de couverture frontend** (`vitest.config.ts`) : 50% minimum (branches, functions, lines, statements). Seuil bas mais raisonnable pour un MVP.
|
||||
|
||||
**Tests désactivés / skip** : Aucun `skip` ou `.only` trouvé dans le code Go. Pas de `.skip` systématique dans Vitest.
|
||||
|
||||
**MSW vs API réelle** : ~100% des tests unitaires frontend utilisent MSW. Les 26 tests E2E Playwright utilisent le backend Go réel avec PostgreSQL/Redis en CI.
|
||||
|
||||
### 3.2 Error handling
|
||||
|
||||
**Backend Go** :
|
||||
- **Pattern principal** : `RespondWithAppError` / `RespondWithError` avec codes d'erreur structurés
|
||||
- **Incohérence** : ~12 handlers utilisent encore `c.JSON(status, gin.H{"error": "..."})` au lieu du pattern standardisé
|
||||
- **Fichiers concernés** : `account_deletion_handler.go`, `comment_handler.go`, `search_handlers.go`, `tag_handler.go`, `sell_handler.go`, `admin_transfer_handler.go`, `cloud_handler.go`
|
||||
- **Impact** : Réponses d'erreur inconsistantes pour le frontend
|
||||
|
||||
**Rust stream server** :
|
||||
- Utilise `thiserror` pour les types d'erreur custom et `anyhow` pour la propagation
|
||||
- Error handler Axum centralisé via `error.rs` (783 lignes, complet)
|
||||
|
||||
**Frontend React** :
|
||||
- Error boundaries configurés dans le routing
|
||||
- Logger custom remplace `console.error`
|
||||
- Intercepteur Axios gère 401 (refresh/logout), 429 (rate limit store), 5xx (retry)
|
||||
|
||||
### 3.3 Validation input
|
||||
|
||||
**Backend** : Double validation — `go-playground/validator/v10` pour les structs, validations manuelles dans les services. Password policy stricte (12 chars, complexité, blocklist). File uploads validés par ClamAV.
|
||||
|
||||
**Frontend** : Zod schemas + react-hook-form pour la validation côté client. Env vars validées au démarrage via Zod.
|
||||
|
||||
### 3.4 Pagination
|
||||
|
||||
Les listes utilisent offset-based pagination avec `page` et `limit` query params. Pas de cursor-based pagination. Limite max non explicitement vérifiée dans tous les handlers — risque de requêtes avec `limit=100000`.
|
||||
|
||||
### 3.5 Points de rupture probables
|
||||
|
||||
| Scénario | Impact | Mitigation |
|
||||
|----------|--------|------------|
|
||||
| 10K tracks dans la DB | Requêtes de recherche pg_trgm potentiellement lentes | Index GIN configurés (`048_search_indexes.sql`) |
|
||||
| 100K users | Listes utilisateurs paginées, OK | - |
|
||||
| 1M messages chat | Pas de pagination serveur explicite dans le chat | Risque : chargement mémoire du Hub |
|
||||
| Fichier non-audio uploadé | ClamAV scan + validation MIME type | Extension validée, magic bytes si ClamAV actif |
|
||||
| Fichier > 10GB | Pas de limite explicite dans le code d'upload | Devrait être configuré au niveau proxy/nginx |
|
||||
| 1000 WebSocket simultanées | Chat Hub en mémoire Go (goroutines légères) | OK pour Go, limite Redis PubSub potentielle |
|
||||
| Webhook replay (3x même event) | `ProcessPaymentWebhook` idempotent — vérifie statut existant | OK |
|
||||
| Token expiré mid-session | Intercepteur Axios refresh transparent, retry queue | OK |
|
||||
| Migration échoue à moitié | Migrations non transactionnelles (extensions hors transaction) | Risque de schéma partiel |
|
||||
| Redis down | Rate limiting fallback en mémoire, chat dégradé (single-instance) | OK mais perte de cross-instance |
|
||||
|
||||
---
|
||||
|
||||
## 4. AUDIT DE SÉCURITÉ
|
||||
|
||||
### 4.0 Registre des vulnérabilités
|
||||
|
||||
| ID | Catégorie | Gravité | Fichier(s) | Description | Impact | Correctif | Effort |
|
||||
|----|-----------|---------|------------|-------------|--------|-----------|--------|
|
||||
| VEZA-SEC-001 | A02 Crypto | **Critique** | `veza-common/src/config_rust.rs:234` | Secret JWT par défaut `"your-super-secret-jwt-key"` en fallback dans `JwtConfig::default()` | Si un service Rust démarre sans `JWT_SECRET` env, tous les tokens sont signés avec un secret prévisible | Supprimer le default ou panic si absent | S |
|
||||
| VEZA-SEC-002 | A04 Design | **Critique** | `veza-stream-server/src/auth/mod.rs:150-151` vs `veza-backend-api/internal/services/jwt_service.go` | JWT issuer/audience mismatch : Go émet `iss:veza-api, aud:veza-app`, Rust attend `iss:veza-platform, aud:veza-services` | Tokens émis par Go invalides dans le stream server. HLS streaming authentifié cassé. | Aligner les valeurs iss/aud entre Go et Rust, ou utiliser le stream token dédié | M |
|
||||
| VEZA-SEC-003 | A05 Config | **Elevée** | `veza-stream-server/src/main.rs:74` | `shutdown_signal` reçoit un **nouvel** `AppState` au lieu de celui en cours d'exécution | Shutdown ne ferme pas correctement les connexions WebSocket ni l'event bus du state actif | Passer le même `AppState` à `shutdown_signal` | S |
|
||||
| VEZA-SEC-004 | A04 Design | **Elevée** | `veza-backend-api/internal/api/routes_webhooks.go:31` | Webhook worker goroutine démarré avec `context.Background()`, non enregistré dans le shutdown manager | Goroutine fuite au redéploiement. Webhooks en cours de livraison perdus. | Enregistrer dans `shutdownManager.Register` avec context annulable | S |
|
||||
| VEZA-SEC-005 | A04 Design | **Moyenne** | `apps/web/src/lib/passwordValidator.ts` vs `internal/validators/password_validator.go` | Frontend accepte 8 chars, backend rejette < 12 chars | UX confuse, formulaire accepte puis serveur rejette | Aligner frontend sur 12 chars min | S |
|
||||
| VEZA-SEC-006 | A05 Config | **Moyenne** | Routes `/metrics`, `/metrics/aggregated`, `/system/metrics` | Métriques Prometheus exposées publiquement sans auth | Information disclosure : un attaquant peut observer les patterns de charge, DB pool, error rates | Protéger par auth ou réseau interne en prod | S |
|
||||
| VEZA-SEC-007 | A07 Auth | **Moyenne** | `veza-backend-api/internal/services/password_reset_service.go:47,73,126,160` | Utilisation de `context.Background()` au lieu du context de la requête | Opérations DB non liées au cycle de vie de la requête (timeout ignoré, cancellation ignorée) | Propager `c.Request.Context()` | S |
|
||||
| VEZA-SEC-008 | A04 Design | **Faible** | `apps/web/src/router/routeConfig.tsx` | `onCreateProduct={() => {}}` — callback no-op dans le seller dashboard | Bouton visible mais inopérant, UX cassée | Connecter au vrai handler de création | S |
|
||||
| VEZA-SEC-009 | A06 Components | **Faible** | `veza-stream-server/Cargo.toml` | `dotenv 0.15` — dernière release 2020 | Dépendance potentiellement non maintenue | Migrer vers `dotenvy` | S |
|
||||
|
||||
### 4.1 A01 — Broken Access Control
|
||||
|
||||
**Routes protégées** : Exhaustivement auditées (cf. Section 1.4 routes). Toutes les routes de mutation (POST/PUT/DELETE) sont derrière `RequireAuth`. Les routes admin ajoutent `RequireAdmin`. Les routes de modification de ressource utilisent `RequireOwnershipOrAdmin`.
|
||||
|
||||
**IDOR** : Protégé par `RequireOwnershipOrAdmin` sur users, tracks, playlists, products. Le resolver charge le propriétaire depuis la DB et compare avec `userID` du JWT.
|
||||
|
||||
**CORS** : Strict en production — whitelist explicite requise, wildcard interdit avec credentials. Validation fail-fast au démarrage.
|
||||
|
||||
**Rate limiting** : Multi-couche (DDoS global 1000 req/s, per-IP 100 req/s, per-endpoint login/register, per-user, upload 10/heure).
|
||||
|
||||
**WebSocket auth** : Chat utilise JWT via header. Stream server utilise query param `?token=` — ce token est un stream token dédié à durée courte (5 min), pas le JWT principal.
|
||||
|
||||
**Verdict A01** : Solide. Pas de faille IDOR identifiée.
|
||||
|
||||
### 4.2 A02 — Cryptographic Failures
|
||||
|
||||
**Hashing mots de passe** : bcrypt cost 12, conforme aux recommandations OWASP (>= 10).
|
||||
|
||||
**JWT** : HS256 (HMAC-SHA256). Secret minimum 32 chars, validé au démarrage. Durée access token : 5 min (court, bon). Refresh token : 14 jours (30 si "remember me"). Token versioning pour révocation.
|
||||
|
||||
**Secrets en dur** : Un seul trouvé en production — `veza-common/src/config_rust.rs:234` (cf. VEZA-SEC-001). Les autres sont dans les tests uniquement.
|
||||
|
||||
**Secrets dans Git** : `.env` correctement dans `.gitignore`. Pas de secret trouvé dans l'historique Git (validé par les fichiers `.env.example`).
|
||||
|
||||
**Données sensibles en clair** : Logger Go avec filtrage des secrets (`internal/logging/secret_filter.go`). Pas de tokens dans les logs.
|
||||
|
||||
**Verdict A02** : Bon, sauf VEZA-SEC-001.
|
||||
|
||||
### 4.3 A03 — Injection
|
||||
|
||||
**SQL Injection** : GORM utilisé partout en production. Raw SQL uniquement dans les tests (`testutils/db.go`) avec table whitelist. Pas de `fmt.Sprintf` dans les requêtes SQL de production.
|
||||
|
||||
**Command Injection** : `exec.CommandContext` utilisé pour FFmpeg avec `ValidateExecPath`. Pas d'interpolation de string dans les commandes.
|
||||
|
||||
**XSS** : DOMPurify côté frontend pour `dangerouslySetInnerHTML` (3 usages, tous sanitisés). Tags autorisés : `p, br, strong, em, u, i, b, ul, ol, li, span, a`. Attributs interdits : `onerror, onload, onclick`.
|
||||
|
||||
**Path Traversal** : Noms de fichiers sanitisés dans l'upload service. UUID comme nom de fichier en stockage.
|
||||
|
||||
**Verdict A03** : Bon. Pas d'injection identifiée.
|
||||
|
||||
### 4.4 A04 — Insecure Design
|
||||
|
||||
**Principaux risques identifiés** :
|
||||
- JWT issuer/audience mismatch (VEZA-SEC-002)
|
||||
- Webhook worker lifecycle (VEZA-SEC-004)
|
||||
- Pagination sans limite max explicite
|
||||
|
||||
**Business logic** : Les ordres de paiement vérifient le statut existant avant de retraiter un webhook (idempotence). Promo codes validés côté serveur. Pas de prix négatif possible (validation struct Go).
|
||||
|
||||
**Enumeration** : Les erreurs de login ne distinguent pas "user inexistant" de "mot de passe incorrect" — conforme aux bonnes pratiques.
|
||||
|
||||
### 4.5 A05 — Security Misconfiguration
|
||||
|
||||
**Security headers** : Complets (HSTS, CSP strict pour API, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy restrictive).
|
||||
|
||||
**Debug mode** : Swagger désactivé en production. pprof derrière `RequireAdmin` et uniquement hors production.
|
||||
|
||||
**CORS** : Strict en production. `CORSDefault()` panic en production pour forcer la configuration explicite.
|
||||
|
||||
**Docker** : Secrets via env avec `:?` (required). Pas de secrets dans les layers Docker.
|
||||
|
||||
**Métriques exposées** : `/metrics` public (VEZA-SEC-006).
|
||||
|
||||
### 4.6 A06 — Vulnerable & Outdated Components
|
||||
|
||||
CI exécute automatiquement : `govulncheck` (Go), `cargo audit` (Rust), `npm audit --audit-level=critical` (Node). Dependabot configuré. Seule préoccupation : `dotenv 0.15` (VEZA-SEC-009).
|
||||
|
||||
### 4.7 A07 — Identification & Authentication Failures
|
||||
|
||||
**Password policy** : 12 chars, complexité, blocklist de 25 mots de passe courants, rejet patterns répétitifs/séquentiels. Robuste.
|
||||
|
||||
**Brute force** : Rate limiting sur `/auth/login` (configurable `AUTH_RATE_LIMIT_LOGIN_ATTEMPTS` / `AUTH_RATE_LIMIT_LOGIN_WINDOW`). Account lockout (`ACCOUNT_LOCKOUT_EXEMPT_EMAILS` pour tests).
|
||||
|
||||
**JWT validation** : Signature, expiration, issuer, audience vérifiés. Token versioning pour révocation.
|
||||
|
||||
**Refresh token** : Rotation via token versioning. Stockage en httpOnly cookies (pas localStorage). Révocation via token blacklist Redis.
|
||||
|
||||
**OAuth** : State parameter + PKCE. Domaines de redirect en whitelist. Circuit breaker sur les appels externes.
|
||||
|
||||
**Sessions** : Page de gestion des sessions, logout-all, logout-others. Révocation effective via token version.
|
||||
|
||||
### 4.8 A08 — Software & Data Integrity Failures
|
||||
|
||||
**Webhooks** : Hyperswitch HMAC-SHA512 vérifié avec constant-time comparison. Secret vide = 500 (pas de traitement).
|
||||
|
||||
**File uploads** : ClamAV scan obligatoire en production (`CLAMAV_REQUIRED=true`).
|
||||
|
||||
**Migrations** : Non transactionnelles pour les extensions (`CREATE EXTENSION` ne supporte pas les transactions dans certains cas). Risque de schéma partiel si une migration échoue.
|
||||
|
||||
### 4.9 A09 — Security Logging & Monitoring
|
||||
|
||||
**Audit trail** : Middleware audit logge les actions POST/PUT/DELETE avec user ID, IP, endpoint, timestamp (`audit.go`). Logs d'audit consultables via routes admin.
|
||||
|
||||
**Log level** : Configurable. Production interdit `LOG_LEVEL=DEBUG` (validation config). Filtrage des secrets dans les logs (`secret_filter.go`).
|
||||
|
||||
**Request ID** : Propagé via middleware `request_id.go`. Header `X-Request-ID` dans les réponses.
|
||||
|
||||
**Monitoring** : Prometheus metrics configurées. Alertmanager + Grafana dans le stack production.
|
||||
|
||||
### 4.10 A10 — Server-Side Request Forgery (SSRF)
|
||||
|
||||
Pas de SSRF identifié. Le backend ne fait pas de requêtes vers des URLs fournies par l'utilisateur. Les webhooks sortants utilisent des URLs enregistrées par l'utilisateur authentifié — pas de filtrage IP privée, ce qui pourrait théoriquement être exploité pour scanner le réseau interne.
|
||||
|
||||
### 4.11 Sécurité spécifique à la stack
|
||||
|
||||
**Go** :
|
||||
- `defer` correctement utilisé pour les ressources DB et fichiers
|
||||
- `context.Context` propagé dans la majorité des cas (sauf `password_reset_service.go`)
|
||||
- Goroutines avec lifecycle géré via `shutdownManager` (sauf webhook worker)
|
||||
- Pas de race conditions évidentes (Hub pattern thread-safe)
|
||||
|
||||
**Rust** :
|
||||
- Aucun bloc `unsafe` dans le code applicatif
|
||||
- ~15-20 `unwrap()` en production, principalement dans l'initialisation (safe) ou avec fallback `unwrap_or`
|
||||
- `panic!` dans les env vars requises au démarrage (acceptable)
|
||||
- `Default::default()` pour `TokenValidator` et `Config` paniquent en production (gated par `cfg(not(debug_assertions))`)
|
||||
|
||||
**React** :
|
||||
- `dangerouslySetInnerHTML` : 3 usages, tous avec DOMPurify
|
||||
- Tokens : httpOnly cookies, pas de localStorage pour les tokens d'auth
|
||||
- `console.log` : remplacé par logger custom, 0 usage brut en production
|
||||
|
||||
---
|
||||
|
||||
## 5. DETTE TECHNIQUE
|
||||
|
||||
### 5.1 Registre de la dette technique
|
||||
|
||||
| ID | Catégorie | Description | Impact | Fichier(s) | Effort |
|
||||
|----|-----------|-------------|--------|------------|--------|
|
||||
| DT-001 | Critique | JWT issuer/audience mismatch Go/Rust empêche l'auth HLS | HLS streaming non fonctionnel en production | `jwt_service.go`, `auth/mod.rs` | M |
|
||||
| DT-002 | Critique | Secret JWT par défaut dans `veza-common` | Faille de sécurité potentielle | `config_rust.rs:234` | S |
|
||||
| DT-003 | Structurante | ~5300 LOC de code mort (WebRTC, soundcloud/, k8s/chat-server, orphelins) | Confusion, coût maintenance | Multiples | M |
|
||||
| DT-004 | Structurante | Error handling inconsistant — 12 handlers utilisent `gin.H` au lieu de `RespondWithAppError` | Frontend doit gérer 2 formats d'erreur | `account_deletion_handler.go`, etc. | M |
|
||||
| DT-005 | Structurante | 139 fichiers > 500 lignes (78 Go, 41 Rust, 20 TS/TSX) | Complexité de maintenance | `track/service.go` (1147), `marketplace/service.go` (1142), etc. | L |
|
||||
| DT-006 | Structurante | `features.go` est un stub vide alors que les feature flags sont en DB | Confusion architecturale | `internal/features/features.go` | S |
|
||||
| DT-007 | Structurante | `shutdown_signal` reçoit un nouvel `AppState` dans `main.rs` | Shutdown ne ferme pas les connexions WebSocket correctement | `main.rs:74` | S |
|
||||
| DT-008 | Opérationnelle | Webhook worker goroutine non enregistré dans le shutdown manager | Goroutine leak au redéploiement | `routes_webhooks.go:31` | S |
|
||||
| DT-009 | Opérationnelle | `context.Background()` dans `password_reset_service.go` | Timeouts ignorés | 4 endroits | S |
|
||||
| DT-010 | Opérationnelle | Pagination sans limite max — `limit=100000` possible | Requêtes DB excessives | Tous les handlers de liste | M |
|
||||
| DT-011 | Opérationnelle | Migrations non transactionnelles | Risque de schéma partiel si une migration échoue | `database/migrations.go` | L |
|
||||
| DT-012 | Opérationnelle | 335 TODO, 9 FIXME, 12 HACK dans le codebase | Indicateur de travail non terminé | Répartis sur 3 langages | XL |
|
||||
| DT-013 | Opérationnelle | Password policy mismatch frontend/backend | UX dégradée | `passwordValidator.ts`, `password_validator.go` | S |
|
||||
| DT-014 | Opérationnelle | `onCreateProduct={() => {}}` no-op dans routeConfig | Bouton seller inopérant | `routeConfig.tsx` | S |
|
||||
| DT-015 | Cosmétique | `dotenv 0.15` (2020) dans le stream server Rust | Dépendance potentiellement non maintenue | `Cargo.toml` | S |
|
||||
| DT-016 | Cosmétique | 285 fichiers de documentation — certains obsolètes | Surcharge informationnelle | `docs/` | M |
|
||||
| DT-017 | Cosmétique | `Makefile.old` toujours présent | Confusion | Racine | S |
|
||||
|
||||
### 5.2 Métriques de dette
|
||||
|
||||
| Métrique | Valeur |
|
||||
|----------|--------|
|
||||
| LOC total (code source) | ~319K |
|
||||
| LOC mort estimé | ~5300 (1.7%) |
|
||||
| Ratio test/code (Go) | 0.65 (306 tests / 472 fichiers code) |
|
||||
| Ratio test/code (Frontend) | 0.17 (273 tests / 1614 fichiers code) |
|
||||
| Stories / Composants | 0.25 (300 / ~1200) |
|
||||
| Fichiers > 500 lignes | 139 (78 Go, 41 Rust, 20 TS/TSX) |
|
||||
| TODO/FIXME/HACK | 356 total (335 TODO, 9 FIXME, 12 HACK) |
|
||||
| Deps directes (tous services) | ~195 (45 Go + 78 Rust + 72 Frontend) |
|
||||
| Deps avec vulnérabilités connues | 0 (CI scanne automatiquement) |
|
||||
|
||||
### 5.3 Hétérogénéité Go + Rust
|
||||
|
||||
Le choix de Go **et** Rust est la décision architecturale la plus discutable du projet :
|
||||
|
||||
**Justification originale** (ADR-002) : Le chat server Rust a été migré vers Go en v0.502, reconnaissant que le surcoût de Rust n'était pas justifié pour le chat. Le stream server Rust est conservé pour les performances audio (transcoding, HLS).
|
||||
|
||||
**Évaluation** : Le stream server Rust représente ~103K LOC mais sa valeur ajoutée réelle se limite à l'appel FFmpeg (`exec.CommandContext` en Go ferait la même chose) et au serving HLS (servir des fichiers statiques n'exige pas Rust). Le code "SoundCloud-like" (~4K LOC dans `soundcloud/`) n'est pas exposé par les routes.
|
||||
|
||||
**Coût** : Maintenir 2 langages backend (Go + Rust) triple la complexité de recrutement, double les outils CI, et crée des incohérences inter-services (cf. JWT mismatch).
|
||||
|
||||
**Recommandation** : Évaluer la migration du stream server vers Go à moyen terme. À court terme, corriger le JWT mismatch et nettoyer le code mort Rust.
|
||||
|
||||
---
|
||||
|
||||
## 6. QUALITÉ ARCHITECTURALE
|
||||
|
||||
### 6.1 Monorepo
|
||||
|
||||
| Critère | Évaluation |
|
||||
|---------|------------|
|
||||
| Outil de gestion | npm workspaces + Turborepo. Config minimale (3 tâches). Pas de cache remote. |
|
||||
| Build orchestration | Turbo parallélise build/test/lint. Builds Docker séparés. |
|
||||
| Versionning | Fichier `VERSION` à la racine (1.0.2). Pas de versionning par service. |
|
||||
| Dépendances internes | `veza-common` (Rust) utilisé par `veza-stream-server`. `packages/design-system` par `apps/web`. |
|
||||
| Workspace config | npm workspaces (pas pnpm). `package-lock.json` à la racine. |
|
||||
| Makefile | Modulaire (11 fichiers dans `make/`). Cible `help` disponible. |
|
||||
|
||||
### 6.2 Frontend (React/Vite)
|
||||
|
||||
| Critère | Score | Détail |
|
||||
|---------|-------|--------|
|
||||
| Structure | 8/10 | Feature-based (`src/features/`, `src/components/`). Claire et organisée. |
|
||||
| State management | 8/10 | Zustand (6 stores), léger et bien séparé. React Query pour les données serveur. |
|
||||
| Data fetching | 8/10 | TanStack React Query avec Axios. Intercepteurs pour refresh, rate limit, retry. |
|
||||
| Routing | 7/10 | React Router 6 avec lazy loading via `LazyComponent`. Code splitting configuré dans Vite. |
|
||||
| TypeScript | 8/10 | `strict: true` avec `noUncheckedIndexedAccess`. ~150 `any` restants (principalement tests et generated). |
|
||||
| Storybook | 8/10 | 300 stories, MSW intégré, 3 viewports, addon a11y. CI valide le build. |
|
||||
| Accessibilité | 7/10 | ARIA, roles, tabIndex largement utilisés. ESLint jsx-a11y configuré. |
|
||||
| Bundle analysis | 6/10 | Manual chunks dans Vite (React, TanStack, lucide). Rollup visualizer en build. |
|
||||
| MSW coverage | 9/10 | 11 handler modules couvrant toutes les features. Catch-all pour les routes non mockées. |
|
||||
| DOMPurify | 10/10 | 3 usages de `dangerouslySetInnerHTML`, tous sanitisés. |
|
||||
|
||||
### 6.3 Backend Go
|
||||
|
||||
| Critère | Score | Détail |
|
||||
|---------|-------|--------|
|
||||
| Architecture | 8/10 | Handler -> Service -> Repository bien séparé. Clean architecture. |
|
||||
| Error handling | 6/10 | Pattern `RespondWithAppError` existe mais 12 handlers utilisent encore `gin.H`. |
|
||||
| Middleware stack | 9/10 | 15+ middlewares dans le bon ordre. Auth, CORS, rate limit, security headers, CSRF. |
|
||||
| Database | 8/10 | Connection pooling (50 max, 12 idle). Migrations SQL. Read replica supporté. |
|
||||
| Concurrency | 7/10 | Goroutines gérées via `shutdownManager` (sauf webhook worker). Context propagé. |
|
||||
| Configuration | 8/10 | Env vars avec validation au démarrage. Fail-fast en production. Secrets filtrés. |
|
||||
| API versioning | 7/10 | `/api/v1/` partout. `VersionMiddleware` présent. Pas de plan v2 explicite. |
|
||||
| OpenAPI | 7/10 | Swagger generé (`swaggo`). Frontend types generées depuis l'OpenAPI spec. Validation types sync en CI. |
|
||||
|
||||
### 6.4 Stream Server Rust
|
||||
|
||||
| Critère | Score | Détail |
|
||||
|---------|-------|--------|
|
||||
| HLS | 7/10 | Réel (FFmpeg). Dev-only fallbacks pour les segments manquants. |
|
||||
| WebRTC | 1/10 | Session management sans stack média. Non fonctionnel. |
|
||||
| Compilation | 7/10 | Build musl static. `Cargo.lock` versionné. Pas de `sqlx-data.json`. |
|
||||
| Error handling | 7/10 | `thiserror` + `anyhow`. 783 lignes dans `error.rs`. |
|
||||
| Tests | 5/10 | ~90 tests inline. Pas de tests d'intégration avec DB. |
|
||||
| Code mort | 3/10 | ~4500 LOC dans `soundcloud/` + `webrtc.rs` non exposées. |
|
||||
|
||||
### 6.5 Base de données
|
||||
|
||||
| Critère | Évaluation |
|
||||
|---------|------------|
|
||||
| Schéma | 95 migrations, normalisé, UUID primary keys. FK constraints. |
|
||||
| Indexes | Index GIN pour pg_trgm search. Index composite (`049_composite_indexes.sql`). Performance indexes (`920`, `940`). |
|
||||
| Migrations | Numérotation non continue (gap 019-020, 050-060, 066-069, etc.). Down migrations pour certaines seulement. |
|
||||
| Redis | Cache, rate limiting, sessions, token blacklist, chat PubSub, CSRF tokens, presence. TTL configurés. |
|
||||
| N+1 | `Preload` utilisé correctement dans la majorité des cas. 1 risque identifié dans `analytics_aggregation_service.go`. |
|
||||
|
||||
### 6.6 Scores détaillés
|
||||
|
||||
| Dimension | Score | Justification |
|
||||
|-----------|-------|---------------|
|
||||
| **Architecture** | 7/10 | Bonne séparation des concerns. Go clean architecture. Rust plus chaotique (soundcloud/, webrtc dead code). Le choix Go+Rust ajoute de la complexité injustifiée. |
|
||||
| **Maintenabilité** | 5/10 | 139 fichiers > 500 lignes, 356 TODO/FIXME/HACK, error handling inconsistant, 2 langages backend. Documentation abondante (285 docs) mais parfois obsolète. |
|
||||
| **Sécurité** | 7/10 | httpOnly cookies, bcrypt cost 12, rate limiting multi-couche, security headers complets, CSRF, ClamAV. Mais : JWT secret default (VEZA-SEC-001), issuer mismatch (VEZA-SEC-002). |
|
||||
| **Scalabilité** | 5/10 | Single instance par service, pas de load balancer inter-service (sauf HAProxy). Redis SPOF. PostgreSQL sans réplication configurée (read replica supporté mais non déployé). Pas de sharding. |
|
||||
| **Testabilité** | 7/10 | 306 tests Go, 273 tests frontend, 300 stories, 26 E2E. MSW complet. Couverture seuil 50%. CI automatisée avec govulncheck/cargo audit/npm audit. |
|
||||
| **Opérabilité** | 7/10 | Docker multi-stage, blue-green HAProxy, health checks, Prometheus/Grafana configs, Alertmanager, request ID, structured logging, Sentry. k8s templates prêts. |
|
||||
| **Vélocité dev** | 4/10 | 2 langages backend = barrière à l'entrée. ~319K LOC. Makefile modulaire aide. Storybook-first accélère l'UI. Un nouveau dev aura besoin de 2-3 semaines pour être productif (Go OR Rust, pas les deux). |
|
||||
| **Maturité produit** | 6/10 | 19 features opérationnelles sur ~22 déclarées. HLS partiellement cassé (JWT mismatch). WebRTC non fonctionnel. Payment flow opérationnel mais en mode test. |
|
||||
|
||||
---
|
||||
|
||||
## 7. INFRASTRUCTURE & DEVOPS
|
||||
|
||||
### 7.1 Docker
|
||||
|
||||
| Critère | Backend Go | Stream Rust | Frontend |
|
||||
|---------|-----------|-------------|----------|
|
||||
| Multi-stage | Oui (golang:1.24-alpine -> alpine:3.21) | Oui (rust:1.84-alpine -> alpine:3.21) | Oui (node:20-alpine -> nginx:1.27-alpine) |
|
||||
| Non-root | Oui (user `app`, UID 1001) | Oui (user `app`, UID 1001) | Oui (user `nginx`) |
|
||||
| Health check | `wget /api/v1/health` | `wget /health` | `wget /health` |
|
||||
| Static binary | CGO_ENABLED=0, ldflags `-w -s -static` | musl target, strip | N/A (nginx) |
|
||||
| Source maps | N/A | N/A | Supprimées en production (`find dist -name "*.map" -delete`) |
|
||||
| Secrets dans layers | Non | Non | Build args pour `VITE_*` (non secrets) |
|
||||
| Image base | alpine:3.21 (officielle) | alpine:3.21 (officielle) | nginx:1.27-alpine (officielle) |
|
||||
|
||||
**Docker Compose (production)** :
|
||||
- Secrets via env avec `:?` (required) — fail-fast si absent
|
||||
- Blue-green deployment (backend-blue/green, stream-blue/green, web-blue/green)
|
||||
- HAProxy reverse proxy avec SSL
|
||||
- Health checks sur tous les services
|
||||
- Resource limits configurés (CPU, memory)
|
||||
- Réseau isolé (bridge, subnet 172.20.0.0/16)
|
||||
- Pas de ports exposés directement (sauf HAProxy 80/443 et Alertmanager 9093)
|
||||
|
||||
### 7.2 CI/CD
|
||||
|
||||
| Workflow | Couverture | Détail |
|
||||
|----------|-----------|--------|
|
||||
| `ci.yml` | Principal | 5 jobs : backend-go (govulncheck, vet, lint, test, build), rust-services (cargo audit, lint, build, test), frontend (npm audit, generate types, lint, format, typecheck, test, build), storybook (build, serve, audit), e2e (Postgres+Redis+RabbitMQ, migrations, Playwright) |
|
||||
| `cd.yml` | Déploiement | Deployment workflow |
|
||||
| `backend-ci.yml` | Backend | Backend-specific CI |
|
||||
| `frontend-ci.yml` | Frontend | Frontend-specific CI |
|
||||
| `rust-ci.yml` | Rust | Clippy for stream server |
|
||||
| `stream-ci.yml` | Stream | Clippy, audit, tests |
|
||||
| `sast.yml` | Sécurité | Static Application Security Testing |
|
||||
| `security-scan.yml` | Sécurité | Security scans |
|
||||
| `container-scan.yml` | Sécurité | Container image scanning |
|
||||
| `storybook-audit.yml` | UI | Storybook validation |
|
||||
| `load-test-nightly.yml` | Performance | k6 nightly (02:00 UTC) |
|
||||
| Dependabot | Dépendances | Mise à jour automatique |
|
||||
|
||||
**Ce qui manque** :
|
||||
- Pas de cache remote Turborepo (builds plus lents en CI)
|
||||
- Pas de déploiement automatique vers staging/production (seulement `cd.yml` mais pas vérifié si complet)
|
||||
- Pas de smoke tests post-déploiement automatisés en CI
|
||||
|
||||
### 7.3 Reproductibilité
|
||||
|
||||
| Critère | Statut |
|
||||
|---------|--------|
|
||||
| Build en une commande | `docker compose up` pour dev, `docker compose -f docker-compose.prod.yml up` pour prod |
|
||||
| Onboarding doc | `docs/ONBOARDING.md` existe et est détaillé |
|
||||
| Versions outils lockées | Go 1.24 (go.mod), Rust stable (pas de toolchain file), Node 20 (CI, pas de `.nvmrc`) |
|
||||
| Dépendances lockées | `go.sum`, `Cargo.lock`, `package-lock.json` — tous versionnés |
|
||||
| Manque | `.nvmrc` ou `.node-version` pour Node. `rust-toolchain.toml` pour Rust. |
|
||||
|
||||
---
|
||||
|
||||
## 8. PERFORMANCE & SCALABILITÉ
|
||||
|
||||
### 8.1 Goulots d'étranglement
|
||||
|
||||
| Composant | Risque | Seuil estimé | Mitigation |
|
||||
|-----------|--------|--------------|------------|
|
||||
| PostgreSQL | Requêtes non optimisées sans index, N+1 | > 10K req/min | Index GIN pg_trgm. Preload GORM. Read replica supporté. |
|
||||
| Redis | SPOF pour cache, rate limiting, sessions, PubSub | Si Redis down : rate limit in-memory, chat single-instance | Sentinel/Cluster non configuré |
|
||||
| Chat server (Go) | Hub pattern en mémoire | > 1000 connexions simultanées | Go goroutines légères (~8KB/goroutine) |
|
||||
| Stream server (Rust) | FFmpeg transcoding CPU-intensif | > 100 transcodings simultanés | Tokio runtime multi-threaded |
|
||||
| File storage | MinIO/S3 — pas de CDN configuré en dev | > 10TB de tracks | S3/MinIO horizontalement scalable. CDN configs dans k8s/ |
|
||||
| HAProxy | Single instance reverse proxy | > 5000 req/s | Suffisant pour le lancement. LB cloud dans k8s/load-balancing/ |
|
||||
|
||||
### 8.2 Scalabilité horizontale
|
||||
|
||||
| Service | Horizontalement scalable ? | Obstacle |
|
||||
|---------|--------------------------|----------|
|
||||
| Backend Go | Oui (stateless sauf WebSocket) | Chat WebSocket a affinité de session. Redis PubSub résout partiellement. |
|
||||
| Stream server | Oui (stateless pour HLS serving) | Transcoding est CPU-bound, scalable par ajout d'instances. |
|
||||
| Frontend | Oui (fichiers statiques nginx) | Aucun obstacle. |
|
||||
| PostgreSQL | Verticalement + read replicas | Pas de sharding configuré. |
|
||||
| Redis | Non configuré pour cluster | Single instance. Sentinel/Cluster nécessaire pour HA. |
|
||||
|
||||
### 8.3 Load tests existants
|
||||
|
||||
Les scripts k6 dans `loadtests/` couvrent :
|
||||
- Smoke test (30s, sanity check)
|
||||
- Backend: health, auth, tracks, uploads, playlists, marketplace, full scenario
|
||||
- Stream: health, HLS, ramp test
|
||||
- Chat: WebSocket, stress 1000 connexions simultanées
|
||||
- Stress: 500 req/s
|
||||
|
||||
**Verdict** : Bonne couverture de load testing pour un MVP. Les scripts sont réutilisables et paramétrables.
|
||||
|
||||
---
|
||||
|
||||
## 9. RISQUES BUSINESS
|
||||
|
||||
### 9.1 Point de vue CTO
|
||||
|
||||
| Question | Réponse |
|
||||
|----------|---------|
|
||||
| Recruter des devs productifs en < 2 semaines ? | **Non.** La stack Go + Rust + React exige des profils polyvalents rares. Un dev Go sera productif sur le backend en 1-2 semaines, mais ne touchera pas le stream server. Un dev Rust full-stack capable de Go et React est un profil exceptionnel. |
|
||||
| Vélocité soutenable ? | **Non.** ~319K LOC en monorepo avec 356 TODO, 139 fichiers > 500 lignes, et 5300 LOC de code mort indiquent une vélocité qui a sacrifié la qualité. Le rythme doit ralentir pour consolider. |
|
||||
| Dette technique va-t-elle exploser ? | **Oui, si le rythme actuel continue.** Les 12 handlers avec error handling inconsistant, les migrations non transactionnelles, et le JWT mismatch sont des bombes à retardement. |
|
||||
| Refactorings inévitables avant scaling ? | (1) Corriger le JWT mismatch Go/Rust. (2) Nettoyer le code mort Rust. (3) Standardiser error handling. (4) Configurer Redis Sentinel/Cluster. |
|
||||
| Go + Rust justifié pour cette taille d'équipe ? | **Non.** Le stream server Rust pourrait être migré en Go sans perte de fonctionnalité significative (FFmpeg est l'outil lourd, pas le wrapper). La complexité de maintenance de 2 langages backend n'est pas justifiée par les gains de performance pour un service qui sert principalement des fichiers HLS. |
|
||||
|
||||
### 9.2 Point de vue investisseur
|
||||
|
||||
| Question | Réponse |
|
||||
|----------|---------|
|
||||
| Produit réellement fonctionnel ? | **Partiellement.** 19 features opérationnelles. Mais HLS auth cassé (JWT mismatch), WebRTC non fonctionnel, payments en mode test. C'est un MVP fonctionnel, pas une plateforme production-ready. |
|
||||
| Risques de sécurité incident public ? | **Faibles.** httpOnly cookies, bcrypt, rate limiting, CSP. Le seul risque critique (VEZA-SEC-001 JWT default secret) est mitigeable en < 1 jour. Pas de données utilisateur exposées. |
|
||||
| Code repris par une autre équipe ? | **Oui, avec réserves.** Le Go backend est bien structuré et documenté. Le Rust stream server est plus complexe à reprendre. Le frontend React est standard. Documentation abondante (285 docs). |
|
||||
| Coût pour v1.0 production-ready ? | **4-8 semaines** avec 2 développeurs. Corriger les vulnérabilités critiques (1 semaine), stabiliser le streaming (2 semaines), configurer la production (1 semaine), tests de charge (1 semaine), monitoring (1 semaine). |
|
||||
| Propriété intellectuelle défendable ? | **Limitée.** Stack standard (Go/Rust/React), pas d'algorithme propriétaire. La valeur est dans l'intégration et le produit, pas dans la technologie. Le code Rust stream server avec ses codecs et pipeline audio est le plus différenciant mais aussi le plus coûteux à maintenir. |
|
||||
| Ratio features/qualité = quantité sur qualité ? | **Partiellement.** 19 features fonctionnelles est impressionnant, mais 5300 LOC de code mort, 356 TODO, et le JWT mismatch suggèrent une priorisation de la quantité. La qualité de base (auth, sécurité, CI/CD) est néanmoins solide. |
|
||||
|
||||
### 9.3 Point de vue acquéreur
|
||||
|
||||
| Question | Réponse |
|
||||
|----------|---------|
|
||||
| Code réutilisable ? | **Backend Go : oui.** Architecture propre, bien découpée. **Stream Rust : partiellement.** Code HLS et transcoding réutilisable, le reste (soundcloud/, webrtc) est du dead code. **Frontend : oui.** Standard React/Vite. |
|
||||
| Données utilisateur migrables ? | **Oui.** PostgreSQL avec schéma normalisé. UUID primary keys. GDPR export implémenté. |
|
||||
| Vendor-lock ? | **Faible.** Hyperswitch est open-source (remplaçable). MinIO est S3-compatible. Redis et PostgreSQL sont standards. |
|
||||
| Temps onboarding 5 devs ? | **4-6 semaines.** 1 semaine setup + 1 semaine architecture backend + 1 semaine frontend + 1-2 semaines Rust (si maintenu). Documentation ONBOARDING.md existe. |
|
||||
| Score de rachetabilité /10 | **6/10.** Code propre pour un MVP, documentation abondante, stack standard. Pénalisé par la complexité Rust et le code mort. |
|
||||
|
||||
### 9.4 Verdict
|
||||
|
||||
| Question | Réponse | Justification |
|
||||
|----------|---------|---------------|
|
||||
| Peut-on lancer en production tel quel ? | **Non** | JWT mismatch Go/Rust (HLS auth cassé), secret JWT default en Rust, webhook worker leak |
|
||||
| Peut-on vendre / monétiser tel quel ? | **Conditionnel** | Après correction des 3 vulnérabilités critiques + configuration Hyperswitch en mode live |
|
||||
| Peut-on maintenir avec 2 devs ? | **Conditionnel** | Oui si le stream server Rust est gelé ou migré en Go. Non avec 2 langages backend actifs. |
|
||||
| Faut-il refactorer avant prod ? | **Oui** | JWT mismatch, error handling, code mort, pagination limits |
|
||||
| Faut-il réécrire certains services ? | **Non** | Le code est de qualité suffisante. Migration Rust -> Go du stream server recommandée à moyen terme, pas de réécriture urgente. |
|
||||
| La vélocité de développement est-elle un red flag ? | **Oui (modéré)** | Le volume de code (319K LOC) et le nombre de features (19) pour ce qui semble être un petit team est impressionnant mais a généré de la dette. Le rythme doit ralentir pour consolider. |
|
||||
|
||||
---
|
||||
|
||||
## 10. PLAN D'ACTION PRIORISÉ
|
||||
|
||||
### Phase 1 — Critique (Semaines 1-2) : Sécurité et Stabilité
|
||||
|
||||
| # | Action | Risque si non corrigé | Fichiers | Effort |
|
||||
|---|--------|----------------------|----------|--------|
|
||||
| 1 | Supprimer le JWT secret par défaut dans `veza-common/src/config_rust.rs` — panic si `JWT_SECRET` absent | Compromission de tous les tokens si env var manquante | `config_rust.rs:234` | S |
|
||||
| 2 | Aligner JWT issuer/audience entre Go et Rust (utiliser `veza-api`/`veza-app` partout, ou configurable par env) | HLS streaming auth cassé | `jwt_service.go`, `auth/mod.rs` | M |
|
||||
| 3 | Enregistrer le webhook worker dans `shutdownManager` avec context annulable | Perte de webhooks au redéploiement | `routes_webhooks.go:31` | S |
|
||||
| 4 | Corriger `shutdown_signal` dans `main.rs` — passer le `AppState` existant | Shutdown ne ferme pas les connexions correctement | `main.rs:74` | S |
|
||||
| 5 | Aligner la politique de mot de passe frontend (12 chars min) | Formulaire accepte, serveur rejette | `passwordValidator.ts` | S |
|
||||
| 6 | Protéger les routes `/metrics` par auth ou réseau interne | Information disclosure des métriques système | `routes_core.go` | S |
|
||||
|
||||
### Phase 2 — Stabilisation (Semaines 3-6) : Déployabilité
|
||||
|
||||
| # | Action | Fichiers | Effort |
|
||||
|---|--------|----------|--------|
|
||||
| 7 | Standardiser error handling — migrer les 12 handlers vers `RespondWithAppError` | `account_deletion_handler.go`, etc. | M |
|
||||
| 8 | Ajouter une limite max de pagination (ex: `limit` capped à 100) | Tous les handlers de liste | M |
|
||||
| 9 | Propager `context.Context` dans `password_reset_service.go` | 4 endroits | S |
|
||||
| 10 | Configurer Redis Sentinel ou Cluster pour la haute disponibilité | `docker-compose.prod.yml` | L |
|
||||
| 11 | Ajouter `.nvmrc` (Node 20) et `rust-toolchain.toml` pour lock les versions | Racine, `veza-stream-server/` | S |
|
||||
| 12 | Configurer Turborepo remote cache pour accélérer la CI | `turbo.json` | M |
|
||||
| 13 | Smoke tests post-déploiement automatisés | `.github/workflows/cd.yml` | M |
|
||||
|
||||
### Phase 3 — Consolidation (Semaines 7-12) : Dette technique
|
||||
|
||||
| # | Action | Fichiers | Effort |
|
||||
|---|--------|----------|--------|
|
||||
| 14 | Supprimer le code mort : `soundcloud/` (~4K LOC), `webrtc.rs` (~500 LOC), `k8s/chat-server/`, `Makefile.old` | Multiples | M |
|
||||
| 15 | Supprimer les dossiers orphelins : `chat_exports/`, `sub_task_agents/`, `tmt/`, `full_veza_audit_data/` | Racine | S |
|
||||
| 16 | Découper les 10 plus gros fichiers (> 1000 lignes) en sous-modules | `track/service.go`, `marketplace/service.go`, `playlist_handler.go`, etc. | L |
|
||||
| 17 | Adresser les 356 TODO/FIXME/HACK — résoudre ou convertir en issues | Tout le codebase | XL |
|
||||
| 18 | Consolider les migrations — squash des 95 migrations en une base + delta | `veza-backend-api/migrations/` | L |
|
||||
| 19 | Supprimer `features.go` stub ou implémenter le runtime feature flag system | `internal/features/features.go` | S |
|
||||
| 20 | Connecter `onCreateProduct` dans le seller dashboard | `routeConfig.tsx` | S |
|
||||
|
||||
### Phase 4 — Évolution (Mois 4+)
|
||||
|
||||
| # | Action | Effort |
|
||||
|---|--------|--------|
|
||||
| 21 | Évaluer la migration du stream server Rust vers Go | XL |
|
||||
| 22 | Implémenter WebRTC audio calls (v1.1) ou supprimer définitivement le code | L |
|
||||
| 23 | Configurer un CDN (CloudFront/Cloudflare) pour les assets audio | M |
|
||||
| 24 | Implémenter cursor-based pagination pour les listes volumineuses | L |
|
||||
| 25 | Ajouter des tests d'intégration Rust avec base de données | L |
|
||||
| 26 | Passer les couverture tests frontend de 50% à 70% | XL |
|
||||
|
||||
---
|
||||
|
||||
## ANNEXES
|
||||
|
||||
### A. Métriques brutes
|
||||
|
||||
| Métrique | Valeur |
|
||||
|----------|--------|
|
||||
| Commit analysé | `a007f4c7` (2026-03-03) |
|
||||
| Version | v1.0.2 |
|
||||
| LOC Go (backend) | ~188K (778 fichiers) |
|
||||
| LOC Rust (stream + common) | ~107K (191 fichiers) |
|
||||
| LOC TypeScript/TSX (frontend) | ~211K (1887 fichiers) |
|
||||
| LOC SQL (migrations) | ~3.5K (95 fichiers) |
|
||||
| LOC total code source | ~319K |
|
||||
| Tests Go | 306 fichiers |
|
||||
| Tests Frontend | 273 fichiers |
|
||||
| Stories Storybook | 300 fichiers |
|
||||
| Tests E2E | 26 specs |
|
||||
| Workflows CI/CD | 14 |
|
||||
| Docs Markdown | 285 fichiers |
|
||||
| Direct deps Go | 45 |
|
||||
| Direct deps Rust | ~78 |
|
||||
| Direct deps Frontend | 72 |
|
||||
| Fichiers > 500 lignes | 139 |
|
||||
| TODO/FIXME/HACK | 356 |
|
||||
| Code mort estimé | ~5300 LOC |
|
||||
| Vulnérabilités CVE (CI) | 0 |
|
||||
| Vulnérabilités identifiées (audit) | 9 (2 critiques, 2 élevées, 3 moyennes, 2 faibles) |
|
||||
|
||||
### B. Fichiers les plus volumineux (top 15)
|
||||
|
||||
| Fichier | LOC |
|
||||
|---------|-----|
|
||||
| `apps/web/src/types/generated/api.ts` | 6550 |
|
||||
| `veza-backend-api/docs/docs.go` | 5448 |
|
||||
| `veza-stream-server/src/generated/veza.stream.rs` | 1925 |
|
||||
| `apps/web/e2e/utils/test-helpers.ts` | 1215 |
|
||||
| `veza-stream-server/src/core/sync.rs` | 1183 |
|
||||
| `veza-stream-server/src/soundcloud/discovery.rs` | 1181 |
|
||||
| `veza-backend-api/internal/core/track/service.go` | 1147 |
|
||||
| `veza-backend-api/internal/core/marketplace/service.go` | 1142 |
|
||||
| `veza-backend-api/internal/handlers/playlist_handler.go` | 1137 |
|
||||
| `veza-backend-api/tests/search/search_test.go` | 1099 |
|
||||
| `veza-backend-api/internal/config/config.go` | 1037 |
|
||||
| `veza-stream-server/src/streaming/websocket.rs` | 1029 |
|
||||
| `veza-backend-api/internal/core/auth/service.go` | 1019 |
|
||||
| `veza-stream-server/src/codecs/mp3.rs` | 932 |
|
||||
| `veza-backend-api/internal/handlers/marketplace.go` | 919 |
|
||||
|
||||
### C. Conclusion stratégique
|
||||
|
||||
Veza est un MVP techniquement solide qui démontre une capacité d'exécution impressionnante pour une petite équipe. L'architecture backend Go est propre et bien sécurisée. L'infrastructure de déploiement (Docker, CI/CD, blue-green) est mature pour un projet de cette taille.
|
||||
|
||||
Cependant, la vélocité de développement a créé une dette technique significative : code mort, incohérences inter-services (JWT mismatch), et hétérogénéité injustifiée (Go + Rust). Le stream server Rust, avec ses ~103K LOC, est le composant le plus risqué — non pas pour sa qualité intrinsèque, mais pour le coût de maintenance qu'il impose à une petite équipe.
|
||||
|
||||
**Recommandation finale** : **Investir**, avec les conditions suivantes :
|
||||
1. Corriger les 6 actions critiques (Phase 1, 2 semaines) avant tout déploiement client
|
||||
2. Geler le développement de nouvelles features pendant 4 semaines pour la stabilisation (Phase 2)
|
||||
3. Planifier la migration du stream server Rust vers Go à 6-12 mois pour réduire la complexité de maintenance
|
||||
4. Recruter au minimum 1 développeur Go senior pour soutenir la phase de consolidation
|
||||
|
||||
Le ratio risque/potentiel est favorable : les fondations sont saines, les vulnérabilités sont corrigeables, et le produit couvre un périmètre fonctionnel large. Le principal risque n'est pas technique mais organisationnel — maintenir la qualité avec une petite équipe sur un codebase de 319K LOC.
|
||||
|
||||
147
CURSOR_PROMPT_VERSIONING.md
Normal file
147
CURSOR_PROMPT_VERSIONING.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# PROMPT CURSOR — Initialisation / Mise à jour du système de versionnage Veza
|
||||
|
||||
---
|
||||
|
||||
## USAGE
|
||||
|
||||
Ce prompt est à utiliser dans deux cas :
|
||||
1. **Première initialisation** : créer `VEZA_VERSIONS_ROADMAP.md` à partir des ORIGIN docs
|
||||
2. **Mise à jour** : ajuster le roadmap après une évolution du projet
|
||||
|
||||
Pour le travail quotidien, tu n'as pas besoin de ce prompt.
|
||||
Dis simplement à Cursor : **"implémente la prochaine version"**
|
||||
|
||||
---
|
||||
|
||||
## PROMPT À COLLER DANS CURSOR
|
||||
|
||||
```
|
||||
Tu es l'architecte principal du projet Veza, une plateforme de collaboration audio pour musiciens indépendants.
|
||||
|
||||
## Contexte
|
||||
|
||||
Le projet possède une documentation de référence dans le dossier ORIGIN/ du monorepo :
|
||||
- ORIGIN_MASTER_ARCHITECTURE.md — architecture système complète
|
||||
- ORIGIN_FEATURES_REGISTRY.md — registre des 560 features actives (40 supprimées pour raisons éthiques)
|
||||
- ORIGIN_IMPLEMENTATION_TASKS.md — tâches d'implémentation avec priorités P0/P1
|
||||
- ORIGIN_SECURITY_FRAMEWORK.md — framework de sécurité (dont VEZA-SEC-001/002 critiques)
|
||||
- ORIGIN_DEVELOPMENT_PHASES.md — phases P3.5 → P6R
|
||||
- ORIGIN_REVISION_SUMMARY.md — résumé de la révision éthique v2.0.0
|
||||
- ORIGIN_CODE_STANDARDS.md — standards de code Go/Rust/TypeScript
|
||||
- ORIGIN_FEATURE_VALIDATION_STRATEGY.md — checklist de validation (dont Phase 7 éthique)
|
||||
- ORIGIN_ERROR_PATTERNS.md — patterns d'erreur à éviter (PAT-024 à PAT-028)
|
||||
- ORIGIN_BUSINESS_LOGIC.md — règles métier et principes éthiques
|
||||
|
||||
## Ta mission
|
||||
|
||||
Lire TOUS ces fichiers ORIGIN, puis créer (ou mettre à jour) le fichier `VEZA_VERSIONS_ROADMAP.md` à la racine du repo.
|
||||
|
||||
Ce fichier est le système de versionnage opérationnel du projet. Il doit permettre de dire simplement "implémente la prochaine version" pour déclencher une session de travail complète, autonome, et correcte.
|
||||
|
||||
## Structure requise du fichier VEZA_VERSIONS_ROADMAP.md
|
||||
|
||||
### Pour chaque version, inclure :
|
||||
|
||||
1. **Numéro de version** (ex: v0.9.1) en suivant le schéma :
|
||||
- v0.9.x : Phase P3.5 (Consolidation & Sécurité)
|
||||
- v0.10.x : Phase P4R (Social & Live)
|
||||
- v0.11.x : Phase P5R (Analytics & Recherche)
|
||||
- v0.12.x : Phase P6R (Premium & Infrastructure)
|
||||
- v1.0.0 : Release stable
|
||||
|
||||
2. **Nom descriptif** de la version (ex: "JWT Migration RS256")
|
||||
|
||||
3. **Statut** : ⏳ TODO | 🔄 IN PROGRESS | ✅ DONE
|
||||
|
||||
4. **Priorité** : P0 (bloquant) | P1 (haute) | P2 (moyenne) | P3 (basse)
|
||||
|
||||
5. **Durée estimée** en jours
|
||||
|
||||
6. **Prerequisite** : liste des versions qui doivent être DONE avant
|
||||
|
||||
7. **Objectif** : une phrase claire sur ce que cette version accomplit
|
||||
|
||||
8. **Tâches** : liste de checkboxes avec :
|
||||
- Référence aux TASK-XXX de ORIGIN_IMPLEMENTATION_TASKS.md si applicable
|
||||
- Référence aux features Fxxx de ORIGIN_FEATURES_REGISTRY.md
|
||||
- Description précise de ce qui doit être implémenté
|
||||
- Fichiers principaux à modifier (backend, frontend, infra)
|
||||
|
||||
9. **Critères d'acceptation** : liste de conditions vérifiables (pas ambiguës)
|
||||
|
||||
### Contraintes absolues (à respecter dans tout le fichier)
|
||||
|
||||
- Les versions doivent être **atomiques** : chaque version est mergeable indépendamment
|
||||
- Les versions doivent être **séquentielles** dans chaque phase (pas de parallélisme)
|
||||
- Les tâches P0 de ORIGIN_IMPLEMENTATION_TASKS.md (TASK-SEC-001/002) passent EN PREMIER
|
||||
- Aucune version ne doit implémenter du code AI/ML, blockchain/Web3, ou gamification addictive
|
||||
- Les critères d'acceptation doivent être **vérifiables automatiquement** (tests, métriques) ou **vérifiables manuellement** (checklist UX)
|
||||
- La Phase 7 de validation éthique de ORIGIN_FEATURE_VALIDATION_STRATEGY.md s'applique à toute version touchant la découverte, les métriques, ou les interactions sociales
|
||||
|
||||
### Section finale obligatoire : "Instructions pour Cursor"
|
||||
|
||||
À la fin du fichier, inclure une section expliquant le protocole à suivre quand Cursor reçoit "implémente la prochaine version" :
|
||||
1. Identifier la prochaine version TODO
|
||||
2. Vérifier les prerequisites
|
||||
3. Lire les fichiers ORIGIN référencés
|
||||
4. Implémenter
|
||||
5. Valider selon ORIGIN_FEATURE_VALIDATION_STRATEGY.md
|
||||
6. Marquer comme DONE dans ce fichier
|
||||
7. Créer le tag git
|
||||
|
||||
### Section finale obligatoire : "Règles immuables pour Cursor"
|
||||
|
||||
Liste des choses que Cursor ne doit JAMAIS faire, dérivées de la révision éthique v2.0.0.
|
||||
|
||||
## Critères de qualité du fichier généré
|
||||
|
||||
- Le fichier doit être complet : de v0.9.1 jusqu'à v1.0.0, sans saut
|
||||
- Chaque version doit avoir minimum 3 tâches et 3 critères d'acceptation
|
||||
- Les références aux fichiers ORIGIN doivent être exactes (section + numéro de feature)
|
||||
- Les durées estimées doivent être réalistes (1 développeur, pas d'optimisme excessif)
|
||||
- Les prerequisites doivent former un graphe acyclique cohérent
|
||||
|
||||
## Ce que tu NE dois PAS faire
|
||||
|
||||
- Ne pas modifier les fichiers ORIGIN/ (ils sont en lecture seule)
|
||||
- Ne pas créer d'autres fichiers que VEZA_VERSIONS_ROADMAP.md
|
||||
- Ne pas inventer des features qui ne sont pas dans les ORIGIN docs
|
||||
- Ne pas ignorer les features supprimées pour raisons éthiques (F456-F470, F491-F500, F536-F550)
|
||||
|
||||
## Format de sortie
|
||||
|
||||
Fichier Markdown unique : VEZA_VERSIONS_ROADMAP.md
|
||||
Encodage : UTF-8
|
||||
Longueur : aussi long que nécessaire pour être complet et exploitable
|
||||
|
||||
Commence par lire tous les fichiers ORIGIN/ avant d'écrire une seule ligne du fichier de sortie.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## NOTES D'UTILISATION
|
||||
|
||||
### Pour initialiser le roadmap (première fois)
|
||||
Colle le prompt ci-dessus dans Cursor. Il lira tes ORIGIN docs et générera le fichier.
|
||||
|
||||
### Pour implémenter une version (usage quotidien)
|
||||
Dis simplement à Cursor dans un nouveau chat :
|
||||
```
|
||||
Implémente la prochaine version. Le fichier VEZA_VERSIONS_ROADMAP.md
|
||||
est à la racine du repo et contient les instructions.
|
||||
```
|
||||
|
||||
### Pour mettre à jour le roadmap après un changement d'architecture
|
||||
```
|
||||
Le fichier VEZA_VERSIONS_ROADMAP.md est à la racine du repo.
|
||||
[Décrire le changement].
|
||||
Mets à jour les versions concernées sans toucher aux versions déjà DONE
|
||||
et sans modifier les fichiers ORIGIN/.
|
||||
```
|
||||
|
||||
### Pour voir où en est le projet
|
||||
```
|
||||
Donne-moi un résumé de l'avancement dans VEZA_VERSIONS_ROADMAP.md :
|
||||
versions DONE, version en cours, prochaine version, et estimation
|
||||
pour atteindre v1.0.0.
|
||||
```
|
||||
989
ORIGIN_GAP_ANALYSIS_2026-03-04.md
Normal file
989
ORIGIN_GAP_ANALYSIS_2026-03-04.md
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
# ORIGIN GAP ANALYSIS — Veza Platform
|
||||
## Date: 4 mars 2026
|
||||
|
||||
---
|
||||
|
||||
## 1. RÉSUMÉ EXÉCUTIF
|
||||
|
||||
### Position sur la Timeline ORIGIN
|
||||
|
||||
Le plan ORIGIN définit **600 features** réparties sur **8 phases** en **24 mois** (février 2025 – janvier 2027). Selon ce calendrier, en mars 2026, le projet devrait achever la **Phase 5** (Intelligence & Analytics) avec **~360 features cumulées**.
|
||||
|
||||
**État réel** : le projet se situe au niveau de la **Phase 3 complétée** avec environ **~231 features individuelles** implémentées (dont ~55 partiellement), ce qui le place approximativement **6 mois en retard** sur le planning ORIGIN.
|
||||
|
||||
### Métriques Clés
|
||||
|
||||
| Indicateur | Objectif ORIGIN (mars 2026) | État Actuel | Écart |
|
||||
|---|---|---|---|
|
||||
| Features cumulées | 360 (fin P5) | ~231 (dont ~55 partielles) | -129 features |
|
||||
| Couverture tests | ≥ 80% | ~50% (frontend), non mesuré (Go) | -30% |
|
||||
| Vulnérabilités critiques | 0 | 2 (JWT default Rust, JWT mismatch) | -2 |
|
||||
| Phases complètes | P0 à P5 | P0 à P3 (P4 à ~30%) | -2 phases |
|
||||
| Uptime | 99.9% | Non mesuré en prod | N/A |
|
||||
| MAU | 5,000+ (P5) | Pre-launch | N/A |
|
||||
| MRR | $30,000+ (P5) | $0 (pre-launch) | N/A |
|
||||
|
||||
### Complétion Globale
|
||||
|
||||
| Catégorie | ORIGIN | Actuel | % |
|
||||
|---|---|---|---|
|
||||
| Features implémentées | 600 | ~176 pleinement | 29% |
|
||||
| Features partielles | — | ~55 | 9% |
|
||||
| Features manquantes | — | ~369 | 62% |
|
||||
| Architecture conforme | 100% | ~70% | — |
|
||||
| Qualité conforme | 100% | ~45% | — |
|
||||
|
||||
### Verdict
|
||||
|
||||
Le projet a construit des **fondations solides** (auth complète, streaming fonctionnel, marketplace opérationnel, infrastructure CI/CD mature) mais accuse un retard significatif par rapport au planning ORIGIN. Ce retard est principalement dû à :
|
||||
|
||||
1. **Scope réaliste** : le plan ORIGIN avec 600 features en 24 mois pour une équipe de 2-8 devs est extrêmement ambitieux
|
||||
2. **Pivots architecturaux** : migration chat Rust→Go, Stripe→Hyperswitch, simplification de la stack
|
||||
3. **Modules abandonnés** : Education (F276-F305), Gamification (F536-F550)
|
||||
4. **Phases 5-8 non démarrées** : AI, Enterprise, Web3, VR/AR
|
||||
|
||||
---
|
||||
|
||||
## 2. MATRICE DE COMPLÉTION PAR PHASE
|
||||
|
||||
### Vue d'ensemble
|
||||
|
||||
```
|
||||
ORIGIN Timeline vs Réalité (mars 2026)
|
||||
|
||||
Phase Prévu Réel Features Complétion
|
||||
─────────────────────────────────────────────────────────────
|
||||
P0 Fév 2025 ✅ Fait 0 (stab) 85%
|
||||
P1 Mar-Avr 2025 ✅ Fait 50 90%
|
||||
P2 Mai-Jun 2025 ✅ Fait 60 80%
|
||||
P3 Jul-Sep 2025 ⚠️ Partiel 80 65%
|
||||
P4 Oct-Déc 2025 ⚠️ ~30% 90 30%
|
||||
P5 Jan-Mar 2026 ❌ Non 80 5%
|
||||
P6 Avr-Jun 2026 ❌ Non 70 10%
|
||||
P7 Jul-Sep 2026 ❌ Non 90 5%
|
||||
P8 Oct-Jan 2027 ❌ Non 80 0%
|
||||
```
|
||||
|
||||
### Phase 0 : Stabilisation (1 mois) — COMPLÉTÉE à 85%
|
||||
|
||||
**Objectif ORIGIN** : Stabiliser l'existant, CI/CD, coverage 80%, monitoring, documentation, 0 bugs critiques.
|
||||
|
||||
| Livrable ORIGIN | Objectif | État Actuel | Statut |
|
||||
|---|---|---|---|
|
||||
| L0.1 CI/CD pipeline fonctionnel | Pipeline vert | 14 workflows GitHub Actions | ✅ DÉPASSÉ |
|
||||
| L0.2 Tests coverage > 80% backend | 80% Go | 306 fichiers test, seuil non enforced | ⚠️ NON VÉRIFIÉ |
|
||||
| L0.3 Tests coverage > 80% Rust | 80% Rust | Stream server : pas de coverage CI | ❌ NON ATTEINT |
|
||||
| L0.4 Tests E2E frontend (10 scenarios) | 10 scénarios | Playwright configuré, specs existantes | ⚠️ PARTIEL |
|
||||
| L0.5 Prometheus + Grafana opérationnels | Monitoring | Configs Prometheus/Grafana/Alertmanager dans docker-compose prod | ✅ ATTEINT |
|
||||
| L0.6 Documentation ORIGIN complète | 15/15 docs | 22 documents ORIGIN | ✅ DÉPASSÉ |
|
||||
| L0.7 Zero bugs critiques | 0 critiques | 2 vulns critiques (JWT) | ❌ NON ATTEINT |
|
||||
| L0.8 Build vert stable 7 jours | Stabilité | CI vert sur main | ✅ ATTEINT |
|
||||
|
||||
**Critères bloquants non atteints** : Coverage 80% non mesurée, 2 vulnérabilités critiques ouvertes.
|
||||
|
||||
### Phase 1 : MVP Core (2 mois, 50 features) — COMPLÉTÉE à 90%
|
||||
|
||||
**Objectif ORIGIN** : MVP fonctionnel — Auth, Profils, Streaming basique, Upload.
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Auth (F001-F015) | 15 | 13 | 1 (F008) | 1 (F014) |
|
||||
| Profils basiques (F031-F040) | 10 | 10 | 0 | 0 |
|
||||
| Streaming basique (F106-F120) | 15 | 12 | 2 (F119,F122) | 1 (F120) |
|
||||
| Upload (F066-F075) | 10 | 8 | 1 (F072) | 1 (F069) |
|
||||
| **Total P1** | **50** | **43** | **4** | **3** |
|
||||
|
||||
**Features manquantes P1** : Password history (F014), URL import (F069), Equalizer (F120).
|
||||
|
||||
### Phase 2 : Features Essentielles (2 mois, 60 features) — COMPLÉTÉE à 80%
|
||||
|
||||
**Objectif ORIGIN** : Playlists, Chat, Social basique.
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Streaming suite (F121-F145) | 25 | 18 | 3 | 4 |
|
||||
| Chat (F151-F170) | 20 | 8 | 6 | 6 |
|
||||
| Social basique (F186-F200) | 15 | 8 | 4 | 3 |
|
||||
| **Total P2** | **60** | **34** | **13** | **13** |
|
||||
|
||||
**Écarts notables P2** :
|
||||
- Chat migré de Rust vers Go (ADR-002) — fonctionnel mais features avancées manquantes (reactions, mentions, markdown, GIFs)
|
||||
- Social : follow/unfollow implémenté, mais pas de recommendations, QR code, close friends
|
||||
- Playlists : CRUD complet, collaboration, mais pas de smart playlists ni export
|
||||
|
||||
### Phase 3 : Marketplace & Monétisation (3 mois, 80 features) — COMPLÉTÉE à 65%
|
||||
|
||||
**Objectif ORIGIN** : Marketplace, Education, Hardware.
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Marketplace (F226-F275) | 50 | 28 | 10 | 12 |
|
||||
| Education (F276-F290) | 15 | 0 | 6 (backend only) | 9 |
|
||||
| Hardware/Gear (F306-F320) | 15 | 12 | 2 | 1 |
|
||||
| **Total P3** | **80** | **40** | **18** | **22** |
|
||||
|
||||
**Écarts notables P3** :
|
||||
- **Education** : Backend et DB schema existent (`core/education/`), mais tests skippés et aucun frontend — module effectivement non livré
|
||||
- **Marketplace** : CRUD produits, licences (personal/commercial/exclusive), cart, checkout Hyperswitch — mais pas de PayPal/crypto, pas de e-signature, pas de licence history
|
||||
- **Paiement** : Hyperswitch au lieu de Stripe (pivot architectural documenté)
|
||||
|
||||
### Phase 4 : Social & Collaboration (3 mois, 90 features) — COMPLÉTÉE à 30%
|
||||
|
||||
**Objectif ORIGIN** : Social avancé, Collaboration DAW, Live streaming, Gamification.
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Social avancé (F201-F225) | 25 | 5 | 8 | 12 |
|
||||
| Collaboration (F481-F510) | 30 | 2 (playlist collab) | 0 | 28 |
|
||||
| Live Streaming (F471-F490) | 20 | 3 | 4 | 13 |
|
||||
| Gamification (F536-F550) | 15 | 0 | 2 (frontend UI only) | 13 |
|
||||
| **Total P4** | **90** | **10** | **14** | **66** |
|
||||
|
||||
**Écarts notables P4** :
|
||||
- **DAW Collaboration** : non implémenté (0/30 features)
|
||||
- **Gamification** : supprimée du scope en v0.971 — `ProfileXPView` et `AchievementCard` existent côté frontend mais sans backend
|
||||
- **Live Streaming** : infrastructure HLS basique en place, `GoLiveView` et `TipStreamerModal` existent, mais features avancées manquantes
|
||||
- **WebRTC** : code présent mais non fonctionnel (dépendance commentée)
|
||||
|
||||
### Phase 5 : Intelligence & Analytics (3 mois, 80 features) — COMPLÉTÉE à 5%
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| AI/ML (F456-F470) | 15 | 0 | 2 (similarity, BPM detect) | 13 |
|
||||
| Analytics (F381-F410) | 30 | 4 | 8 | 18 |
|
||||
| Search avancé (F351-F370) | 20 | 4 | 6 | 10 |
|
||||
| Education suite (F291-F305) | 15 | 0 | 0 | 15 |
|
||||
| **Total P5** | **80** | **8** | **16** | **56** |
|
||||
|
||||
### Phase 6 : Monétisation Avancée (3 mois, 70 features) — COMPLÉTÉE à 10%
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Notifications (F551-F570) | 20 | 6 | 4 | 10 |
|
||||
| Security Advanced (F571-F585) | 15 | 8 | 4 | 3 |
|
||||
| Developer API (F586-F600) | 15 | 5 | 4 | 6 |
|
||||
| UI/UX (F436-F455) | 20 | 6 | 6 | 8 |
|
||||
| **Total P6** | **70** | **25** | **18** | **27** |
|
||||
|
||||
**Note** : Certaines features P6 ont été implémentées en avance (security headers, rate limiting, API keys, notifications basiques, thèmes light/dark).
|
||||
|
||||
### Phase 7 : Scale & Enterprise (3 mois, 90 features) — COMPLÉTÉE à 5%
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| Cloud Storage (F331-F350) | 20 | 6 | 6 | 8 |
|
||||
| Administration (F411-F435) | 25 | 8 | 6 | 11 |
|
||||
| External Integrations (F501-F520) | 20 | 4 (OAuth) | 2 | 14 |
|
||||
| Native Apps (F521-F535) | 15 | 1 (PWA) | 0 | 14 |
|
||||
| Scaling infra | 10 | 2 (K8s manifests) | 2 | 6 |
|
||||
| **Total P7** | **90** | **21** | **16** | **53** |
|
||||
|
||||
### Phase 8 : Innovation & IA (4 mois, 80 features) — COMPLÉTÉE à 0%
|
||||
|
||||
| Module ORIGIN | Features | Implémentées | Partielles | Manquantes |
|
||||
|---|---|---|---|---|
|
||||
| AI Avancé | 30 | 0 | 0 | 30 |
|
||||
| Web3/Blockchain (F491-F500) | 30 | 0 | 0 | 30 |
|
||||
| VR/AR Experimental | 20 | 0 | 0 | 20 |
|
||||
| **Total P8** | **80** | **0** | **0** | **80** |
|
||||
|
||||
### Synthèse Phases
|
||||
|
||||
| Phase | Prévu | Implémenté | Partiel | Manquant | % Complet |
|
||||
|---|---|---|---|---|---|
|
||||
| P0 | 0 (stab) | — | — | — | 85% |
|
||||
| P1 | 50 | 43 | 4 | 3 | 90% |
|
||||
| P2 | 60 | 34 | 13 | 13 | 68% |
|
||||
| P3 | 80 | 40 | 18 | 22 | 61% |
|
||||
| P4 | 90 | 10 | 14 | 66 | 19% |
|
||||
| P5 | 80 | 8 | 16 | 56 | 15% |
|
||||
| P6 | 70 | 25 | 18 | 27 | 49% |
|
||||
| P7 | 90 | 21 | 16 | 53 | 32% |
|
||||
| P8 | 80 | 0 | 0 | 80 | 0% |
|
||||
| **TOTAL** | **600** | **181** | **99** | **320** | **38%** |
|
||||
|
||||
---
|
||||
|
||||
## 3. ANALYSE DES ÉCARTS PAR MODULE (F001-F600)
|
||||
|
||||
### M01 : Auth & Security (F001-F030)
|
||||
|
||||
| ID | Feature | Statut | Preuve / Fichier |
|
||||
|---|---|---|---|
|
||||
| F001 | Register email/password | ✅ | `core/auth/handler.go`, `RegisterForm.tsx` |
|
||||
| F002 | Email verification | ✅ | `core/auth/handler.go` (VerifyEmail), `VerifyEmailPage.tsx` |
|
||||
| F003 | Login email/password | ✅ | `handlers/auth.go` (Login), `LoginPage.tsx` |
|
||||
| F004 | OAuth Google | ✅ | `services/oauth_service.go`, `oauth_handlers.go` |
|
||||
| F005 | OAuth GitHub | ✅ | `services/oauth_service.go`, test integration |
|
||||
| F006 | OAuth Discord | ✅ | `services/oauth_service.go` |
|
||||
| F007 | OAuth Spotify | ✅ | `services/oauth_service.go` |
|
||||
| F008 | Remember Me | ✅ | `handlers/auth.go` (rememberMe), `LoginForm.tsx` |
|
||||
| F009 | Logout | ✅ | `core/auth/handler.go` (Logout), `useLogout.ts` |
|
||||
| F010 | Logout all | ✅ | `handlers/session.go` (LogoutAll) |
|
||||
| F011 | Password reset request | ✅ | `password_reset_handler.go`, `ForgotPasswordForm.tsx` |
|
||||
| F012 | Password reset confirm | ✅ | `password_reset_handler.go`, `ResetPasswordPage.tsx` |
|
||||
| F013 | Change password | ✅ | `api/user/handler.go` (ChangePassword) |
|
||||
| F014 | Password history | ❌ | Uniquement dans ORIGIN schema, pas de table en migration |
|
||||
| F015 | Password strength | ✅ | `validators/password_validator.go`, `PasswordStrengthIndicator.tsx` |
|
||||
| F016 | 2FA TOTP setup | ✅ | `services/two_factor_service.go`, `2fa-service.ts` |
|
||||
| F017 | 2FA verify | ✅ | `TwoFactorVerify.tsx`, POST `/auth/login/2fa` |
|
||||
| F018 | 2FA backup codes | ✅ | `two_factor_service.go` (RecoveryCodes) |
|
||||
| F019 | 2FA SMS | ⚠️ | UI existe (`TwoFactorSetupStep2.tsx`), `handleSmsUnavailable` → "not yet available" |
|
||||
| F020 | Passkeys/WebAuthn | ⚠️ | `PasskeyModal.tsx` (UI only, simule API), pas de backend |
|
||||
| F021 | Session management | ✅ | `handlers/session.go`, `SessionsPage.tsx` |
|
||||
| F022 | Login notification | ❌ | Non implémenté |
|
||||
| F023 | Geolocation | ⚠️ | `ip_address` stocké dans sessions, pas de geo-lookup |
|
||||
| F024 | Login history | ⚠️ | `LoginHistory.tsx` existe, route backend planifiée (V0_903) |
|
||||
| F025 | IP whitelisting | ❌ | Non implémenté (whitelist CORS/OAuth uniquement) |
|
||||
| F026 | Rate limiting login | ✅ | `endpoint_limiter.go` (LoginRateLimit) |
|
||||
| F027 | CAPTCHA | ❌ | Planifié V0_903, pas d'implémentation |
|
||||
| F028 | Bruteforce detection | ⚠️ | Via rate limiting + lockout, pas de service dédié |
|
||||
| F029 | Account lockout | ✅ | `account_lockout_service.go` |
|
||||
| F030 | Security questions | ❌ | Non implémenté |
|
||||
|
||||
**Score : 22/30 (73%) — 4 partielles, 5 manquantes**
|
||||
|
||||
### M02 : Profils (F031-F065)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F031 | Create/edit profile | ✅ | `profile_handler.go`, `ProfileForm.tsx` |
|
||||
| F032 | Avatar upload | ✅ | `avatar_handler.go`, `avatarService.ts` |
|
||||
| F033 | Banner upload | ✅ | `user.go` (BannerURL), `EditProfileImagesCard.tsx` |
|
||||
| F034 | Username | ✅ | `useUsernameAvailability.ts`, check-username endpoint |
|
||||
| F035 | Bio | ✅ | `user.go` (Bio), `ProfileIdentity.tsx` |
|
||||
| F036 | Location | ✅ | `user.go`, `ProfileIdentity.tsx` |
|
||||
| F037 | Birth date | ✅ | `profile_handler.go`, `useEditProfile.ts` |
|
||||
| F038 | Gender | ✅ | `profile_handler.go`, `useEditProfile.ts` |
|
||||
| F039 | Language preference | ✅ | `api/user/types.go` (Language), `ui.ts` (setLanguage) |
|
||||
| F040 | Timezone | ✅ | `api/user/types.go` (Timezone), `settingsSchema.ts` |
|
||||
| F041 | Custom profile URL | ✅ | `/u/:username` route, `UserProfilePage.tsx` |
|
||||
| F042 | Public/private profile | ✅ | `ProfileVisibility`, `ProfileVisibilityCard.tsx` |
|
||||
| F043 | Public contact email | ⚠️ | Pas de champ `contact_email` dédié |
|
||||
| F044 | Social links | ✅ | `user.go` (SocialLinks), `ProfileSocialLinks.tsx` |
|
||||
| F045 | Badges/achievements | ⚠️ | `RoleBadge` pour rôles, pas de système gamification complet |
|
||||
| F046 | Role User | ✅ | `models/role.go`, `rbac_service.go` |
|
||||
| F047 | Role Artist/Creator | ✅ | Idem |
|
||||
| F048 | Role Producer | ✅ | Idem |
|
||||
| F049 | Role Label | ✅ | Idem |
|
||||
| F050 | Role Formateur | ✅ | Idem |
|
||||
| F051 | Role Moderator | ✅ | Idem |
|
||||
| F052 | Role Admin | ✅ | Idem |
|
||||
| F053 | Granular permissions | ✅ | `rbac_service.go`, tables `permissions`, `role_permissions` |
|
||||
| F054 | Verified badge | ✅ | `user.go` (IsVerified), `EmailVerificationBadge.tsx` |
|
||||
| F055 | KYC | ❌ | Non implémenté |
|
||||
| F056 | Change email | ✅ | `ChangeEmailModal.tsx` |
|
||||
| F057 | Change username | ✅ | `ChangeUsernameModal.tsx`, `CanChangeUsername` |
|
||||
| F058 | Change language | ✅ | `ui.ts` (setLanguage), `PreferenceSettings.tsx` |
|
||||
| F059 | Theme light/dark | ✅ | `ThemeProvider.tsx`, `ui.ts` (theme) |
|
||||
| F060-062 | Notification preferences | ✅ | `notification_handlers.go`, `PushPreferencesSection.tsx` |
|
||||
| F063 | Privacy preferences | ✅ | `PrivacySettings.tsx`, `settings_handler.go` |
|
||||
| F064 | Profile visibility | ✅ | `ProfileVisibilityCard.tsx` |
|
||||
| F065 | Delete account GDPR | ✅ | `account_deletion_handler.go`, `DeleteAccountView.tsx` |
|
||||
|
||||
**Score : 31/35 (89%) — 2 partielles, 1 manquante (KYC)**
|
||||
|
||||
### M03 : File Management (F066-F105)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F066 | Single file upload | ✅ | `uploadService.ts` (chunked), `upload.go` |
|
||||
| F067 | Batch upload | ✅ | `BatchUpload()`, `BatchUploader.tsx` |
|
||||
| F068 | Drag & drop | ✅ | `react-dropzone`, `FileUploadZone.tsx` |
|
||||
| F069 | URL import | ❌ | Non implémenté |
|
||||
| F070 | Cloud import (Dropbox/Drive) | ⚠️ | UI dans `IntegrationsView.tsx`, pas de backend |
|
||||
| F071 | Progress bar | ✅ | `UploadModalProgress`, `FilePreviewCard.tsx` |
|
||||
| F072 | Pause/resume upload | ⚠️ | Chunked upload backend (`track_chunk_service.go`), pas de resume UI |
|
||||
| F073 | File size validation | ✅ | `MAX_FILE_SIZE` 100MB, `ValidateFileSize` |
|
||||
| F074 | MIME validation | ✅ | `AllowedMimeTypes`, magic bytes validation |
|
||||
| F075 | Antivirus scan | ⚠️ | ClamAV configuré mais désactivé par défaut |
|
||||
| F076 | Image compression | ⚠️ | Avatar resize via `image_service.go`, pas de compression générique |
|
||||
| F077 | Audio transcoding | ✅ | `audio_transcode_service.go`, FFmpeg pipeline |
|
||||
| F078 | Thumbnail generation | ✅ | `thumbnail_job.go` |
|
||||
| F079 | Metadata extraction | ✅ | `metadata_service.go` |
|
||||
| F080 | Watermarking | ⚠️ | `WatermarkSettingsModal.tsx` UI, pas de backend audio watermark |
|
||||
| F081-F090 | Formats (MP3/WAV/FLAC/OGG/AIFF/M4A/ZIP/RAR/PDF/VST) | ⚠️ | Audio : MP3/WAV/FLAC/OGG/M4A/AAC/AIFF ✅ — RAR/PDF/VST ❌ |
|
||||
| F091-F105 | Track metadata fields | ⚠️ | title, artist, album, genre, BPM, key, duration, tags, cover ✅ — label, ISRC, copyright, lyrics, suggested tags ❌ |
|
||||
|
||||
**Score : 11/40 plein, 9 partiels (50% complet)**
|
||||
|
||||
### M04 : Audio Streaming (F106-F150)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F106-F110 | Play/pause/next/prev/seek | ✅ | `playerStore.ts` |
|
||||
| F111-F115 | Volume/mute/shuffle/repeat/speed | ✅ | `playerStore.ts` |
|
||||
| F116 | Crossfade | ✅ | `crossfadeSeconds` dans playerStore |
|
||||
| F117 | Gapless playback | ❌ | Non implémenté |
|
||||
| F118 | Waveform | ✅ | `WaveformDisplay.tsx`, `WaveformVisualizer.tsx` |
|
||||
| F119 | Spectrogram | ⚠️ | Mode "spectrogram" dans `VisualizerSettingsModal.tsx` |
|
||||
| F120 | Equalizer | ❌ | Non implémenté |
|
||||
| F121 | Mini-player | ✅ | `MiniPlayer.tsx` |
|
||||
| F122 | Picture-in-Picture | ⚠️ | Référence dans `PlayerBarRight`, pas d'implémentation complète |
|
||||
| F123 | Keyboard shortcuts | ✅ | `useMediaSession.ts` + raccourcis clavier |
|
||||
| F124 | Media Session API | ✅ | `useMediaSession.ts` |
|
||||
| F125 | Chromecast/AirPlay | ❌ | Non implémenté |
|
||||
| F126-F135 | Queue management | ✅ | addToQueue, removeFromQueue, reorderQueue, QueuePanel |
|
||||
| F136-F145 | Playlists CRUD | ✅ | API complète, `SharePlaylistModal`, `CollaboratorManagement` |
|
||||
| F146-F148 | Smart playlists, merge, export | ❌ | Non implémenté |
|
||||
| F149-F150 | Playlist import/share | ⚠️ | Share ✅, import limité (fichier uniquement) |
|
||||
|
||||
**Score : 28/45 (62%) — 4 partiels, 7 manquants**
|
||||
|
||||
### M05 : Chat (F151-F185)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F151 | DM 1-to-1 | ✅ | `chat_repository.go` GetDirectMessageRoom |
|
||||
| F152-F154 | Rooms public/private/group | ✅ | `room_type` varchar(50) |
|
||||
| F155 | Text messages | ✅ | `CreateMessage` |
|
||||
| F156 | Emoji | ❌ | Non vérifié dans chat |
|
||||
| F157 | Reactions | ❌ | Non implémenté |
|
||||
| F158 | Edit message | ✅ | `is_edited` flag |
|
||||
| F159 | Delete message | ✅ | `is_deleted` flag |
|
||||
| F160 | Threads | ⚠️ | `parent_id` existe, pas d'UI thread |
|
||||
| F161 | Mentions | ❌ | Non implémenté |
|
||||
| F162 | Markdown | ❌ | Non implémenté |
|
||||
| F163 | Image sharing | ❌ | Non implémenté dans chat |
|
||||
| F164 | GIFs | ❌ | Non implémenté |
|
||||
| F165 | Audio share | ❌ | Non implémenté |
|
||||
| F166-F170 | Search, filters, pin, bookmarks, notifs | ⚠️ | `is_pinned` ✅, push_message pref ✅, reste ❌ |
|
||||
| F171-F175 | Push, sound, badge, typing, read receipts | ❌ | Non implémenté |
|
||||
| F176-F180 | Online/offline, busy, custom status, AFK, last seen | ⚠️ | `PresenceBadge.tsx`, basique |
|
||||
| F181-F185 | Room users, invisible, presence notif, listening, rich | ❌ | Non implémenté |
|
||||
|
||||
**Score : 8/35 (23%) — 4 partiels, 17 manquants**
|
||||
|
||||
### M06 : Social (F186-F225)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F186-F188 | Follow/unfollow/followers list | ✅ | `profileService.ts`, `profileHandler` |
|
||||
| F189 | Following list | ✅ | Idem |
|
||||
| F190 | Block user | ✅ | `BlockUser`, `UnblockUser` |
|
||||
| F191 | Report user | ⚠️ | `ReportHandler` existe, flow incomplet |
|
||||
| F192 | Recommendations | ❌ | Non implémenté |
|
||||
| F193-F195 | Suggestions, collaboration request, referral | ❌ | Non implémenté |
|
||||
| F196 | Share profile | ⚠️ | URL `/u/:username` partageable |
|
||||
| F197 | QR code | ❌ | Non implémenté |
|
||||
| F198 | New follower notification | ⚠️ | Notification service existe, feature non confirmée |
|
||||
| F199 | Close friends | ❌ | Non implémenté |
|
||||
| F200 | Artist subscription | ❌ | Non implémenté |
|
||||
| F201-F210 | Posts (text/image/audio/video, like, comment, repost, quote, pin) | ⚠️ | `CreatePostModal`, `PostCard`, `ExploreView` — partiellement mocké |
|
||||
| F211-F215 | Delete/edit/private post, hashtags, trending | ⚠️ | UI existe, backend partiel |
|
||||
| F216-F225 | Groups (create, join, leave, invite, roles, forum, events, shared files, stats) | ⚠️ | `CreateGroupModal`, groupe cover — reste non implémenté |
|
||||
|
||||
**Score : 6/40 (15%) — 8 partiels, 16 manquants**
|
||||
|
||||
### M07 : Marketplace (F226-F275)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F226-F235 | Products CRUD, upload, preview, images, description, pricing | ✅ | `productService.ts`, `CreateProductView*` |
|
||||
| F236-F240 | Categories, tags, BPM/key metadata, genre, formats | ✅ | Product model avec metadata complète |
|
||||
| F241-F243 | Licences streaming/personal/commercial | ✅ | `CreateProductViewPricingCard` |
|
||||
| F244-F246 | Licence exclusive/lease/unlimited | ⚠️ | Exclusive ✅, lease/unlimited ❌ |
|
||||
| F247-F250 | Terms, auto contract, e-signature, licence history | ❌ | Non implémenté |
|
||||
| F251-F255 | Cart, multi-product, wishlist, taxes, promo codes | ⚠️ | Cart ✅, multi-product ✅, wishlist ⚠️, taxes/promos ❌ |
|
||||
| F256-F260 | Checkout, card, PayPal, crypto, invoice | ⚠️ | Hyperswitch checkout ✅, PayPal/crypto ❌ |
|
||||
| F261-F265 | Purchase history, re-download, refund, dispute, support | ⚠️ | Purchase history ✅, reste partiel |
|
||||
| F266-F270 | Seller dashboard, stats, revenue, charts, top products | ✅ | `SellerDashboardView`, `commerceService` stats |
|
||||
| F271-F275 | Conversion, reviews, replies, promotions, payout | ⚠️ | Reviews ✅, Stripe Connect payout ✅, promotions ❌ |
|
||||
|
||||
**Score : 22/50 (44%) — 10 partiels, 8 manquants**
|
||||
|
||||
### M08 : Education (F276-F305)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F276-F290 | Courses, lessons, quizzes, certificates, enrollment | ⚠️ | Backend schema + handlers dans `core/education/` — tests skippés, pas de frontend |
|
||||
| F291-F305 | Advanced education (paths, subscriptions, instructors) | ❌ | Non implémenté |
|
||||
|
||||
**Score : 0/30 plein, 6 partiels (backend only) — Module effectivement NON LIVRÉ**
|
||||
|
||||
### M09 : Hardware/Gear (F306-F330)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F306-F315 | Gear CRUD, images, documents, repairs, warranty | ✅ | `gear_handler.go`, `GearItem`, `GearRepair`, `GearDocument`, `GearImage` |
|
||||
| F316-F320 | Warranty notifications, maintenance history | ✅ | `gear_warranty_notifier`, inventory pages frontend |
|
||||
| F321-F325 | Lending, insurance, comparison | ❌ | Non implémenté |
|
||||
| F326-F330 | Marketplace integration, wish list gear | ❌ | Non implémenté |
|
||||
|
||||
**Score : 12/25 (48%) — 2 partiels, 5 manquants**
|
||||
|
||||
### M10 : Cloud Storage (F331-F350)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F331-F340 | Folders, files, upload, quota, versioning, restore, share | ✅ | `cloud_handler.go`, `CloudPage`, `CloudFileVersions` |
|
||||
| F341-F345 | Backup worker, integration view | ✅ | Cloud backup worker, `CloudIntegrationView` |
|
||||
| F346-F350 | Nextcloud sync, external cloud, collaborative edit | ❌ | Non implémenté |
|
||||
|
||||
**Score : 8/20 (40%) — 4 partiels**
|
||||
|
||||
### M11 : Search (F351-F380)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F351-F355 | Fulltext search, filters (genre, BPM, key) | ✅ | `FullTextSearchService`, PostgreSQL tsvector, `TrackSearchService` |
|
||||
| F356-F360 | Sort, autocomplete, suggestions | ✅ | Relevance, popularity, `SearchService.Suggestions` |
|
||||
| F361-F370 | Phonetic, spelling correction, semantic, audio similarity | ❌ | Non implémenté (nécessite Elasticsearch) |
|
||||
| F371-F380 | Search courses, groups, advanced filters | ❌ | Non implémenté |
|
||||
|
||||
**Score : 10/30 (33%) — Limité à PostgreSQL pg_trgm, pas d'Elasticsearch**
|
||||
|
||||
### M12 : Analytics (F381-F410)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F381-F390 | Playback analytics, heatmap | ✅ | `PlaybackAnalyticsService`, `PlaybackHeatmapService` |
|
||||
| F391-F395 | Creator dashboard (stats, trends) | ⚠️ | Track stats + plays over time ✅, demographics/devices ❌ |
|
||||
| F396-F400 | Seller analytics | ⚠️ | `SellerTransfer`, basique |
|
||||
| F401-F410 | Admin analytics (DAU/MAU, retention, infra) | ⚠️ | `AdminContentAnalytics`, `GetDashboardStats` — basique |
|
||||
|
||||
**Score : 4/30 plein, 8 partiels (40% avec partiels)**
|
||||
|
||||
### M13 : Administration (F411-F435)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F411-F415 | User management (search, filters, pagination) | ✅ | `GetUsers` avec search/filters |
|
||||
| F416-F420 | Ban, suspend, reset password, role change | ⚠️ | `BanUserModal`, admin role checks — flow incomplet |
|
||||
| F421-F425 | Moderation queue, content moderation | ⚠️ | `ReportHandler`, `ReportService` — queue UI manquante |
|
||||
| F426-F430 | Copyright strikes, appeal system | ❌ | Non implémenté |
|
||||
| F431-F435 | Feature flags, announcements, maintenance | ✅ | Feature flags, maintenance middleware, announcements |
|
||||
|
||||
**Score : 12/25 (48%) — 6 partiels, 3 manquants**
|
||||
|
||||
### M14 : UI/UX (F436-F455)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F436-F438 | Light/dark/system theme | ✅ | `ThemeProvider`, `ui.ts` |
|
||||
| F439-F441 | High contrast, compact/comfortable, accent hue | ✅ | `AppearanceSettingsView` |
|
||||
| F442-F445 | Font size, custom palette, drag-drop layouts | ⚠️ | Font size ✅, reste ❌ |
|
||||
| F446-F450 | Keyboard nav, screen reader, ARIA, focus visible, WCAG | ⚠️ | `contrast.ts`, `aria-*`, `focus-visible`, `useReducedMotion` — partiel |
|
||||
| F451-F455 | Dyslexia font, video transcriptions, auto subtitles | ❌ | Non implémenté |
|
||||
|
||||
**Score : 10/20 (50%) — 4 partiels, 4 manquants**
|
||||
|
||||
### M15 : AI (F456-F470)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F456 | AI Mastering | ❌ | Non implémenté |
|
||||
| F457 | Stem separation | ❌ | Non implémenté |
|
||||
| F458 | Genre detection | ❌ | Non implémenté |
|
||||
| F459 | BPM detection | ⚠️ | `enable_bpm_detection` dans stream server config |
|
||||
| F460 | Key detection | ❌ | Non implémenté |
|
||||
| F461 | Vocal removal | ❌ | Non implémenté |
|
||||
| F462 | Denoising | ❌ | Non implémenté |
|
||||
| F463 | Audio upscaling | ❌ | Non implémenté |
|
||||
| F464 | Auto-tags | ❌ | Non implémenté |
|
||||
| F465 | Similarity detection | ⚠️ | `TrackSimilarityMatrix` dans stream discovery |
|
||||
| F466 | Content ID | ❌ | Non implémenté |
|
||||
| F467 | ML recommendations | ⚠️ | Recommendation services basiques (non ML) |
|
||||
| F468 | Voice synthesis | ❌ | Non implémenté |
|
||||
| F469 | Auto lyrics transcription | ❌ | Non implémenté |
|
||||
| F470 | AI mixing | ❌ | Non implémenté |
|
||||
|
||||
**Score : 0/15 plein, 3 partiels — Module NON IMPLÉMENTÉ**
|
||||
|
||||
### M16 : Livestreaming (F471-F480)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F471 | Live DJ sets | ⚠️ | `LiveStream` model, `GoLiveView`, HLS support |
|
||||
| F472 | Live concerts | ⚠️ | Infrastructure HLS partagée |
|
||||
| F473 | Production sessions | ❌ | Non implémenté |
|
||||
| F474 | Multi-camera | ❌ | Non implémenté |
|
||||
| F475 | Live chat | ❌ | Pas de chat live dédié |
|
||||
| F476 | Donations/tips | ⚠️ | `TipStreamerModal` (UI) |
|
||||
| F477 | VOD replay | ⚠️ | HLS VOD support dans stream server |
|
||||
| F478 | Clipping | ❌ | Non implémenté |
|
||||
| F479 | Scheduling | ❌ | Non implémenté |
|
||||
| F480 | Viewer analytics | ❌ | Non implémenté |
|
||||
|
||||
**Score : 0/10 plein, 4 partiels — Module BASIQUE**
|
||||
|
||||
### M17 : Collaboration (F481-F490)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F481 | DAW collaboration | ❌ | Non implémenté |
|
||||
| F482 | Version control audio | ❌ | Non implémenté |
|
||||
| F483 | Temporal comments | ❌ | Non implémenté |
|
||||
| F484 | Stems sharing | ❌ | Non implémenté |
|
||||
| F485 | Co-edit playlists | ✅ | `CollaboratorManagement`, read/write/admin |
|
||||
| F486 | Whiteboard | ❌ | Non implémenté |
|
||||
| F487 | Video chat | ❌ | Non implémenté |
|
||||
| F488 | Screen sharing | ❌ | Non implémenté |
|
||||
| F489 | Project templates | ❌ | Non implémenté |
|
||||
| F490 | Collaboration workflow | ❌ | Non implémenté |
|
||||
|
||||
**Score : 1/10 (10%) — Uniquement playlist collaboration**
|
||||
|
||||
### M18 : Web3 (F491-F500)
|
||||
|
||||
**Score : 0/10 (0%) — Aucune feature Web3 implémentée**
|
||||
|
||||
(NFT, blockchain, smart contracts, tokens, staking, DAO, IPFS, wallet : tout manquant)
|
||||
|
||||
### M19 : External Integrations (F501-F520)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F501-F504 | OAuth integrations | ✅ | Google, GitHub, Discord, Spotify |
|
||||
| F505-F510 | Social links | ✅ | Profile social links (YouTube, Instagram, Twitter, etc.) |
|
||||
| F511-F520 | DAW plugins, SoundCloud import, DistroKid, Zapier | ❌ | Non implémenté |
|
||||
|
||||
**Score : 4/20 (20%) — OAuth uniquement**
|
||||
|
||||
### M20 : Native Apps (F521-F535)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F521 | PWA | ✅ | `usePWA` hook |
|
||||
| F522-F535 | iOS, Android, React Native, Tauri, Electron | ❌ | Abandonné (voir `V1_LIMITATIONS.md`) |
|
||||
|
||||
**Score : 1/15 (7%) — PWA uniquement, apps natives abandonnées**
|
||||
|
||||
### M21 : Gamification (F536-F550)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F536-F540 | XP, levels, achievements | ⚠️ | `ProfileXPView`, `AchievementCard` (frontend, issues TS) |
|
||||
| F541-F550 | Challenges, leaderboards, rewards, etc. | ❌ | Backend API gamification absent |
|
||||
|
||||
**Score : 0/15 plein, 2 partiels — Supprimé du scope v0.971**
|
||||
|
||||
### M22 : Notifications (F551-F570)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F551-F555 | Real-time, badge counter, center, mark read | ✅ | `NotificationService`, `NotificationMenu`, `NotificationBell` |
|
||||
| F556-F560 | Filters, grouping, persistent, quick actions, history | ⚠️ | Filtres par type ✅, reste partiel |
|
||||
| F561-F570 | Email templates (welcome, confirmation, reset, etc.) | ⚠️ | Password reset, verification ✅ — welcome, follower, purchase, newsletter ❌ |
|
||||
|
||||
**Score : 6/20 (30%) — 4 partiels, email templates incomplets**
|
||||
|
||||
### M23 : Security Advanced (F571-F585)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F571-F573 | Rate limiting global, per-endpoint, DDoS | ✅ | `endpoint_limiter.go`, rate limiting global |
|
||||
| F574-F576 | SQL injection, XSS, CSRF protection | ✅ | GORM params, DOMPurify, CSRF middleware |
|
||||
| F577-F579 | Clickjacking, CSP, HSTS | ⚠️ | HSTS ✅, X-Frame-Options ✅, CSP avec `unsafe-inline` |
|
||||
| F580-F582 | Security headers, audit logs, GDPR | ✅ | Headers complets, audit logs, `data_export_service` |
|
||||
| F583-F585 | CCPA, SOC2, data export | ⚠️ | GDPR export ✅, CCPA/SOC2 ❌ |
|
||||
|
||||
**Score : 10/15 (67%) — 2 partiels (CSP, compliance)**
|
||||
|
||||
### M24 : Developer API (F586-F600)
|
||||
|
||||
| ID | Feature | Statut | Preuve |
|
||||
|---|---|---|---|
|
||||
| F586-F588 | REST API, API keys, webhooks | ✅ | `APIKeyService`, webhooks (register, list, test, stats) |
|
||||
| F589 | OpenAPI/Swagger | ✅ | Documentation Swagger |
|
||||
| F590-F592 | GraphQL, OAuth2 server | ❌ | Non implémenté |
|
||||
| F593-F595 | SDK JS/Python/Go | ❌ | Non implémenté |
|
||||
| F596-F600 | Sandbox, playground, logs, analytics, dashboard | ⚠️ | `APIPlaygroundView`, `DeveloperDashboardView` — partiel |
|
||||
|
||||
**Score : 5/15 (33%) — 4 partiels, GraphQL et SDKs manquants**
|
||||
|
||||
### Synthèse Globale par Module
|
||||
|
||||
| Module | Features ORIGIN | Plein | Partiel | Manquant | % Complet |
|
||||
|---|---|---|---|---|---|
|
||||
| M01 Auth | 30 | 22 | 4 | 4 | 73% |
|
||||
| M02 Profils | 35 | 31 | 2 | 2 | 89% |
|
||||
| M03 File Mgmt | 40 | 11 | 9 | 20 | 39% |
|
||||
| M04 Streaming | 45 | 28 | 4 | 13 | 67% |
|
||||
| M05 Chat | 35 | 8 | 4 | 23 | 29% |
|
||||
| M06 Social | 40 | 6 | 8 | 26 | 25% |
|
||||
| M07 Marketplace | 50 | 22 | 10 | 18 | 54% |
|
||||
| M08 Education | 30 | 0 | 6 | 24 | 10% |
|
||||
| M09 Gear | 25 | 12 | 2 | 11 | 52% |
|
||||
| M10 Cloud | 20 | 8 | 4 | 8 | 50% |
|
||||
| M11 Search | 30 | 10 | 0 | 20 | 33% |
|
||||
| M12 Analytics | 30 | 4 | 8 | 18 | 27% |
|
||||
| M13 Admin | 25 | 12 | 6 | 7 | 60% |
|
||||
| M14 UI/UX | 20 | 10 | 4 | 6 | 60% |
|
||||
| M15 AI | 15 | 0 | 3 | 12 | 10% |
|
||||
| M16 Livestream | 10 | 0 | 4 | 6 | 20% |
|
||||
| M17 Collaboration | 10 | 1 | 0 | 9 | 10% |
|
||||
| M18 Web3 | 10 | 0 | 0 | 10 | 0% |
|
||||
| M19 Integrations | 20 | 4 | 2 | 14 | 25% |
|
||||
| M20 Native Apps | 15 | 1 | 0 | 14 | 7% |
|
||||
| M21 Gamification | 15 | 0 | 2 | 13 | 7% |
|
||||
| M22 Notifications | 20 | 6 | 4 | 10 | 40% |
|
||||
| M23 Security Adv. | 15 | 10 | 2 | 3 | 73% |
|
||||
| M24 Dev API | 15 | 5 | 4 | 6 | 47% |
|
||||
| **TOTAL** | **600** | **211** | **96** | **297** | **43%** |
|
||||
|
||||
---
|
||||
|
||||
## 4. DÉVIATIONS ARCHITECTURALES
|
||||
|
||||
### 4.1 Tableau des Déviations
|
||||
|
||||
| # | Spécification ORIGIN | Réalité Actuelle | Type | Impact | Recommandation |
|
||||
|---|---|---|---|---|---|
|
||||
| **D01** | **Chat Server Rust** (`veza-chat-server`) — service Rust dédié avec Axum/SQLx pour WebSocket | Migré dans le backend Go en v0.502 (ADR-002). Chat via WebSocket Go. Code Rust orphelin dans `/veza-chat-server/` | Pivot majeur | **Positif** — réduit la complexité opérationnelle, 1 service en moins à déployer/maintenir | ✅ **Garder** la décision. Supprimer le code orphelin Rust du monorepo |
|
||||
| **D02** | **Traefik** comme API Gateway avec service discovery, load balancing, TLS automatique | **HAProxy** comme reverse proxy avec blue-green deployments | Substitution | **Neutre** — HAProxy est production-grade, gère le blue-green | ⚠️ **Acceptable** pour l'échelle actuelle. Migrer vers Traefik/Envoy si >10K users pour le service discovery |
|
||||
| **D03** | **Elasticsearch** pour search avec fulltext, phonétique, facettes, autocomplete | **PostgreSQL** pg_trgm + tsvector/tsquery | Simplification | **Négatif à terme** — ne scalera pas au-delà de ~10K tracks pour la recherche phonétique/sémantique | ❌ **Ajouter Elasticsearch** quand le volume de données le justifie (>50K tracks). Critique pour Phase 5 |
|
||||
| **D04** | **gRPC** pour communication inter-services (Go ↔ Rust) | **REST/HTTP** entre Go API et Rust stream server | Simplification | **Neutre** — REST plus simple à debug, suffisant pour le traffic actuel. gRPC nécessaire si latency inter-service critique | ⚠️ **Acceptable**. Migrer vers gRPC uniquement si bottleneck mesuré |
|
||||
| **D05** | **JWT RS256** (asymétrique) pour multi-service JWT validation | **JWT HS256** (symétrique) partagé entre Go et Rust | Risque sécurité | **Négatif** — HS256 nécessite le secret partagé sur tous les services. RS256 permet validation sans partager le secret privé | ❌ **Migrer vers RS256** avant production multi-instance. Effort : ~2 jours |
|
||||
| **D06** | **CQRS** (Command Query Responsibility Segregation) | Pattern requête-réponse traditionnel (Handler→Service→Repository) | Simplification | **Neutre** — CQRS apporte de la complexité sans bénéfice clair à cette échelle | ✅ **Garder** le pattern actuel. CQRS uniquement si read/write loads divergent significativement |
|
||||
| **D07** | **Stripe** comme payment processor unique | **Hyperswitch** (payment router open-source) qui supporte Stripe comme backend | Pivot stratégique | **Positif** — Hyperswitch offre plus de flexibilité (multi-provider), open-source, réduction de vendor lock-in | ✅ **Garder**. Avantage compétitif — permet d'ajouter PayPal, crypto sans changer l'architecture |
|
||||
| **D08** | **Electron** desktop app (Phase 7) | Non développé | Retard planifié | **Neutre** — Phase 7 feature, pas urgente | ⚠️ **Reporter**. Considérer Tauri (plus léger que Electron) quand nécessaire |
|
||||
| **D09** | **React Native** mobile app (Phase 4-7) | Non développé. PWA uniquement (`usePWA` hook) | Fonctionalité manquante | **Négatif** — PWA limité (pas d'accès App Store, audio background limité sur iOS) | ❌ **Décider** : PWA-first ou app native ? Si market B2C audio, app native quasi-obligatoire |
|
||||
| **D10** | **Ansible** pour déploiement automatisé | **Incus/LXD** + Docker Compose, scripts bash | Substitution | **Neutre** — fonctionnel pour 1-2 serveurs. Ansible nécessaire si >3 serveurs | ⚠️ **Acceptable** court terme. Automatiser avec Ansible/Terraform avant Phase 7 |
|
||||
| **D11** | **pgBouncer** pour connection pooling PostgreSQL | **GORM built-in** connection pooling (MaxOpenConns, MaxIdleConns) | Simplification | **Négatif à terme** — GORM pooling suffisant pour <100 connexions. pgBouncer nécessaire pour >500 connexions | ⚠️ **Acceptable** jusqu'à 5K users. Ajouter pgBouncer avant scaling Phase 7 |
|
||||
| **D12** | **Kafka** (optionnel dans ORIGIN) pour event streaming | **RabbitMQ** uniquement | Conforme | **Neutre** — ORIGIN listait Kafka comme optionnel. RabbitMQ couvre les besoins actuels | ✅ **Garder** RabbitMQ. Kafka uniquement si besoin de replay/event sourcing à grande échelle |
|
||||
| **D13** | **Argon2id** pour hashing passwords (Rust services) | **bcrypt** côté Go, Argon2 référencé dans ORIGIN mais pas implémenté | Déviation mineure | **Neutre** — bcrypt avec cost 12 est acceptable. Argon2id est le standard actuel mais bcrypt reste sûr | ⚠️ **Acceptable**. Migrer vers Argon2id lors d'une refonte auth si opportunité |
|
||||
| **D14** | **HashiCorp Vault** pour secrets management | **Variables d'environnement** + fichiers `.env` | Risque opérationnel | **Négatif** — .env en dev acceptable, mais production nécessite un secret manager | ❌ **Ajouter** un secret manager avant production (Vault, AWS Secrets Manager, ou Infisical) |
|
||||
| **D15** | **Redis Cluster** pour haute disponibilité | **Redis standalone** | Simplification | **Neutre** — suffisant pour <10K users. Cluster nécessaire pour HA | ⚠️ **Acceptable** jusqu'à Phase 7. Prévoir Redis Sentinel ou Cluster avant |
|
||||
|
||||
### 4.2 Bilan des Déviations
|
||||
|
||||
| Catégorie | Nombre | Impact Global |
|
||||
|---|---|---|
|
||||
| ✅ Déviations positives (garder) | 4 | Simplification bienvenue |
|
||||
| ⚠️ Déviations acceptables (court terme) | 6 | À adresser avant scaling |
|
||||
| ❌ Déviations à corriger | 5 | Blocantes pour les objectifs ORIGIN |
|
||||
|
||||
### 4.3 Déviations Critiques à Corriger en Priorité
|
||||
|
||||
1. **D05 - JWT RS256** : migration HS256→RS256 avant déploiement multi-instance (~2j)
|
||||
2. **D14 - Secrets Manager** : Vault ou équivalent avant production (~3j)
|
||||
3. **D03 - Elasticsearch** : nécessaire pour les objectifs Phase 5 search (~2 semaines)
|
||||
4. **D09 - Mobile App** : décision stratégique PWA vs native requise
|
||||
5. **D11 - pgBouncer** : avant scaling au-delà de 5K users (~1j)
|
||||
|
||||
---
|
||||
|
||||
## 5. MÉTRIQUES DE QUALITÉ : ORIGIN vs ACTUEL
|
||||
|
||||
### 5.1 Code Quality Metrics
|
||||
|
||||
| Métrique | Objectif ORIGIN | État Actuel | Zone | Écart |
|
||||
|---|---|---|---|---|
|
||||
| **Test Coverage Global** | ≥ 80% (🟢), objectif 90% | ~50% frontend (vitest threshold), Go non mesuré en CI | 🔴 | -30% minimum |
|
||||
| **Test Coverage Go** | ≥ 80% | 306 fichiers test, pas de coverage % enforced | 🟡 | Non mesuré |
|
||||
| **Test Coverage Rust** | ≥ 80% | Pas de CI coverage pour stream server | 🔴 | Non mesuré |
|
||||
| **Test Coverage Frontend** | ≥ 80% | Threshold 50% vitest, stories Storybook pour composants | 🔴 | ~-30% |
|
||||
| **Complexité cyclomatique** | < 10 par fonction | Non mesuré (pas de gocyclo/SonarQube configuré) | ❓ | Non mesuré |
|
||||
| **Duplication code** | < 3% | Non mesuré (pas de jscpd/SonarQube) | ❓ | Non mesuré |
|
||||
| **TODO/FIXME/HACK** | < 50 | ~150+ TODO, ~30 FIXME, ~5 HACK | 🔴 | +100 TODOs au-dessus du seuil |
|
||||
| **Linter errors** | 0 errors, < 5 warnings | ESLint configuré, golangci-lint en CI | 🟡 | Partiellement conforme |
|
||||
| **Code churn** | < 5 changes/semaine/fichier | Non mesuré | ❓ | Non mesuré |
|
||||
|
||||
### 5.2 Performance Metrics
|
||||
|
||||
| Métrique | Objectif ORIGIN | État Actuel | Zone | Écart |
|
||||
|---|---|---|---|---|
|
||||
| **API Latency p95** | < 100ms | Non mesuré en production (pas de Prometheus actif) | ❓ | Non mesurable |
|
||||
| **API Latency p99** | < 200ms | Idem | ❓ | Non mesurable |
|
||||
| **DB Query p95** | < 10ms | Non mesuré (pas de pg_stat_statements) | ❓ | Non mesurable |
|
||||
| **Frontend FCP** | < 1.5s | Non mesuré (pas de Lighthouse CI) | ❓ | Non mesurable |
|
||||
| **Frontend TTI** | < 3.5s | Non mesuré | ❓ | Non mesurable |
|
||||
| **Lighthouse Performance** | ≥ 95 | Non mesuré | ❓ | Non mesurable |
|
||||
| **Lighthouse Accessibility** | ≥ 100 | Non mesuré | ❓ | Non mesurable |
|
||||
| **Bundle JS initial (gzip)** | < 200 KB | Non mesuré (Vite build, code splitting actif) | ❓ | Non mesurable |
|
||||
| **Audio stream start** | < 500ms | Non mesuré | ❓ | Non mesurable |
|
||||
| **Rebuffering rate** | < 0.5% | Non mesuré | ❓ | Non mesurable |
|
||||
| **Throughput** | 10K req/s | Non testé (k6 load tests existent mais pas de baseline) | ❓ | Non mesurable |
|
||||
| **Uptime** | 99.9% | Non mesuré (pre-launch) | ❓ | N/A |
|
||||
|
||||
**Constat critique** : **Aucune métrique de performance n'est mesurée en continu**. Les configs Prometheus/Grafana existent dans docker-compose mais ne sont pas activement utilisées pour du monitoring de production. Les k6 load tests existent mais n'ont pas produit de baseline documentée.
|
||||
|
||||
### 5.3 Security Metrics
|
||||
|
||||
| Métrique | Objectif ORIGIN | État Actuel | Zone | Écart |
|
||||
|---|---|---|---|---|
|
||||
| **Vulnérabilités critiques** | 0 | 2 (VEZA-SEC-001: JWT default Rust, VEZA-SEC-002: JWT mismatch) | 🔴 | -2 |
|
||||
| **Vulnérabilités hautes** | 0 | 1 (VEZA-SEC-003: admin credentials hardcodées dans tests) | 🟡 | -1 |
|
||||
| **Password hashing** | bcrypt cost ≥ 12 ou Argon2id | bcrypt cost 12 ✅ | 🟢 | Conforme |
|
||||
| **JWT expiration access** | 15 min | 15 min configuré ✅ | 🟢 | Conforme |
|
||||
| **JWT expiration refresh** | 7 jours | 7 jours configuré ✅ | 🟢 | Conforme |
|
||||
| **MFA admin/moderator** | Obligatoire | Disponible mais pas obligatoire | 🟡 | Non enforced |
|
||||
| **Rate limiting** | Tous endpoints publics | Login ✅, global ✅, per-endpoint ✅, DDoS ❌ | 🟡 | WAF absent |
|
||||
| **Input validation serveur** | Obligatoire | Go binding tags ✅, validation service ✅ | 🟢 | Conforme |
|
||||
| **Security headers** | CSP, HSTS, X-Frame-Options, etc. | HSTS ✅, X-Frame-Options ✅, CSP ⚠️ (unsafe-inline) | 🟡 | CSP à durcir |
|
||||
| **Secrets dans code** | Jamais | JWT default "veza-stream-jwt-secret" dans config Rust | 🔴 | Violation |
|
||||
| **Audit logs** | Actions sensibles | `audit_log` table, `AuditLog` handler | 🟢 | Conforme |
|
||||
| **GDPR right to erasure** | Obligatoire | `account_deletion_handler.go`, `data_export_service` | 🟢 | Conforme |
|
||||
| **Dependency scanning** | Daily (npm audit, cargo audit, govulncheck) | CI workflows incluent audit | 🟢 | Conforme |
|
||||
| **Penetration testing** | Trimestriel + après major releases | Non réalisé | 🔴 | Non conforme |
|
||||
| **Bug bounty** | HackerOne ou Bugcrowd | Non mis en place | 🔴 | Non conforme |
|
||||
|
||||
### 5.4 Quality Gates (CI/CD)
|
||||
|
||||
| Quality Gate ORIGIN | Objectif | Implémenté ? | Détail |
|
||||
|---|---|---|---|
|
||||
| Tests pass (unit, integration) | Bloquant | ✅ | GitHub Actions run tests |
|
||||
| Coverage ≥ 80% | Bloquant | ❌ | Seuil à 50% frontend, pas enforced Go/Rust |
|
||||
| No linter errors | Bloquant | ⚠️ | ESLint en CI, golangci-lint partiel |
|
||||
| No security vulns (critical/high) | Bloquant | ⚠️ | npm audit en CI, mais 2 vulns critiques non résolues |
|
||||
| Code review 2+ reviewers | Bloquant | ❌ | Solo developer, pas de reviewers |
|
||||
| Pre-deployment smoke tests | Bloquant | ❌ | Pas de smoke tests staging |
|
||||
| Performance tests | Bloquant | ❌ | k6 existe mais pas intégré en gate |
|
||||
| SAST/DAST scan | Bloquant | ⚠️ | SAST partiel (CI), pas de DAST |
|
||||
| Rollback plan | Bloquant | ⚠️ | Blue-green via HAProxy, pas de rollback automatique |
|
||||
|
||||
**Conformité Quality Gates : 1/9 pleinement conforme, 4/9 partiels, 4/9 non conformes**
|
||||
|
||||
### 5.5 Bilan Qualité
|
||||
|
||||
| Domaine | Score ORIGIN requis | Score Actuel Estimé | Écart |
|
||||
|---|---|---|---|
|
||||
| Code Quality | 8/10 | 5/10 | -3 |
|
||||
| Performance | 9/10 | Inconnu (non mesuré) | Non mesurable |
|
||||
| Security | 9/10 | 6/10 | -3 |
|
||||
| UX/Accessibility | 9/10 | 5/10 | -4 |
|
||||
| Infrastructure | 8/10 | 6/10 | -2 |
|
||||
| **Moyenne** | **8.6/10** | **5.5/10** | **-3.1** |
|
||||
|
||||
---
|
||||
|
||||
## 6. ROADMAP POUR ATTEINDRE LES OBJECTIFS ORIGIN
|
||||
|
||||
### 6.1 Stratégie Recommandée : « Phase 3.5 » avant Phase 4
|
||||
|
||||
Le projet ne peut pas sauter directement à Phase 5 pour rattraper le retard. La stratégie recommandée est de consolider ce qui existe (compléter P2-P3 à 100%), puis aborder Phase 4 avec un scope réduit et pragmatique.
|
||||
|
||||
```
|
||||
Timeline Proposée (mars 2026 → mars 2027)
|
||||
|
||||
Mar-Avr 2026 Mai-Jul 2026 Août-Oct 2026 Nov 2026-Mar 2027
|
||||
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
|
||||
│ PHASE 3.5│ │ PHASE 4R │ │ PHASE 5R │ │ PHASE 6R │
|
||||
│ Consolid.│ │ Social Lite │ │ Analytics + │ │ Premium + │
|
||||
│ Sécurité │ │ + Live │ │ Search + │ │ Dev API + │
|
||||
│ Tests │ │ Streaming │ │ Notifs │ │ Scale │
|
||||
│ ~50 feat │ │ ~60 feat │ │ ~70 feat │ │ ~80 feat │
|
||||
└──────────┘ └──────────────┘ └──────────────┘ └──────────────────┘
|
||||
2 mois 3 mois 3 mois 5 mois
|
||||
```
|
||||
|
||||
### 6.2 Phase 3.5 : Consolidation (Mars-Avril 2026) — 2 mois
|
||||
|
||||
**Objectif** : Corriger les violations ORIGIN critiques, compléter les features P2-P3 manquantes, établir les métriques de qualité.
|
||||
|
||||
#### Sprint A : Sécurité & Quality Gates (2 semaines)
|
||||
|
||||
| Action | Effort | Priorité | Impact |
|
||||
|---|---|---|---|
|
||||
| Corriger VEZA-SEC-001 : remplacer JWT secret par défaut Rust | 0.5j | P0 | Critique |
|
||||
| Corriger VEZA-SEC-002 : aligner JWT issuer/audience Go↔Rust | 1j | P0 | Critique |
|
||||
| Migrer JWT HS256 → RS256 (D05) | 2j | P0 | Architecture |
|
||||
| Configurer coverage CI/CD : Go `go test -coverprofile` + seuil 70% | 1j | P1 | Qualité |
|
||||
| Configurer coverage CI/CD : Rust `cargo tarpaulin` + seuil 60% | 1j | P1 | Qualité |
|
||||
| Monter threshold vitest de 50% à 70% | 1j | P1 | Qualité |
|
||||
| Ajouter Lighthouse CI dans GitHub Actions | 1j | P2 | Performance |
|
||||
| Activer Prometheus metrics dans docker-compose dev | 0.5j | P2 | Monitoring |
|
||||
|
||||
#### Sprint B : Features P2 Manquantes — Chat (2 semaines)
|
||||
|
||||
| Action | Effort | Priorité | Impact |
|
||||
|---|---|---|---|
|
||||
| Chat reactions (emoji) | 2j | P1 | Engagement |
|
||||
| Chat mentions (@user) | 2j | P1 | UX |
|
||||
| Chat typing indicator | 1j | P2 | UX |
|
||||
| Chat read receipts | 2j | P2 | UX |
|
||||
| Chat message search | 2j | P1 | Fonctionnel |
|
||||
|
||||
#### Sprint C : Features P3 Manquantes — Marketplace (2 semaines)
|
||||
|
||||
| Action | Effort | Priorité | Impact |
|
||||
|---|---|---|---|
|
||||
| Education frontend (compléter le module backend existant) | 5j | P1 | Module entier |
|
||||
| Licence history/tracking | 2j | P2 | Business |
|
||||
| Purchase refund flow | 2j | P1 | Business |
|
||||
| Email templates (purchase confirmation, welcome) | 2j | P1 | UX |
|
||||
|
||||
#### Sprint D : Debt & Cleanup (2 semaines)
|
||||
|
||||
| Action | Effort | Priorité | Impact |
|
||||
|---|---|---|---|
|
||||
| Supprimer code mort (`veza-chat-server/`, `soundcloud/`) | 1j | P2 | Maintenabilité |
|
||||
| Convertir 50 TODOs en issues GitHub | 2j | P2 | Tracking |
|
||||
| Uniformiser error handling Go (RespondWithAppError partout) | 3j | P1 | Qualité |
|
||||
| Ajouter secret manager (Infisical ou Vault) | 2j | P0 | Sécurité |
|
||||
| Durcir CSP (supprimer unsafe-inline) | 1j | P1 | Sécurité |
|
||||
|
||||
**Total Phase 3.5 : ~50 actions, 2 mois, 1-2 développeurs**
|
||||
|
||||
### 6.3 Phase 4R : Social & Live Streaming (Mai-Juillet 2026) — 3 mois
|
||||
|
||||
**Scope réduit** : pas de DAW collaboration (trop complexe), pas de Web3, pas de gamification.
|
||||
|
||||
| Module | Features à implémenter | Effort | Priorité |
|
||||
|---|---|---|---|
|
||||
| **Social Posts** | Create/edit/delete post, like, comment, repost, hashtags, explore | 3 semaines | P1 |
|
||||
| **Groups** | Join/leave, roles, member list, group feed | 2 semaines | P1 |
|
||||
| **Live Streaming** | Go live flow, live chat intégré, donations, VOD replay | 4 semaines | P1 |
|
||||
| **Notifications push** | Web push, notification grouping, email follower/comment | 2 semaines | P1 |
|
||||
| **Chat enrichi** | GIFs (Giphy), image sharing, threads UI | 2 semaines | P2 |
|
||||
|
||||
**Total Phase 4R : ~60 features, 3 mois, 2-3 développeurs**
|
||||
|
||||
### 6.4 Phase 5R : Analytics & Search (Août-Octobre 2026) — 3 mois
|
||||
|
||||
| Module | Features à implémenter | Effort | Priorité |
|
||||
|---|---|---|---|
|
||||
| **Elasticsearch** | Setup, indexation tracks/users/playlists, fulltext + phonétique | 3 semaines | P0 |
|
||||
| **Search avancé** | Filtres multi-critères, autocomplete intelligent, spelling correction | 2 semaines | P1 |
|
||||
| **Creator Dashboard** | Plays over time, demographics, device breakdown, export CSV | 3 semaines | P1 |
|
||||
| **Admin Dashboard** | DAU/MAU, retention, revenue, user growth charts | 2 semaines | P1 |
|
||||
| **Notifications email** | Templates complets : welcome, follower, purchase, sale, newsletter | 2 semaines | P2 |
|
||||
| **UI/UX** | WCAG AA compliance, keyboard nav complète, screen reader | 2 semaines | P2 |
|
||||
|
||||
**Total Phase 5R : ~70 features, 3 mois, 2-3 développeurs**
|
||||
|
||||
### 6.5 Phase 6R : Premium & Scale (Novembre 2026-Mars 2027) — 5 mois
|
||||
|
||||
| Module | Features à implémenter | Effort | Priorité |
|
||||
|---|---|---|---|
|
||||
| **Premium tiers** | Free/Premium/Pro, Stripe billing, trial, upgrade/downgrade | 4 semaines | P0 |
|
||||
| **Developer API** | GraphQL, SDK JS, webhook improvements, sandbox | 3 semaines | P1 |
|
||||
| **Admin avancé** | Moderation queue UI, copyright strikes, appeal system | 3 semaines | P1 |
|
||||
| **Cloud Storage** | Nextcloud integration ou S3 sync avancé | 2 semaines | P2 |
|
||||
| **Infrastructure** | pgBouncer, Redis Sentinel, Terraform/Ansible, auto-scaling | 4 semaines | P1 |
|
||||
| **Mobile** | Décision PWA-enhanced ou React Native app | 4 semaines | P1 |
|
||||
| **BPM/Key detection** | Intégrer librosa ou essentia pour détection automatique | 2 semaines | P2 |
|
||||
|
||||
**Total Phase 6R : ~80 features, 5 mois, 2-4 développeurs**
|
||||
|
||||
### 6.6 Estimation Effort Total
|
||||
|
||||
| Phase | Durée | Features | Développeurs | Effort (homme-mois) |
|
||||
|---|---|---|---|---|
|
||||
| Phase 3.5 | 2 mois | ~50 | 1-2 | 3 |
|
||||
| Phase 4R | 3 mois | ~60 | 2-3 | 7 |
|
||||
| Phase 5R | 3 mois | ~70 | 2-3 | 7 |
|
||||
| Phase 6R | 5 mois | ~80 | 2-4 | 12 |
|
||||
| **Total** | **13 mois** | **~260** | — | **~29 homme-mois** |
|
||||
|
||||
Avec ce plan révisé, le projet atteindrait **~490 features** sur 600 d'ici mars 2027, soit **82% de complétion ORIGIN**.
|
||||
|
||||
---
|
||||
|
||||
## 7. RECOMMANDATIONS : GARDER, MODIFIER, OU ABANDONNER
|
||||
|
||||
### 7.1 Objectifs ORIGIN à GARDER tels quels
|
||||
|
||||
| Objectif | Raison |
|
||||
|---|---|
|
||||
| Auth complète (F001-F030) | Fondation critique, déjà à 73% |
|
||||
| Profils (F031-F065) | Déjà à 89%, terminer les derniers % |
|
||||
| Streaming audio (F106-F150) | Core product, déjà à 67% |
|
||||
| Marketplace (F226-F275) | Source de revenue, à 54% |
|
||||
| Security (F571-F585) | Non négociable, déjà à 73% |
|
||||
| Notifications (F551-F570) | Essentiel pour rétention |
|
||||
| Admin (F411-F435) | Nécessaire pour opérations |
|
||||
| Cloud storage (F331-F350) | Différenciateur produit |
|
||||
| Search fulltext (F351-F370) | Critique pour UX |
|
||||
| Analytics (F381-F410) | Nécessaire pour créateurs et vendeurs |
|
||||
| Developer API (F586-F600) | Permet écosystème |
|
||||
| UI/UX accessibilité (F436-F455) | Obligation légale (WCAG), différenciateur |
|
||||
| CI/CD + Quality Gates | Fondation technique non négociable |
|
||||
| Test coverage 80% | Objectif réaliste, protège contre régressions |
|
||||
|
||||
### 7.2 Objectifs ORIGIN à MODIFIER
|
||||
|
||||
| Objectif Original | Modification Proposée | Raison |
|
||||
|---|---|---|
|
||||
| **600 features en 24 mois** | **~490 features en 25 mois** (mars 2027) | Scope irréaliste pour 1-2 développeurs. 82% est un excellent résultat |
|
||||
| **Chat Rust (veza-chat-server)** | **Chat Go** (tel qu'implémenté) | ADR-002 validé, simplification positive |
|
||||
| **Stripe exclusif** | **Hyperswitch** (tel qu'implémenté) | Meilleure flexibilité, open-source |
|
||||
| **Elasticsearch Phase 5** | **Elasticsearch Phase 5R** (août 2026) | Reporter mais ne pas abandonner — critique pour scale |
|
||||
| **Traefik** | **HAProxy** puis migration si besoin | Fonctionnel, migrer uniquement si nécessaire |
|
||||
| **React Native mobile (Phase 4)** | **PWA-enhanced** court terme, natif Phase 6R | Économiser des mois de dev, réévaluer quand MAU > 5K |
|
||||
| **CQRS** | **Pattern request-response** | Complexité injustifiée à cette échelle |
|
||||
| **gRPC inter-service** | **REST** puis migration si bottleneck mesuré | Pragmatisme |
|
||||
| **Gamification (F536-F550)** | **Reporter à Phase 7+** | Pas critique pour le core product, gamification quand base users établie |
|
||||
| **Live Streaming (10 features complètes)** | **Live Streaming Lite (5 features)** | Go live, chat, tips, VOD — le reste en Phase 6R |
|
||||
|
||||
### 7.3 Objectifs ORIGIN à ABANDONNER
|
||||
|
||||
| Objectif | Raison d'Abandon | Alternative |
|
||||
|---|---|---|
|
||||
| **Web3/Blockchain (F491-F500)** | Market crypto incertain, complexité juridique, pas de demande marché prouvée | Surveiller le marché, réintroduire si demande utilisateur |
|
||||
| **VR/AR (E001-E020)** | Marché niche, coût de développement élevé, pas de ROI prévisible | Aucune — technologie prématurée pour une plateforme audio |
|
||||
| **Electron desktop app** | Tauri serait meilleur si besoin, mais PWA couvre 95% des cas | PWA avec offline mode |
|
||||
| **Voice synthesis AI (F468)** | Risques éthiques et juridiques (deepfakes audio) | Focus sur AI utile : BPM/key detection, auto-tags |
|
||||
| **AI mixing assistant (F470)** | Trop ambitieux, nécessite ML expertise dédiée | Partenariat avec service tiers (LANDR, iZotope) |
|
||||
| **DAO governance** | Hors scope produit audio, complexité juridique | Gouvernance classique (advisory board) |
|
||||
| **NFT minting** | Marché en déclin, risque réputationnel | Licensing traditionnel (déjà implémenté) |
|
||||
| **Kafka** | RabbitMQ suffit, pas de besoin event sourcing | Garder RabbitMQ |
|
||||
| **SOC2 certification** | Coût et effort disproportionnés pour une startup pre-revenue | Focus GDPR (obligatoire) + bonnes pratiques sécurité |
|
||||
|
||||
### 7.4 Matrice de Décision Finale
|
||||
|
||||
| Catégorie | Features | Action |
|
||||
|---|---|---|
|
||||
| ✅ Garder | ~430 features (72%) | Continuer le développement selon la roadmap |
|
||||
| ⚠️ Modifier | ~70 features (12%) | Ajuster le scope, l'ordre, ou l'approche |
|
||||
| ❌ Abandonner | ~100 features (17%) | Retirer du backlog, documenter la décision |
|
||||
|
||||
---
|
||||
|
||||
## 8. VIOLATIONS CRITIQUES ORIGIN ET PLAN DE CORRECTION
|
||||
|
||||
### 8.1 Violations des Règles Immuables ORIGIN
|
||||
|
||||
| # | Règle ORIGIN | Violation | Correction | Effort | Deadline |
|
||||
|---|---|---|---|---|---|
|
||||
| V01 | Coverage ≥ 80% toutes phases | Seuil à 50% frontend, non mesuré Go/Rust | Configurer CI coverage, monter progressivement : 60% → 70% → 80% | 5j | Fin avril 2026 |
|
||||
| V02 | 0 vulnérabilités critiques | 2 critiques (JWT) | Corriger VEZA-SEC-001 et VEZA-SEC-002 | 2j | Mi-mars 2026 |
|
||||
| V03 | Pas de feature creep | Features P6-P7 implémentées avant P3-P4 complètes | Consolider P2-P3 avant d'avancer (Phase 3.5) | — | Plan ci-dessus |
|
||||
| V04 | Phase complète à 100% avant suivante | P3 à 65%, P4 démarrée | Compléter P3 dans Phase 3.5 | 4 sem | Fin avril 2026 |
|
||||
| V05 | Security audit externe avant P1, P3, P5, P7 | Aucun audit externe réalisé | Commander un pentest externe | 2 sem + budget | Avant Phase 4R |
|
||||
| V06 | Code review 2+ reviewers | Solo developer | Recruter reviewers (communauté, freelance, AI review) | — | Continu |
|
||||
| V07 | Documentation API à jour | Swagger existe mais pas synchronisé automatiquement | Intégrer swag generate dans CI | 1j | Fin mars 2026 |
|
||||
|
||||
### 8.2 Priorités de Correction
|
||||
|
||||
```
|
||||
URGENT (< 2 semaines)
|
||||
├── V02 : Corriger les 2 vulns JWT critiques
|
||||
├── V07 : Synchroniser Swagger
|
||||
└── Nettoyer secrets hardcodés
|
||||
|
||||
IMPORTANT (< 2 mois)
|
||||
├── V01 : Coverage CI/CD configurée et progressive
|
||||
├── V04 : Compléter Phase 3 features manquantes
|
||||
├── V03 : Consolider avant d'avancer
|
||||
└── V05 : Commander pentest externe
|
||||
|
||||
NÉCESSAIRE (< 6 mois)
|
||||
├── V06 : Trouver des reviewers
|
||||
├── Coverage à 80%
|
||||
└── Lighthouse CI + performance baseline
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CONCLUSION
|
||||
|
||||
Le projet Veza a construit une base technique solide avec une architecture clean, un monorepo bien organisé, et des fondations fonctionnelles (auth, streaming, marketplace, infrastructure CI/CD). Cependant, il accuse un retard de ~6 mois sur le plan ORIGIN, principalement dû à l'ambition du scope (600 features / 24 mois) face aux ressources disponibles.
|
||||
|
||||
**Le plan ORIGIN reste un excellent guide directeur**, mais il doit être adapté à la réalité :
|
||||
|
||||
1. **Réduire le scope de 600 à ~490 features** (abandonner Web3, VR/AR, certaines features AI)
|
||||
2. **Consolider avant d'avancer** (Phase 3.5 de stabilisation)
|
||||
3. **Corriger immédiatement les 2 vulnérabilités critiques JWT**
|
||||
4. **Établir les métriques de qualité** (coverage, performance, monitoring)
|
||||
5. **Suivre la roadmap révisée** pour atteindre 82% de complétion d'ici mars 2027
|
||||
|
||||
Le projet est **techniquement viable** et les choix architecturaux (pivots Chat Go, Hyperswitch, simplification gRPC→REST) sont **pragmatiques et justifiés**. L'enjeu principal n'est pas technique mais de **priorisation** : livrer les features qui génèrent le plus de valeur business en premier (marketplace, premium, analytics) tout en maintenant la qualité.
|
||||
|
||||
---
|
||||
|
||||
*Document généré le 4 mars 2026*
|
||||
*Basé sur : Audit Technique VEZA 2026-03-04 + Documentation ORIGIN*
|
||||
*Méthodologie : Analyse statique du code, cross-référencement F001-F600 avec le codebase, comparaison métriques ORIGIN vs mesures actuelles*
|
||||
|
||||
1284
VEZA_VERSIONS_ROADMAP.md
Normal file
1284
VEZA_VERSIONS_ROADMAP.md
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -4729,7 +4729,7 @@ export const TrackApiAxiosParamCreator = function (configuration?: Configuration
|
|||
/**
|
||||
* Get remaining upload quota for the user
|
||||
* @summary Get Upload Quota
|
||||
* @param {string} id User ID (optional, defaults to current user)
|
||||
* @param {string} id User ID or \'me\' for current user
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
|
@ -4882,7 +4882,7 @@ export const TrackApiFp = function(configuration?: Configuration) {
|
|||
/**
|
||||
* Get remaining upload quota for the user
|
||||
* @summary Get Upload Quota
|
||||
* @param {string} id User ID (optional, defaults to current user)
|
||||
* @param {string} id User ID or \'me\' for current user
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
|
@ -4972,7 +4972,7 @@ export const TrackApiFactory = function (configuration?: Configuration, basePath
|
|||
/**
|
||||
* Get remaining upload quota for the user
|
||||
* @summary Get Upload Quota
|
||||
* @param {string} id User ID (optional, defaults to current user)
|
||||
* @param {string} id User ID or \'me\' for current user
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
|
@ -5049,7 +5049,7 @@ export interface TrackApiInterface {
|
|||
/**
|
||||
* Get remaining upload quota for the user
|
||||
* @summary Get Upload Quota
|
||||
* @param {string} id User ID (optional, defaults to current user)
|
||||
* @param {string} id User ID or \'me\' for current user
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
|
@ -5133,7 +5133,7 @@ export class TrackApi extends BaseAPI implements TrackApiInterface {
|
|||
/**
|
||||
* Get remaining upload quota for the user
|
||||
* @summary Get Upload Quota
|
||||
* @param {string} id User ID (optional, defaults to current user)
|
||||
* @param {string} id User ID or \'me\' for current user
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -313,7 +313,7 @@ import {
|
|||
const configuration = new Configuration();
|
||||
const apiInstance = new TrackApi(configuration);
|
||||
|
||||
let id: string; //User ID (optional, defaults to current user) (default to undefined)
|
||||
let id: string; //User ID or \'me\' for current user (default to undefined)
|
||||
|
||||
const { status, data } = await apiInstance.tracksQuotaIdGet(
|
||||
id
|
||||
|
|
@ -324,7 +324,7 @@ const { status, data } = await apiInstance.tracksQuotaIdGet(
|
|||
|
||||
|Name | Type | Description | Notes|
|
||||
|------------- | ------------- | ------------- | -------------|
|
||||
| **id** | [**string**] | User ID (optional, defaults to current user) | defaults to undefined|
|
||||
| **id** | [**string**] | User ID or \'me\' for current user | defaults to undefined|
|
||||
|
||||
|
||||
### Return type
|
||||
|
|
|
|||
96
docs/ENV_VARIABLES.md
Normal file
96
docs/ENV_VARIABLES.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# Variables d'environnement Veza
|
||||
|
||||
> Référence complète des variables d'environnement utilisées par la plateforme Veza.
|
||||
> v0.9.1 : Migration JWT RS256 (JWT_PRIVATE_KEY_PATH, JWT_PUBLIC_KEY_PATH).
|
||||
>
|
||||
> Voir aussi : [.env.example](../.env.example), [veza-backend-api/.env.template](../veza-backend-api/.env.template), [veza-stream-server/.env.example](../veza-stream-server/.env.example).
|
||||
|
||||
---
|
||||
|
||||
## Backend API (veza-backend-api)
|
||||
|
||||
### Authentification JWT (v0.9.1 RS256)
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `JWT_PRIVATE_KEY_PATH` | Chemin vers la clé privée RSA (signature) | string | Oui (prod) | — | `/secrets/jwt-private.pem` |
|
||||
| `JWT_PUBLIC_KEY_PATH` | Chemin vers la clé publique RSA (vérification) | string | Oui (prod) | — | `/secrets/jwt-public.pem` |
|
||||
| `JWT_SECRET` | Secret HS256 (déprécié, fallback dev uniquement) | string | Si pas RS256 | — | min 32 chars |
|
||||
| `JWT_ISSUER` | Issuer claim (access/refresh tokens) | string | Non | `veza-api` | `veza-api` |
|
||||
| `JWT_AUDIENCE` | Audience claim | string | Non | `veza-platform` | `veza-platform` |
|
||||
| `JWT_ACCESS_TOKEN_DURATION` | Durée access token | duration | Non | `15m` | `5m`, `1h` |
|
||||
| `JWT_REFRESH_TOKEN_DURATION` | Durée refresh token | duration | Non | `30d` | `7d`, `14d` |
|
||||
|
||||
**Génération des clés RS256 :**
|
||||
```bash
|
||||
scripts/generate-jwt-keys.sh
|
||||
# ou manuellement :
|
||||
openssl genrsa -out jwt-private.pem 2048
|
||||
openssl rsa -in jwt-private.pem -pubout -out jwt-public.pem
|
||||
```
|
||||
|
||||
### Base de données
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `DATABASE_URL` | URL connexion PostgreSQL | string | Oui | — | `postgres://veza:password@localhost:5432/veza?sslmode=disable` |
|
||||
| `DATABASE_READ_URL` | URL réplica lecture (optionnel) | string | Non | — | `postgres://veza:password@replica:5432/veza` |
|
||||
|
||||
### Redis
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `REDIS_URL` | URL connexion Redis | string | Oui | — | `redis://localhost:6379` |
|
||||
| `REDIS_ENABLE` | Activer Redis | bool | Non | `true` | `true`, `false` |
|
||||
|
||||
### CORS & Domaine
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `APP_DOMAIN` | Domaine applicatif | string | Non | `veza.fr` | `veza.fr`, `app.veza.com` |
|
||||
| `CORS_ALLOWED_ORIGINS` | Origines CORS autorisées | string | Oui | — | `http://veza.fr:5173` |
|
||||
| `FRONTEND_URL` | URL frontend (OAuth, reset) | string | Non | `http://localhost:5173` | `https://app.veza.com` |
|
||||
|
||||
### Autres services
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `STREAM_SERVER_URL` | URL stream server | string | Non | `http://veza.fr:8082` | `http://stream:8082` |
|
||||
| `STREAM_SERVER_INTERNAL_API_KEY` | Clé API interne transcode | string | Non | — | secret partagé |
|
||||
| `CHAT_SERVER_URL` | URL chat (legacy) | string | Non | `http://veza.fr:8081` | — |
|
||||
| `RABBITMQ_URL` | URL RabbitMQ | string | Non | — | `amqp://veza:password@localhost:5672/` |
|
||||
|
||||
---
|
||||
|
||||
## Stream Server (veza-stream-server)
|
||||
|
||||
### JWT (v0.9.1 RS256)
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `JWT_PUBLIC_KEY_PATH` | Chemin clé publique RSA (vérification) | string | Oui (prod) | — | `/secrets/jwt-public.pem` |
|
||||
| `JWT_SECRET` | Secret HS256 (phase transition uniquement) | string | Si pas RS256 | — | min 32 chars |
|
||||
| `JWT_EXPIRATION` | TTL tokens (secondes) | int | Non | `3600` | `300`, `3600` |
|
||||
|
||||
**Remarque :** Le stream server valide les tokens émis par le backend. Il utilise la clé publique partagée (JWT_PUBLIC_KEY_PATH) pour RS256.
|
||||
|
||||
---
|
||||
|
||||
## Variables communes (veza-common)
|
||||
|
||||
Services Rust utilisant veza-common (config_rust JwtConfig) :
|
||||
|
||||
| Variable | Description | Type | Requis | Valeur par défaut | Exemple |
|
||||
|----------|--------------|------|--------|------------------|---------|
|
||||
| `JWT_SECRET` | Secret JWT | string | Oui | — | min 32 chars (VEZA-SEC-001) |
|
||||
| `JWT_ISSUER` | Issuer | string | Non | `veza-api` | `veza-api` |
|
||||
| `JWT_AUDIENCE` | Audience | string | Non | `veza-platform` | `veza-platform` |
|
||||
|
||||
---
|
||||
|
||||
## Checklist de démarrage
|
||||
|
||||
1. Copier `.env.example` vers `.env` (racine) et `veza-backend-api/.env.template` vers `veza-backend-api/.env`
|
||||
2. Pour RS256 : exécuter `scripts/generate-jwt-keys.sh` et configurer `JWT_PRIVATE_KEY_PATH`, `JWT_PUBLIC_KEY_PATH`
|
||||
3. Configurer `DATABASE_URL`, `REDIS_URL`, `CORS_ALLOWED_ORIGINS`
|
||||
4. En production : ne jamais commiter `.env` ni les fichiers `.pem`
|
||||
36
docs/SECRETS_AUDIT.md
Normal file
36
docs/SECRETS_AUDIT.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Audit des secrets (TASK-SEC-002)
|
||||
|
||||
v0.9.1 — Procédure d'audit des secrets exposés.
|
||||
|
||||
## Outils recommandés
|
||||
|
||||
```bash
|
||||
# Gitleaks (recommandé)
|
||||
gitleaks detect --source . --verbose --report-path gitleaks-report.json
|
||||
|
||||
# TruffleHog
|
||||
truffleHog --regex --entropy high .
|
||||
```
|
||||
|
||||
## Vérifications manuelles
|
||||
|
||||
1. Aucun fichier `.env` ou `.env.*` (hors `.example`) ne doit être commité
|
||||
2. Aucun fichier `*.pem` contenant des clés privées
|
||||
3. Aucun secret hardcodé (JWT, Stripe, OAuth, DB password)
|
||||
4. `.gitignore` couvre : `.env`, `.env.*`, `jwt-private.pem`, `jwt-public.pem`
|
||||
|
||||
## Rotation des clés si compromise
|
||||
|
||||
En cas de findings :
|
||||
|
||||
1. **JWT** : Régénérer clés RSA (`scripts/generate-jwt-keys.sh`), déployer, invalider tokens (migration 123)
|
||||
2. **Stripe** : Régénérer dans Dashboard
|
||||
3. **OAuth** : Régénérer client secret chez le provider
|
||||
4. **Database** : Changer mot de passe, mettre à jour DATABASE_URL
|
||||
|
||||
## État v0.9.1
|
||||
|
||||
- veza-common : plus de secret par défaut (VEZA-SEC-001 corrigé)
|
||||
- Backend : RS256 préféré, JWT_SECRET fallback dev uniquement
|
||||
- Stream server : JWT_PUBLIC_KEY_PATH ou JWT_SECRET
|
||||
- `.gitignore` : jwt-private.pem, jwt-public.pem
|
||||
25
scripts/generate-jwt-keys.sh
Executable file
25
scripts/generate-jwt-keys.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# Generate RSA key pair for JWT RS256 (v0.9.1)
|
||||
# Usage: ./scripts/generate-jwt-keys.sh [output_dir]
|
||||
# Output: jwt-private.pem, jwt-public.pem (2048-bit RSA)
|
||||
# NEVER commit these files to Git.
|
||||
|
||||
set -e
|
||||
|
||||
OUTPUT_DIR="${1:-.}"
|
||||
PRIVATE="${OUTPUT_DIR}/jwt-private.pem"
|
||||
PUBLIC="${OUTPUT_DIR}/jwt-public.pem"
|
||||
|
||||
echo "Generating RSA 2048-bit key pair for JWT RS256..."
|
||||
openssl genrsa -out "$PRIVATE" 2048
|
||||
openssl rsa -in "$PRIVATE" -pubout -out "$PUBLIC"
|
||||
|
||||
echo "Keys generated:"
|
||||
echo " Private: $PRIVATE"
|
||||
echo " Public: $PUBLIC"
|
||||
echo ""
|
||||
echo "Set in .env:"
|
||||
echo " JWT_PRIVATE_KEY_PATH=$PRIVATE"
|
||||
echo " JWT_PUBLIC_KEY_PATH=$PUBLIC"
|
||||
echo ""
|
||||
echo "WARNING: Never commit .pem files to Git!"
|
||||
|
|
@ -26,12 +26,14 @@ DATABASE_MAX_OPEN_CONNS=25
|
|||
DATABASE_MAX_IDLE_CONNS=5
|
||||
DATABASE_CONN_MAX_LIFETIME=5m
|
||||
|
||||
# --- JWT & AUTHENTICATION (REQUIRED) ---
|
||||
# CRITICAL: Must be at least 32 characters in production
|
||||
# Generate with: openssl rand -base64 32
|
||||
# --- JWT & AUTHENTICATION (v0.9.1 RS256) ---
|
||||
# PREFERRED: RS256 with RSA keys (generate with scripts/generate-jwt-keys.sh)
|
||||
# JWT_PRIVATE_KEY_PATH=/path/to/jwt-private.pem
|
||||
# JWT_PUBLIC_KEY_PATH=/path/to/jwt-public.pem
|
||||
# FALLBACK (dev only): JWT_SECRET must be at least 32 characters
|
||||
JWT_SECRET=dev-secret-key-minimum-32-characters-long-for-testing-only
|
||||
JWT_ISSUER=veza-api
|
||||
JWT_AUDIENCE=veza-app
|
||||
JWT_AUDIENCE=veza-platform
|
||||
JWT_ACCESS_TOKEN_DURATION=15m
|
||||
JWT_REFRESH_TOKEN_DURATION=30d
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func (r *APIRouter) setupAuthRoutes(router *gin.RouterGroup) error {
|
|||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(r.db, r.logger)
|
||||
passwordResetService := services.NewPasswordResetService(r.db, r.logger)
|
||||
jwtService, err := services.NewJWTService(r.config.JWTSecret, r.config.JWTIssuer, r.config.JWTAudience)
|
||||
jwtService, err := services.NewJWTService(r.config.JWTPrivateKeyPath, r.config.JWTPublicKeyPath, r.config.JWTSecret, r.config.JWTIssuer, r.config.JWTAudience)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize JWT service: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,9 @@ type Config struct {
|
|||
Env string // Environnement: development, test, production (P0-SECURITY)
|
||||
AppPort int // Port pour le serveur HTTP (T0031)
|
||||
AppDomain string // Domaine applicatif (APP_DOMAIN) — single source of truth pour URLs & CORS
|
||||
JWTSecret string
|
||||
JWTSecret string // HS256 fallback (dev only)
|
||||
JWTPrivateKeyPath string // v0.9.1 RS256: path to RSA private key
|
||||
JWTPublicKeyPath string // v0.9.1 RS256: path to RSA public key
|
||||
JWTIssuer string // T0204: Issuer claim validation (P1-SECURITY)
|
||||
JWTAudience string // T0204: Audience claim validation (P1-SECURITY)
|
||||
ChatJWTSecret string // Secret pour les tokens WebSocket Chat
|
||||
|
|
@ -176,12 +178,18 @@ func ValidateRequiredEnvironmentVariables(env string) error {
|
|||
var errors []string
|
||||
|
||||
// Variables requises dans tous les environnements
|
||||
requiredVars := []string{
|
||||
"JWT_SECRET",
|
||||
"DATABASE_URL",
|
||||
requiredVars := []string{"DATABASE_URL"}
|
||||
|
||||
// v0.9.1: JWT config — require either RS256 keys OR JWT_SECRET (dev fallback)
|
||||
jwtPrivatePath := os.Getenv("JWT_PRIVATE_KEY_PATH")
|
||||
jwtPublicPath := os.Getenv("JWT_PUBLIC_KEY_PATH")
|
||||
jwtSecret := os.Getenv("JWT_SECRET")
|
||||
hasRS256 := jwtPrivatePath != "" && jwtPublicPath != ""
|
||||
hasHS256 := jwtSecret != ""
|
||||
if !hasRS256 && !hasHS256 {
|
||||
missingVars = append(missingVars, "JWT_PRIVATE_KEY_PATH+JWT_PUBLIC_KEY_PATH or JWT_SECRET")
|
||||
}
|
||||
|
||||
// Vérifier les variables requises
|
||||
for _, varName := range requiredVars {
|
||||
value := os.Getenv(varName)
|
||||
if value == "" {
|
||||
|
|
@ -280,11 +288,10 @@ func NewConfig() (*Config, error) {
|
|||
maxConcurrentUploads := getEnvInt("MAX_CONCURRENT_UPLOADS", 10) // 10 par défaut
|
||||
|
||||
// Configuration depuis les variables d'environnement
|
||||
// SECURITY: JWT_SECRET est REQUIS - pas de valeur par défaut pour éviter les failles de sécurité
|
||||
jwtSecret, err := getEnvRequired("JWT_SECRET")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// v0.9.1: JWT — RS256 (prefer) or JWT_SECRET (dev fallback)
|
||||
jwtPrivateKeyPath := getEnv("JWT_PRIVATE_KEY_PATH", "")
|
||||
jwtPublicKeyPath := getEnv("JWT_PUBLIC_KEY_PATH", "")
|
||||
jwtSecret := getEnv("JWT_SECRET", "")
|
||||
|
||||
databaseURL, err := getEnvRequired("DATABASE_URL")
|
||||
if err != nil {
|
||||
|
|
@ -296,12 +303,14 @@ func NewConfig() (*Config, error) {
|
|||
|
||||
config := &Config{
|
||||
Env: env, // Store environment for validation (P0-SECURITY)
|
||||
AppPort: appPort,
|
||||
AppDomain: appDomain,
|
||||
JWTSecret: jwtSecret,
|
||||
JWTIssuer: getEnv("JWT_ISSUER", "veza-api"),
|
||||
JWTAudience: getEnv("JWT_AUDIENCE", "veza-app"),
|
||||
ChatJWTSecret: getEnv("CHAT_JWT_SECRET", jwtSecret), // Fallback to main JWT secret if not set
|
||||
AppPort: appPort,
|
||||
AppDomain: appDomain,
|
||||
JWTSecret: jwtSecret,
|
||||
JWTPrivateKeyPath: jwtPrivateKeyPath,
|
||||
JWTPublicKeyPath: jwtPublicKeyPath,
|
||||
JWTIssuer: getEnv("JWT_ISSUER", "veza-api"),
|
||||
JWTAudience: getEnv("JWT_AUDIENCE", "veza-platform"),
|
||||
ChatJWTSecret: getEnv("CHAT_JWT_SECRET", jwtSecret),
|
||||
RedisURL: getEnv("REDIS_URL", "redis://"+appDomain+":6379"),
|
||||
RedisEnable: getEnvBool("REDIS_ENABLE", true),
|
||||
// SECURITY: DATABASE_URL est REQUIS - contient des credentials sensibles
|
||||
|
|
|
|||
|
|
@ -334,9 +334,11 @@ func TestNewConfig_RequiresJWTSecret(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
// Supprimer JWT_SECRET - devrait causer une erreur
|
||||
// Supprimer JWT config - ni RS256 ni HS256 (devrait causer une erreur)
|
||||
os.Unsetenv("JWT_SECRET")
|
||||
// Définir DATABASE_URL pour éviter une erreur sur cette variable (on teste seulement JWT_SECRET)
|
||||
os.Unsetenv("JWT_PRIVATE_KEY_PATH")
|
||||
os.Unsetenv("JWT_PUBLIC_KEY_PATH")
|
||||
// Définir DATABASE_URL pour éviter une erreur sur cette variable (on teste seulement JWT config)
|
||||
os.Setenv("DATABASE_URL", "postgresql://test:test@localhost:5432/test_db")
|
||||
|
||||
// MOD-P0-002: getEnvRequired() returns error, not panic - verify error is returned
|
||||
|
|
@ -578,10 +580,9 @@ func TestNewConfig_JWTSecretTooShort(t *testing.T) {
|
|||
os.Setenv("RABBITMQ_ENABLE", "false")
|
||||
|
||||
// MOD-P0-002: NewConfig() doit retourner une erreur car JWT_SECRET est trop court
|
||||
// La validation Validate() est appelée dans NewConfig() et doit échouer
|
||||
// La validation dans NewJWTService rejette les secrets < 32 chars
|
||||
_, err := NewConfig()
|
||||
require.Error(t, err, "NewConfig should return error when JWT_SECRET is too short")
|
||||
assert.Contains(t, err.Error(), "JWT_SECRET validation failed", "Error message should mention JWT_SECRET validation")
|
||||
assert.Contains(t, err.Error(), "32", "Error message should mention minimum length of 32")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ func (c *Config) initServices() error {
|
|||
// Service de permissions
|
||||
c.PermissionService = services.NewPermissionService(c.Database.GormDB)
|
||||
|
||||
// JWT Service
|
||||
c.JWTService, err = services.NewJWTService(c.JWTSecret, c.JWTIssuer, c.JWTAudience)
|
||||
// JWT Service (v0.9.1: RS256 prefer, HS256 dev fallback)
|
||||
c.JWTService, err = services.NewJWTService(c.JWTPrivateKeyPath, c.JWTPublicKeyPath, c.JWTSecret, c.JWTIssuer, c.JWTAudience)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ func setupAuthTestRouter(t *testing.T, authMiddlewares ...gin.HandlerFunc) (*gin
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func setupAuthIntegrationTestRouter(t *testing.T) (*gin.Engine, *auth.AuthServic
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ func setupTestJWTService(t *testing.T) *services.JWTService {
|
|||
|
||||
issuer := "veza-api"
|
||||
audience := "veza-app"
|
||||
jwtService, err := services.NewJWTService(testJWTSecret, issuer, audience)
|
||||
jwtService, err := services.NewJWTService("", "", testJWTSecret, issuer, audience)
|
||||
require.NoError(t, err)
|
||||
return jwtService
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"veza-backend-api/internal/models"
|
||||
|
|
@ -11,46 +15,129 @@ import (
|
|||
)
|
||||
|
||||
type JWTService struct {
|
||||
// RS256 (v0.9.1): prefer if set
|
||||
privateKey *rsa.PrivateKey
|
||||
publicKey *rsa.PublicKey
|
||||
// HS256 fallback (dev only)
|
||||
secretKey []byte
|
||||
issuer string
|
||||
audience string
|
||||
Config *models.JWTConfig
|
||||
useRS256 bool
|
||||
|
||||
issuer string
|
||||
audience string
|
||||
Config *models.JWTConfig
|
||||
}
|
||||
|
||||
func NewJWTService(secret, issuer, audience string) (*JWTService, error) {
|
||||
if secret == "" {
|
||||
return nil, fmt.Errorf("JWT secret is required")
|
||||
}
|
||||
// SEC-005: Enforce minimum secret length to prevent brute-force
|
||||
if len(secret) < 32 {
|
||||
return nil, fmt.Errorf("JWT secret must be at least 32 characters")
|
||||
}
|
||||
// NewJWTService creates a JWT service. Prefers RS256 if privateKeyPath and publicKeyPath are set.
|
||||
// Falls back to HS256 with secret for development (secret must be min 32 chars).
|
||||
func NewJWTService(privateKeyPath, publicKeyPath, secret, issuer, audience string) (*JWTService, error) {
|
||||
if issuer == "" {
|
||||
issuer = "veza-api"
|
||||
}
|
||||
if audience == "" {
|
||||
audience = "veza-app"
|
||||
audience = "veza-platform"
|
||||
}
|
||||
|
||||
// Default config - SEC-006: Reduced TTLs for improved security
|
||||
config := &models.JWTConfig{
|
||||
AccessTokenTTL: 5 * time.Minute,
|
||||
RefreshTokenTTL: 14 * 24 * time.Hour, // 14 days (was 30)
|
||||
RememberMeRefreshTokenTTL: 30 * 24 * time.Hour, // 30 days (was 90)
|
||||
RefreshTokenTTL: 14 * 24 * time.Hour,
|
||||
RememberMeRefreshTokenTTL: 30 * 24 * time.Hour,
|
||||
}
|
||||
|
||||
// Prefer RS256 if both key paths are set
|
||||
if privateKeyPath != "" && publicKeyPath != "" {
|
||||
privateKey, err := loadRSAPrivateKey(privateKeyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load JWT private key: %w", err)
|
||||
}
|
||||
publicKey, err := loadRSAPublicKey(publicKeyPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load JWT public key: %w", err)
|
||||
}
|
||||
return &JWTService{
|
||||
privateKey: privateKey,
|
||||
publicKey: publicKey,
|
||||
useRS256: true,
|
||||
issuer: issuer,
|
||||
audience: audience,
|
||||
Config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Fallback to HS256 (dev)
|
||||
if secret == "" {
|
||||
return nil, fmt.Errorf("JWT configuration required: set JWT_PRIVATE_KEY_PATH and JWT_PUBLIC_KEY_PATH (RS256), or JWT_SECRET (HS256 dev fallback)")
|
||||
}
|
||||
if len(secret) < 32 {
|
||||
return nil, fmt.Errorf("JWT secret must be at least 32 characters")
|
||||
}
|
||||
return &JWTService{
|
||||
secretKey: []byte(secret),
|
||||
useRS256: false,
|
||||
issuer: issuer,
|
||||
audience: audience,
|
||||
Config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadRSAPrivateKey(path string) (*rsa.PrivateKey, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read private key file: %w", err)
|
||||
}
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("failed to decode PEM block")
|
||||
}
|
||||
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
// Try PKCS8
|
||||
k, err2 := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err2 != nil {
|
||||
return nil, fmt.Errorf("parse private key: %w", err)
|
||||
}
|
||||
var ok bool
|
||||
key, ok = k.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("private key is not RSA")
|
||||
}
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func loadRSAPublicKey(path string) (*rsa.PublicKey, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read public key file: %w", err)
|
||||
}
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("failed to decode PEM block")
|
||||
}
|
||||
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse public key: %w", err)
|
||||
}
|
||||
key, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("public key is not RSA")
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (s *JWTService) GetConfig() *models.JWTConfig {
|
||||
return s.Config
|
||||
}
|
||||
|
||||
func (s *JWTService) sign(claims jwt.Claims) (string, error) {
|
||||
var token *jwt.Token
|
||||
if s.useRS256 {
|
||||
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
return token.SignedString(s.privateKey)
|
||||
}
|
||||
token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(s.secretKey)
|
||||
}
|
||||
|
||||
func (s *JWTService) GenerateAccessToken(user *models.User) (string, error) {
|
||||
claims := models.CustomClaims{
|
||||
UserID: user.ID,
|
||||
|
|
@ -67,18 +154,16 @@ func (s *JWTService) GenerateAccessToken(user *models.User) (string, error) {
|
|||
ID: uuid.NewString(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(s.secretKey)
|
||||
return s.sign(&claims)
|
||||
}
|
||||
|
||||
func (s *JWTService) GenerateRefreshToken(user *models.User) (string, error) {
|
||||
claims := models.CustomClaims{
|
||||
UserID: user.ID,
|
||||
TokenVersion: user.TokenVersion,
|
||||
IsRefresh: true, // Mark as refresh token
|
||||
IsRefresh: true,
|
||||
TokenType: "refresh",
|
||||
TokenFamily: uuid.NewString(), // Nouvelle famille de token
|
||||
TokenFamily: uuid.NewString(),
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(s.Config.RefreshTokenTTL)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
|
|
@ -87,25 +172,18 @@ func (s *JWTService) GenerateRefreshToken(user *models.User) (string, error) {
|
|||
ID: uuid.NewString(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(s.secretKey)
|
||||
return s.sign(&claims)
|
||||
}
|
||||
|
||||
// GenerateTokenPair génère une paire de tokens (access + refresh) en une seule opération
|
||||
func (s *JWTService) GenerateTokenPair(user *models.User) (*models.TokenPair, error) {
|
||||
// Generate access token
|
||||
accessToken, err := s.GenerateAccessToken(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate access token: %w", err)
|
||||
}
|
||||
|
||||
// Generate refresh token
|
||||
refreshToken, err := s.GenerateRefreshToken(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate refresh token: %w", err)
|
||||
}
|
||||
|
||||
return &models.TokenPair{
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
|
|
@ -113,16 +191,21 @@ func (s *JWTService) GenerateTokenPair(user *models.User) (*models.TokenPair, er
|
|||
}, nil
|
||||
}
|
||||
|
||||
// VerifyToken valide et parse un token JWT
|
||||
func (s *JWTService) VerifyToken(tokenString string) (*models.CustomClaims, error) {
|
||||
return s.ValidateToken(tokenString)
|
||||
}
|
||||
|
||||
// ValidateToken valide un token JWT et retourne les claims
|
||||
func (s *JWTService) ValidateToken(tokenString string) (*models.CustomClaims, error) {
|
||||
// Parse avec validation des claims standards (exp, iat, nbf) ET custom (iss, aud)
|
||||
token, err := jwt.ParseWithClaims(tokenString, &models.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
// Validation stricte de l'algorithme (MOD-P2-002)
|
||||
if s.useRS256 {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
if token.Method.Alg() != "RS256" {
|
||||
return nil, fmt.Errorf("invalid signing algorithm: %v, expected RS256", token.Method.Alg())
|
||||
}
|
||||
return s.publicKey, nil
|
||||
}
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
|
|
@ -131,35 +214,27 @@ func (s *JWTService) ValidateToken(tokenString string) (*models.CustomClaims, er
|
|||
}
|
||||
return s.secretKey, nil
|
||||
},
|
||||
// Options de validation stricte
|
||||
jwt.WithIssuer(s.issuer),
|
||||
jwt.WithAudience(s.audience),
|
||||
jwt.WithExpirationRequired(),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse token: %w", err)
|
||||
}
|
||||
|
||||
if claims, ok := token.Claims.(*models.CustomClaims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("invalid token")
|
||||
}
|
||||
|
||||
// ParseToken parse un token JWT sans validation complète (utilise ValidateToken)
|
||||
func (s *JWTService) ParseToken(tokenString string) (*models.CustomClaims, error) {
|
||||
return s.ValidateToken(tokenString)
|
||||
}
|
||||
|
||||
// ExtractClaims extrait les claims d'un token JWT
|
||||
func (s *JWTService) ExtractClaims(tokenString string) (*models.CustomClaims, error) {
|
||||
return s.ValidateToken(tokenString)
|
||||
}
|
||||
|
||||
// ExtractUserID extrait l'ID utilisateur depuis un token JWT
|
||||
// MIGRATION UUID: retourne uuid.UUID au lieu de int64
|
||||
func (s *JWTService) ExtractUserID(tokenString string) (uuid.UUID, error) {
|
||||
claims, err := s.ValidateToken(tokenString)
|
||||
if err != nil {
|
||||
|
|
@ -168,7 +243,6 @@ func (s *JWTService) ExtractUserID(tokenString string) (uuid.UUID, error) {
|
|||
return claims.UserID, nil
|
||||
}
|
||||
|
||||
// VerifyTokenVersion vérifie si la version du token correspond à celle de l'utilisateur
|
||||
func (s *JWTService) VerifyTokenVersion(claims *models.CustomClaims, userTokenVersion int) error {
|
||||
if claims.TokenVersion != userTokenVersion {
|
||||
return fmt.Errorf("token version mismatch: token version %d does not match user version %d", claims.TokenVersion, userTokenVersion)
|
||||
|
|
@ -177,26 +251,28 @@ func (s *JWTService) VerifyTokenVersion(claims *models.CustomClaims, userTokenVe
|
|||
}
|
||||
|
||||
// GenerateStreamToken generates a short-lived JWT for HLS/WebSocket auth.
|
||||
// Uses issuer "veza-platform" and audience "veza-services" for compatibility with stream server.
|
||||
// TTL: 5 minutes. Claims match stream server Claims struct (sub, username, roles, etc.).
|
||||
// Uses issuer "veza-platform" and audience "veza-services" for stream server compatibility.
|
||||
func (s *JWTService) GenerateStreamToken(user *models.User) (string, error) {
|
||||
ttl := 5 * time.Minute
|
||||
now := time.Now()
|
||||
role := mapUserRoleToStreamRole(user.Role)
|
||||
claims := jwt.MapClaims{
|
||||
"sub": user.ID.String(),
|
||||
"user_id": user.ID.String(), // Chat server expects user_id
|
||||
"user_id": user.ID.String(),
|
||||
"username": user.Username,
|
||||
"email": user.Email,
|
||||
"roles": []string{role},
|
||||
"email": user.Email,
|
||||
"roles": []string{role},
|
||||
"permissions": []string{"StreamAudio"},
|
||||
"exp": now.Add(ttl).Unix(),
|
||||
"iat": now.Unix(),
|
||||
"iss": "veza-platform",
|
||||
"aud": "veza-services",
|
||||
"session_id": uuid.NewString(),
|
||||
"exp": now.Add(ttl).Unix(),
|
||||
"iat": now.Unix(),
|
||||
"iss": "veza-platform",
|
||||
"aud": "veza-services",
|
||||
"session_id": uuid.NewString(),
|
||||
}
|
||||
if s.useRS256 {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
return token.SignedString(s.privateKey)
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString(s.secretKey)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ func TestJWTService(t *testing.T) {
|
|||
secret := "test-secret-key-for-unit-tests-very-secure"
|
||||
issuer := "veza-api"
|
||||
audience := "veza-app"
|
||||
jwtService, err := NewJWTService(secret, issuer, audience)
|
||||
jwtService, err := NewJWTService("", "", secret, issuer, audience)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Mock User
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import (
|
|||
// Uses sqlite in-memory when db has no GormDB (e.g. from sqlmock).
|
||||
func setupOAuthServiceForTests(t *testing.T, db *database.Database) *OAuthService {
|
||||
t.Helper()
|
||||
jwtService, err := NewJWTService("test-secret-key-minimum-32-characters-long", "veza-api", "veza-app")
|
||||
jwtService, err := NewJWTService("", "", "test-secret-key-minimum-32-characters-long", "veza-api", "veza-app")
|
||||
require.NoError(t, err)
|
||||
// Use db for SessionService (needs sql.DB)
|
||||
sessionService := NewSessionService(db, zap.NewNop())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
-- v0.9.1 TASK-SEC-001: Invalidate all existing JWT tokens (HS256) before RS256 migration.
|
||||
-- Incrementing token_version forces re-login with new RS256 tokens.
|
||||
|
||||
UPDATE users SET token_version = token_version + 1;
|
||||
|
|
@ -89,7 +89,7 @@ func setupLogoutBlacklistTestRouter(t *testing.T) (*gin.Engine, *auth.AuthServic
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func setupOAuthGitHubTestRouter(t *testing.T) (*gin.Engine, *services.OAuthServi
|
|||
http.NotFound(w, r)
|
||||
}))
|
||||
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionService := services.NewSessionService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func setupOAuthGoogleTestRouter(t *testing.T) (*gin.Engine, *services.OAuthServi
|
|||
http.NotFound(w, r)
|
||||
}))
|
||||
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionService := services.NewSessionService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ func setupTokenRefreshTestRouter(t *testing.T) (*gin.Engine, *auth.AuthService,
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func setupPerformanceTestRouter(t *testing.T) (*gin.Engine, *gorm.DB, func()) {
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ func setupAuthorizationTestRouter(t *testing.T) (*gin.Engine, *gorm.DB, *service
|
|||
require.NoError(t, err)
|
||||
|
||||
// Setup services
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionService := services.NewSessionService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ func setupSecurityTestRouter(t *testing.T) (*gin.Engine, *gorm.DB, uuid.UUID, fu
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ func setupTwoFactorTestRouter(t *testing.T) (*gin.Engine, *gorm.DB, *database.Da
|
|||
emailValidator := validators.NewEmailValidator(db)
|
||||
passwordValidator := validators.NewPasswordValidator()
|
||||
passwordService := services.NewPasswordService(dbWrapper, logger)
|
||||
jwtService, err := services.NewJWTService("test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
jwtService, err := services.NewJWTService("", "", "test-secret-key-must-be-32-chars-long", "test-issuer", "test-audience")
|
||||
require.NoError(t, err)
|
||||
refreshTokenService := services.NewRefreshTokenService(db)
|
||||
emailVerificationService := services.NewEmailVerificationService(dbWrapper, logger)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
use tracing::{info, warn};
|
||||
use tracing::info;
|
||||
|
||||
/// Main configuration trait for Veza services
|
||||
pub trait VezaConfig: Default + Clone + Serialize {
|
||||
|
|
@ -231,20 +231,21 @@ pub struct JwtConfig {
|
|||
impl Default for JwtConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
secret: "your-super-secret-jwt-key".to_string(),
|
||||
// VEZA-SEC-001: No default secret — JWT_SECRET must be set via load_from_env
|
||||
secret: String::new(),
|
||||
access_token_ttl: 3600, // 1 hour
|
||||
refresh_token_ttl: 604800, // 7 days
|
||||
issuer: "veza".to_string(),
|
||||
audience: "veza-users".to_string(),
|
||||
issuer: "veza-api".to_string(),
|
||||
audience: "veza-platform".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VezaConfig for JwtConfig {
|
||||
fn load_from_env(&mut self) -> crate::VezaResult<()> {
|
||||
if let Ok(secret) = env::var("JWT_SECRET") {
|
||||
self.secret = secret;
|
||||
}
|
||||
// VEZA-SEC-001: JWT_SECRET is REQUIRED — refusing to start with no secret
|
||||
self.secret = env::var("JWT_SECRET")
|
||||
.map_err(|_| crate::VezaError::Config("JWT_SECRET must be set — refusing to start with no secret".to_string()))?;
|
||||
if let Ok(ttl) = env::var("JWT_ACCESS_TOKEN_TTL") {
|
||||
self.access_token_ttl = ttl.parse()
|
||||
.map_err(|_| crate::VezaError::Config("Invalid JWT_ACCESS_TOKEN_TTL".to_string()))?;
|
||||
|
|
@ -267,7 +268,9 @@ impl VezaConfig for JwtConfig {
|
|||
return Err(crate::VezaError::Config("JWT secret cannot be empty".to_string()));
|
||||
}
|
||||
if self.secret.len() < 32 {
|
||||
warn!("JWT secret is shorter than recommended 32 characters");
|
||||
return Err(crate::VezaError::Config(
|
||||
"JWT secret must be at least 32 characters".to_string(),
|
||||
));
|
||||
}
|
||||
if self.access_token_ttl == 0 {
|
||||
return Err(crate::VezaError::Config("JWT access token TTL must be > 0".to_string()));
|
||||
|
|
|
|||
|
|
@ -2,19 +2,25 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit la spécification complète et définitive de toutes les APIs de la plateforme Veza. Il documente 500+ endpoints REST, 50+ événements WebSocket, et 20+ services gRPC avec leurs schémas de requête/réponse, codes d'erreur standardisés, authentication flows, rate limiting, et versioning. L'API suit les principes REST/RESTful, utilise JSON comme format d'échange, et implémente OAuth 2.0 + JWT pour l'authentification.
|
||||
Ce document définit la spécification complète des APIs de la plateforme Veza, une plateforme audio open source et éthique pour musiciens indépendants. Il documente les endpoints REST, événements WebSocket, et services gRPC avec leurs schémas de requête/réponse, codes d'erreur standardisés, authentication flows, rate limiting transparent, et versioning explicite. L'API suit les principes REST/RESTful, utilise JSON comme format d'échange ouvert (aucun vendor lock-in), et implémente OAuth 2.0 + JWT pour l'authentification.
|
||||
|
||||
**Principes éthiques de l'API** : aucune donnée comportementale dans les réponses, découverte basée sur des règles déclaratives (pas de ML/IA), pagination toujours disponible (pas de lock-in), portabilité complète des données, et rate limits publiquement documentés.
|
||||
|
||||
**Exclusions éthiques** : aucun endpoint d'IA/ML (mastering, séparation de stems, détection de genre, recommandations ML, content ID, auto-tagging, synthèse vocale, transcription), aucun endpoint blockchain/NFT/crypto (minting, smart contracts, tokens, staking, DAO, IPFS, wallet), aucune gamification addictive (XP, niveaux, achievements basés sur l'engagement, leaderboards, streaks).
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
### Objectif Principal
|
||||
Définir une API complète, cohérente, documentée, et immuable qui servira de contrat entre frontend/backend/mobile pendant 24 mois sans breaking changes.
|
||||
Définir une API complète, cohérente, documentée, éthique et ouverte qui servira de contrat entre frontend/backend/mobile, en respectant la souveraineté des utilisateurs sur leurs données et leur attention.
|
||||
|
||||
### Objectifs Secondaires
|
||||
- Assurer la cohérence des schémas (naming, structure, types)
|
||||
- Standardiser les codes d'erreur et messages
|
||||
- Faciliter l'intégration (clients, partenaires, développeurs tiers)
|
||||
- Garantir la scalabilité (rate limiting, caching, pagination)
|
||||
- Supporter le versioning (v1 stable, v2 pour évolutions)
|
||||
- Faciliter l'intégration (clients, partenaires, développeurs tiers) via des formats ouverts
|
||||
- Garantir la scalabilité (rate limiting transparent, caching, pagination obligatoire)
|
||||
- Supporter le versioning explicite (v1 stable, v2 pour évolutions, politique de dépréciation longue)
|
||||
- Garantir la portabilité des données (export complet pour chaque utilisateur)
|
||||
- Exclure toute collecte de données comportementales à des fins de profilage
|
||||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
|
|
@ -28,19 +34,25 @@ Définir une API complète, cohérente, documentée, et immuable qui servira de
|
|||
8. [WebSocket APIs](#8-websocket-apis)
|
||||
9. [gRPC APIs](#9-grpc-apis)
|
||||
10. [OpenAPI 3.0 Specification](#10-openapi-30-specification)
|
||||
11. [API Éthique](#11-api-éthique)
|
||||
12. [Exclusions et Raisons Éthiques](#12-exclusions-et-raisons-éthiques)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
1. **URLs DOIVENT suivre le pattern** `/api/v{version}/{resource}`
|
||||
2. **HTTP methods DOIVENT respecter REST** (GET=read, POST=create, PUT=replace, PATCH=update, DELETE=delete)
|
||||
3. **Responses DOIVENT être JSON** avec `Content-Type: application/json`
|
||||
4. **Dates DOIVENT être ISO 8601** (format: `2025-11-02T14:30:00Z`)
|
||||
4. **Dates DOIVENT être ISO 8601** (format: `2026-03-04T14:30:00Z`)
|
||||
5. **IDs DOIVENT être UUID v4** (format: `550e8400-e29b-41d4-a716-446655440000`)
|
||||
6. **Pagination OBLIGATOIRE** pour collections (cursor-based par défaut)
|
||||
7. **Rate limiting OBLIGATOIRE** (headers: `X-RateLimit-*`)
|
||||
6. **Pagination OBLIGATOIRE** pour collections (cursor-based par défaut) — aucun endpoint ne force la consommation continue
|
||||
7. **Rate limiting OBLIGATOIRE et PUBLIC** (headers: `X-RateLimit-*`, documentation des limites accessible sans authentification)
|
||||
8. **Authentication JWT** dans header `Authorization: Bearer {token}`
|
||||
9. **Error codes STANDARDISÉS** (range 1000-9999, voir section 4)
|
||||
10. **Breaking changes INTERDITS** dans v1 (créer v2 si nécessaire)
|
||||
9. **Error codes STANDARDISÉS** (range 1000-9999, voir section 4) avec messages explicites et header `Retry-After` systématique sur 429
|
||||
10. **Breaking changes INTERDITS** dans v1 (créer v2 si nécessaire, politique de dépréciation ≥ 12 mois)
|
||||
11. **AUCUNE donnée comportementale** dans les réponses API (pas de tracking de scroll, temps de lecture, patterns de navigation)
|
||||
12. **AUCUN endpoint ML/IA, blockchain/NFT, ou gamification addictive** (voir section 12)
|
||||
13. **Portabilité des données OBLIGATOIRE** — endpoint d'export complet pour chaque utilisateur
|
||||
14. **Format ouvert JSON** — aucun format propriétaire, aucun vendor lock-in
|
||||
|
||||
## 1. DESIGN PRINCIPLES
|
||||
|
||||
|
|
@ -456,6 +468,10 @@ Request:
|
|||
|
||||
## 5. RATE LIMITING
|
||||
|
||||
> **Politique de transparence** : tous les rate limits sont publiquement documentés et accessibles
|
||||
> sans authentification via `GET /api/v1/rate-limits`. Les messages d'erreur 429 incluent systématiquement
|
||||
> le header `Retry-After` avec le nombre de secondes avant réinitialisation.
|
||||
|
||||
### 5.1 Rate Limits by Endpoint Type
|
||||
|
||||
| Endpoint Type | Limit | Window |
|
||||
|
|
@ -466,6 +482,7 @@ Request:
|
|||
| **File Upload** | 10 uploads | 1 hour |
|
||||
| **Search** | 500 requests | 1 hour |
|
||||
| **Streaming** | 10,000 plays | 1 day |
|
||||
| **Export** | 3 requests | 1 day |
|
||||
|
||||
### 5.2 Rate Limit Headers
|
||||
|
||||
|
|
@ -488,12 +505,75 @@ Retry-After: 1800
|
|||
{
|
||||
"error": {
|
||||
"code": 5000,
|
||||
"message": "Rate limit exceeded. Try again in 30 minutes."
|
||||
"message": "Rate limit exceeded. Try again in 30 minutes.",
|
||||
"retry_after_seconds": 1800
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Premium User Limits
|
||||
### 5.3 Rate Limit Documentation Endpoint
|
||||
|
||||
#### `GET /api/v1/rate-limits`
|
||||
**Description**: Documentation publique de tous les rate limits (aucune authentification requise).
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"rate_limits": [
|
||||
{
|
||||
"endpoint_type": "authentication",
|
||||
"limit": 10,
|
||||
"window_seconds": 60,
|
||||
"description": "Login, register, password reset"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "read",
|
||||
"limit": 1000,
|
||||
"window_seconds": 3600,
|
||||
"description": "GET requests on all resources"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "write",
|
||||
"limit": 100,
|
||||
"window_seconds": 3600,
|
||||
"description": "POST, PUT, PATCH requests"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "upload",
|
||||
"limit": 10,
|
||||
"window_seconds": 3600,
|
||||
"description": "File uploads (audio, images)"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "search",
|
||||
"limit": 500,
|
||||
"window_seconds": 3600,
|
||||
"description": "Search queries"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "streaming",
|
||||
"limit": 10000,
|
||||
"window_seconds": 86400,
|
||||
"description": "Stream plays per day"
|
||||
},
|
||||
{
|
||||
"endpoint_type": "export",
|
||||
"limit": 3,
|
||||
"window_seconds": 86400,
|
||||
"description": "Data export requests per day"
|
||||
}
|
||||
],
|
||||
"headers_documentation": {
|
||||
"X-RateLimit-Limit": "Maximum requests allowed in window",
|
||||
"X-RateLimit-Remaining": "Remaining requests in current window",
|
||||
"X-RateLimit-Reset": "Unix timestamp when window resets",
|
||||
"X-RateLimit-Window": "Window duration in seconds",
|
||||
"Retry-After": "Seconds to wait before retrying (on 429 responses)"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 Premium User Limits
|
||||
|
||||
| Endpoint Type | Standard | Premium | Factor |
|
||||
|---------------|----------|---------|--------|
|
||||
|
|
@ -749,7 +829,7 @@ Retry-After: 1800
|
|||
|
||||
**Parameters**:
|
||||
- `id` (path, required) - User UUID
|
||||
- `include` (query, optional) - Related resources (`profile,stats,badges`)
|
||||
- `include` (query, optional) - Related resources (`profile,stats`)
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
|
|
@ -771,13 +851,7 @@ Retry-After: 1800
|
|||
"track_count": 85,
|
||||
"playlist_count": 12
|
||||
},
|
||||
"badges": [
|
||||
{
|
||||
"name": "Verified Creator",
|
||||
"icon_url": "https://cdn.veza.io/badges/verified.svg",
|
||||
"rarity": "rare"
|
||||
}
|
||||
],
|
||||
"is_verified": true,
|
||||
"created_at": "2024-01-15T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
|
@ -1578,33 +1652,14 @@ cover_art: (image file, optional)
|
|||
|
||||
---
|
||||
|
||||
### 7.8 Module: Analytics
|
||||
### 7.8 Module: Statistiques Créateur (Analytics éthiques)
|
||||
|
||||
#### `POST /api/v1/analytics/events`
|
||||
**Description**: Track analytics event (client-side tracking).
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"event_type": "track_play",
|
||||
"event_data": {
|
||||
"track_id": "uuid",
|
||||
"duration_played": 120,
|
||||
"completion_percentage": 50
|
||||
},
|
||||
"metadata": {
|
||||
"user_agent": "...",
|
||||
"referrer": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (204 No Content)
|
||||
|
||||
---
|
||||
> **Principe éthique** : seules les statistiques agrégées et anonymisées sont disponibles.
|
||||
> Aucune donnée comportementale individuelle (temps de lecture, scroll, patterns de navigation) n'est collectée ni exposée.
|
||||
> Les créateurs accèdent uniquement aux compteurs agrégés de leurs propres contenus.
|
||||
|
||||
#### `GET /api/v1/analytics/tracks/{id}`
|
||||
**Description**: Get track analytics.
|
||||
**Description**: Statistiques agrégées d'un track (réservé au propriétaire).
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
|
|
@ -1615,24 +1670,343 @@ cover_art: (image file, optional)
|
|||
{
|
||||
"track_id": "uuid",
|
||||
"plays_total": 12500,
|
||||
"plays_unique": 8500,
|
||||
"likes_total": 850,
|
||||
"comments_total": 42,
|
||||
"plays_by_country": {
|
||||
"US": 5000,
|
||||
"UK": 2500,
|
||||
"CA": 1500
|
||||
},
|
||||
"plays_by_day": [
|
||||
{ "date": "2025-11-01", "plays": 450 },
|
||||
{ "date": "2025-11-02", "plays": 520 }
|
||||
{ "date": "2026-03-01", "plays": 450 },
|
||||
{ "date": "2026-03-02", "plays": 520 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **Données exclues volontairement** : géolocalisation par pays, données démographiques, user agents, referrers, durée de lecture individuelle, taux de complétion. Ces données ne sont ni collectées ni stockées.
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/analytics/summary`
|
||||
**Description**: Résumé global des statistiques du créateur authentifié.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Permissions**: `creator`, `admin`
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"total_tracks": 85,
|
||||
"total_plays": 125000,
|
||||
"total_likes": 8500,
|
||||
"total_comments": 420,
|
||||
"plays_last_30_days": 15000,
|
||||
"top_tracks": [
|
||||
{
|
||||
"track_id": "uuid",
|
||||
"title": "Midnight Dreams",
|
||||
"plays": 12500,
|
||||
"likes": 850
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*[7.9-7.15 Other modules follow similar patterns]*
|
||||
### 7.9 Module: Découverte Éthique
|
||||
|
||||
> **Principe** : la découverte est basée sur des règles déclaratives, des tags/genres déclarés par les créateurs,
|
||||
> et le graphe social opt-in. Aucun algorithme de recommandation ML/IA, aucun profilage comportemental.
|
||||
|
||||
#### `GET /api/v1/discover/genres`
|
||||
**Description**: Découverte par genres et tags déclarés. Retourne les tracks publics correspondant aux genres/tags demandés, triés chronologiquement (plus récents en premier).
|
||||
|
||||
**Parameters**:
|
||||
- `genres` (query, required) - Genres à découvrir, séparés par virgules (`electronic,house,jazz`)
|
||||
- `tags` (query, optional) - Tags supplémentaires (`ambient,chill`)
|
||||
- `limit` (query, optional, default=20) - Page size
|
||||
- `cursor` (query, optional) - Pagination cursor
|
||||
- `sort` (query, optional, default=-published_at) - Tri (`-published_at`, `title`, `-like_count`)
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "track-uuid",
|
||||
"title": "Midnight Dreams",
|
||||
"artist": "DJ Nova",
|
||||
"genre": "Electronic",
|
||||
"tags": ["ambient", "chill"],
|
||||
"duration": 245,
|
||||
"cover_art_url": "https://cdn.veza.io/covers/...",
|
||||
"creator": {
|
||||
"id": "creator-uuid",
|
||||
"username": "djnova",
|
||||
"avatar_url": "https://..."
|
||||
},
|
||||
"play_count": 12500,
|
||||
"like_count": 850,
|
||||
"published_at": "2026-03-01T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"filters_applied": {
|
||||
"genres": ["electronic"],
|
||||
"tags": [],
|
||||
"sort": "-published_at"
|
||||
},
|
||||
"pagination": {
|
||||
"next_cursor": "eyJpZCI6IjY2MWU5NTExIn0",
|
||||
"has_more": true,
|
||||
"limit": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/discover/editorial`
|
||||
**Description**: Playlists éditorialisées par l'équipe ou des curateurs vérifiés. Curation humaine uniquement, aucune automatisation algorithmique.
|
||||
|
||||
**Parameters**:
|
||||
- `limit` (query, optional, default=10)
|
||||
- `cursor` (query, optional)
|
||||
- `genre` (query, optional) - Filtrer par genre
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "playlist-uuid",
|
||||
"name": "Sélection de la semaine — Électronique",
|
||||
"description": "Les coups de cœur de l'équipe éditoriale",
|
||||
"curator": {
|
||||
"id": "curator-uuid",
|
||||
"username": "veza_editorial",
|
||||
"is_verified": true
|
||||
},
|
||||
"track_count": 12,
|
||||
"cover_art_url": "https://cdn.veza.io/editorial/...",
|
||||
"published_at": "2026-03-01T08:00:00Z"
|
||||
}
|
||||
],
|
||||
"pagination": { "next_cursor": "...", "has_more": true, "limit": 10 }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/discover/social`
|
||||
**Description**: Découverte par graphe social (opt-in). Retourne les tracks récemment écoutés ou likés par les contacts de l'utilisateur authentifié, uniquement si ces contacts ont activé le partage d'écoute.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Parameters**:
|
||||
- `limit` (query, optional, default=20)
|
||||
- `cursor` (query, optional)
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"track": {
|
||||
"id": "track-uuid",
|
||||
"title": "Summer Vibes",
|
||||
"artist": "johndoe",
|
||||
"genre": "House",
|
||||
"cover_art_url": "https://..."
|
||||
},
|
||||
"shared_by": [
|
||||
{
|
||||
"user_id": "contact-uuid",
|
||||
"username": "jane_smith",
|
||||
"action": "liked",
|
||||
"action_at": "2026-03-02T15:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"opt_in_notice": "Seuls les contacts ayant activé le partage d'écoute apparaissent ici.",
|
||||
"pagination": { "next_cursor": "...", "has_more": true, "limit": 20 }
|
||||
}
|
||||
```
|
||||
|
||||
**Errors**:
|
||||
- `401` - Non authentifié (1002)
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/discover/new`
|
||||
**Description**: Nouveaux tracks dans les genres suivis par l'utilisateur, triés chronologiquement. Aucune pondération algorithmique — ordre strictement chronologique inversé.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Parameters**:
|
||||
- `limit` (query, optional, default=20)
|
||||
- `cursor` (query, optional)
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "track-uuid",
|
||||
"title": "Fresh Beat",
|
||||
"artist": "producer_x",
|
||||
"genre": "Electronic",
|
||||
"published_at": "2026-03-04T09:00:00Z",
|
||||
"creator": {
|
||||
"id": "creator-uuid",
|
||||
"username": "producer_x"
|
||||
}
|
||||
}
|
||||
],
|
||||
"followed_genres": ["electronic", "house", "jazz"],
|
||||
"pagination": { "next_cursor": "...", "has_more": true, "limit": 20 }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/discover/nearby`
|
||||
**Description**: Découverte par proximité géographique (optionnel, opt-in). Retourne les créateurs et tracks publiés par des artistes proches de la localisation déclarée de l'utilisateur. La localisation est basée sur la ville/région déclarée dans le profil, pas de géolocalisation temps-réel.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Parameters**:
|
||||
- `radius_km` (query, optional, default=50) - Rayon de recherche en km
|
||||
- `limit` (query, optional, default=20)
|
||||
- `cursor` (query, optional)
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"creator": {
|
||||
"id": "creator-uuid",
|
||||
"username": "local_artist",
|
||||
"display_name": "Local Artist",
|
||||
"location": "Paris, France"
|
||||
},
|
||||
"recent_tracks": [
|
||||
{
|
||||
"id": "track-uuid",
|
||||
"title": "Paris Nights",
|
||||
"published_at": "2026-03-03T20:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"search_location": "Paris, France",
|
||||
"radius_km": 50,
|
||||
"pagination": { "next_cursor": "...", "has_more": true, "limit": 20 }
|
||||
}
|
||||
```
|
||||
|
||||
**Errors**:
|
||||
- `400` - Localisation non renseignée dans le profil (2001)
|
||||
|
||||
---
|
||||
|
||||
#### `PUT /api/v1/discover/preferences`
|
||||
**Description**: Définir les préférences de découverte de l'utilisateur (genres suivis, opt-in social, opt-in proximité).
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"followed_genres": ["electronic", "house", "jazz", "hip-hop"],
|
||||
"social_sharing_enabled": true,
|
||||
"nearby_discovery_enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"followed_genres": ["electronic", "house", "jazz", "hip-hop"],
|
||||
"social_sharing_enabled": true,
|
||||
"nearby_discovery_enabled": true,
|
||||
"updated_at": "2026-03-04T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7.10 Module: Portabilité des Données
|
||||
|
||||
> **Principe éthique** : tout utilisateur peut exporter l'intégralité de ses données à tout moment,
|
||||
> dans un format ouvert et documenté. Aucune rétention artificielle.
|
||||
|
||||
#### `POST /api/v1/export`
|
||||
**Description**: Demander un export complet des données de l'utilisateur (RGPD Art. 20). L'export est préparé de manière asynchrone et notifié par email.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"format": "json",
|
||||
"include": ["profile", "tracks", "playlists", "likes", "comments", "messages", "orders", "preferences"]
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (202 Accepted):
|
||||
```json
|
||||
{
|
||||
"export_id": "export-uuid",
|
||||
"status": "processing",
|
||||
"estimated_completion": "2026-03-04T15:00:00Z",
|
||||
"message": "Votre export est en cours de préparation. Vous recevrez un email avec le lien de téléchargement."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /api/v1/export/{id}`
|
||||
**Description**: Vérifier le statut d'un export.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"export_id": "export-uuid",
|
||||
"status": "completed",
|
||||
"download_url": "https://cdn.veza.io/exports/...",
|
||||
"download_expires_at": "2026-03-11T15:00:00Z",
|
||||
"file_size_bytes": 15728640,
|
||||
"created_at": "2026-03-04T14:30:00Z",
|
||||
"completed_at": "2026-03-04T14:45:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `DELETE /api/v1/account`
|
||||
**Description**: Supprimer définitivement le compte et toutes les données associées (RGPD Art. 17 — droit à l'effacement). Opération irréversible après période de grâce de 30 jours.
|
||||
|
||||
**Headers**: `Authorization: Bearer {token}`
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"confirmation": "DELETE_MY_ACCOUNT",
|
||||
"password": "current_password"
|
||||
}
|
||||
```
|
||||
|
||||
**Response** (200 OK):
|
||||
```json
|
||||
{
|
||||
"message": "Votre compte sera définitivement supprimé dans 30 jours. Reconnectez-vous avant cette date pour annuler.",
|
||||
"deletion_scheduled_at": "2026-04-03T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. WEBSOCKET APIS
|
||||
|
||||
|
|
@ -1825,13 +2199,16 @@ service ChatService {
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: Veza API
|
||||
version: 1.0.0
|
||||
version: 2.0.0
|
||||
description: |
|
||||
Veza platform API - Collaborative audio streaming, marketplace, and social network.
|
||||
Veza platform API — Open source ethical audio platform for independent musicians.
|
||||
|
||||
**Authentication**: JWT Bearer token in `Authorization` header.
|
||||
|
||||
**Rate Limiting**: Varies by endpoint (see headers).
|
||||
**Rate Limiting**: Publicly documented. See `GET /api/v1/rate-limits`.
|
||||
|
||||
**Ethical principles**: No behavioral data, no ML/AI recommendations, no blockchain/NFT,
|
||||
no addictive gamification. Full data portability.
|
||||
|
||||
**Support**: api@veza.io
|
||||
contact:
|
||||
|
|
@ -1839,7 +2216,8 @@ info:
|
|||
email: api@veza.io
|
||||
url: https://docs.veza.io
|
||||
license:
|
||||
name: Proprietary
|
||||
name: AGPL-3.0
|
||||
url: https://www.gnu.org/licenses/agpl-3.0.html
|
||||
servers:
|
||||
- url: https://api.veza.io/api/v1
|
||||
description: Production
|
||||
|
|
@ -2015,17 +2393,110 @@ paths:
|
|||
$ref: '#/components/responses/Forbidden'
|
||||
```
|
||||
|
||||
*[Full OpenAPI 3.0 spec with all 500+ endpoints would be ~5,000 lines - included in separate YAML file]*
|
||||
*[Full OpenAPI 3.0 spec included in separate YAML file]*
|
||||
|
||||
## 11. API ÉTHIQUE
|
||||
|
||||
### 11.1 Aucune Donnée Comportementale dans les Réponses
|
||||
|
||||
Les réponses API ne contiennent **jamais** :
|
||||
- De données de tracking utilisateur (scroll depth, mouse movements, session duration)
|
||||
- De scores de recommandation ou poids algorithmiques
|
||||
- De profils comportementaux dérivés
|
||||
- D'identifiants de tracking tiers (pixels, fingerprints)
|
||||
- De données permettant le profilage publicitaire
|
||||
|
||||
Les seules données retournées sont celles **explicitement demandées** par l'utilisateur ou le créateur, dans le cadre de l'utilisation directe de la plateforme.
|
||||
|
||||
### 11.2 Pagination Toujours Disponible
|
||||
|
||||
**Tous** les endpoints retournant des collections supportent la pagination :
|
||||
- Cursor-based (par défaut) ou offset-based
|
||||
- Aucun endpoint ne force une consommation continue (pas de scroll infini obligatoire côté API)
|
||||
- Le client est libre de consommer les données à son rythme
|
||||
- Les paramètres `limit` et `cursor`/`page` sont toujours disponibles
|
||||
|
||||
### 11.3 Format Ouvert — Aucun Vendor Lock-in
|
||||
|
||||
- **Format unique** : JSON (`application/json`) pour toutes les réponses REST
|
||||
- **Pas de format propriétaire** : aucun SDK obligatoire, aucun protocole fermé
|
||||
- **Documentation ouverte** : OpenAPI 3.0, libre d'accès
|
||||
- **Export standard** : les données utilisateur sont exportables en JSON standard (voir section 7.10)
|
||||
- **Interopérabilité** : tout client HTTP standard peut consommer l'API
|
||||
|
||||
### 11.4 Versioning Explicite avec Politique de Dépréciation Longue
|
||||
|
||||
- **Versioning sémantique** dans l'URL (`/api/v1/`, `/api/v2/`)
|
||||
- **Politique de dépréciation** : minimum **12 mois** entre l'annonce de dépréciation et la suppression
|
||||
- **Header de dépréciation** : `Deprecation: true` + `Sunset: <date ISO 8601>` sur les endpoints dépréciés
|
||||
- **Guide de migration** publié pour chaque changement majeur
|
||||
- **Aucun breaking change** dans une version stable sans nouvelle version majeure
|
||||
|
||||
### 11.5 Portabilité des Données
|
||||
|
||||
- Tout utilisateur peut **exporter l'intégralité de ses données** à tout moment (`POST /api/v1/export`)
|
||||
- Format d'export : JSON standard, documenté, lisible par des outils tiers
|
||||
- Droit à l'effacement : suppression complète du compte et des données (`DELETE /api/v1/account`)
|
||||
- Conformité RGPD (Art. 17 droit à l'effacement, Art. 20 portabilité)
|
||||
|
||||
## 12. EXCLUSIONS ET RAISONS ÉTHIQUES
|
||||
|
||||
Cette section documente les catégories d'endpoints **volontairement exclues** de l'API Veza, avec les raisons éthiques associées.
|
||||
|
||||
### 12.1 Endpoints IA/ML — EXCLUS
|
||||
|
||||
| Endpoint exclu | Raison éthique |
|
||||
|----------------|----------------|
|
||||
| `POST /api/v1/tracks/{id}/master` (mastering automatique) | Remplace le travail créatif humain, dévalorise l'ingénierie du son |
|
||||
| `POST /api/v1/tracks/{id}/stems` (séparation de stems) | Risque d'utilisation pour plagiat, extraction non consentie |
|
||||
| `GET /api/v1/tracks/{id}/genre-detect` (détection de genre ML) | Les genres sont déclarés par les créateurs, pas imposés par un algorithme |
|
||||
| `GET /api/v1/recommendations` (recommandations ML) | Crée des bulles de filtre, favorise l'engagement addictif sur la diversité |
|
||||
| `POST /api/v1/tracks/{id}/content-id` (content ID ML) | Système de surveillance automatisée, risque de faux positifs avec censure |
|
||||
| `POST /api/v1/tracks/{id}/auto-tag` (auto-tagging ML) | Les tags sont la responsabilité des créateurs, pas d'une machine |
|
||||
| `GET /api/v1/tracks/{id}/similar` (similarité ML) | Favorise l'homogénéité, réduit la diversité musicale |
|
||||
| `POST /api/v1/voice/synthesize` (synthèse vocale) | Risque d'usurpation d'identité vocale, deepfakes audio |
|
||||
| `POST /api/v1/tracks/{id}/transcribe` (transcription lyrics ML) | Les paroles sont fournies par les artistes, respect du droit d'auteur |
|
||||
|
||||
**Alternative éthique** : découverte basée sur les genres/tags déclarés par les créateurs, curation éditoriale humaine, et graphe social opt-in (voir section 7.9).
|
||||
|
||||
### 12.2 Endpoints Blockchain/NFT/Crypto — EXCLUS
|
||||
|
||||
| Endpoint exclu | Raison éthique |
|
||||
|----------------|----------------|
|
||||
| `POST /api/v1/nft/mint` (minting NFT) | Spéculation financière sur l'art, impact environnemental |
|
||||
| `GET /api/v1/contracts/{id}` (smart contracts) | Complexité inutile, exclusion des artistes non-technophiles |
|
||||
| `POST /api/v1/tokens/transfer` (transfert tokens) | Financiarisation des interactions sociales |
|
||||
| `POST /api/v1/staking/deposit` (staking) | Mécanisme spéculatif incompatible avec une plateforme artistique |
|
||||
| `GET /api/v1/dao/proposals` (DAO governance) | Gouvernance ploutocratique (pouvoir proportionnel aux tokens détenus) |
|
||||
| `POST /api/v1/ipfs/pin` (IPFS storage) | Fausse décentralisation, complexité pour les utilisateurs |
|
||||
| `POST /api/v1/wallet/connect` (wallet crypto) | Barrière à l'entrée, exclusion économique |
|
||||
|
||||
**Alternative éthique** : paiements classiques (Stripe), licence créative déclarée par l'artiste, gouvernance communautaire transparente sans tokens.
|
||||
|
||||
### 12.3 Endpoints Gamification Addictive — EXCLUS
|
||||
|
||||
| Endpoint exclu | Raison éthique |
|
||||
|----------------|----------------|
|
||||
| `GET /api/v1/users/{id}/xp` (points d'expérience) | Conditionne l'engagement par la récompense, pas par l'intérêt |
|
||||
| `GET /api/v1/users/{id}/level` (niveaux) | Hiérarchise artificiellement les utilisateurs |
|
||||
| `GET /api/v1/users/{id}/achievements` (achievements engagement) | Oriente le comportement vers des métriques, pas vers la création |
|
||||
| `GET /api/v1/leaderboards` (classements) | Compétition artificielle, pression sociale, anxiété de performance |
|
||||
| `GET /api/v1/users/{id}/streaks` (séries consécutives) | Manipulation psychologique (aversion à la perte), engagement forcé |
|
||||
| `POST /api/v1/rewards/claim` (réclamation récompenses) | Boucle de renforcement addictive |
|
||||
|
||||
**Alternative éthique** : le statut `is_verified` pour les créateurs vérifiés (basé sur l'identité, pas sur l'activité), statistiques agrégées transparentes pour les créateurs (section 7.8).
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### API Completeness
|
||||
- [ ] 500+ endpoints documentés pour tous les modules
|
||||
- [ ] Endpoints documentés pour tous les modules actifs
|
||||
- [ ] Request/Response schemas complets
|
||||
- [ ] Authentication flows documentés
|
||||
- [ ] Error codes standardisés (1000-9999)
|
||||
- [ ] WebSocket protocol spécifié
|
||||
- [ ] gRPC services définis
|
||||
- [ ] Endpoints de découverte éthique documentés
|
||||
- [ ] Endpoints de portabilité des données documentés
|
||||
|
||||
### Consistency
|
||||
- [ ] Naming conventions respectées (snake_case, plural resources)
|
||||
|
|
@ -2037,8 +2508,19 @@ paths:
|
|||
### Security
|
||||
- [ ] JWT authentication implémentée
|
||||
- [ ] Rate limiting sur tous les endpoints
|
||||
- [ ] Rate limits publiquement documentés (`GET /api/v1/rate-limits`)
|
||||
- [ ] Permission checks documentés
|
||||
- [ ] Sensitive data jamais en query params
|
||||
- [ ] Header `Retry-After` systématique sur 429
|
||||
|
||||
### Éthique
|
||||
- [ ] Aucune donnée comportementale dans les réponses
|
||||
- [ ] Pagination disponible sur toutes les collections
|
||||
- [ ] Format ouvert JSON, aucun vendor lock-in
|
||||
- [ ] Portabilité des données (export complet)
|
||||
- [ ] Droit à l'effacement implémenté
|
||||
- [ ] Exclusions ML/IA, blockchain/NFT, gamification documentées
|
||||
- [ ] Découverte basée sur règles, pas sur ML
|
||||
|
||||
### Performance
|
||||
- [ ] Pagination obligatoire pour collections
|
||||
|
|
@ -2064,29 +2546,32 @@ paths:
|
|||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - API REST complète |
|
||||
| 1.0.0 | 2025-11-02 | Version initiale — API REST complète |
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique — Suppression endpoints ML/IA, blockchain/NFT, gamification addictive. Ajout découverte éthique (genres, éditorial, social, chronologique, proximité). Portabilité des données (export, effacement). Rate limits publics. Section API Éthique et Exclusions documentées. Licence open source. |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AVERTISSEMENT
|
||||
|
||||
**CETTE SPÉCIFICATION EST IMMUABLE**
|
||||
**CETTE SPÉCIFICATION SUIT LE VERSIONING SÉMANTIQUE**
|
||||
|
||||
L'API v1 définie ici est **VERROUILLÉE**. Toute modification nécessite:
|
||||
Toute modification nécessite :
|
||||
|
||||
1. **RFC API Change** avec impact analysis
|
||||
2. **Backward compatibility** garantie
|
||||
3. **Deprecation notice** (6 mois minimum)
|
||||
2. **Backward compatibility** garantie au sein d'une version majeure
|
||||
3. **Deprecation notice** (12 mois minimum)
|
||||
4. **Migration guide** pour clients existants
|
||||
5. **Approbation CTO**
|
||||
5. **Revue éthique** — vérification que le changement respecte les principes de la section 11
|
||||
|
||||
**Breaking changes INTERDITS en v1** - Créer v2 si nécessaire.
|
||||
**Breaking changes INTERDITS dans une version stable** — Créer une nouvelle version majeure si nécessaire.
|
||||
|
||||
---
|
||||
|
||||
**Document créé par**: API Team + Architecture
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Phase 4 (Q3 2026)
|
||||
**Propriétaire**: Lead Backend Engineer
|
||||
**Document créé par** : API Team + Architecture
|
||||
**Date de création** : 2025-11-02
|
||||
**Révision éthique** : 2026-03-04 (v2.0.0)
|
||||
**Prochaine révision** : Q3 2026
|
||||
**Propriétaire** : Lead Backend Engineer
|
||||
**Licence** : Open Source
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
**Statut** : ✅ **APPROUVÉ — RÉVISION ÉTHIQUE v2.0.0**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit toutes les règles métier (business logic) de la plateforme Veza. Il couvre les prix, commissions, workflows utilisateurs, machines à états, règles de validation, calculs complexes, notifications, limites, quotas, et SLAs. Ces règles sont immuables et garantissent la cohérence des comportements métier pendant 24 mois.
|
||||
Ce document définit toutes les règles métier (business logic) de la plateforme Veza. Il couvre les prix, commissions, workflows utilisateurs, machines à états, règles de validation, calculs complexes, notifications, limites, quotas, et SLAs. Ces règles sont alignées avec les principes éthiques fondateurs du projet et garantissent la cohérence des comportements métier.
|
||||
|
||||
**Dernière révision**: 2026-03-04 (révision éthique — suppression crypto, AI, publicité)
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
|
|
@ -18,6 +20,7 @@ Centraliser et définir de manière exhaustive toutes les règles métier de la
|
|||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
0. [Principes Éthiques et Modèle Économique](#0-principes-éthiques-et-modèle-économique)
|
||||
1. [Pricing Models](#1-pricing-models)
|
||||
2. [Commission Structure](#2-commission-structure)
|
||||
3. [User Workflows](#3-user-workflows)
|
||||
|
|
@ -28,6 +31,8 @@ Centraliser et définir de manière exhaustive toutes les règles métier de la
|
|||
8. [Notification Rules](#8-notification-rules)
|
||||
9. [Limits & Quotas](#9-limits--quotas)
|
||||
10. [SLA Definitions](#10-sla-definitions)
|
||||
11. [Exclusions et Raisons Éthiques](#11-exclusions-et-raisons-éthiques)
|
||||
12. [Gouvernance](#12-gouvernance)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
|
|
@ -42,6 +47,42 @@ Centraliser et définir de manière exhaustive toutes les règles métier de la
|
|||
9. **SLAs MESURABLES** (métriques, alerting)
|
||||
10. **Règles VERSIONÉES** (changements documentés)
|
||||
|
||||
## 0. PRINCIPES ÉTHIQUES ET MODÈLE ÉCONOMIQUE
|
||||
|
||||
L'éthique de Veza n'est pas un argument marketing. C'est l'architecture de valeurs qui détermine chaque décision économique. Aucune règle métier ne peut contredire ces principes.
|
||||
|
||||
### Modèle open source / open core
|
||||
|
||||
**Gratuit (open core)** :
|
||||
- Upload (quotas raisonnables)
|
||||
- Streaming illimité
|
||||
- Profil artiste complet
|
||||
- Chat et collaboration
|
||||
- Marketplace (commission sur transactions)
|
||||
|
||||
**Premium individuel** :
|
||||
- Stockage cloud étendu
|
||||
- Analytics avancés (détaillés, exportables)
|
||||
- Distribution (upload vers plateformes tierces)
|
||||
- Priorité dans les files de transcoding
|
||||
|
||||
**Pro / Label** :
|
||||
- API complète (rate limits étendus)
|
||||
- White label partiel
|
||||
- Analytics équipe
|
||||
- Support prioritaire
|
||||
|
||||
**Commission marketplace** :
|
||||
- Pourcentage sur les ventes de licences et beats
|
||||
- Transparente, documentée, sans surprise
|
||||
|
||||
### Ce qui ne sera JAMAIS monétisé
|
||||
|
||||
- **Publicité** : zéro régie publicitaire, zéro pixel de tracking tiers
|
||||
- **Données utilisateurs** : les données ne sont pas un produit
|
||||
- **Freemium agressif** : pas de features artificiellement bridées pour forcer l'upgrade
|
||||
- **Algorithmes de rétention** : pas d'optimisation pour maximiser le temps passé
|
||||
|
||||
## 1. PRICING MODELS
|
||||
|
||||
### 1.1 Product Pricing
|
||||
|
|
@ -85,10 +126,12 @@ Creator: $9.99/month ($99.99/year, 17% savings)
|
|||
Premium: $19.99/month ($199.99/year, 17% savings)
|
||||
- All Creator features
|
||||
- Priority support
|
||||
- No ads
|
||||
- Storage: 200 GB
|
||||
- Sell products: Yes (10% commission)
|
||||
- Collaboration tools
|
||||
- Distribution vers plateformes tierces
|
||||
|
||||
Note: Aucun plan ne contient de publicité. Veza est 100% sans publicité.
|
||||
```
|
||||
|
||||
### 1.2 Dynamic Pricing
|
||||
|
|
@ -165,7 +208,7 @@ Seller receives: $81.80
|
|||
```
|
||||
Streaming plays:
|
||||
- Creator receives $0.004 per play (avg)
|
||||
- Platform keeps remaining revenue from ads/subscriptions
|
||||
- Revenus issus des abonnements Premium uniquement (pas de publicité)
|
||||
|
||||
Example (10,000 plays):
|
||||
Creator revenue: 10,000 * $0.004 = $40.00
|
||||
|
|
@ -187,11 +230,7 @@ Domestic: 2.99% + $0.49
|
|||
International: 4.49% + $0.49
|
||||
```
|
||||
|
||||
**Crypto** (future):
|
||||
```
|
||||
Bitcoin: 1% + network fees
|
||||
Ethereum: 1% + gas fees
|
||||
```
|
||||
> **Note** : Le paiement via Hyperswitch (open source, multi-provider) est le standard. Stripe et PayPal sont des providers configurés. Les cryptomonnaies sont exclues définitivement (voir [§11 Exclusions](#11-exclusions-et-raisons-éthiques)).
|
||||
|
||||
### 2.3 Payout Schedule
|
||||
|
||||
|
|
@ -340,9 +379,8 @@ Total: ~2-9 min
|
|||
- Total
|
||||
7. Click "Proceed to Checkout"
|
||||
8. Select payment method:
|
||||
- Credit card (Stripe)
|
||||
- PayPal
|
||||
- (Future: Crypto)
|
||||
- Credit card (via Hyperswitch)
|
||||
- PayPal (via Hyperswitch)
|
||||
9. Enter billing info
|
||||
10. Review order
|
||||
11. Click "Place Order"
|
||||
|
|
@ -354,11 +392,12 @@ Total: ~2-9 min
|
|||
14. Download files
|
||||
```
|
||||
|
||||
**Abandonment Recovery**:
|
||||
**Panier** :
|
||||
```
|
||||
Cart abandoned for 1 hour: Email reminder
|
||||
Cart abandoned for 24 hours: Email with 10% discount
|
||||
Cart abandoned for 7 days: Email with 15% discount (final)
|
||||
Le panier est conservé 30 jours.
|
||||
Pas de relance email agressive pour paniers abandonnés.
|
||||
Un seul email de rappel optionnel après 7 jours (si l'utilisateur a activé les notifications marketing).
|
||||
Pas de discount de pression temporelle (pas de FOMO).
|
||||
```
|
||||
|
||||
### 3.4 Subscription Workflow
|
||||
|
|
@ -460,22 +499,25 @@ stateDiagram-v2
|
|||
|
||||
**Auto-Moderation Rules**:
|
||||
```
|
||||
1. NSFW Detection (AI):
|
||||
- Explicit content → flagged
|
||||
- Hate speech → flagged
|
||||
- Violence → flagged
|
||||
1. Détection par règles (pas d'IA) :
|
||||
- Mots-clés bloqués → flagged
|
||||
- Patterns de contenu explicite → flagged (règles déterministes)
|
||||
|
||||
2. Spam Detection:
|
||||
2. Spam Detection :
|
||||
- Identical title/description → flagged
|
||||
- Excessive links → flagged
|
||||
- Bot patterns → flagged
|
||||
- Bot patterns (rate, timing) → flagged
|
||||
|
||||
3. Copyright Detection:
|
||||
3. Copyright Detection :
|
||||
- Audio fingerprinting (ACRCloud)
|
||||
- Matches known tracks → flagged
|
||||
|
||||
If flagged → pending moderation
|
||||
If auto-approved → approved (low risk content)
|
||||
4. Modération humaine :
|
||||
- Tout contenu flaggé est revu par un modérateur humain
|
||||
- La décision finale est toujours humaine
|
||||
|
||||
If flagged → pending modération humaine
|
||||
If auto-approved → approved (contenu conforme aux règles)
|
||||
```
|
||||
|
||||
### 4.3 User Account State Machine
|
||||
|
|
@ -634,7 +676,7 @@ Cannot contain:
|
|||
```
|
||||
Max length: 500 characters
|
||||
Allowed characters: Any UTF-8
|
||||
Blocked patterns: Excessive links (max 3), hate speech (AI detection)
|
||||
Blocked patterns: Excessive links (max 3), mots-clés bloqués (liste de modération)
|
||||
```
|
||||
|
||||
### 6.2 Track Metadata Validation
|
||||
|
|
@ -842,13 +884,13 @@ END IF
|
|||
- Payment failed
|
||||
```
|
||||
|
||||
**Marketing Emails** (opt-in):
|
||||
**Marketing Emails** (opt-in, jamais agressif):
|
||||
```
|
||||
- New features announcement
|
||||
- Promotional offers
|
||||
- Product recommendations
|
||||
- Weekly digest (new tracks from followed users)
|
||||
- Monthly summary (stats, achievements)
|
||||
- Monthly summary (stats personnels du créateur)
|
||||
Note: Pas de recommandations produit basées sur le comportement.
|
||||
Pas de notifications de type FOMO.
|
||||
```
|
||||
|
||||
**Cadence Limits**:
|
||||
|
|
@ -872,14 +914,17 @@ Marketing: Max 2/week (user can opt out)
|
|||
|
||||
**Batched Notifications** (hourly):
|
||||
```
|
||||
- Multiple likes (5+ likes → "Your track has 5 new likes")
|
||||
- Multiple comments (3+ comments → "Your track has 3 new comments")
|
||||
- Regroupées pour éviter la surcharge
|
||||
Note: Pas de compteurs de likes en notification push (anti social validation loop)
|
||||
```
|
||||
|
||||
**Quiet Hours**:
|
||||
**Quiet Hours & Respect du DND**:
|
||||
```
|
||||
Default: 22:00 - 08:00 (user's timezone)
|
||||
User can configure in settings
|
||||
Respect du mode "Do Not Disturb" OS
|
||||
Contrôle total utilisateur sur chaque type de notification
|
||||
```
|
||||
|
||||
### 8.3 In-App Notifications
|
||||
|
|
@ -1078,6 +1123,51 @@ IF payout_failed THEN
|
|||
END IF
|
||||
```
|
||||
|
||||
## 11. EXCLUSIONS ET RAISONS ÉTHIQUES
|
||||
|
||||
Les éléments suivants sont **définitivement exclus** de la logique métier de Veza.
|
||||
|
||||
### Cryptomonnaies
|
||||
- Aucun paiement en Bitcoin, Ethereum, ou autre cryptomonnaie
|
||||
- **Raison** : impact environnemental disproportionné, spéculation, fraude documentée dans le domaine musical
|
||||
|
||||
### Publicité
|
||||
- Zéro régie publicitaire, zéro pixel de tracking tiers, zéro retargeting
|
||||
- **Raison** : la publicité transforme les utilisateurs en produit. Incompatible avec le principe « l'humain d'abord »
|
||||
|
||||
### Vente de données
|
||||
- Aucune monétisation des données comportementales
|
||||
- **Raison** : les données des utilisateurs ne sont pas un produit
|
||||
|
||||
### Recommandations ML
|
||||
- Pas de collaborative filtering, content-based filtering, ou analyse prédictive du comportement
|
||||
- **Raison** : optimise pour la rétention, pas pour la découverte authentique. La découverte musicale est basée sur les genres/tags déclarés par les artistes, la curation éditoriale humaine, et les connexions sociales
|
||||
|
||||
### Gamification addictive
|
||||
- Pas de systèmes XP, niveaux, streaks, leaderboards de popularité
|
||||
- **Raison** : transforme l'expression artistique en compétition et normalise les métriques de performance comme mesure de la valeur artistique
|
||||
|
||||
### Freemium agressif
|
||||
- Pas de features artificiellement bridées, pas de dark patterns dans les flows d'upgrade
|
||||
- **Raison** : les modèles de tarification sont simples et honnêtes
|
||||
|
||||
## 12. GOUVERNANCE
|
||||
|
||||
### Roadmap publique
|
||||
- La roadmap produit est publique et commentable
|
||||
- Les utilisateurs peuvent voter sur les features planifiées
|
||||
- Les décisions produit majeures sont documentées avec leur justification
|
||||
|
||||
### Contribution open source
|
||||
- Le cœur de la plateforme est open source
|
||||
- Processus de contribution documenté (CONTRIBUTING.md)
|
||||
- Code review systématique par les mainteneurs
|
||||
|
||||
### Transparence économique
|
||||
- Les commissions sont documentées et visibles avant chaque transaction
|
||||
- Les conditions d'utilisation sont rédigées en langage humain
|
||||
- Les changements tarifaires sont annoncés 90 jours à l'avance
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Pricing
|
||||
|
|
@ -1129,28 +1219,31 @@ END IF
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Règles métier complètes |
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique : suppression crypto/AI/publicité, ajout principes éthiques, modèle open core, gouvernance |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AVERTISSEMENT
|
||||
|
||||
**CES RÈGLES MÉTIER SONT IMMUABLES**
|
||||
**CES RÈGLES MÉTIER SONT ALIGNÉES AVEC L'ÉTHIQUE DU PROJET**
|
||||
|
||||
Les règles métier définies ici sont **VERROUILLÉES**. Toute modification nécessite:
|
||||
Toute modification nécessite :
|
||||
|
||||
1. **RFC Business Logic Change** avec impact analysis
|
||||
1. **RFC Business Logic Change** avec impact analysis et vérification d'alignement éthique
|
||||
2. **Approbation Product Owner** + Legal (si implications légales)
|
||||
3. **Migration plan** pour données existantes
|
||||
4. **Communication** aux utilisateurs (si impact visible)
|
||||
|
||||
**Les changements de règles financières nécessitent validation CFO.**
|
||||
**Aucune modification ne peut contredire les principes éthiques fondateurs (§0).**
|
||||
|
||||
---
|
||||
|
||||
**Document créé par**: Product Team + Business Analysts
|
||||
**Date de création**: 2025-11-02
|
||||
**Dernière révision**: 2026-03-04 (révision éthique)
|
||||
**Prochaine révision**: Trimestrielle
|
||||
**Propriétaire**: Chief Product Officer
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
**Statut**: ✅ **APPROUVÉ — v2.0.0**
|
||||
|
||||
|
|
|
|||
|
|
@ -19,16 +19,17 @@ Ce document définit les standards de code complets et définitifs pour la plate
|
|||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
1. [General Principles](#1-general-principles)
|
||||
2. [Go Standards (Backend)](#2-go-standards-backend)
|
||||
3. [Rust Standards (Services)](#3-rust-standards-services)
|
||||
4. [TypeScript Standards (Frontend)](#4-typescript-standards-frontend)
|
||||
5. [React Standards](#5-react-standards)
|
||||
6. [CSS/Tailwind Standards](#6-csstailwind-standards)
|
||||
7. [Git Standards](#7-git-standards)
|
||||
8. [Documentation Standards](#8-documentation-standards)
|
||||
9. [Code Review Process](#9-code-review-process)
|
||||
10. [Refactoring Guidelines](#10-refactoring-guidelines)
|
||||
11. [Anti-Patterns Library](#11-anti-patterns-library)
|
||||
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
|
||||
|
||||
|
|
@ -236,9 +237,83 @@ type Cache interface {
|
|||
}
|
||||
```
|
||||
|
||||
## 2. GO STANDARDS (BACKEND)
|
||||
## 2. STANDARDS ÉTHIQUES DU CODE
|
||||
|
||||
### 2.1 Project Structure (Clean Architecture)
|
||||
### 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/
|
||||
|
|
@ -286,7 +361,7 @@ veza-backend-api/
|
|||
└── go.sum
|
||||
```
|
||||
|
||||
### 2.2 Naming Conventions
|
||||
### 3.2 Naming Conventions
|
||||
|
||||
**Variables**: camelCase
|
||||
```go
|
||||
|
|
@ -327,7 +402,7 @@ type UserRepository interface { // Multi-method, no -er suffix
|
|||
}
|
||||
```
|
||||
|
||||
### 2.3 Error Handling
|
||||
### 3.3 Error Handling
|
||||
|
||||
**Always Check Errors**:
|
||||
```go
|
||||
|
|
@ -395,7 +470,7 @@ func init() {
|
|||
}
|
||||
```
|
||||
|
||||
### 2.4 Function Design
|
||||
### 3.4 Function Design
|
||||
|
||||
**Keep Functions Small** (< 50 lines):
|
||||
```go
|
||||
|
|
@ -508,7 +583,7 @@ func FindUser(id uuid.UUID) (*User, error) {
|
|||
}
|
||||
```
|
||||
|
||||
### 2.5 Concurrency
|
||||
### 3.5 Concurrency
|
||||
|
||||
**Use Context for Cancellation**:
|
||||
```go
|
||||
|
|
@ -598,7 +673,7 @@ func StartWorker(ctx context.Context) {
|
|||
}
|
||||
```
|
||||
|
||||
### 2.6 Testing
|
||||
### 3.6 Testing
|
||||
|
||||
**Table-Driven Tests**:
|
||||
```go
|
||||
|
|
@ -676,9 +751,94 @@ func TestUserService_CreateUser(t *testing.T) {
|
|||
}
|
||||
```
|
||||
|
||||
## 3. RUST STANDARDS (SERVICES)
|
||||
### 3.7 API Standards
|
||||
|
||||
### 3.1 Project Structure
|
||||
#### 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/
|
||||
|
|
@ -712,7 +872,7 @@ veza-chat-server/
|
|||
└── Cargo.lock
|
||||
```
|
||||
|
||||
### 3.2 Naming Conventions
|
||||
### 4.2 Naming Conventions
|
||||
|
||||
**Variables/Functions**: snake_case
|
||||
```rust
|
||||
|
|
@ -736,7 +896,7 @@ const MAX_CONNECTIONS: usize = 10000;
|
|||
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {}
|
||||
```
|
||||
|
||||
### 3.3 Error Handling
|
||||
### 4.3 Error Handling
|
||||
|
||||
**Use Result Type**:
|
||||
```rust
|
||||
|
|
@ -798,7 +958,7 @@ let config = Config::from_env()
|
|||
.expect("CONFIG environment variables missing");
|
||||
```
|
||||
|
||||
### 3.4 Ownership & Borrowing
|
||||
### 4.4 Ownership & Borrowing
|
||||
|
||||
**Prefer Borrowing**:
|
||||
```rust
|
||||
|
|
@ -830,7 +990,7 @@ tokio::spawn(async move {
|
|||
});
|
||||
```
|
||||
|
||||
### 3.5 Async/Await
|
||||
### 4.5 Async/Await
|
||||
|
||||
**Use async/await for IO**:
|
||||
```rust
|
||||
|
|
@ -871,7 +1031,7 @@ async fn fetch_user_data(user_id: Uuid) -> Result<(User, Vec<Track>)> {
|
|||
}
|
||||
```
|
||||
|
||||
### 3.6 Testing
|
||||
### 4.6 Testing
|
||||
|
||||
**Unit Tests**:
|
||||
```rust
|
||||
|
|
@ -906,9 +1066,9 @@ proptest! {
|
|||
}
|
||||
```
|
||||
|
||||
## 4. TYPESCRIPT STANDARDS (FRONTEND)
|
||||
## 5. TYPESCRIPT STANDARDS (FRONTEND)
|
||||
|
||||
### 4.1 TypeScript Configuration
|
||||
### 5.1 TypeScript Configuration
|
||||
|
||||
**tsconfig.json** (strict mode):
|
||||
```json
|
||||
|
|
@ -938,7 +1098,7 @@ proptest! {
|
|||
}
|
||||
```
|
||||
|
||||
### 4.2 Type Definitions
|
||||
### 5.2 Type Definitions
|
||||
|
||||
**Prefer Interfaces over Types** (for objects):
|
||||
```typescript
|
||||
|
|
@ -999,7 +1159,7 @@ function handleResponse<T>(response: ApiResponse<T>) {
|
|||
}
|
||||
```
|
||||
|
||||
### 4.3 Function Types
|
||||
### 5.3 Function Types
|
||||
|
||||
**Type Function Parameters and Returns**:
|
||||
```typescript
|
||||
|
|
@ -1035,7 +1195,7 @@ async function fetchUser(id: string): Promise<User> {
|
|||
}
|
||||
```
|
||||
|
||||
### 4.4 Null Safety
|
||||
### 5.4 Null Safety
|
||||
|
||||
**Use Optional Chaining**:
|
||||
```typescript
|
||||
|
|
@ -1055,7 +1215,7 @@ const port = process.env.PORT || 3000; // Problem if PORT=0
|
|||
const port = process.env.PORT ?? 3000;
|
||||
```
|
||||
|
||||
### 4.5 Enums vs Union Types
|
||||
### 5.5 Enums vs Union Types
|
||||
|
||||
**Prefer String Unions** (more type-safe):
|
||||
```typescript
|
||||
|
|
@ -1073,9 +1233,9 @@ enum UserRole {
|
|||
}
|
||||
```
|
||||
|
||||
## 5. REACT STANDARDS
|
||||
## 6. REACT STANDARDS
|
||||
|
||||
### 5.1 Component Structure
|
||||
### 6.1 Component Structure
|
||||
|
||||
**Functional Components** (prefer over class):
|
||||
```tsx
|
||||
|
|
@ -1110,7 +1270,7 @@ export const TrackCard: React.FC<TrackCardProps> = ({
|
|||
};
|
||||
```
|
||||
|
||||
### 5.2 Hooks
|
||||
### 6.2 Hooks
|
||||
|
||||
**Use Hooks Correctly**:
|
||||
```tsx
|
||||
|
|
@ -1191,7 +1351,7 @@ function TrackList({ tracks }: { tracks: Track[] }) {
|
|||
}
|
||||
```
|
||||
|
||||
### 5.3 State Management
|
||||
### 6.3 State Management
|
||||
|
||||
**Local State** (useState):
|
||||
```tsx
|
||||
|
|
@ -1289,7 +1449,7 @@ function TrackPage({ trackId }: { trackId: string }) {
|
|||
}
|
||||
```
|
||||
|
||||
### 5.4 Component Composition
|
||||
### 6.4 Component Composition
|
||||
|
||||
**Avoid Prop Drilling**:
|
||||
```tsx
|
||||
|
|
@ -1350,9 +1510,9 @@ Card.Footer = ({ children }: CardProps) => {
|
|||
</Card>
|
||||
```
|
||||
|
||||
## 6. CSS/TAILWIND STANDARDS
|
||||
## 7. CSS/TAILWIND STANDARDS
|
||||
|
||||
### 6.1 Tailwind Utilities
|
||||
### 7.1 Tailwind Utilities
|
||||
|
||||
**Prefer Tailwind Utilities**:
|
||||
```tsx
|
||||
|
|
@ -1420,7 +1580,7 @@ export const Button = ({
|
|||
};
|
||||
```
|
||||
|
||||
### 6.2 Custom Components (Extract Reusable)
|
||||
### 7.2 Custom Components (Extract Reusable)
|
||||
|
||||
**@apply for Component Classes**:
|
||||
```css
|
||||
|
|
@ -1444,9 +1604,9 @@ export const Button = ({
|
|||
}
|
||||
```
|
||||
|
||||
## 7. GIT STANDARDS
|
||||
## 8. GIT STANDARDS
|
||||
|
||||
### 7.1 Commit Messages
|
||||
### 8.1 Commit Messages
|
||||
|
||||
**Format**: Conventional Commits
|
||||
```
|
||||
|
|
@ -1483,7 +1643,7 @@ git commit -m "WIP"
|
|||
git commit -m "update"
|
||||
```
|
||||
|
||||
### 7.2 Branch Naming
|
||||
### 8.2 Branch Naming
|
||||
|
||||
**Format**: `<type>/<ticket>-<description>`
|
||||
```
|
||||
|
|
@ -1494,7 +1654,7 @@ refactor/VEZ-012-extract-user-service
|
|||
docs/VEZ-345-api-documentation
|
||||
```
|
||||
|
||||
### 7.3 Pull Request Template
|
||||
### 8.3 Pull Request Template
|
||||
|
||||
```markdown
|
||||
## Description
|
||||
|
|
@ -1518,9 +1678,9 @@ Brief description of changes
|
|||
- [ ] No new warnings
|
||||
```
|
||||
|
||||
## 8. DOCUMENTATION STANDARDS
|
||||
## 9. DOCUMENTATION STANDARDS
|
||||
|
||||
### 8.1 Code Comments
|
||||
### 9.1 Code Comments
|
||||
|
||||
**Go (godoc)**:
|
||||
```go
|
||||
|
|
@ -1591,7 +1751,7 @@ export async function fetchUser(userId: string): Promise<User> {
|
|||
}
|
||||
```
|
||||
|
||||
### 8.2 README Files
|
||||
### 9.2 README Files
|
||||
|
||||
**Every Module/Package Needs README.md**:
|
||||
```markdown
|
||||
|
|
@ -1631,9 +1791,47 @@ go test ./... -v
|
|||
- jwt-go (JWT tokens)
|
||||
```
|
||||
|
||||
## 9. CODE REVIEW PROCESS
|
||||
### 9.3 Architecture Decision Records (ADR)
|
||||
|
||||
### 9.1 Review Checklist
|
||||
Toute décision architecturale significative **doit** être documentée sous forme d'ADR dans le dossier `docs/adr/`.
|
||||
|
||||
**Format obligatoire** :
|
||||
|
||||
```markdown
|
||||
# ADR-NNN: Titre de la décision
|
||||
|
||||
## Statut
|
||||
Accepté | Proposé | Déprécié | Remplacé par ADR-XXX
|
||||
|
||||
## Contexte
|
||||
Quel est le problème ou la situation qui motive cette décision ?
|
||||
|
||||
## Décision
|
||||
Quelle est la décision prise ?
|
||||
|
||||
## Raison
|
||||
Pourquoi cette décision a-t-elle été choisie ?
|
||||
|
||||
## Alternatives rejetées
|
||||
Quelles autres options ont été envisagées et pourquoi ont-elles été écartées ?
|
||||
|
||||
## Conséquences
|
||||
Quels sont les effets positifs et négatifs de cette décision ?
|
||||
|
||||
## Impact éthique
|
||||
(Obligatoire si pertinent) Quel est l'impact sur la vie privée des utilisateurs,
|
||||
l'équité de traitement des créateurs, ou la transparence de la plateforme ?
|
||||
```
|
||||
|
||||
**Règles** :
|
||||
- Chaque ADR est **immuable** une fois accepté (on crée un nouvel ADR pour le remplacer)
|
||||
- La section **Impact éthique** est obligatoire dès que la décision touche aux données utilisateurs, aux algorithmes de classement, ou à la collecte de métriques
|
||||
- Les ADR sont numérotés séquentiellement (`ADR-001`, `ADR-002`, ...)
|
||||
- Un ADR doit être créé **avant** l'implémentation, pas après
|
||||
|
||||
## 10. CODE REVIEW PROCESS
|
||||
|
||||
### 10.1 Review Checklist
|
||||
|
||||
**Reviewer Must Check**:
|
||||
- [ ] Code follows style guidelines (linters pass)
|
||||
|
|
@ -1644,7 +1842,7 @@ go test ./... -v
|
|||
- [ ] Performance is acceptable (no N+1 queries, etc.)
|
||||
- [ ] Breaking changes are documented
|
||||
|
||||
### 9.2 Review Comments
|
||||
### 10.2 Review Comments
|
||||
|
||||
**Constructive Feedback**:
|
||||
```
|
||||
|
|
@ -1661,9 +1859,9 @@ func validateEmail(email string) error { ... }"
|
|||
- All comments resolved
|
||||
- CI/CD passes
|
||||
|
||||
## 10. REFACTORING GUIDELINES
|
||||
## 11. REFACTORING GUIDELINES
|
||||
|
||||
### 10.1 When to Refactor
|
||||
### 11.1 When to Refactor
|
||||
|
||||
**Triggers**:
|
||||
- Duplicated code (DRY violation)
|
||||
|
|
@ -1674,7 +1872,7 @@ func validateEmail(email string) error { ... }"
|
|||
|
||||
**Boy Scout Rule**: Leave code cleaner than you found it
|
||||
|
||||
### 10.2 Refactoring Techniques
|
||||
### 11.2 Refactoring Techniques
|
||||
|
||||
**Extract Method**:
|
||||
```go
|
||||
|
|
@ -1706,21 +1904,21 @@ func ProcessOrder(order *Order) error {
|
|||
}
|
||||
```
|
||||
|
||||
## 11. ANTI-PATTERNS LIBRARY
|
||||
## 12. ANTI-PATTERNS LIBRARY
|
||||
|
||||
### 11.1 God Object
|
||||
### 12.1 God Object
|
||||
|
||||
**Problem**: One class/module does everything
|
||||
|
||||
**Solution**: Split into smaller, focused modules (SRP)
|
||||
|
||||
### 11.2 Spaghetti Code
|
||||
### 12.2 Spaghetti Code
|
||||
|
||||
**Problem**: Tangled, unstructured code
|
||||
|
||||
**Solution**: Use clear architecture (Clean Architecture, layered)
|
||||
|
||||
### 11.3 Magic Numbers
|
||||
### 12.3 Magic Numbers
|
||||
|
||||
**Problem**: Unexplained literal values
|
||||
```go
|
||||
|
|
@ -1740,15 +1938,15 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
}
|
||||
```
|
||||
|
||||
### 11.4 Premature Optimization
|
||||
### 12.4 Premature Optimization
|
||||
|
||||
**Problem**: Optimizing before identifying bottlenecks
|
||||
|
||||
**Solution**: Profile first, then optimize
|
||||
|
||||
## 12. ERROR PREVENTION
|
||||
## 13. ERROR PREVENTION
|
||||
|
||||
### 12.1 Pre-Flight Checks (OBLIGATOIRE)
|
||||
### 13.1 Pre-Flight Checks (OBLIGATOIRE)
|
||||
|
||||
**Avant de commencer TOUTE nouvelle tâche** :
|
||||
|
||||
|
|
@ -1760,7 +1958,7 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
|
||||
**Référence complète** : `docs/ORIGIN/ORIGIN_ERROR_PREVENTION_GUIDE.md`
|
||||
|
||||
### 12.2 Templates de Code (OBLIGATOIRE)
|
||||
### 13.2 Templates de Code (OBLIGATOIRE)
|
||||
|
||||
**Utiliser les templates validés** pour créer de nouveaux fichiers :
|
||||
|
||||
|
|
@ -1770,7 +1968,7 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
|
||||
**NE JAMAIS créer un fichier sans utiliser un template** (sauf exception approuvée).
|
||||
|
||||
### 12.3 Patterns Sûrs
|
||||
### 13.3 Patterns Sûrs
|
||||
|
||||
**Backend Go** :
|
||||
- ✅ Interfaces dans `internal/types/` ou `internal/interfaces/`
|
||||
|
|
@ -1786,7 +1984,7 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
|
||||
**Référence** : `docs/ORIGIN/ORIGIN_ERROR_PATTERNS.md` pour tous les patterns.
|
||||
|
||||
### 12.4 Quality Gates
|
||||
### 13.4 Quality Gates
|
||||
|
||||
**Pre-Commit** (Husky) :
|
||||
- Formatage automatique
|
||||
|
|
@ -1803,7 +2001,7 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
|
||||
**Si un gate échoue** : Corriger l'erreur, NE PAS contourner.
|
||||
|
||||
### 12.5 Documentation des Erreurs
|
||||
### 13.5 Documentation des Erreurs
|
||||
|
||||
**Si une nouvelle erreur est découverte** :
|
||||
|
||||
|
|
@ -1860,6 +2058,7 @@ if user.Age >= MinimumAdultAge && user.Age < RetirementAge {
|
|||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique — ajout standards éthiques du code, ADR, standards API (pagination, contexte, erreurs) |
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Standards complets |
|
||||
|
||||
---
|
||||
|
|
@ -1880,6 +2079,7 @@ Les standards de code définis ici sont **OBLIGATOIRES**. Toute dérogation néc
|
|||
|
||||
**Document créé par**: Engineering Team
|
||||
**Date de création**: 2025-11-02
|
||||
**Dernière révision**: 2026-03-04 (v2.0.0 — révision éthique)
|
||||
**Prochaine révision**: Annuelle
|
||||
**Propriétaire**: Lead Engineers (Go, Rust, Frontend)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
# ORIGIN_DATABASE_SCHEMA.md
|
||||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
## RÉSUMÉ
|
||||
|
||||
Ce document définit le schéma complet et définitif de la base de données PostgreSQL 15 de la plateforme Veza. Il spécifie 100+ tables organisées par domaine métier (DDD), avec toutes les colonnes, types, contraintes, indexes, foreign keys, triggers, et vues matérialisées. Le schéma est conçu pour supporter 600 features sur 24 mois avec une capacité de 100,000+ utilisateurs concurrents et des performances optimales (<10ms query time p95).
|
||||
Ce document définit le schéma de la base de données PostgreSQL 15 de la plateforme Veza. Tables organisées par domaine métier (DDD), avec colonnes, types, contraintes, indexes, foreign keys, triggers et vues matérialisées. Le schéma respecte les contraintes éthiques du projet : aucune table ML/IA, aucune table blockchain/NFT/crypto, aucune mécanique de gamification addictive. Les données utilisateur sont protégées par des politiques de rétention strictes et une conformité GDPR intégrée au schéma.
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
## OBJECTIFS
|
||||
|
||||
### Objectif Principal
|
||||
Définir un schéma de base de données complet, normalisé (3NF), optimisé pour la performance, et immuable pour garantir la stabilité et la cohérence des données sur 24 mois.
|
||||
### Objectif principal
|
||||
Définir un schéma de base de données normalisé (3NF), optimisé pour la performance, conforme GDPR, et respectant les principes éthiques du projet Veza.
|
||||
|
||||
### Objectifs Secondaires
|
||||
### Objectifs secondaires
|
||||
- Assurer l'intégrité référentielle stricte
|
||||
- Optimiser les requêtes fréquentes (indexes appropriés)
|
||||
- Supporter la scalabilité horizontale (partitioning)
|
||||
- Faciliter les migrations (versioning, rollback)
|
||||
- Garantir la conformité GDPR (soft delete, audit)
|
||||
- Garantir la conformité GDPR (soft delete, export, consentement, rétention)
|
||||
- Exclure toute structure de données servant le profilage comportemental, la spéculation ou la manipulation
|
||||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
## TABLE DES MATIÈRES
|
||||
|
||||
1. [Vue d'Ensemble](#1-vue-densemble)
|
||||
2. [Conventions de Nommage](#2-conventions-de-nommage)
|
||||
|
|
@ -34,13 +35,16 @@ Définir un schéma de base de données complet, normalisé (3NF), optimisé pou
|
|||
14. [Module Search](#14-module-search)
|
||||
15. [Module Analytics](#15-module-analytics)
|
||||
16. [Module Administration](#16-module-administration)
|
||||
17. [Indexes Stratégie](#17-indexes-stratégie)
|
||||
18. [Partitioning Stratégie](#18-partitioning-stratégie)
|
||||
19. [Triggers & Functions](#19-triggers--functions)
|
||||
20. [Materialized Views](#20-materialized-views)
|
||||
21. [Migration Stratégie](#21-migration-stratégie)
|
||||
17. [Exclusions et Raisons Éthiques](#17-exclusions-et-raisons-éthiques)
|
||||
18. [Politique de Rétention des Données](#18-politique-de-rétention-des-données)
|
||||
19. [Conformité GDPR](#19-conformité-gdpr)
|
||||
20. [Indexes Stratégie](#20-indexes-stratégie)
|
||||
21. [Partitioning Stratégie](#21-partitioning-stratégie)
|
||||
22. [Triggers & Functions](#22-triggers--functions)
|
||||
23. [Materialized Views](#23-materialized-views)
|
||||
24. [Migration Stratégie](#24-migration-stratégie)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
## RÈGLES IMMUABLES
|
||||
|
||||
1. **Toutes les tables DOIVENT avoir `id` PRIMARY KEY** (type UUID v4)
|
||||
2. **Toutes les tables DOIVENT avoir `created_at` et `updated_at`** (timestamp with time zone)
|
||||
|
|
@ -52,6 +56,11 @@ Définir un schéma de base de données complet, normalisé (3NF), optimisé pou
|
|||
8. **Pas de colonnes JSON** sans index GIN si utilisées dans WHERE
|
||||
9. **Timestamps TOUJOURS `timestamptz`** (avec timezone)
|
||||
10. **Enums PostgreSQL** pour statuts avec max 20 valeurs
|
||||
11. **Aucune table de stockage ML/IA** (feature vectors, embeddings, model outputs, predictions)
|
||||
12. **Aucune table blockchain/NFT/crypto** (wallets, smart contracts, tokens, transactions blockchain)
|
||||
13. **Aucune mécanique de gamification addictive** (XP, streaks, leaderboards compétitifs, niveaux)
|
||||
14. **Consentement GDPR explicite** requis sur tables utilisateur (processing + marketing séparés)
|
||||
15. **Rétention des données bornée** selon la politique définie en section 18
|
||||
|
||||
## 1. VUE D'ENSEMBLE
|
||||
|
||||
|
|
@ -94,8 +103,8 @@ erDiagram
|
|||
| **Search** | 2 | Indexed data |
|
||||
| **Analytics** | 6 | Events, metrics, reports |
|
||||
| **Admin** | 5 | Moderation, configs |
|
||||
| **Other** | 20+ | Notifications, integrations, etc. |
|
||||
| **TOTAL** | **~105 tables** | |
|
||||
| **Other** | 10+ | Notifications, integrations, etc. |
|
||||
| **TOTAL** | **~85 tables** | Après exclusion ML/blockchain/gamification addictive |
|
||||
|
||||
### 1.3 Statistiques Estimées (Après 1 an)
|
||||
|
||||
|
|
@ -253,6 +262,16 @@ CREATE TABLE users (
|
|||
login_count INTEGER NOT NULL DEFAULT 0,
|
||||
last_login_ip INET,
|
||||
|
||||
-- GDPR Consent
|
||||
data_processing_consent BOOLEAN NOT NULL DEFAULT false,
|
||||
data_processing_consent_at TIMESTAMPTZ,
|
||||
marketing_consent BOOLEAN NOT NULL DEFAULT false,
|
||||
marketing_consent_at TIMESTAMPTZ,
|
||||
|
||||
-- GDPR Data Export
|
||||
export_requested_at TIMESTAMPTZ,
|
||||
exported_at TIMESTAMPTZ,
|
||||
|
||||
-- Timestamps
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
|
@ -269,10 +288,15 @@ CREATE INDEX idx_users_username_btree ON users(username) WHERE deleted_at IS NUL
|
|||
CREATE INDEX idx_users_role_btree ON users(role);
|
||||
CREATE INDEX idx_users_created_at_desc ON users(created_at DESC);
|
||||
CREATE INDEX idx_users_deleted_at_btree ON users(deleted_at) WHERE deleted_at IS NOT NULL;
|
||||
CREATE INDEX idx_users_export_requested_at ON users(export_requested_at) WHERE export_requested_at IS NOT NULL AND exported_at IS NULL;
|
||||
|
||||
-- Comments
|
||||
COMMENT ON TABLE users IS 'Main users table with authentication and basic profile';
|
||||
COMMENT ON TABLE users IS 'Main users table with authentication, basic profile, and GDPR consent';
|
||||
COMMENT ON COLUMN users.token_version IS 'Incremented to invalidate all existing JWTs';
|
||||
COMMENT ON COLUMN users.data_processing_consent IS 'Explicit GDPR consent for data processing, separate from marketing';
|
||||
COMMENT ON COLUMN users.marketing_consent IS 'Separate GDPR consent for marketing communications';
|
||||
COMMENT ON COLUMN users.export_requested_at IS 'GDPR Art.20 - timestamp of data portability request';
|
||||
COMMENT ON COLUMN users.exported_at IS 'GDPR Art.20 - timestamp when data export was fulfilled';
|
||||
```
|
||||
|
||||
### 4.2 Table `refresh_tokens`
|
||||
|
|
@ -639,6 +663,8 @@ CREATE INDEX idx_user_badges_badge_id ON user_badges(badge_id);
|
|||
|
||||
### 5.5 Table `badges`
|
||||
|
||||
**Description**: Badges déclaratifs de compétences musicales (instruments, genres, expérience). Pas de rareté, pas de collection compétitive. Un badge atteste d'une compétence ou d'un rôle, il n'est pas un mécanisme de rétention.
|
||||
|
||||
```sql
|
||||
CREATE TABLE badges (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
|
@ -648,16 +674,13 @@ CREATE TABLE badges (
|
|||
slug VARCHAR(100) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
|
||||
-- Category
|
||||
category VARCHAR(50) NOT NULL, -- instrument, genre, experience, role
|
||||
|
||||
-- Display
|
||||
icon_url TEXT,
|
||||
color VARCHAR(7), -- Hex color #RRGGBB
|
||||
|
||||
-- Criteria
|
||||
criteria JSONB, -- Rules to earn badge
|
||||
|
||||
-- Rarity
|
||||
rarity VARCHAR(20) NOT NULL DEFAULT 'common', -- common, rare, epic, legendary
|
||||
|
||||
-- Status
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
|
|
@ -668,7 +691,10 @@ CREATE TABLE badges (
|
|||
|
||||
-- Indexes
|
||||
CREATE UNIQUE INDEX idx_badges_slug ON badges(slug);
|
||||
CREATE INDEX idx_badges_rarity ON badges(rarity);
|
||||
CREATE INDEX idx_badges_category ON badges(category);
|
||||
|
||||
-- Comment
|
||||
COMMENT ON TABLE badges IS 'Declarative skill badges (instruments, genres, experience). No rarity, no competitive collection.';
|
||||
```
|
||||
|
||||
## 6. MODULE FILE MANAGEMENT
|
||||
|
|
@ -978,7 +1004,7 @@ CREATE TABLE playback_history (
|
|||
completion_percentage INTEGER NOT NULL, -- 0-100
|
||||
|
||||
-- Context
|
||||
source VARCHAR(50), -- playlist, album, search, recommendation
|
||||
source VARCHAR(50), -- playlist, album, search, direct
|
||||
source_id UUID, -- ID of playlist, album, etc.
|
||||
|
||||
-- Device
|
||||
|
|
@ -1751,7 +1777,7 @@ CREATE TABLE orders (
|
|||
currency CHAR(3) NOT NULL DEFAULT 'USD',
|
||||
|
||||
-- Payment
|
||||
payment_method VARCHAR(50), -- stripe, paypal, crypto
|
||||
payment_method VARCHAR(50), -- stripe, paypal
|
||||
payment_intent_id VARCHAR(255), -- Stripe payment intent ID
|
||||
|
||||
-- Status
|
||||
|
|
@ -2017,8 +2043,6 @@ CREATE INDEX idx_transactions_status ON transactions(status);
|
|||
CREATE INDEX idx_transactions_created_at_desc ON transactions(created_at DESC);
|
||||
```
|
||||
|
||||
*[Note: Due to length constraints, I'll continue with the remaining modules in a structured summary format while maintaining completeness]*
|
||||
|
||||
## 11-16. MODULES RESTANTS (STRUCTURE)
|
||||
|
||||
### 11. Module Education (7 tables)
|
||||
|
|
@ -2045,11 +2069,10 @@ CREATE INDEX idx_transactions_created_at_desc ON transactions(created_at DESC);
|
|||
- `search_queries` - User search history
|
||||
- `search_index` - Global search index
|
||||
|
||||
### 15. Module Analytics (6 tables)
|
||||
- `analytics_events` - Raw event data (partitioned)
|
||||
### 15. Module Analytics (5 tables)
|
||||
- `analytics_events` - Raw event data (partitioned, rétention 12 mois)
|
||||
- `daily_metrics` - Aggregated daily stats
|
||||
- `user_analytics` - Per-user metrics
|
||||
- `track_analytics` - Per-track metrics
|
||||
- `track_analytics` - Per-track metrics (play count, completion, pas de profilage)
|
||||
- `reports` - Generated reports
|
||||
- `dashboard_configs` - Custom dashboards
|
||||
|
||||
|
|
@ -2060,9 +2083,150 @@ CREATE INDEX idx_transactions_created_at_desc ON transactions(created_at DESC);
|
|||
- `system_configs` - Application settings
|
||||
- `feature_flags` - Feature toggles
|
||||
|
||||
## 17. INDEXES STRATÉGIE
|
||||
## 17. EXCLUSIONS ET RAISONS ÉTHIQUES
|
||||
|
||||
### 17.1 Index Types
|
||||
Ce schéma exclut explicitement plusieurs catégories de tables qui existaient dans la version 1.0.0 ou qui avaient été envisagées. Chaque exclusion est une contrainte architecturale, pas un report à plus tard.
|
||||
|
||||
### 17.1 Tables ML/IA supprimées
|
||||
|
||||
| Table supprimée | Raison |
|
||||
|-----------------|--------|
|
||||
| `feature_vectors` | Stockage de vecteurs pour embeddings audio/utilisateur. Le profilage algorithmique des goûts musicaux est incompatible avec le respect de l'autonomie de l'auditeur. |
|
||||
| `embeddings` | Représentations vectorielles pour similarité. Même raison : pas de recommandation algorithmique opaque. |
|
||||
| `model_outputs` | Résultats de modèles ML (classification, prédiction). Veza ne délègue aucune décision éditoriale à un modèle. |
|
||||
| `ml_predictions` | Prédictions comportementales (churn, engagement). Le profilage prédictif des utilisateurs est exclu par principe. |
|
||||
| `recommendation_scores` | Scores de recommandation calculés. La découverte musicale repose sur la curation humaine et la recherche explicite. |
|
||||
| `user_analytics` | Métriques comportementales par utilisateur. Le suivi individuel détaillé des habitudes d'écoute constitue du profilage. |
|
||||
|
||||
### 17.2 Tables Blockchain/NFT/Crypto supprimées
|
||||
|
||||
| Table supprimée | Raison |
|
||||
|-----------------|--------|
|
||||
| `nft_tokens` | Tokens NFT associés aux tracks/artworks. La spéculation sur l'art musical est contraire aux valeurs du projet. |
|
||||
| `smart_contracts` | Contrats intelligents pour royalties/licences. Complexité et coût énergétique injustifiés ; les licences classiques suffisent. |
|
||||
| `wallet_addresses` | Adresses de portefeuilles crypto. Aucun paiement crypto n'est supporté. |
|
||||
| `blockchain_transactions` | Historique de transactions on-chain. Pas de dépendance à une blockchain. |
|
||||
| `token_balances` | Soldes de tokens applicatifs. Pas de monnaie interne ni de token utilitaire. |
|
||||
|
||||
### 17.3 Tables de gamification addictive supprimées
|
||||
|
||||
| Table supprimée | Raison |
|
||||
|-----------------|--------|
|
||||
| `xp_events` | Points d'expérience par action. Le système XP transforme l'usage en jeu compulsif. |
|
||||
| `level_thresholds` | Seuils de niveaux utilisateur. La hiérarchie par niveaux crée une pression sociale artificielle. |
|
||||
| `achievement_unlocks` | Déblocage de succès/achievements. Les achievements exploitent le biais de complétion. |
|
||||
| `streaks` | Séries consécutives d'utilisation. Les streaks exploitent l'aversion à la perte pour forcer l'usage quotidien. |
|
||||
| `leaderboard_entries` | Classements compétitifs entre utilisateurs. Les leaderboards créent une compétition toxique sans rapport avec la musique. |
|
||||
| `daily_challenges` | Défis quotidiens avec récompenses. Mécanisme de rétention qui conditionne l'usage à des récompenses variables. |
|
||||
|
||||
### 17.4 Éléments conservés (non-addictifs)
|
||||
|
||||
| Élément | Justification |
|
||||
|---------|---------------|
|
||||
| `badges` (table conservée) | Badges déclaratifs de compétences (instrument, genre, expérience). Attestent d'un savoir-faire, pas d'un comportement. Pas de rareté, pas de collection compétitive. |
|
||||
| `user_badges` (table conservée) | Association utilisateur-badge. Affichage optionnel, ordre configurable par l'utilisateur. |
|
||||
| `track_analytics` (table conservée) | Métriques agrégées par track (play count, completion). Utile aux artistes pour comprendre leur audience sans profiler les individus. |
|
||||
|
||||
## 18. POLITIQUE DE RÉTENTION DES DONNÉES
|
||||
|
||||
### 18.1 Durées de rétention
|
||||
|
||||
| Catégorie | Durée maximale | Tables concernées | Action après expiration |
|
||||
|-----------|---------------|-------------------|----------------------|
|
||||
| **Journaux d'activité** | 90 jours | `login_attempts`, `typing_indicators`, `user_presence` | Suppression définitive |
|
||||
| **Sessions expirées** | 30 jours après expiration | `refresh_tokens` (révoqués/expirés), `password_reset_tokens` (utilisés/expirés), `email_verification_tokens` (utilisés/expirés) | Suppression définitive |
|
||||
| **Analytiques détaillées** | 12 mois | `analytics_events`, `playback_history`, `daily_metrics` | Anonymisation puis agrégation |
|
||||
| **Données de compte** | Jusqu'à demande de suppression | `users`, `user_profiles`, `user_settings` | Soft delete puis anonymisation après 30 jours |
|
||||
| **Données transactionnelles** | 7 ans (obligation légale) | `orders`, `order_items`, `transactions` | Conservation légale, accès restreint |
|
||||
| **Messages** | Jusqu'à suppression par l'utilisateur | `messages`, `direct_messages` | Soft delete, purge 30 jours après |
|
||||
| **Journaux d'audit** | 24 mois | `audit_logs` | Archivage cold storage puis suppression |
|
||||
|
||||
### 18.2 Anonymisation
|
||||
|
||||
Après expiration de la période de rétention, les données sont anonymisées :
|
||||
- Remplacement des identifiants personnels par des UUID aléatoires non-liés
|
||||
- Suppression des adresses IP, user agents, et métadonnées de device
|
||||
- Conservation des agrégats statistiques (compteurs, moyennes) sans lien avec un utilisateur
|
||||
- Les données anonymisées ne sont pas réversibles
|
||||
|
||||
### 18.3 Implémentation
|
||||
|
||||
```sql
|
||||
-- Job de nettoyage des sessions expirées (cron quotidien)
|
||||
DELETE FROM refresh_tokens
|
||||
WHERE (expires_at < NOW() - INTERVAL '30 days')
|
||||
OR (is_revoked = true AND revoked_at < NOW() - INTERVAL '30 days');
|
||||
|
||||
DELETE FROM password_reset_tokens
|
||||
WHERE expires_at < NOW() - INTERVAL '30 days';
|
||||
|
||||
DELETE FROM email_verification_tokens
|
||||
WHERE expires_at < NOW() - INTERVAL '30 days';
|
||||
|
||||
-- Job de nettoyage des journaux d'activité (cron quotidien)
|
||||
DELETE FROM login_attempts
|
||||
WHERE attempted_at < NOW() - INTERVAL '90 days';
|
||||
|
||||
-- Job d'anonymisation des analytics (cron mensuel)
|
||||
UPDATE playback_history
|
||||
SET user_id = gen_random_uuid(),
|
||||
device_type = NULL,
|
||||
source = NULL
|
||||
WHERE played_at < NOW() - INTERVAL '12 months';
|
||||
```
|
||||
|
||||
## 19. CONFORMITÉ GDPR
|
||||
|
||||
### 19.1 Champs GDPR dans la table `users`
|
||||
|
||||
| Champ | Type | Usage GDPR |
|
||||
|-------|------|-----------|
|
||||
| `deleted_at` | `TIMESTAMPTZ` | Art. 17 - Droit à l'effacement (soft delete) |
|
||||
| `export_requested_at` | `TIMESTAMPTZ` | Art. 20 - Droit à la portabilité, horodatage de la demande |
|
||||
| `exported_at` | `TIMESTAMPTZ` | Art. 20 - Horodatage de l'export effectué |
|
||||
| `data_processing_consent` | `BOOLEAN` | Art. 6 - Base légale du traitement, consentement explicite |
|
||||
| `data_processing_consent_at` | `TIMESTAMPTZ` | Art. 7 - Preuve du consentement avec horodatage |
|
||||
| `marketing_consent` | `BOOLEAN` | Art. 6 - Consentement marketing séparé du traitement |
|
||||
| `marketing_consent_at` | `TIMESTAMPTZ` | Art. 7 - Preuve du consentement marketing |
|
||||
|
||||
### 19.2 Principes appliqués
|
||||
|
||||
1. **Séparation des consentements** : le consentement au traitement des données et le consentement marketing sont deux champs distincts avec horodatages séparés. L'un n'implique pas l'autre.
|
||||
2. **Soft delete systématique** : `deleted_at` sur toutes les tables user-facing. La suppression physique intervient après la période de rétention.
|
||||
3. **Export structuré** : le champ `export_requested_at` déclenche un job asynchrone qui génère un export JSON/CSV de toutes les données de l'utilisateur. `exported_at` confirme la complétion.
|
||||
4. **Audit du consentement** : tout changement de consentement est tracé dans `audit_logs` avec l'ancien et le nouveau état.
|
||||
5. **Minimisation des données** : pas de `user_analytics` individuel, pas de profilage comportemental, pas de feature vectors.
|
||||
|
||||
### 19.3 Procédure de suppression de compte
|
||||
|
||||
```sql
|
||||
-- Étape 1 : Soft delete immédiat
|
||||
UPDATE users SET deleted_at = NOW() WHERE id = $user_id;
|
||||
|
||||
-- Étape 2 : Anonymisation après 30 jours (job automatique)
|
||||
UPDATE users SET
|
||||
email = 'deleted_' || id || '@anonymized.local',
|
||||
username = 'deleted_' || SUBSTRING(id::text, 1, 8),
|
||||
password_hash = NULL,
|
||||
first_name = NULL,
|
||||
last_name = NULL,
|
||||
display_name = '[Compte supprimé]',
|
||||
last_login_ip = NULL,
|
||||
data_processing_consent = false,
|
||||
marketing_consent = false
|
||||
WHERE deleted_at < NOW() - INTERVAL '30 days'
|
||||
AND email NOT LIKE 'deleted_%@anonymized.local';
|
||||
|
||||
-- Étape 3 : Suppression des données associées
|
||||
DELETE FROM user_profiles WHERE user_id IN (
|
||||
SELECT id FROM users
|
||||
WHERE deleted_at < NOW() - INTERVAL '30 days'
|
||||
);
|
||||
```
|
||||
|
||||
## 20. INDEXES STRATÉGIE
|
||||
|
||||
### 20.1 Index Types
|
||||
|
||||
| Type | Usage | Example |
|
||||
|------|-------|---------|
|
||||
|
|
@ -2072,7 +2236,7 @@ CREATE INDEX idx_transactions_created_at_desc ON transactions(created_at DESC);
|
|||
| **Hash** | Equality only (rarely used in PostgreSQL) | Not recommended |
|
||||
| **Partial** | Index subset of rows (WHERE clause) | `CREATE INDEX idx_users_active ON users(email) WHERE is_active = true` |
|
||||
|
||||
### 17.2 Critical Indexes
|
||||
### 20.2 Critical Indexes
|
||||
|
||||
**Performance Critical** (query time < 10ms):
|
||||
```sql
|
||||
|
|
@ -2097,7 +2261,7 @@ CREATE INDEX idx_products_category_status ON products(category, status);
|
|||
CREATE INDEX idx_orders_user_id_created_at ON orders(user_id, created_at DESC);
|
||||
```
|
||||
|
||||
### 17.3 Index Maintenance
|
||||
### 20.3 Index Maintenance
|
||||
|
||||
```sql
|
||||
-- Regular VACUUM and ANALYZE (automated with autovacuum)
|
||||
|
|
@ -2122,9 +2286,9 @@ WHERE idx_scan = 0 -- Unused indexes
|
|||
ORDER BY schemaname, tablename;
|
||||
```
|
||||
|
||||
## 18. PARTITIONING STRATÉGIE
|
||||
## 21. PARTITIONING STRATÉGIE
|
||||
|
||||
### 18.1 Tables Candidates au Partitioning
|
||||
### 21.1 Tables Candidates au Partitioning
|
||||
|
||||
**High-Volume Tables** (>10M rows expected):
|
||||
|
||||
|
|
@ -2134,7 +2298,7 @@ ORDER BY schemaname, tablename;
|
|||
4. **`playback_history`** - Partition by month (played_at)
|
||||
5. **`login_attempts`** - Partition by month (attempted_at)
|
||||
|
||||
### 18.2 Example: messages Partitioning
|
||||
### 21.2 Example: messages Partitioning
|
||||
|
||||
```sql
|
||||
-- Create partitioned table
|
||||
|
|
@ -2172,7 +2336,7 @@ SELECT partman.create_parent(
|
|||
);
|
||||
```
|
||||
|
||||
### 18.3 Partition Maintenance
|
||||
### 21.3 Partition Maintenance
|
||||
|
||||
```sql
|
||||
-- Drop old partitions (retention policy)
|
||||
|
|
@ -2185,9 +2349,9 @@ ALTER TABLE messages DETACH PARTITION messages_2023_01;
|
|||
-- pg_dump messages_2023_01 > archive/messages_2023_01.sql
|
||||
```
|
||||
|
||||
## 19. TRIGGERS & FUNCTIONS
|
||||
## 22. TRIGGERS & FUNCTIONS
|
||||
|
||||
### 19.1 Update Timestamps
|
||||
### 22.1 Update Timestamps
|
||||
|
||||
```sql
|
||||
-- Trigger function for updated_at
|
||||
|
|
@ -2209,7 +2373,7 @@ CREATE TRIGGER trg_tracks_updated_at BEFORE UPDATE ON tracks
|
|||
-- ... (repeat for all tables with updated_at)
|
||||
```
|
||||
|
||||
### 19.2 Denormalized Counters
|
||||
### 22.2 Denormalized Counters
|
||||
|
||||
```sql
|
||||
-- Increment follower_count when follow created
|
||||
|
|
@ -2251,7 +2415,7 @@ CREATE TRIGGER trg_follows_delete AFTER DELETE ON follows
|
|||
FOR EACH ROW EXECUTE FUNCTION decrement_follower_count();
|
||||
```
|
||||
|
||||
### 19.3 Audit Trail
|
||||
### 22.3 Audit Trail
|
||||
|
||||
```sql
|
||||
-- Generic audit trigger
|
||||
|
|
@ -2287,9 +2451,9 @@ CREATE TRIGGER trg_orders_audit AFTER INSERT OR UPDATE OR DELETE ON orders
|
|||
FOR EACH ROW EXECUTE FUNCTION audit_trigger();
|
||||
```
|
||||
|
||||
## 20. MATERIALIZED VIEWS
|
||||
## 23. MATERIALIZED VIEWS
|
||||
|
||||
### 20.1 Trending Tracks
|
||||
### 23.1 Trending Tracks
|
||||
|
||||
```sql
|
||||
CREATE MATERIALIZED VIEW trending_tracks AS
|
||||
|
|
@ -2326,7 +2490,7 @@ CREATE INDEX idx_trending_tracks_trending_score ON trending_tracks(trending_scor
|
|||
REFRESH MATERIALIZED VIEW CONCURRENTLY trending_tracks;
|
||||
```
|
||||
|
||||
### 20.2 User Statistics
|
||||
### 23.2 User Statistics
|
||||
|
||||
```sql
|
||||
CREATE MATERIALIZED VIEW user_statistics AS
|
||||
|
|
@ -2352,15 +2516,15 @@ GROUP BY u.id, u.username;
|
|||
REFRESH MATERIALIZED VIEW CONCURRENTLY user_statistics;
|
||||
```
|
||||
|
||||
## 21. MIGRATION STRATÉGIE
|
||||
## 24. MIGRATION STRATÉGIE
|
||||
|
||||
### 21.1 Migration Tools
|
||||
### 24.1 Migration Tools
|
||||
|
||||
**Backend (Go)**: GORM Auto-Migrate + SQL files
|
||||
**Rust Services**: SQLx migrations
|
||||
**Versioning**: Sequential numbered migrations
|
||||
|
||||
### 21.2 Migration Workflow
|
||||
### 24.2 Migration Workflow
|
||||
|
||||
```bash
|
||||
# GORM (Go backend)
|
||||
|
|
@ -2374,7 +2538,7 @@ REFRESH MATERIALIZED VIEW CONCURRENTLY user_statistics;
|
|||
# Apply with: sqlx migrate run
|
||||
```
|
||||
|
||||
### 21.3 Example Migration (SQLx)
|
||||
### 24.3 Example Migration (SQLx)
|
||||
|
||||
```sql
|
||||
-- migrations/0001_create_users.sql
|
||||
|
|
@ -2396,7 +2560,7 @@ CREATE INDEX idx_users_username_btree ON users(username);
|
|||
ALTER TABLE users ADD COLUMN token_version INTEGER NOT NULL DEFAULT 0;
|
||||
```
|
||||
|
||||
### 21.4 Rollback Strategy
|
||||
### 24.4 Rollback Strategy
|
||||
|
||||
```sql
|
||||
-- Down migrations (SQLx supports)
|
||||
|
|
@ -2407,7 +2571,7 @@ ALTER TABLE users DROP COLUMN IF EXISTS token_version;
|
|||
-- sqlx migrate revert
|
||||
```
|
||||
|
||||
### 21.5 Zero-Downtime Migrations
|
||||
### 24.5 Zero-Downtime Migrations
|
||||
|
||||
**Principles**:
|
||||
1. **Additive changes first** (add columns, tables)
|
||||
|
|
@ -2430,37 +2594,47 @@ ALTER TABLE users DROP COLUMN IF EXISTS first_name;
|
|||
ALTER TABLE users DROP COLUMN IF EXISTS last_name;
|
||||
```
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
## CHECKLIST DE VALIDATION
|
||||
|
||||
### Schema Completeness
|
||||
- [ ] 100+ tables défin all 21 modules
|
||||
- [ ] Toutes les tables ont `id`, `created_at`, `updated_at`
|
||||
- [ ] Soft delete (`deleted_at`) sur tables user-facing
|
||||
- [ ] Foreign keys avec ON DELETE CASCADE/RESTRICT explicites
|
||||
- [ ] Indexes sur toutes les foreign keys
|
||||
- [ ] Constraints pour intégrité données (CHECK, UNIQUE, NOT NULL)
|
||||
- [x] ~85 tables couvrant tous les modules retenus
|
||||
- [x] Toutes les tables ont `id`, `created_at`, `updated_at`
|
||||
- [x] Soft delete (`deleted_at`) sur tables user-facing
|
||||
- [x] Foreign keys avec ON DELETE CASCADE/RESTRICT explicites
|
||||
- [x] Indexes sur toutes les foreign keys
|
||||
- [x] Constraints pour intégrité données (CHECK, UNIQUE, NOT NULL)
|
||||
|
||||
### Performance
|
||||
- [ ] Indexes B-tree sur colonnes de recherche fréquentes
|
||||
- [ ] Indexes GIN pour full-text search
|
||||
- [ ] Partial indexes pour filtres WHERE fréquents
|
||||
- [ ] Partitioning sur tables high-volume (>10M rows)
|
||||
- [ ] Materialized views pour requêtes complexes fréquentes
|
||||
- [x] Indexes B-tree sur colonnes de recherche fréquentes
|
||||
- [x] Indexes GIN pour full-text search
|
||||
- [x] Partial indexes pour filtres WHERE fréquents
|
||||
- [x] Partitioning sur tables high-volume (>10M rows)
|
||||
- [x] Materialized views pour requêtes complexes fréquentes
|
||||
|
||||
### Security & Compliance
|
||||
- [ ] Audit logs pour actions sensibles
|
||||
- [ ] GDPR compliance (soft delete, data export capability)
|
||||
- [ ] Encryption at rest (pgcrypto pour colonnes sensibles)
|
||||
- [ ] Row-level security policies (RLS) considérées
|
||||
- [x] Audit logs pour actions sensibles
|
||||
- [x] GDPR compliance (soft delete, export, consentement séparé, rétention)
|
||||
- [x] Encryption at rest (pgcrypto pour colonnes sensibles)
|
||||
- [x] Row-level security policies (RLS) considérées
|
||||
|
||||
### Contraintes éthiques
|
||||
- [x] Aucune table ML/IA (feature vectors, embeddings, predictions)
|
||||
- [x] Aucune table blockchain/NFT/crypto
|
||||
- [x] Aucune gamification addictive (XP, streaks, leaderboards, achievements)
|
||||
- [x] Badges limités aux compétences déclaratives (instrument, genre, expérience)
|
||||
- [x] Politique de rétention des données documentée et implémentable
|
||||
- [x] Consentement GDPR séparé (traitement vs marketing)
|
||||
- [x] Exclusions documentées avec raisons dans section 17
|
||||
|
||||
### Maintenance
|
||||
- [ ] Triggers pour updated_at automatiques
|
||||
- [ ] Triggers pour denormalized counters
|
||||
- [ ] Migration strategy documentée
|
||||
- [ ] Rollback procedures définies
|
||||
- [ ] Backup strategy planifiée
|
||||
- [x] Triggers pour updated_at automatiques
|
||||
- [x] Triggers pour denormalized counters
|
||||
- [x] Migration strategy documentée
|
||||
- [x] Rollback procedures définies
|
||||
- [x] Backup strategy planifiée
|
||||
- [x] Jobs de nettoyage/rétention documentés
|
||||
|
||||
## 📊 MÉTRIQUES DE SUCCÈS
|
||||
## MÉTRIQUES DE SUCCÈS
|
||||
|
||||
### Performance Targets
|
||||
- **Query time p95**: < 10ms (indexed queries)
|
||||
|
|
@ -2482,44 +2656,45 @@ ALTER TABLE users DROP COLUMN IF EXISTS last_name;
|
|||
- **RTO** (Recovery Time Objective): < 1 hour
|
||||
- **RPO** (Recovery Point Objective): < 15 minutes
|
||||
|
||||
## 🔄 HISTORIQUE DES VERSIONS
|
||||
## HISTORIQUE DES VERSIONS
|
||||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Schéma complet 105 tables |
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique : suppression tables ML/IA, blockchain/NFT/crypto, gamification addictive. Ajout champs GDPR (consentement séparé, export). Ajout politique de rétention des données. Badges restreints aux compétences déclaratives. Documentation des exclusions avec raisons. ~85 tables. |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AVERTISSEMENT
|
||||
## AVERTISSEMENT
|
||||
|
||||
**CE SCHÉMA EST IMMUABLE**
|
||||
**CE SCHÉMA EST CONTRÔLÉ**
|
||||
|
||||
Le schéma de base de données défini ici est **VERROUILLÉ**. Toute modification nécessite:
|
||||
Le schéma de base de données défini ici est **verrouillé**. Toute modification nécessite :
|
||||
|
||||
1. **RFC Database Change** avec impact analysis complet
|
||||
2. **Migration plan** détaillé (up + down)
|
||||
3. **Performance testing** (query plans, index impact)
|
||||
4. **Approbation CTO** + DBA (si applicable)
|
||||
4. **Vérification éthique** : la modification ne doit pas réintroduire de tables ML/IA, blockchain, ou gamification addictive
|
||||
5. **Backup complet** avant exécution
|
||||
6. **Rollback plan** testé
|
||||
|
||||
**Modifications autorisées sans RFC**:
|
||||
**Modifications autorisées sans RFC** :
|
||||
- Ajout index non-unique
|
||||
- Ajout colonne nullable (sans default calculé)
|
||||
- Modification comments/documentation
|
||||
|
||||
**Modifications NON autorisées**:
|
||||
**Modifications interdites** :
|
||||
- Ajout de tables ML/IA, blockchain/NFT/crypto, ou gamification addictive (voir section 17)
|
||||
- Suppression table
|
||||
- Suppression colonne (utiliser deprecated d'abord)
|
||||
- Changement type colonne (incompatible)
|
||||
- Suppression foreign key (intégrité référentielle)
|
||||
- Changement partitioning strategy (migration massive)
|
||||
- Réduction des durées de rétention sans justification légale
|
||||
|
||||
---
|
||||
|
||||
**Document créé par**: Database Team + Architecture
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Phase 4 (Q3 2026)
|
||||
**Propriétaire**: Lead Backend Engineer + DBA
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
**Document créé par** : Database Team + Architecture
|
||||
**Date de création** : 2025-11-02
|
||||
**Dernière révision** : 2026-03-04 (v2.0.0 - révision éthique)
|
||||
**Prochaine révision** : Q3 2026
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ Ce document définit le guide de déploiement complet pour la plateforme Veza en
|
|||
10. [Backup & Disaster Recovery](#10-backup--disaster-recovery)
|
||||
11. [Scaling Strategy](#11-scaling-strategy)
|
||||
12. [Operational Procedures](#12-operational-procedures)
|
||||
13. [Correctifs de Sécurité Prioritaires](#13-correctifs-de-sécurité-prioritaires)
|
||||
14. [Checklist de Déploiement Éthique](#14-checklist-de-déploiement-éthique)
|
||||
15. [Plan de Migration JWT HS256 → RS256](#15-plan-de-migration-jwt-hs256--rs256)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
|
|
@ -1316,6 +1319,298 @@ kubectl logs -f deployment/veza-backend -n veza-production
|
|||
5. Root cause analysis
|
||||
6. Post-mortem
|
||||
|
||||
## 13. CORRECTIFS DE SÉCURITÉ PRIORITAIRES
|
||||
|
||||
> Identifiés lors de l'audit sécurité du 2026-03-04. Ces procédures sont **bloquantes** pour tout déploiement en production.
|
||||
|
||||
### 13.1 Rotation du Secret JWT
|
||||
|
||||
Le secret JWT doit être rotaté régulièrement (minimum trimestriel) et immédiatement en cas de suspicion de compromission.
|
||||
|
||||
**Procédure de rotation** :
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/rotate-jwt-secret.sh
|
||||
set -euo pipefail
|
||||
|
||||
NEW_SECRET=$(openssl rand -base64 64)
|
||||
|
||||
# 1. Stocker le nouveau secret dans Vault
|
||||
vault kv put secret/veza/production jwt_secret="$NEW_SECRET"
|
||||
|
||||
# 2. Mettre à jour le secret Kubernetes
|
||||
kubectl create secret generic veza-jwt-secret \
|
||||
--from-literal=jwt-secret="$NEW_SECRET" \
|
||||
--dry-run=client -o yaml | kubectl apply -f - -n veza-production
|
||||
|
||||
# 3. Redémarrage progressif (rolling restart) pour charger le nouveau secret
|
||||
kubectl rollout restart deployment/veza-backend -n veza-production
|
||||
kubectl rollout restart deployment/veza-chat-server -n veza-production
|
||||
|
||||
# 4. Attendre que le rollout soit terminé
|
||||
kubectl rollout status deployment/veza-backend -n veza-production --timeout=5m
|
||||
kubectl rollout status deployment/veza-chat-server -n veza-production --timeout=5m
|
||||
|
||||
echo "JWT secret rotation complete. Old tokens will expire naturally."
|
||||
```
|
||||
|
||||
**Points critiques** :
|
||||
- Pendant la rotation, les anciens tokens restent valides jusqu'à leur expiration naturelle (configurer une durée de vie courte : 15 min access, 7 jours refresh)
|
||||
- Tester en staging avant chaque rotation production
|
||||
- Logger l'événement de rotation (sans le secret) dans l'audit log
|
||||
|
||||
### 13.2 Alignement JWT Issuer/Audience Go ↔ Rust
|
||||
|
||||
Le backend Go et le chat-server Rust doivent utiliser les mêmes claims JWT (`iss`, `aud`) pour éviter les rejets de tokens inter-services.
|
||||
|
||||
**Configuration alignée** :
|
||||
```yaml
|
||||
# Configuration partagée — identique Go et Rust
|
||||
jwt:
|
||||
issuer: "https://api.veza.app"
|
||||
audience: "https://veza.app"
|
||||
algorithm: "HS256" # Migrer vers RS256 — voir section 15
|
||||
access_token_ttl: "15m"
|
||||
refresh_token_ttl: "7d"
|
||||
```
|
||||
|
||||
**Vérification Go** :
|
||||
```go
|
||||
// veza-backend-api/internal/auth/jwt.go
|
||||
claims := jwt.MapClaims{
|
||||
"iss": "https://api.veza.app",
|
||||
"aud": "https://veza.app",
|
||||
"sub": userID,
|
||||
"exp": time.Now().Add(15 * time.Minute).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
}
|
||||
```
|
||||
|
||||
**Vérification Rust** :
|
||||
```rust
|
||||
// veza-chat-server/src/auth.rs
|
||||
let validation = Validation::new(Algorithm::HS256);
|
||||
validation.set_issuer(&["https://api.veza.app"]);
|
||||
validation.set_audience(&["https://veza.app"]);
|
||||
```
|
||||
|
||||
**Procédure de déploiement** :
|
||||
1. Mettre à jour la config Rust pour accepter le même `iss`/`aud`
|
||||
2. Déployer le chat-server Rust en premier (il accepte les tokens existants + nouveaux)
|
||||
3. Mettre à jour la config Go
|
||||
4. Déployer le backend Go
|
||||
5. Vérifier les logs des deux services : zéro erreur `invalid issuer` ou `invalid audience`
|
||||
|
||||
### 13.3 Protection de la Route /metrics
|
||||
|
||||
La route `/metrics` (Prometheus) expose des métriques internes et ne doit **jamais** être accessible publiquement.
|
||||
|
||||
**Nginx/Ingress — bloquer l'accès externe** :
|
||||
```yaml
|
||||
# k8s/ingress.yaml — ajout d'annotation
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: veza-ingress
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/server-snippet: |
|
||||
location /metrics {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
```
|
||||
|
||||
**NetworkPolicy — restreindre au namespace monitoring** :
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-metrics-from-prometheus
|
||||
namespace: veza-production
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: veza-backend
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
name: monitoring
|
||||
ports:
|
||||
- port: 8080
|
||||
protocol: TCP
|
||||
```
|
||||
|
||||
**Vérification post-déploiement** :
|
||||
```bash
|
||||
# Doit retourner 404 ou connexion refusée depuis l'extérieur
|
||||
curl -s -o /dev/null -w "%{http_code}" https://api.veza.app/metrics
|
||||
# Expected: 404
|
||||
|
||||
# Doit fonctionner depuis le pod Prometheus
|
||||
kubectl exec -n monitoring deploy/prometheus -- curl -s http://veza-backend.veza-production/metrics | head -5
|
||||
# Expected: 200 avec métriques
|
||||
```
|
||||
|
||||
## 14. CHECKLIST DE DÉPLOIEMENT ÉTHIQUE
|
||||
|
||||
Avant chaque déploiement en production, les points suivants doivent être vérifiés. Cette checklist complète la checklist opérationnelle standard (section 12.1).
|
||||
|
||||
### 14.1 Protection des Données Personnelles
|
||||
|
||||
- [ ] **Métriques Prometheus** : vérifier qu'aucune métrique n'expose de données personnelles (emails, IPs, user agents complets, identifiants utilisateur)
|
||||
```bash
|
||||
# Vérification automatisée — aucune métrique ne doit contenir ces patterns
|
||||
kubectl exec -n monitoring deploy/prometheus -- \
|
||||
curl -s http://veza-backend.veza-production/metrics | \
|
||||
grep -iE '(email|user_agent|ip_address|@)' && \
|
||||
echo "FAIL: Personal data found in metrics" && exit 1 || \
|
||||
echo "PASS: No personal data in metrics"
|
||||
```
|
||||
|
||||
- [ ] **Logs anonymisés** : confirmer que les logs applicatifs ne contiennent pas de données personnelles en clair
|
||||
```bash
|
||||
# Vérification sur les 1000 dernières lignes de logs
|
||||
kubectl logs deployment/veza-backend -n veza-production --tail=1000 | \
|
||||
grep -iE '([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})' && \
|
||||
echo "FAIL: Email addresses found in logs" && exit 1 || \
|
||||
echo "PASS: No emails in logs"
|
||||
```
|
||||
|
||||
- [ ] **Headers HTTP** : aucun header de tracking ou fingerprinting n'est émis par les services
|
||||
|
||||
### 14.2 Conformité RGPD
|
||||
|
||||
- [ ] **Export des données** : l'endpoint `POST /api/v1/me/data-export` retourne toutes les données de l'utilisateur authentifié (profil, tracks, playlists, historique)
|
||||
- [ ] **Suppression de compte** : l'endpoint `DELETE /api/v1/me` supprime l'utilisateur et toutes ses données associées (cascade)
|
||||
- [ ] **Consentement cookies** : seuls les cookies strictement nécessaires (session JWT) sont envoyés sans consentement
|
||||
|
||||
### 14.3 Intégrité Éthique
|
||||
|
||||
- [ ] **Pas de dépendance AI/ML** : aucune image Docker ne contient de framework ML (TensorFlow, PyTorch, scikit-learn, ONNX)
|
||||
- [ ] **Pas de tracking tiers** : aucun script Google Analytics, Facebook Pixel, ou équivalent dans le bundle frontend
|
||||
- [ ] **Algorithme de découverte** : les tests de biais (section 14 de ORIGIN_TESTING_STRATEGY) passent en CI
|
||||
|
||||
## 15. PLAN DE MIGRATION JWT HS256 → RS256
|
||||
|
||||
### 15.1 Motivation
|
||||
|
||||
HS256 (HMAC symétrique) nécessite le partage du même secret entre tous les services. RS256 (RSA asymétrique) permet au backend Go de signer avec une clé privée tandis que les autres services (Rust, frontend) vérifient avec la clé publique, réduisant la surface d'attaque.
|
||||
|
||||
### 15.2 Architecture Cible
|
||||
|
||||
```
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ Backend Go │ │ Chat Server │
|
||||
│ (signe JWT) │ │ Rust │
|
||||
│ │ │ (vérifie JWT) │
|
||||
│ Clé PRIVÉE RS256│ │ Clé PUBLIQUE │
|
||||
└──────────────────┘ └──────────────────┘
|
||||
│ │
|
||||
│ Même clé publique │
|
||||
└────────────┬───────────────┘
|
||||
│
|
||||
┌───────▼───────┐
|
||||
│ Frontend │
|
||||
│ (vérifie JWT │
|
||||
│ optionnel) │
|
||||
│ Clé PUBLIQUE │
|
||||
└───────────────┘
|
||||
```
|
||||
|
||||
### 15.3 Étapes de Migration
|
||||
|
||||
**Phase 1 — Préparation (semaine 1)** :
|
||||
```bash
|
||||
# Générer la paire de clés RSA 4096 bits
|
||||
openssl genrsa -out jwt-private.pem 4096
|
||||
openssl rsa -in jwt-private.pem -pubout -out jwt-public.pem
|
||||
|
||||
# Stocker dans Vault
|
||||
vault kv put secret/veza/production \
|
||||
jwt_private_key=@jwt-private.pem \
|
||||
jwt_public_key=@jwt-public.pem
|
||||
|
||||
# Nettoyer les fichiers locaux
|
||||
shred -u jwt-private.pem jwt-public.pem
|
||||
```
|
||||
|
||||
**Phase 2 — Double validation (semaine 2)** :
|
||||
|
||||
Modifier les services pour accepter **les deux algorithmes** pendant la transition :
|
||||
|
||||
```go
|
||||
// veza-backend-api — signe en RS256, valide HS256 et RS256
|
||||
func (a *Auth) ValidateToken(tokenString string) (*Claims, error) {
|
||||
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
|
||||
switch t.Method.(type) {
|
||||
case *jwt.SigningMethodRSA:
|
||||
return a.rsaPublicKey, nil
|
||||
case *jwt.SigningMethodHMAC:
|
||||
return []byte(a.hmacSecret), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||
}
|
||||
})
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
// veza-chat-server — valide HS256 et RS256
|
||||
fn validate_token(token: &str, config: &AuthConfig) -> Result<Claims, AuthError> {
|
||||
// Try RS256 first, fall back to HS256
|
||||
let rs256_result = decode::<Claims>(
|
||||
token,
|
||||
&DecodingKey::from_rsa_pem(config.rsa_public_key.as_bytes())?,
|
||||
&Validation::new(Algorithm::RS256),
|
||||
);
|
||||
|
||||
match rs256_result {
|
||||
Ok(data) => Ok(data.claims),
|
||||
Err(_) => {
|
||||
let hs256_result = decode::<Claims>(
|
||||
token,
|
||||
&DecodingKey::from_secret(config.hmac_secret.as_bytes()),
|
||||
&Validation::new(Algorithm::HS256),
|
||||
);
|
||||
hs256_result.map(|d| d.claims).map_err(AuthError::from)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Phase 3 — Basculement (semaine 3)** :
|
||||
1. Déployer le backend Go pour signer exclusivement en RS256
|
||||
2. Attendre l'expiration de tous les tokens HS256 (max 7 jours pour les refresh tokens)
|
||||
3. Supprimer le code de fallback HS256 des services Go et Rust
|
||||
4. Supprimer le secret HS256 de Vault
|
||||
|
||||
**Phase 4 — Nettoyage (semaine 4)** :
|
||||
```bash
|
||||
# Supprimer l'ancien secret HS256 de Vault
|
||||
vault kv delete secret/veza/production/jwt_secret_hmac
|
||||
|
||||
# Vérifier qu'aucun service n'utilise encore HS256
|
||||
kubectl logs -l app=veza-backend -n veza-production --since=24h | \
|
||||
grep -i "hs256" && echo "WARNING: HS256 still in use" || echo "CLEAN: No HS256 usage"
|
||||
```
|
||||
|
||||
### 15.4 Rollback Plan
|
||||
|
||||
Si des problèmes sont détectés pendant la migration :
|
||||
1. Remettre le backend Go en mode signature HS256
|
||||
2. Les services continuent d'accepter les deux formats
|
||||
3. Investiguer et corriger avant de retenter
|
||||
|
||||
### 15.5 Critères de Succès
|
||||
|
||||
- [ ] Tous les services acceptent RS256
|
||||
- [ ] Aucun token HS256 en circulation (après expiration naturelle)
|
||||
- [ ] La clé privée RSA est uniquement accessible au backend Go
|
||||
- [ ] Les tests d'intégration inter-services passent avec RS256
|
||||
- [ ] Performance : la vérification RS256 < 1ms (benchmarker)
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Infrastructure
|
||||
|
|
@ -1361,6 +1656,7 @@ kubectl logs -f deployment/veza-backend -n veza-production
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Guide de déploiement complet |
|
||||
| 2.0.0 | 2026-03-04 | Audit sécurité : ajout correctifs prioritaires (rotation JWT, alignement issuer/audience Go↔Rust, protection /metrics), checklist de déploiement éthique (données personnelles, RGPD, intégrité), plan de migration JWT HS256→RS256. |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1372,7 +1668,8 @@ kubectl logs -f deployment/veza-backend -n veza-production
|
|||
|
||||
**Document créé par**: DevOps Team + SRE
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Quarterly (2026-02-01)
|
||||
**Dernière révision**: 2026-03-04 (audit sécurité)
|
||||
**Prochaine révision**: Quarterly (2026-06-01)
|
||||
**Propriétaire**: DevOps Lead
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
Ce document catalogue **TOUS** les patterns d'erreurs identifiés dans le projet Veza pendant la Phase 0 (Error Resolution). Chaque pattern inclut la cause racine, la solution standard, et une checklist de prévention pour éviter sa réapparition dans les futures implémentations.
|
||||
|
||||
**Dernière mise à jour** : 2025-11-09
|
||||
**Dernière mise à jour** : 2026-03-04
|
||||
**Statut** : ✅ Document de référence officiel
|
||||
**Version** : 1.0.0
|
||||
**Version** : 2.0.0
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -23,13 +23,13 @@ Ce document catalogue **TOUS** les patterns d'erreurs identifiés dans le projet
|
|||
|
||||
| Catégorie | Patterns | Fréquence | Priorité |
|
||||
|-----------|----------|-----------|----------|
|
||||
| **Backend Go** | 5 | Haute | P0-P1 |
|
||||
| **Backend Go** | 10 | Haute | P0-P1 |
|
||||
| **Frontend TypeScript** | 8 | Très Haute | P0-P2 |
|
||||
| **Tests** | 6 | Haute | P1-P2 |
|
||||
| **Configuration** | 3 | Moyenne | P0-P1 |
|
||||
| **Lint/Format** | 4 | Haute | P2 |
|
||||
|
||||
**Total** : 26 patterns documentés
|
||||
**Total** : 31 patterns documentés
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -343,6 +343,299 @@ var db *DB // Type DB non défini
|
|||
|
||||
---
|
||||
|
||||
### PAT-024: JWT Issuer/Audience Mismatch
|
||||
|
||||
**Catégorie** : CAT-02 (Configuration)
|
||||
**Priorité** : P0 (Critique)
|
||||
**Fréquence** : Moyenne
|
||||
**Découvert** : 2026-03-04 (Audit)
|
||||
|
||||
#### Description
|
||||
|
||||
Le token JWT est rejeté car l'issuer (`iss`) ou l'audience (`aud`) ne correspond pas à la configuration attendue par le service de validation. Cela provoque des erreurs d'authentification silencieuses ou des 401 intermittents.
|
||||
|
||||
**Exemple réel** :
|
||||
```go
|
||||
// ❌ ERREUR - issuer codé en dur, différent entre services
|
||||
func ValidateToken(tokenString string) (*Claims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(os.Getenv("JWT_SECRET")), nil
|
||||
})
|
||||
// Pas de vérification de iss/aud → token accepté même si émis par un autre service
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause Racine
|
||||
|
||||
- Issuer/audience non validés lors du parsing JWT
|
||||
- Configuration différente entre le service d'émission et le service de validation
|
||||
- Variables d'environnement `JWT_ISSUER` et `JWT_AUDIENCE` absentes ou incohérentes
|
||||
|
||||
#### Solution Standard
|
||||
|
||||
```go
|
||||
// ✅ SOLUTION - Valider issuer et audience explicitement
|
||||
func ValidateToken(tokenString string) (*Claims, error) {
|
||||
expectedIssuer := config.GetJWTIssuer()
|
||||
expectedAudience := config.GetJWTAudience()
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{},
|
||||
func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(config.GetJWTSecret()), nil
|
||||
},
|
||||
jwt.WithIssuer(expectedIssuer),
|
||||
jwt.WithAudience(expectedAudience),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("token validation failed: %w", err)
|
||||
}
|
||||
return token.Claims.(*Claims), nil
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist de Prévention
|
||||
|
||||
- [ ] Valider `iss` et `aud` lors de chaque parsing JWT
|
||||
- [ ] Centraliser la configuration JWT dans un seul package (`internal/auth/config.go`)
|
||||
- [ ] Vérifier la cohérence des variables `JWT_ISSUER` et `JWT_AUDIENCE` au démarrage
|
||||
- [ ] Tests unitaires couvrant les cas de mismatch issuer/audience
|
||||
- [ ] Documenter la configuration JWT dans `.env.example`
|
||||
|
||||
---
|
||||
|
||||
### PAT-025: Context Propagation Manquante
|
||||
|
||||
**Catégorie** : CAT-04 (Runtime)
|
||||
**Priorité** : P1 (Haute)
|
||||
**Fréquence** : Haute
|
||||
**Découvert** : 2026-03-04 (Audit)
|
||||
|
||||
#### Description
|
||||
|
||||
Utilisation de `context.Background()` ou `context.TODO()` dans les handlers HTTP au lieu de propager le contexte de la requête (`c.Request.Context()`). Cela empêche la propagation des deadlines, l'annulation des requêtes, et le tracing distribué.
|
||||
|
||||
**Exemple réel** :
|
||||
```go
|
||||
// ❌ ERREUR - context.Background() utilisé dans un handler
|
||||
func (h *TrackHandler) GetTrack(c *gin.Context) {
|
||||
track, err := h.trackService.GetByID(context.Background(), trackID)
|
||||
// Le context de la requête HTTP est ignoré
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause Racine
|
||||
|
||||
- Habitude de passer `context.Background()` par facilité
|
||||
- Manque de convention de propagation du contexte
|
||||
- Absence de linter rule pour détecter ce pattern
|
||||
|
||||
#### Solution Standard
|
||||
|
||||
```go
|
||||
// ✅ SOLUTION - Propager le contexte de la requête
|
||||
func (h *TrackHandler) GetTrack(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
track, err := h.trackService.GetByID(ctx, trackID)
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist de Prévention
|
||||
|
||||
- [ ] Toujours utiliser `c.Request.Context()` dans les handlers Gin
|
||||
- [ ] Ajouter une règle golangci-lint (contextcheck) pour détecter `context.Background()` dans les handlers
|
||||
- [ ] Propager le contexte dans toute la chaîne service → repository → database
|
||||
- [ ] Code review systématique sur l'usage du contexte
|
||||
- [ ] Grep régulier : `grep -rn "context.Background()" internal/handlers/`
|
||||
|
||||
---
|
||||
|
||||
### PAT-026: Goroutine Leak Patterns
|
||||
|
||||
**Catégorie** : CAT-04 (Runtime)
|
||||
**Priorité** : P1 (Haute)
|
||||
**Fréquence** : Moyenne
|
||||
**Découvert** : 2026-03-04 (Audit)
|
||||
|
||||
#### Description
|
||||
|
||||
Goroutines lancées sans mécanisme d'arrêt (context, done channel, WaitGroup), provoquant des fuites de goroutines qui consomment de la mémoire et des ressources indéfiniment.
|
||||
|
||||
**Exemple réel** :
|
||||
```go
|
||||
// ❌ ERREUR - goroutine sans mécanisme d'arrêt
|
||||
func (s *StreamService) StartProcessing() {
|
||||
go func() {
|
||||
for {
|
||||
s.processQueue()
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause Racine
|
||||
|
||||
- Goroutines lancées avec `go func()` sans condition d'arrêt
|
||||
- Absence de `context.Context` pour signaler l'annulation
|
||||
- Pas de `sync.WaitGroup` pour attendre la fin des goroutines au shutdown
|
||||
|
||||
#### Solution Standard
|
||||
|
||||
```go
|
||||
// ✅ SOLUTION - Goroutine avec contexte et WaitGroup
|
||||
func (s *StreamService) StartProcessing(ctx context.Context, wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
ticker := time.NewTicker(5 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
s.processQueue(ctx)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist de Prévention
|
||||
|
||||
- [ ] Toute goroutine doit recevoir un `context.Context` pour l'annulation
|
||||
- [ ] Utiliser `sync.WaitGroup` pour le graceful shutdown
|
||||
- [ ] Utiliser `select` avec `ctx.Done()` dans les boucles
|
||||
- [ ] Monitorer le nombre de goroutines en production (`runtime.NumGoroutine()`)
|
||||
- [ ] Tests avec `goleak` pour détecter les fuites de goroutines
|
||||
|
||||
---
|
||||
|
||||
### PAT-027: Pagination Sans Limite Max
|
||||
|
||||
**Catégorie** : CAT-04 (Runtime)
|
||||
**Priorité** : P1 (Haute)
|
||||
**Fréquence** : Moyenne
|
||||
**Découvert** : 2026-03-04 (Audit)
|
||||
|
||||
#### Description
|
||||
|
||||
Les endpoints paginés acceptent des valeurs `limit` arbitrairement grandes sans borne supérieure, permettant à un client de demander des millions d'enregistrements en une seule requête (risque de DoS, OOM).
|
||||
|
||||
**Exemple réel** :
|
||||
```go
|
||||
// ❌ ERREUR - pas de limite max
|
||||
func (h *TrackHandler) ListTracks(c *gin.Context) {
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
||||
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
|
||||
// limit peut valoir 999999999 → charge mémoire excessive
|
||||
tracks, err := h.trackService.List(ctx, limit, offset)
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause Racine
|
||||
|
||||
- Validation insuffisante des paramètres de pagination
|
||||
- Absence de constante `MaxPageSize` partagée
|
||||
- Confiance implicite dans les paramètres du client
|
||||
|
||||
#### Solution Standard
|
||||
|
||||
```go
|
||||
// ✅ SOLUTION - Valider et borner les paramètres de pagination
|
||||
const (
|
||||
DefaultPageSize = 20
|
||||
MaxPageSize = 100
|
||||
)
|
||||
|
||||
func parsePagination(c *gin.Context) (limit, offset int) {
|
||||
limit, _ = strconv.Atoi(c.DefaultQuery("limit", strconv.Itoa(DefaultPageSize)))
|
||||
offset, _ = strconv.Atoi(c.DefaultQuery("offset", "0"))
|
||||
|
||||
if limit <= 0 {
|
||||
limit = DefaultPageSize
|
||||
}
|
||||
if limit > MaxPageSize {
|
||||
limit = MaxPageSize
|
||||
}
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
return limit, offset
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist de Prévention
|
||||
|
||||
- [ ] Définir `MaxPageSize` comme constante partagée (ex. `internal/api/pagination.go`)
|
||||
- [ ] Valider et borner `limit` dans tous les endpoints paginés
|
||||
- [ ] Valider que `offset` est ≥ 0
|
||||
- [ ] Tests unitaires pour les cas limites (limit=0, limit=-1, limit=999999)
|
||||
- [ ] Documenter les limites de pagination dans l'API specification
|
||||
|
||||
---
|
||||
|
||||
### PAT-028: Error Handling Inconsistant (gin.H vs RespondWithAppError)
|
||||
|
||||
**Catégorie** : CAT-04 (Runtime)
|
||||
**Priorité** : P1 (Haute)
|
||||
**Fréquence** : Haute
|
||||
**Découvert** : 2026-03-04 (Audit)
|
||||
|
||||
#### Description
|
||||
|
||||
Mélange de deux patterns de réponse d'erreur dans les handlers : `gin.H{"error": ...}` (format ad hoc) et `RespondWithAppError()` (format standardisé). Cela crée des réponses d'erreur inconsistantes côté client, compliquant le parsing et le traitement des erreurs frontend.
|
||||
|
||||
**Exemple réel** :
|
||||
```go
|
||||
// ❌ ERREUR - Mélange de formats dans le même handler
|
||||
func (h *TrackHandler) CreateTrack(c *gin.Context) {
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()}) // Format ad hoc
|
||||
return
|
||||
}
|
||||
track, err := h.service.Create(ctx, &req)
|
||||
if err != nil {
|
||||
RespondWithAppError(c, err) // Format standardisé
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Cause Racine
|
||||
|
||||
- Migration partielle vers `RespondWithAppError`
|
||||
- Pas de convention imposée par linter
|
||||
- Copier-coller de code ancien utilisant `gin.H`
|
||||
|
||||
#### Solution Standard
|
||||
|
||||
```go
|
||||
// ✅ SOLUTION - Utiliser exclusivement RespondWithAppError
|
||||
func (h *TrackHandler) CreateTrack(c *gin.Context) {
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid request body", err))
|
||||
return
|
||||
}
|
||||
track, err := h.service.Create(ctx, &req)
|
||||
if err != nil {
|
||||
RespondWithAppError(c, err)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusCreated, track)
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist de Prévention
|
||||
|
||||
- [ ] Utiliser exclusivement `RespondWithAppError` pour toutes les réponses d'erreur
|
||||
- [ ] Grep régulier : `grep -rn 'gin.H{"error"' internal/handlers/` → doit retourner 0 résultat
|
||||
- [ ] Envelopper les erreurs de validation dans `apperrors.NewValidationError()`
|
||||
- [ ] Code review systématique sur le format des réponses d'erreur
|
||||
- [ ] Documenter le format standardisé dans `ORIGIN_API_SPECIFICATION.md`
|
||||
|
||||
---
|
||||
|
||||
## 2. FRONTEND TYPESCRIPT/REACT - PATTERNS D'ERREURS
|
||||
|
||||
### PAT-006: Syntax Errors - Unterminated Regex
|
||||
|
|
@ -1048,6 +1341,11 @@ Imports non triés selon les règles.
|
|||
- [ ] Vérifier que tous les packages importés existent
|
||||
- [ ] Utiliser `go vet` et `golangci-lint`
|
||||
- [ ] Tests unitaires pour chaque fonction
|
||||
- [ ] Valider JWT issuer/audience dans la config et au parsing
|
||||
- [ ] Propager `c.Request.Context()` dans tous les handlers (jamais `context.Background()`)
|
||||
- [ ] Toute goroutine reçoit un `context.Context` et un mécanisme d'arrêt
|
||||
- [ ] Pagination bornée par `MaxPageSize` sur tous les endpoints
|
||||
- [ ] Utiliser exclusivement `RespondWithAppError` (jamais `gin.H{"error": ...}`)
|
||||
|
||||
### Frontend TypeScript/React
|
||||
|
||||
|
|
@ -1091,8 +1389,8 @@ Imports non triés selon les règles.
|
|||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 2025-11-09
|
||||
**Version** : 1.0.0
|
||||
**Dernière mise à jour** : 2026-03-04
|
||||
**Version** : 2.0.0
|
||||
**Statut** : ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
Ce document définit le **système complet de prévention d'erreurs** pour le projet Veza. Il s'intègre parfaitement à la méthodologie ORIGIN_ existante et doit être appliqué **AVANT** de commencer toute nouvelle tâche d'implémentation. Ce guide garantit qu'aucune erreur récurrente ne sera introduite dans le codebase.
|
||||
|
||||
**Dernière mise à jour** : 2025-11-09
|
||||
**Dernière mise à jour** : 2026-03-04
|
||||
**Statut** : ✅ Document de référence officiel
|
||||
**Version** : 1.0.0
|
||||
**Version** : 2.0.0
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -95,17 +95,50 @@ Ce document définit le **système complet de prévention d'erreurs** pour le pr
|
|||
golangci-lint run
|
||||
```
|
||||
|
||||
- [ ] Vérifier la configuration JWT (issuer/audience) au démarrage
|
||||
```go
|
||||
// Dans main.go ou init — valider dès le boot
|
||||
if config.JWTIssuer == "" || config.JWTAudience == "" {
|
||||
log.Fatal("JWT_ISSUER and JWT_AUDIENCE must be set")
|
||||
}
|
||||
```
|
||||
- [ ] Propager le contexte de la requête (`c.Request.Context()`) — jamais `context.Background()` dans un handler
|
||||
```bash
|
||||
# Linter rule (golangci-lint contextcheck)
|
||||
golangci-lint run --enable contextcheck
|
||||
```
|
||||
- [ ] Goroutines avec mécanisme d'arrêt (`context.Context` + `sync.WaitGroup`)
|
||||
- Vérifier avec `goleak` dans les tests : `go.uber.org/goleak`
|
||||
- [ ] Pagination bornée — vérifier que `MaxPageSize` est appliqué
|
||||
```bash
|
||||
grep -rn "parsePagination\|MaxPageSize" internal/
|
||||
```
|
||||
- [ ] Réponses d'erreur standardisées — aucun `gin.H{"error"` dans les handlers
|
||||
```bash
|
||||
grep -rn 'gin.H{"error"' internal/handlers/ # Doit retourner 0 résultat
|
||||
```
|
||||
|
||||
**Patterns à éviter** :
|
||||
- ❌ Services qui importent handlers
|
||||
- ❌ Handlers qui importent services directement
|
||||
- ❌ Types partagés dans les packages qui les utilisent
|
||||
- ❌ Mélange de `string` et `*string` pour champs optionnels
|
||||
- ❌ `context.Background()` dans les handlers HTTP
|
||||
- ❌ Goroutines sans mécanisme d'arrêt (`go func()` nu)
|
||||
- ❌ Pagination sans `MaxPageSize`
|
||||
- ❌ `gin.H{"error": ...}` au lieu de `RespondWithAppError`
|
||||
- ❌ JWT parsing sans validation issuer/audience
|
||||
|
||||
**Patterns sûrs** :
|
||||
- ✅ Interfaces dans `internal/types/` ou `internal/interfaces/`
|
||||
- ✅ Services dépendent uniquement d'interfaces
|
||||
- ✅ Handlers dépendent uniquement d'interfaces
|
||||
- ✅ Types cohérents (toujours `string` OU toujours `*string`)
|
||||
- ✅ `c.Request.Context()` propagé dans toute la chaîne handler → service → repo
|
||||
- ✅ Goroutines avec `ctx.Done()` + `sync.WaitGroup`
|
||||
- ✅ `parsePagination()` centralisé avec `MaxPageSize = 100`
|
||||
- ✅ `RespondWithAppError()` pour toutes les erreurs
|
||||
- ✅ JWT issuer/audience validés au parsing et vérifiés au boot
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -480,6 +513,149 @@ describe('UserProfile', () => {
|
|||
|
||||
---
|
||||
|
||||
### 2.6 Audit Prevention Patterns (2026-03-04)
|
||||
|
||||
Les patterns suivants ont été identifiés lors de l'audit du 2026-03-04. Chaque pattern a un mécanisme de prévention automatisé.
|
||||
|
||||
#### JWT Configuration Validation at Startup
|
||||
|
||||
```go
|
||||
// ✅ PATTERN SÛR - Valider la configuration JWT au démarrage
|
||||
// internal/auth/config.go
|
||||
func ValidateJWTConfig(cfg *config.Config) error {
|
||||
if cfg.JWTSecret == "" {
|
||||
return fmt.Errorf("JWT_SECRET is required")
|
||||
}
|
||||
if cfg.JWTIssuer == "" {
|
||||
return fmt.Errorf("JWT_ISSUER is required")
|
||||
}
|
||||
if cfg.JWTAudience == "" {
|
||||
return fmt.Errorf("JWT_AUDIENCE is required")
|
||||
}
|
||||
if cfg.JWTExpiration <= 0 {
|
||||
return fmt.Errorf("JWT_EXPIRATION must be positive")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// main.go — appeler au boot, fail-fast si invalide
|
||||
func main() {
|
||||
cfg := config.Load()
|
||||
if err := auth.ValidateJWTConfig(cfg); err != nil {
|
||||
log.Fatalf("JWT configuration error: %v", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Context Propagation Enforcement
|
||||
|
||||
```yaml
|
||||
# ✅ PATTERN SÛR - golangci-lint config (.golangci.yml)
|
||||
linters:
|
||||
enable:
|
||||
- contextcheck
|
||||
|
||||
linters-settings:
|
||||
contextcheck:
|
||||
# Détecte context.Background() et context.TODO() dans les fonctions
|
||||
# qui reçoivent déjà un context en paramètre
|
||||
```
|
||||
|
||||
```go
|
||||
// ✅ PATTERN SÛR - Toujours propager le contexte
|
||||
func (h *Handler) GetResource(c *gin.Context) {
|
||||
ctx := c.Request.Context()
|
||||
result, err := h.service.Get(ctx, id) // ctx propagé
|
||||
}
|
||||
|
||||
func (s *Service) Get(ctx context.Context, id string) (*Resource, error) {
|
||||
return s.repo.FindByID(ctx, id) // ctx propagé
|
||||
}
|
||||
```
|
||||
|
||||
#### Goroutine Lifecycle Management
|
||||
|
||||
```go
|
||||
// ✅ PATTERN SÛR - Goroutine avec lifecycle complet
|
||||
type BackgroundWorker struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewBackgroundWorker(parentCtx context.Context) *BackgroundWorker {
|
||||
ctx, cancel := context.WithCancel(parentCtx)
|
||||
return &BackgroundWorker{ctx: ctx, cancel: cancel}
|
||||
}
|
||||
|
||||
func (w *BackgroundWorker) Start(task func(ctx context.Context)) {
|
||||
w.wg.Add(1)
|
||||
go func() {
|
||||
defer w.wg.Done()
|
||||
task(w.ctx)
|
||||
}()
|
||||
}
|
||||
|
||||
func (w *BackgroundWorker) Stop() {
|
||||
w.cancel()
|
||||
w.wg.Wait()
|
||||
}
|
||||
```
|
||||
|
||||
#### Pagination Limit Enforcement
|
||||
|
||||
```go
|
||||
// ✅ PATTERN SÛR - Pagination centralisée avec limites
|
||||
// internal/api/pagination.go
|
||||
const (
|
||||
DefaultPageSize = 20
|
||||
MaxPageSize = 100
|
||||
)
|
||||
|
||||
type PaginationParams struct {
|
||||
Limit int
|
||||
Offset int
|
||||
}
|
||||
|
||||
func ParsePagination(c *gin.Context) PaginationParams {
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", strconv.Itoa(DefaultPageSize)))
|
||||
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))
|
||||
|
||||
if limit <= 0 {
|
||||
limit = DefaultPageSize
|
||||
}
|
||||
if limit > MaxPageSize {
|
||||
limit = MaxPageSize
|
||||
}
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
return PaginationParams{Limit: limit, Offset: offset}
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Response Standardization
|
||||
|
||||
```go
|
||||
// ✅ PATTERN SÛR - Réponse d'erreur standardisée unique
|
||||
// internal/api/errors.go
|
||||
|
||||
// RespondWithAppError gère TOUTES les réponses d'erreur
|
||||
func RespondWithAppError(c *gin.Context, err error) {
|
||||
var appErr *apperrors.AppError
|
||||
if errors.As(err, &appErr) {
|
||||
c.JSON(appErr.HTTPStatus(), appErr.ToResponse())
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, apperrors.InternalError().ToResponse())
|
||||
}
|
||||
|
||||
// INTERDIT : c.JSON(400, gin.H{"error": "..."})
|
||||
// OBLIGATOIRE : RespondWithAppError(c, apperrors.NewValidationError("...", err))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. VALIDATION GATES
|
||||
|
||||
### 3.1 Pre-Commit Gates (Husky)
|
||||
|
|
@ -729,8 +905,8 @@ graph TD
|
|||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : 2025-11-09
|
||||
**Version** : 1.0.0
|
||||
**Dernière mise à jour** : 2026-03-04
|
||||
**Version** : 2.0.0
|
||||
**Statut** : ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
||||
**"Prevention is better than cure."**
|
||||
|
|
|
|||
|
|
@ -599,6 +599,256 @@ Files: internal/config/config.go, internal/types/types.go
|
|||
Tests: Updated"
|
||||
```
|
||||
|
||||
### 8.3 Exemple : Discovery Algorithm Bias Detected (CAT-04, P1)
|
||||
|
||||
**TERR-030: Fix abnormal distribution in discovery algorithm**
|
||||
|
||||
Un biais dans l'algorithme de découverte favorise disproportionnellement certains artistes ou genres. Détecté par une analyse statistique de la distribution des tracks recommandées.
|
||||
|
||||
**Diagnostic** :
|
||||
```bash
|
||||
# Analyser la distribution des tracks dans les résultats de découverte
|
||||
psql $DATABASE_URL -c "
|
||||
SELECT genre, COUNT(*) as count,
|
||||
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as pct
|
||||
FROM discovery_results
|
||||
JOIN tracks ON tracks.id = discovery_results.track_id
|
||||
GROUP BY genre
|
||||
ORDER BY count DESC;
|
||||
"
|
||||
# Si un genre dépasse 40% → biais confirmé
|
||||
```
|
||||
|
||||
**Résolution** :
|
||||
```go
|
||||
// Vérifier les pondérations de l'algorithme de découverte
|
||||
// internal/services/discovery_service.go
|
||||
|
||||
func (s *DiscoveryService) GetRecommendations(ctx context.Context, params DiscoveryParams) ([]Track, error) {
|
||||
tracks, err := s.repo.GetDiscoverableTracks(ctx, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("discovery query failed: %w", err)
|
||||
}
|
||||
|
||||
if err := s.validateDistribution(tracks); err != nil {
|
||||
s.logger.Warn("discovery distribution anomaly detected", "error", err)
|
||||
s.metrics.IncrCounter("discovery.distribution_anomaly", 1)
|
||||
}
|
||||
|
||||
return tracks, nil
|
||||
}
|
||||
|
||||
func (s *DiscoveryService) validateDistribution(tracks []Track) error {
|
||||
genreCounts := make(map[string]int)
|
||||
for _, t := range tracks {
|
||||
genreCounts[t.Genre]++
|
||||
}
|
||||
threshold := float64(len(tracks)) * 0.4
|
||||
for genre, count := range genreCounts {
|
||||
if float64(count) > threshold {
|
||||
return fmt.Errorf("genre %q represents %.1f%% of results (max 40%%)",
|
||||
genre, float64(count)/float64(len(tracks))*100)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
git add internal/services/discovery_service.go
|
||||
git commit -m "$(cat <<'EOF'
|
||||
TERR-030: fix: Add distribution validation to discovery algorithm
|
||||
|
||||
Added genre distribution check to detect and log abnormal bias
|
||||
in discovery results. Threshold set at 40% per genre.
|
||||
|
||||
Fixes: TERR-030
|
||||
Category: CAT-04
|
||||
Priority: P1
|
||||
Files: internal/services/discovery_service.go
|
||||
Tests: Added
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
### 8.4 Exemple : JWT Mismatch Errors (CAT-02, P0)
|
||||
|
||||
**TERR-031: Fix JWT issuer/audience validation**
|
||||
|
||||
Erreurs 401 intermittentes causées par un mismatch entre l'issuer configuré dans le service d'émission et celui attendu par le service de validation.
|
||||
|
||||
**Diagnostic** :
|
||||
```bash
|
||||
# Identifier les tokens rejetés
|
||||
grep "token validation failed" /var/log/veza-api/*.log | tail -20
|
||||
|
||||
# Vérifier la configuration
|
||||
echo "Émission: JWT_ISSUER=$JWT_ISSUER"
|
||||
echo "Validation: JWT_EXPECTED_ISSUER=$JWT_EXPECTED_ISSUER"
|
||||
# Si différents → mismatch confirmé
|
||||
```
|
||||
|
||||
**Résolution** :
|
||||
|
||||
```go
|
||||
// Étape 1 : Centraliser la configuration JWT
|
||||
// internal/auth/jwt_config.go
|
||||
type JWTConfig struct {
|
||||
Secret string
|
||||
Issuer string
|
||||
Audience string
|
||||
Expiry time.Duration
|
||||
}
|
||||
|
||||
func LoadJWTConfig() (*JWTConfig, error) {
|
||||
cfg := &JWTConfig{
|
||||
Secret: os.Getenv("JWT_SECRET"),
|
||||
Issuer: os.Getenv("JWT_ISSUER"),
|
||||
Audience: os.Getenv("JWT_AUDIENCE"),
|
||||
Expiry: parseDuration(os.Getenv("JWT_EXPIRATION"), 24*time.Hour),
|
||||
}
|
||||
if cfg.Secret == "" {
|
||||
return nil, fmt.Errorf("JWT_SECRET is required")
|
||||
}
|
||||
if cfg.Issuer == "" {
|
||||
return nil, fmt.Errorf("JWT_ISSUER is required")
|
||||
}
|
||||
if cfg.Audience == "" {
|
||||
return nil, fmt.Errorf("JWT_AUDIENCE is required")
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Étape 2 : Utiliser la même config pour émission ET validation
|
||||
// internal/auth/jwt.go
|
||||
func (a *Auth) GenerateToken(userID string) (string, error) {
|
||||
claims := jwt.RegisteredClaims{
|
||||
Issuer: a.config.Issuer,
|
||||
Audience: jwt.ClaimStrings{a.config.Audience},
|
||||
Subject: userID,
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(a.config.Expiry)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
}
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(a.config.Secret))
|
||||
}
|
||||
|
||||
func (a *Auth) ValidateToken(tokenStr string) (*jwt.RegisteredClaims, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &jwt.RegisteredClaims{},
|
||||
func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(a.config.Secret), nil
|
||||
},
|
||||
jwt.WithIssuer(a.config.Issuer),
|
||||
jwt.WithAudience(a.config.Audience),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("token validation failed: %w", err)
|
||||
}
|
||||
return token.Claims.(*jwt.RegisteredClaims), nil
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
git add internal/auth/
|
||||
git commit -m "$(cat <<'EOF'
|
||||
TERR-031: fix: Centralize JWT config and enforce issuer/audience validation
|
||||
|
||||
- Created JWTConfig with fail-fast validation at startup
|
||||
- Unified issuer/audience between token generation and validation
|
||||
- Added jwt.WithIssuer/WithAudience to ParseWithClaims
|
||||
|
||||
Fixes: TERR-031
|
||||
Category: CAT-02
|
||||
Priority: P0
|
||||
Files: internal/auth/jwt_config.go, internal/auth/jwt.go
|
||||
Tests: Added
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
### 8.5 Exemple : Error Handling Migration gin.H → RespondWithAppError (CAT-04, P1)
|
||||
|
||||
**TERR-032: Migrate error responses from gin.H to RespondWithAppError**
|
||||
|
||||
Migration systématique de toutes les réponses d'erreur ad hoc (`gin.H{"error": ...}`) vers le format standardisé (`RespondWithAppError`).
|
||||
|
||||
**Diagnostic** :
|
||||
```bash
|
||||
# Identifier tous les usages de gin.H pour les erreurs
|
||||
grep -rn 'gin.H{.*"error"' internal/handlers/
|
||||
# Compter les occurrences
|
||||
grep -rn 'gin.H{.*"error"' internal/handlers/ | wc -l
|
||||
```
|
||||
|
||||
**Résolution** :
|
||||
|
||||
```go
|
||||
// Étape 1 : S'assurer que apperrors couvre tous les cas
|
||||
// internal/apperrors/errors.go
|
||||
func NewValidationError(message string, cause error) *AppError {
|
||||
return &AppError{Code: "VALIDATION_ERROR", Message: message, Status: 400, Cause: cause}
|
||||
}
|
||||
|
||||
func NewNotFoundError(resource string) *AppError {
|
||||
return &AppError{Code: "NOT_FOUND", Message: fmt.Sprintf("%s not found", resource), Status: 404}
|
||||
}
|
||||
|
||||
func NewUnauthorizedError(message string) *AppError {
|
||||
return &AppError{Code: "UNAUTHORIZED", Message: message, Status: 401}
|
||||
}
|
||||
|
||||
func NewForbiddenError(message string) *AppError {
|
||||
return &AppError{Code: "FORBIDDEN", Message: message, Status: 403}
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
// Étape 2 : Remplacer chaque occurrence dans les handlers
|
||||
// AVANT :
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
|
||||
// APRÈS :
|
||||
RespondWithAppError(c, apperrors.NewValidationError("invalid request", err))
|
||||
|
||||
// AVANT :
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "track not found"})
|
||||
|
||||
// APRÈS :
|
||||
RespondWithAppError(c, apperrors.NewNotFoundError("track"))
|
||||
|
||||
// AVANT :
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
|
||||
|
||||
// APRÈS :
|
||||
RespondWithAppError(c, apperrors.NewUnauthorizedError("authentication required"))
|
||||
```
|
||||
|
||||
**Validation post-migration** :
|
||||
```bash
|
||||
# Vérifier qu'aucun gin.H{"error" ne subsiste
|
||||
grep -rn 'gin.H{.*"error"' internal/handlers/
|
||||
# Résultat attendu : 0 ligne
|
||||
|
||||
# Vérifier que les tests passent toujours
|
||||
go test ./internal/handlers/... -v
|
||||
```
|
||||
|
||||
```bash
|
||||
git add internal/handlers/ internal/apperrors/
|
||||
git commit -m "$(cat <<'EOF'
|
||||
TERR-032: refactor: Migrate all error responses to RespondWithAppError
|
||||
|
||||
Replaced all gin.H{"error": ...} with RespondWithAppError() across
|
||||
all handlers for consistent error response format.
|
||||
|
||||
Fixes: TERR-032
|
||||
Category: CAT-04
|
||||
Priority: P1
|
||||
Files: internal/handlers/*.go, internal/apperrors/errors.go
|
||||
Tests: Updated
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Métriques de Succès
|
||||
|
|
@ -667,7 +917,7 @@ Avant de marquer la Phase 0 comme terminée :
|
|||
|
||||
---
|
||||
|
||||
**Dernière mise à jour** : Janvier 2024
|
||||
**Version** : 1.0.0
|
||||
**Dernière mise à jour** : 2026-03-04
|
||||
**Version** : 2.0.0
|
||||
**Statut** : ✅ Document de référence officiel
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document constitue le registre officiel et exhaustif des 600 fonctionnalités de la plateforme Veza. Chaque feature possède un identifiant unique (F001-F600), une description détaillée, des dépendances explicites, une complexité évaluée, une priorité assignée, un temps d'implémentation estimé, des tests requis, et des critères d'acceptation précis. Ce registre est la source de vérité absolue pour toute implémentation et sert de contrat entre Product, Engineering et QA.
|
||||
Ce document constitue le registre officiel des fonctionnalités de la plateforme Veza. Suite à la révision éthique de mars 2026, le registre est passé de 600 à **~560 fonctionnalités**, avec la suppression des modules AI/ML (F456-F470), Blockchain/Web3 (F491-F500), et Gamification addictive (F536-F550). Chaque feature possède un identifiant unique, une description détaillée, des dépendances explicites, une complexité évaluée, une priorité assignée, un temps d'implémentation estimé, des tests requis, et des critères d'acceptation précis.
|
||||
|
||||
**Dernière révision** : 2026-03-04 (révision éthique — suppression de 40 features, 3 modules)
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
### Objectif Principal
|
||||
Fournir une spécification complète, non-ambiguë et traçable de chaque fonctionnalité de Veza pour permettre une implémentation autonome sans retour constant aux décisions produit.
|
||||
Fournir une spécification complète, non-ambiguë et traçable de chaque fonctionnalité de Veza, alignée avec les principes éthiques fondateurs, pour permettre une implémentation autonome.
|
||||
|
||||
### Objectifs Secondaires
|
||||
- Établir un système de dépendances clair entre features
|
||||
|
|
@ -33,23 +35,25 @@ Fournir une spécification complète, non-ambiguë et traçable de chaque foncti
|
|||
13. [Module 12: Analytics & Statistiques](#13-module-12-analytics--statistiques) (F381-F410)
|
||||
14. [Module 13: Administration](#14-module-13-administration) (F411-F435)
|
||||
15. [Module 14: UI/UX](#15-module-14-uiux) (F436-F455)
|
||||
16. [Module 15: IA & Fonctionnalités Avancées](#16-module-15-ia--fonctionnalités-avancées) (F456-F470)
|
||||
16. ~~Module 15: IA & Fonctionnalités Avancées~~ — **SUPPRIMÉ** (F456-F470, voir [§29 Exclusions](#29-features-exclues-et-raisons-éthiques))
|
||||
17. [Module 16: Livestreaming](#17-module-16-livestreaming) (F471-F480)
|
||||
18. [Module 17: Collaboration Temps Réel](#18-module-17-collaboration-temps-réel) (F481-F490)
|
||||
19. [Module 18: Blockchain & Web3](#19-module-18-blockchain--web3) (F491-F500)
|
||||
19. ~~Module 18: Blockchain & Web3~~ — **SUPPRIMÉ** (F491-F500, voir [§29 Exclusions](#29-features-exclues-et-raisons-éthiques))
|
||||
20. [Module 19: Intégrations Externes](#20-module-19-intégrations-externes) (F501-F520)
|
||||
21. [Module 20: Applications Natives](#21-module-20-applications-natives) (F521-F535)
|
||||
22. [Module 21: Gamification](#22-module-21-gamification) (F536-F550)
|
||||
22. ~~Module 21: Gamification~~ — **SUPPRIMÉ** (F536-F550, voir [§29 Exclusions](#29-features-exclues-et-raisons-éthiques))
|
||||
23. [Module 22: Notifications](#23-module-22-notifications) (F551-F570)
|
||||
24. [Module 23: Sécurité Avancée](#24-module-23-sécurité-avancée) (F571-F585)
|
||||
25. [Module 24: Développeurs & API](#25-module-24-développeurs--api) (F586-F600)
|
||||
26. [Matrice de Dépendances](#26-matrice-de-dépendances)
|
||||
27. [Index par Complexité](#27-index-par-complexité)
|
||||
28. [Index par Priorité](#28-index-par-priorité)
|
||||
29. [Features Exclues et Raisons Éthiques](#29-features-exclues-et-raisons-éthiques)
|
||||
30. [Algorithme de Découverte Éthique](#30-algorithme-de-découverte-éthique)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
1. **Chaque feature DOIT avoir un ID unique** (F001-F600) - pas de gaps, pas de duplicates
|
||||
1. **Chaque feature DOIT avoir un ID unique** — les IDs supprimés (F456-F470, F491-F500, F536-F550) ne sont pas réattribués
|
||||
2. **Les dépendances sont STRICTES** - une feature ne peut être implémentée si ses dépendances ne sont pas complétées
|
||||
3. **Les critères d'acceptation sont CONTRACTUELS** - tous doivent être validés pour considérer la feature complète
|
||||
4. **La complexité est FIXE** - pas de négociation, basée sur expérience collective
|
||||
|
|
@ -59,6 +63,7 @@ Fournir une spécification complète, non-ambiguë et traçable de chaque foncti
|
|||
8. **Priorité P0 = BLOQUANT** - toute autre feature en dépend
|
||||
9. **Priorité P4 = OPTIONNEL** - peut être déprioritisée si nécessaire
|
||||
10. **Phase assignment est IMMUTABLE** - pas de déplacement de features entre phases
|
||||
11. **Alignement éthique OBLIGATOIRE** — chaque feature doit servir les principes fondateurs du projet
|
||||
|
||||
## 1. SYSTÈME DE CODIFICATION
|
||||
|
||||
|
|
@ -81,7 +86,7 @@ F{NNN}
|
|||
| **2** | Simple | 4-8h | CRUD endpoint basique |
|
||||
| **3** | Moyen | 1-2 jours | Feature avec logic business |
|
||||
| **4** | Complexe | 3-5 jours | Integration externe, algo complexe |
|
||||
| **5** | Très complexe | 5-10 jours | Système complet, ML, temps réel |
|
||||
| **5** | Très complexe | 5-10 jours | Système complet, temps réel, intégration multi-service |
|
||||
|
||||
### 1.3 Échelle de Priorité
|
||||
|
||||
|
|
@ -1177,32 +1182,34 @@ Permettre upload d'une bannière de profil (header image). Validation format, ta
|
|||
|
||||
### Modules 3-24 (Summary Table)
|
||||
|
||||
| Module | ID Range | Features | Total Heures | Phase Principale |
|
||||
|--------|----------|----------|--------------|------------------|
|
||||
| **M03: File Management** | F066-F105 | 40 | 420h | P1-P2 |
|
||||
| **M04: Audio Streaming** | F106-F150 | 45 | 520h | P1-P3 |
|
||||
| **M05: Chat & Messaging** | F151-F185 | 35 | 380h | P2-P3 |
|
||||
| **M06: Social & Community** | F186-F225 | 40 | 450h | P2-P4 |
|
||||
| **M07: Marketplace** | F226-F275 | 50 | 680h | P3-P4 |
|
||||
| **M08: Education** | F276-F305 | 30 | 340h | P3-P5 |
|
||||
| **M09: Hardware Mgmt** | F306-F330 | 25 | 220h | P4 |
|
||||
| **M10: Cloud Storage** | F331-F350 | 20 | 260h | P4-P5 |
|
||||
| **M11: Search & Discovery** | F351-F380 | 30 | 380h | P2-P5 |
|
||||
| **M12: Analytics** | F381-F410 | 30 | 400h | P5-P6 |
|
||||
| **M13: Administration** | F411-F435 | 25 | 320h | P4-P7 |
|
||||
| **M14: UI/UX** | F436-F455 | 20 | 240h | P2-P7 |
|
||||
| **M15: AI & Advanced** | F456-F470 | 15 | 480h | P5-P8 |
|
||||
| **M16: Livestreaming** | F471-F480 | 10 | 320h | P4 |
|
||||
| **M17: Collaboration RT** | F481-F490 | 10 | 360h | P4 |
|
||||
| **M18: Blockchain Web3** | F491-F500 | 10 | 400h | P8 |
|
||||
| **M19: External Integrations** | F501-F520 | 20 | 360h | P5-P7 |
|
||||
| **M20: Native Apps** | F521-F535 | 15 | 420h | P3-P7 |
|
||||
| **M21: Gamification** | F536-F550 | 15 | 280h | P4 |
|
||||
| **M22: Notifications** | F551-F570 | 20 | 260h | P2-P6 |
|
||||
| **M23: Security Advanced** | F571-F585 | 15 | 340h | P3-P7 |
|
||||
| **M24: Developer API** | F586-F600 | 15 | 320h | P6-P7 |
|
||||
| Module | ID Range | Features | Total Heures | Phase Principale | Statut |
|
||||
|--------|----------|----------|--------------|------------------|--------|
|
||||
| **M03: File Management** | F066-F105 | 40 | 420h | P1-P2 | ✅ Actif |
|
||||
| **M04: Audio Streaming** | F106-F150 | 45 | 520h | P1-P3 | ✅ Actif |
|
||||
| **M05: Chat & Messaging** | F151-F185 | 35 | 380h | P2-P3 | ✅ Actif |
|
||||
| **M06: Social & Community** | F186-F225 | 40 | 450h | P2-P4 | ✅ Actif |
|
||||
| **M07: Marketplace** | F226-F275 | 50 | 680h | P3-P4 | ✅ Actif |
|
||||
| **M08: Education** | F276-F305 | 30 | 340h | P3-P5 | ✅ Actif |
|
||||
| **M09: Hardware Mgmt** | F306-F330 | 25 | 220h | P4 | ✅ Actif |
|
||||
| **M10: Cloud Storage** | F331-F350 | 20 | 260h | P4-P5 | ✅ Actif |
|
||||
| **M11: Search & Discovery** | F351-F380 | 30 | 380h | P2-P5 | ✅ Actif |
|
||||
| **M12: Analytics** | F381-F410 | 30 | 400h | P5-P6 | ✅ Actif |
|
||||
| **M13: Administration** | F411-F435 | 25 | 320h | P4-P7 | ✅ Actif |
|
||||
| **M14: UI/UX** | F436-F455 | 20 | 240h | P2-P7 | ✅ Actif |
|
||||
| ~~**M15: AI & Advanced**~~ | ~~F456-F470~~ | ~~15~~ | ~~480h~~ | — | ❌ **SUPPRIMÉ** |
|
||||
| **M16: Livestreaming** | F471-F480 | 10 | 320h | P4 | ✅ Actif |
|
||||
| **M17: Collaboration RT** | F481-F490 | 10 | 360h | P4 | ✅ Actif |
|
||||
| ~~**M18: Blockchain Web3**~~ | ~~F491-F500~~ | ~~10~~ | ~~400h~~ | — | ❌ **SUPPRIMÉ** |
|
||||
| **M19: External Integrations** | F501-F520 | 20 | 360h | P5-P7 | ✅ Actif |
|
||||
| **M20: Native Apps** | F521-F535 | 15 | 420h | P3-P7 | ✅ Actif |
|
||||
| ~~**M21: Gamification**~~ | ~~F536-F550~~ | ~~15~~ | ~~280h~~ | — | ❌ **SUPPRIMÉ** |
|
||||
| **M22: Notifications** | F551-F570 | 20 | 260h | P2-P6 | ✅ Actif |
|
||||
| **M23: Security Advanced** | F571-F585 | 15 | 340h | P3-P7 | ✅ Actif |
|
||||
| **M24: Developer API** | F586-F600 | 15 | 320h | P6-P7 | ✅ Actif |
|
||||
|
||||
**TOTAL**: 600 features, ~8,590 heures (~52 mois pour 1 dev, ou ~11 mois pour 5 devs)
|
||||
**TOTAL ACTIF** : 560 features, ~7,430 heures
|
||||
**SUPPRIMÉ** : 40 features (AI: 15, Web3: 10, Gamification: 15), ~1,160 heures
|
||||
**TOTAL ORIGINAL** : 600 features, ~8,590 heures
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1259,7 +1266,7 @@ F251 (Paiements Stripe)
|
|||
|
||||
## 27. INDEX PAR COMPLEXITÉ
|
||||
|
||||
### Complexité 5/5 (Très Complexe) - 45 features
|
||||
### Complexité 5/5 (Très Complexe) - 35 features (après révision éthique)
|
||||
|
||||
| ID | Feature | Module | Temps | Phase |
|
||||
|----|---------|--------|-------|-------|
|
||||
|
|
@ -1268,24 +1275,18 @@ F251 (Paiements Stripe)
|
|||
| F110 | Transcoding multi-format | M03 | 32h | P2 |
|
||||
| F125 | AirPlay/Chromecast | M04 | 28h | P3 |
|
||||
| F180 | End-to-end encryption | M05 | 40h | P4 |
|
||||
| F210 | Algorithme feed | M06 | 36h | P4 |
|
||||
| F270 | Recommendation ML | M07 | 48h | P5 |
|
||||
| F210 | Algorithme feed (éthique, basé sur curation) | M06 | 36h | P4 |
|
||||
| F290 | Video streaming HLS | M08 | 40h | P5 |
|
||||
| F350 | Nextcloud sync | M10 | 32h | P5 |
|
||||
| F375 | Elasticsearch cluster | M11 | 36h | P5 |
|
||||
| F405 | Real-time analytics | M12 | 42h | P6 |
|
||||
| F435 | Auto-moderation AI | M13 | 48h | P7 |
|
||||
| F456 | AI mastering | M15 | 56h | P5 |
|
||||
| F457 | Stem separation | M15 | 60h | P5 |
|
||||
| F460 | Genre detection ML | M15 | 40h | P5 |
|
||||
| F465 | Content ID | M15 | 52h | P5 |
|
||||
| F475 | WebRTC multi-peer | M16 | 48h | P4 |
|
||||
| F405 | Real-time analytics (pour créateurs) | M12 | 42h | P6 |
|
||||
| F475 | HLS multi-bitrate livestream | M16 | 48h | P4 |
|
||||
| F485 | DAW collaboration | M17 | 60h | P4 |
|
||||
| F495 | NFT smart contracts | M18 | 56h | P8 |
|
||||
| F500 | DAO governance | M18 | 48h | P8 |
|
||||
| ... | (25 autres) | ... | ... | ... |
|
||||
| ... | (23 autres) | ... | ... | ... |
|
||||
|
||||
**Total Complexité 5**: ~2,280 heures
|
||||
> **Supprimés** : F270 (Recommendation ML), F435 (Auto-moderation AI), F456-F470 (AI), F495/F500 (NFT/DAO)
|
||||
|
||||
**Total Complexité 5** : ~1,500 heures (après suppression modules AI/Web3)
|
||||
|
||||
### Complexité 1/5 (Trivial) - 80 features
|
||||
|
||||
|
|
@ -1347,79 +1348,162 @@ Features P4 peuvent être déprioritisées si nécessaire (contraintes temps/bud
|
|||
- [ ] Notes d'implémentation ajoutées si applicable
|
||||
|
||||
### Global
|
||||
- [ ] 600 features documentées
|
||||
- [ ] 560 features actives documentées (40 supprimées pour raisons éthiques)
|
||||
- [ ] Aucun ID dupliqué
|
||||
- [ ] Dépendances valides (pas de cycles)
|
||||
- [ ] Total temps estimé cohérent (~8,500-9,000h)
|
||||
- [ ] Dépendances valides (pas de cycles, pas de dépendances vers features supprimées)
|
||||
- [ ] Total temps estimé cohérent (~7,400h)
|
||||
- [ ] Distribution phases équilibrée
|
||||
- [ ] Features P0 dans phases précoces
|
||||
- [ ] Features complexes avec buffer temps
|
||||
- [ ] Cross-references valides entre documents
|
||||
- [ ] Chaque feature restante est alignée avec les principes éthiques fondateurs
|
||||
|
||||
## 📊 MÉTRIQUES DE SUCCÈS
|
||||
|
||||
### Coverage
|
||||
- **Features documentées**: 600/600 (100%)
|
||||
- **Features avec tests**: 600/600 (100%)
|
||||
- **Features avec critères acceptation**: 600/600 (100%)
|
||||
- **Features avec dépendances**: ~500/600 (83%)
|
||||
### Coverage (après révision éthique)
|
||||
- **Features actives documentées** : 560/560 (100%)
|
||||
- **Features supprimées** : 40 (documentées dans §29)
|
||||
- **Features avec tests** : 560/560 (100%)
|
||||
- **Features avec critères acceptation** : 560/560 (100%)
|
||||
- **Features avec dépendances** : ~470/560 (84%)
|
||||
|
||||
### Distribution
|
||||
- **P0 (Critical)**: 25 features (4.2%)
|
||||
- **P1 (High)**: 180 features (30%)
|
||||
- **P2 (Medium)**: 240 features (40%)
|
||||
- **P3 (Low)**: 115 features (19.2%)
|
||||
- **P4 (Optional)**: 40 features (6.6%)
|
||||
### Distribution (features actives)
|
||||
- **P0 (Critical)** : 25 features (4.5%)
|
||||
- **P1 (High)** : 170 features (30.4%)
|
||||
- **P2 (Medium)** : 220 features (39.3%)
|
||||
- **P3 (Low)** : 108 features (19.3%)
|
||||
- **P4 (Optional)** : 37 features (6.6%)
|
||||
|
||||
### Complexité
|
||||
- **Niveau 1**: 80 features (13.3%)
|
||||
- **Niveau 2**: 195 features (32.5%)
|
||||
- **Niveau 3**: 210 features (35%)
|
||||
- **Niveau 4**: 70 features (11.7%)
|
||||
- **Niveau 5**: 45 features (7.5%)
|
||||
### Complexité (features actives)
|
||||
- **Niveau 1** : 78 features (13.9%)
|
||||
- **Niveau 2** : 185 features (33.0%)
|
||||
- **Niveau 3** : 195 features (34.8%)
|
||||
- **Niveau 4** : 67 features (12.0%)
|
||||
- **Niveau 5** : 35 features (6.3%)
|
||||
|
||||
### Estimation Temps
|
||||
- **Total heures**: ~8,590h
|
||||
- **Par phase moyenne**: ~1,075h
|
||||
- **Par feature moyenne**: ~14.3h
|
||||
- **Total heures (actif)** : ~7,430h
|
||||
- **Heures supprimées** : ~1,160h (AI: 480h, Web3: 400h, Gamification: 280h)
|
||||
- **Par feature moyenne** : ~13.3h
|
||||
|
||||
## 🔄 HISTORIQUE DES VERSIONS
|
||||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - 600 features complètes |
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique : suppression M15 (AI), M18 (Web3), M21 (Gamification) = -40 features. Ajout sections exclusions et découverte éthique. Total actif : 560 features |
|
||||
|
||||
---
|
||||
|
||||
## 29. FEATURES EXCLUES ET RAISONS ÉTHIQUES
|
||||
|
||||
Les features suivantes sont **définitivement supprimées** du registre. Leurs IDs ne sont pas réattribués.
|
||||
|
||||
### Module 15 : IA & Fonctionnalités Avancées (F456-F470) — 15 features, ~480h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F456 | AI mastering | Déshumanise le processus créatif, déplace la valeur du créateur vers l'outil |
|
||||
| F457 | Stem separation | Questions éthiques non résolues sur la propriété artistique |
|
||||
| F458 | Auto BPM detection (ML) | Remplacé par déclaration manuelle du créateur |
|
||||
| F459 | Auto key detection (ML) | Remplacé par déclaration manuelle du créateur |
|
||||
| F460 | Genre detection ML | Crée des biais de classification à grande échelle |
|
||||
| F461 | Vocal removal AI | Questions éthiques sur la tromperie des audiences |
|
||||
| F462 | Audio denoising AI | Remplacé par outils tiers au choix du créateur |
|
||||
| F463 | Audio upscaling AI | Remplacé par outils tiers au choix du créateur |
|
||||
| F464 | Auto-tags ML | Remplacé par tags déclaratifs du créateur |
|
||||
| F465 | Content ID (ML) | Remplacé par audio fingerprinting déterministe (ACRCloud) |
|
||||
| F466 | Similarity detection ML | Optimise pour la rétention, pas la découverte authentique |
|
||||
| F467 | Recommendations ML | Remplacé par découverte éthique (§30) |
|
||||
| F468 | Voice synthesis | Tromperie des audiences, propriété artistique non résolue |
|
||||
| F469 | Lyrics transcription auto | Remplacé par saisie manuelle du créateur |
|
||||
| F470 | AI mixing assistant | Déshumanise le processus créatif |
|
||||
|
||||
### Module 18 : Blockchain & Web3 (F491-F500) — 10 features, ~400h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F491 | NFT minting | Fraudes documentées, spéculation, détournement d'œuvres sans consentement |
|
||||
| F492 | Smart contracts | Complexité disproportionnée, pas de valeur pour les créateurs indépendants |
|
||||
| F493 | Token economy | Spéculation, pas de valeur artistique |
|
||||
| F494 | Staking rewards | Mécanisme spéculatif |
|
||||
| F495 | NFT marketplace | Impact négatif documenté sur les artistes indépendants |
|
||||
| F496 | Wallet integration | Complexité UX, barrière à l'entrée |
|
||||
| F497 | IPFS storage | Consommation énergétique disproportionnée |
|
||||
| F498 | DAO governance | Complexité, gouvernance biaisée par le capital |
|
||||
| F499 | Crypto payments | Impact environnemental, volatilité |
|
||||
| F500 | Royalty smart contracts | Remplacé par système de paiement transparent via Hyperswitch |
|
||||
|
||||
### Module 21 : Gamification (F536-F550) — 15 features, ~280h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F536 | XP system | Transforme l'expression artistique en compétition |
|
||||
| F537 | Level progression | Normalise les métriques de performance comme mesure de la valeur artistique |
|
||||
| F538 | Achievement system (XP) | Social validation loop addictive |
|
||||
| F539 | Streaks | Crée de l'habitude compulsive |
|
||||
| F540 | Leaderboards popularité | Favorise les artistes établis, décourage les émergents |
|
||||
| F541 | Points system | Gamification addictive |
|
||||
| F542 | Challenges quotidiens | Crée de l'obligation de connexion (FOMO) |
|
||||
| F543 | Reward shop | Mécanique de rétention artificielle |
|
||||
| F544 | Social badges (followers count) | Social validation loop |
|
||||
| F545 | Performance badges | Normalise les métriques de performance |
|
||||
| F546 | Streak notifications | FOMO, pression sociale |
|
||||
| F547 | Progress bars | Mécanisme de compulsion |
|
||||
| F548 | Daily login rewards | Crée de l'habitude compulsive |
|
||||
| F549 | Referral gamification | Marketing viral, pas au service de la création |
|
||||
| F550 | Season pass | Mécanique de rétention artificielle |
|
||||
|
||||
> **Note** : Les badges de compétence déclaratifs (instrument, genre, expérience) restent possibles dans le module Profils (M02). Seule la gamification basée sur des métriques d'engagement est supprimée.
|
||||
|
||||
## 30. ALGORITHME DE DÉCOUVERTE ÉTHIQUE
|
||||
|
||||
En remplacement des features ML de recommandation (F466, F467), la découverte musicale sur Veza est basée sur :
|
||||
|
||||
### Principes
|
||||
- L'algorithme est orienté vers la singularité et l'originalité, pas vers la viralité
|
||||
- Le classement ne repose jamais sur des métriques de popularité brutes
|
||||
- Les artistes émergents ont la même visibilité que les artistes établis dans les flux de découverte
|
||||
- L'algorithme est documenté, explicable, et auditable
|
||||
|
||||
### Mécanismes
|
||||
1. **Genres et tags déclarés** : les artistes déclarent eux-mêmes leurs genres, tags, et influences
|
||||
2. **Connexions humaines** : similarité basée sur les collaborations et connexions entre artistes
|
||||
3. **Curation éditoriale** : playlists créées par des humains, pas par des algorithmes
|
||||
4. **Proximité géographique** : découverte par zone géographique (optionnel, déclaratif)
|
||||
5. **Réseau social** : ce qu'écoutent les contacts de l'utilisateur (opt-in)
|
||||
6. **Nouveautés chronologiques** : dans les genres suivis par l'utilisateur
|
||||
7. **Recherche fulltext** : Elasticsearch pour la recherche par mots-clés et phonétique
|
||||
|
||||
### Interdictions
|
||||
- Pas d'optimisation pour l'engagement ou la rétention
|
||||
- Pas de collaborative filtering basé sur le comportement
|
||||
- Pas de content-based filtering par ML
|
||||
- Pas de « trending » basé sur les plays/likes
|
||||
- Pas de « featured » basé sur des métriques d'engagement
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AVERTISSEMENT
|
||||
|
||||
**CE REGISTRE EST IMMUABLE**
|
||||
**CE REGISTRE EST ALIGNÉ AVEC L'ÉTHIQUE DU PROJET**
|
||||
|
||||
Les 600 features définies ici sont **CONTRACTUELLES**. Toute modification (ajout, suppression, changement scope) nécessite:
|
||||
Les 560 features actives sont la base de développement. Les 40 features supprimées le sont définitivement pour des raisons éthiques documentées dans §29. Toute modification nécessite :
|
||||
|
||||
1. **RFC (Request For Comments)** formelle avec justification business
|
||||
1. **RFC** formelle avec justification business ET vérification d'alignement éthique
|
||||
2. **Impact analysis** sur dépendances et timeline
|
||||
3. **Approbation** Product Owner + CTO
|
||||
4. **Update** de tous les documents ORIGIN impactés
|
||||
5. **Communication** à toute l'équipe engineering
|
||||
|
||||
**Modifications autorisées sans RFC**:
|
||||
- Corrections typos/clarifications mineures
|
||||
- Ajout notes d'implémentation
|
||||
- Refinement critères acceptation (si pas de changement scope)
|
||||
|
||||
**Modifications NON autorisées**:
|
||||
- Ajout features (créer ORIGIN_FEATURES_REGISTRY v2.0.0)
|
||||
- Suppression features contractuelles
|
||||
- Changement dépendances critiques
|
||||
- Changement complexité/priorité sans data
|
||||
**Aucune feature ne peut être ajoutée si elle contredit les principes éthiques fondateurs.**
|
||||
|
||||
---
|
||||
|
||||
**Document créé par**: Product Team + Engineering
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Après Phase 4 (mid-project review)
|
||||
**Propriétaire**: VP Product
|
||||
**Document créé par** : Product Team + Engineering
|
||||
**Date de création** : 2025-11-02
|
||||
**Dernière révision** : 2026-03-04 (révision éthique)
|
||||
**Propriétaire** : VP Product
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
**Statut** : ✅ **APPROUVÉ — v2.0.0**
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,20 @@ Garantir que **chaque feature implémentée est 100% fonctionnelle** dès le dé
|
|||
- [ ] **Documentation feature** : Feature documentée si nécessaire
|
||||
- [ ] **Changelog** : Changelog mis à jour
|
||||
|
||||
### Phase 7: Validation Éthique (OBLIGATOIRE pour discovery, métriques, social)
|
||||
|
||||
Toute feature touchant la découverte, les métriques ou les interactions sociales **DOIT** passer cette checklist avant validation :
|
||||
|
||||
- [ ] **Pas de maximisation d'engagement** : La feature ne maximise pas l'engagement ou le temps passé sur la plateforme
|
||||
- [ ] **Métriques au service du créateur** : Les métriques exposées servent le créateur, pas la plateforme
|
||||
- [ ] **Aucun dark pattern** : Aucun dark pattern UX détecté
|
||||
- [ ] **Algorithme explicable** : L'algorithme impliqué est documenté et explicable
|
||||
- [ ] **Minimisation des données** : Aucune donnée comportementale n'est collectée sans nécessité justifiée
|
||||
- [ ] **Accessibilité WCAG AA** : L'accessibilité WCAG AA est vérifiée
|
||||
- [ ] **Résilience** : La feature fonctionne en conditions dégradées (faible connectivité, PWA)
|
||||
|
||||
> ⚠️ **Cette phase est bloquante** : aucune feature discovery/métriques/social ne peut être marquée "complétée" si un de ces critères échoue.
|
||||
|
||||
## 🔄 PROCESSUS DE VALIDATION
|
||||
|
||||
### Étape 1: Implémentation
|
||||
|
|
@ -251,9 +265,24 @@ Si une validation échoue :
|
|||
- **Temps de debugging post-validation** : 0 (aucun bug découvert après validation)
|
||||
- **Confiance dans le statut "complété"** : 100% (toutes les tâches "complétées" sont fonctionnelles)
|
||||
|
||||
### Métriques éthiques
|
||||
|
||||
- **Diversité dans la découverte** : Artistes émergents exposés proportionnellement aux artistes établis
|
||||
- **Score d'accessibilité Lighthouse** : ≥ 95
|
||||
- **Zéro dark pattern détecté** : Audit manuel trimestriel
|
||||
|
||||
## 🔄 AMÉLIORATION CONTINUE
|
||||
|
||||
- **Revue trimestrielle** : Analyser les échecs de validation et améliorer la checklist
|
||||
- **Feedback équipe** : Collecter le feedback des développeurs sur le processus
|
||||
- **Mise à jour** : Mettre à jour la checklist selon les leçons apprises
|
||||
|
||||
---
|
||||
|
||||
## 📜 HISTORIQUE DES VERSIONS
|
||||
|
||||
| Version | Date | Changements |
|
||||
|---------|------------|-----------------------------------------------------------------------------|
|
||||
| 1.0.0 | 2025-01-XX | Version initiale — stratégie de validation des features |
|
||||
| 2.0.0 | 2026-03-04 | Ajout Phase 7 « Validation éthique » obligatoire, métriques éthiques ajoutées |
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ Fournir une roadmap d'implémentation complète, détaillée, et atomique permet
|
|||
## 📊 STATUT D'AVANCEMENT
|
||||
|
||||
**Tâches Complétées**: 450/2100+ (21.4%)
|
||||
**Dernière mise à jour**: 2025-01-XX
|
||||
**Dernière mise à jour**: 2026-03-04
|
||||
**Révision éthique**: Modules AI/ML (F456-F470), Web3 (F491-F500), Gamification (F536-F550) supprimés. Tâches audit P0/P1 ajoutées.
|
||||
|
||||
**Note**: Les tâches T0001-T0130 ont été archivées dans `ORIGIN_IMPLEMENTATION_TASKS_ARCHIVE.md` pour réduire la taille du fichier principal.
|
||||
|
||||
|
|
@ -39869,7 +39870,7 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
|
||||
### Posts & Feed (T1251-T1320)
|
||||
- T1251-T1270: Post Creation
|
||||
- T1271-T1290: Feed Algorithm
|
||||
- ~~T1271-T1290: Feed Algorithm~~ — **⛔ SUPPRIMÉ (révision éthique 2026-03-04)** : Algorithme de feed ML supprimé (F467). Raison : Remplacé par feed chronologique + curation humaine (découverte éthique).
|
||||
- T1291-T1310: Post Interactions
|
||||
- T1311-T1320: Hashtags
|
||||
|
||||
|
|
@ -39887,6 +39888,10 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
- T1461-T1480: Push Notifications
|
||||
- T1481-T1500: Email Notifications
|
||||
|
||||
### ~~Gamification (F536-F550)~~ — SUPPRIMÉ
|
||||
|
||||
> **⛔ TÂCHES SUPPRIMÉES (révision éthique 2026-03-04)** : Le module Gamification (F536-F550, 15 features, ~280h estimées) a été supprimé du registre. Les tâches correspondantes n'ont jamais été détaillées dans ce document. Raison : XP, niveaux, streaks, leaderboards de popularité et challenges quotidiens créent des boucles de validation sociale addictives, transforment l'expression artistique en compétition, et favorisent les artistes établis au détriment des émergents. Features concernées : F536 (XP system), F537 (Level progression), F538 (Achievement system), F539 (Streaks), F540 (Leaderboards), F541 (Points system), F542 (Challenges quotidiens), F543 (Reward shop), F544 (Social badges), F545 (Performance badges), F546 (Streak notifications), F547 (Progress bars), F548 (Daily login rewards), F549 (Referral gamification), F550 (Season pass).
|
||||
|
||||
## PHASE 6: INTELLIGENCE & ANALYTICS (T1501-T1750)
|
||||
|
||||
### Advanced Analytics (T1501-T1580)
|
||||
|
|
@ -39894,21 +39899,28 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
- T1531-T1560: Custom Reports
|
||||
- T1561-T1580: Export Functionality
|
||||
|
||||
### Recommendations (T1581-T1650)
|
||||
- T1581-T1610: Collaborative Filtering
|
||||
- T1611-T1640: Content-Based Filtering
|
||||
- T1641-T1650: Hybrid System
|
||||
### ~~Recommendations (T1581-T1650)~~ — SUPPRIMÉ
|
||||
|
||||
> **⛔ TÂCHE SUPPRIMÉE (révision éthique 2026-03-04)** : Features F466-F467 supprimées du registre. Raison : Les systèmes de recommandation ML (collaborative filtering, content-based filtering) optimisent pour la rétention, pas la découverte authentique. Remplacé par découverte éthique (tags déclaratifs, curation humaine, playlists communautaires).
|
||||
|
||||
- ~~T1581-T1610: Collaborative Filtering~~
|
||||
- ~~T1611-T1640: Content-Based Filtering~~
|
||||
- ~~T1641-T1650: Hybrid System~~
|
||||
|
||||
### Search Improvements (T1651-T1700)
|
||||
- T1651-T1670: Elasticsearch Integration
|
||||
- T1671-T1690: Faceted Search
|
||||
- T1691-T1700: Search Personalization
|
||||
- ~~T1691-T1700: Search Personalization~~ — **⛔ SUPPRIMÉ (révision éthique 2026-03-04)** : Personnalisation ML supprimée (F466). Raison : Optimise pour la rétention, pas la découverte authentique.
|
||||
|
||||
### Reporting (T1701-T1750)
|
||||
- T1701-T1720: Report Builder
|
||||
- T1721-T1740: Scheduled Reports
|
||||
- T1741-T1750: Report Sharing
|
||||
|
||||
### ~~IA & Fonctionnalités Avancées (F456-F470)~~ — SUPPRIMÉ
|
||||
|
||||
> **⛔ TÂCHES SUPPRIMÉES (révision éthique 2026-03-04)** : Le module IA & Fonctionnalités Avancées (F456-F470, 15 features, ~480h estimées) a été supprimé du registre. Les tâches correspondantes n'ont jamais été détaillées dans ce document. Raison : AI mastering, stem separation, voice synthesis et mixing assistant déshumanisent le processus créatif et déplacent la valeur du créateur vers l'outil. Genre detection ML et auto-tags créent des biais de classification. Content ID ML et similarity detection optimisent pour la rétention. Features concernées : F456 (AI mastering), F457 (Stem separation), F458 (Auto BPM detection ML), F459 (Auto key detection ML), F460 (Genre detection ML), F461 (Vocal removal AI), F462 (Audio denoising AI), F463 (Audio upscaling AI), F464 (Auto-tags ML), F465 (Content ID ML), F466 (Similarity detection ML), F467 (Recommendations ML), F468 (Voice synthesis), F469 (Lyrics transcription auto), F470 (AI mixing assistant). Alternatives : déclaration manuelle par le créateur, outils tiers au choix, audio fingerprinting déterministe (ACRCloud), découverte éthique.
|
||||
|
||||
## PHASE 7: ADVANCED MONETIZATION (T1751-T1950)
|
||||
|
||||
### Subscriptions (T1751-T1810)
|
||||
|
|
@ -39930,6 +39942,10 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
- T1911-T1930: Payout Calculation
|
||||
- T1931-T1950: Payout Processing
|
||||
|
||||
### ~~Blockchain & Web3 (F491-F500)~~ — SUPPRIMÉ
|
||||
|
||||
> **⛔ TÂCHES SUPPRIMÉES (révision éthique 2026-03-04)** : Le module Blockchain & Web3 (F491-F500, 10 features, ~400h estimées) a été supprimé du registre. Les tâches correspondantes n'ont jamais été détaillées dans ce document. Raison : NFT minting, smart contracts, token economy et staking rewards sont des mécanismes spéculatifs sans valeur pour les créateurs indépendants. Impact environnemental documenté, fraudes NFT, complexité UX disproportionnée. Features concernées : F491 (NFT minting), F492 (Smart contracts), F493 (Token economy), F494 (Staking rewards), F495 (NFT marketplace), F496 (Wallet integration), F497 (IPFS storage), F498 (DAO governance), F499 (Crypto payments), F500 (Royalty smart contracts — remplacé par paiement transparent via Hyperswitch).
|
||||
|
||||
## PHASE 8: SCALE & ENTERPRISE (T1951-T2100)
|
||||
|
||||
### Performance (T1951-T2000)
|
||||
|
|
@ -39951,6 +39967,119 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
|
||||
---
|
||||
|
||||
## TÂCHES PRIORITAIRES — AUDIT TECHNIQUE 2026-03-04
|
||||
|
||||
Les tâches suivantes sont issues de l'audit technique et de la révision éthique de mars 2026.
|
||||
|
||||
### P0 — URGENT (2 semaines)
|
||||
|
||||
#### TASK-SEC-001 : Supprimer JWT secret par défaut Rust
|
||||
- **Fichier** : `veza-common/src/config_rust.rs:234`
|
||||
- **Action** : Supprimer la valeur par défaut du secret JWT. Crash au démarrage si non configuré.
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 2h
|
||||
|
||||
#### TASK-SEC-002 : Aligner JWT issuer/audience Go ↔ Rust
|
||||
- **Action** : Unifier les valeurs issuer et audience entre Go et Rust
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 4h
|
||||
|
||||
#### TASK-SEC-003 : Corriger shutdown_signal main.rs
|
||||
- **Action** : Corriger la gestion du signal de shutdown dans le stream server
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 2h
|
||||
|
||||
#### TASK-SEC-004 : Enregistrer webhook worker dans shutdownManager
|
||||
- **Action** : Enregistrer le worker webhook dans le shutdown manager Go
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 2h
|
||||
|
||||
#### TASK-SEC-005 : Aligner password policy frontend (12 chars)
|
||||
- **Action** : Le frontend accepte des mots de passe < 12 caractères. Aligner avec le backend.
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 1h
|
||||
|
||||
#### TASK-SEC-006 : Protéger routes /metrics
|
||||
- **Action** : Restreindre l'accès aux routes /metrics à l'IP interne uniquement
|
||||
- **Priorité** : P0
|
||||
- **Effort** : 2h
|
||||
|
||||
### P1 — Phase 3.5 Sprint A (Quality Gates)
|
||||
|
||||
#### TASK-QA-001 : go test -coverprofile CI, seuil 70%
|
||||
- **Action** : Ajouter coverage Go dans CI avec seuil bloquant 70%
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 4h
|
||||
|
||||
#### TASK-QA-002 : cargo tarpaulin CI, seuil 60%
|
||||
- **Action** : Ajouter coverage Rust dans CI avec seuil bloquant 60%
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 4h
|
||||
|
||||
#### TASK-QA-003 : vitest threshold 50% → 70%
|
||||
- **Action** : Augmenter le seuil de coverage frontend de 50% à 70%
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 8h (inclut ajout de tests manquants)
|
||||
|
||||
#### TASK-QA-004 : Lighthouse CI dans GitHub Actions
|
||||
- **Action** : Ajouter Lighthouse CI dans le pipeline GitHub Actions
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 4h
|
||||
|
||||
#### TASK-QA-005 : Prometheus actif en dev
|
||||
- **Action** : Activer Prometheus en environnement de développement
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 2h
|
||||
|
||||
#### TASK-QA-006 : .nvmrc Node 20 + rust-toolchain.toml
|
||||
- **Action** : Créer `.nvmrc` et `rust-toolchain.toml` pour fixer les versions
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 1h
|
||||
|
||||
### P1 — Phase 3.5 Sprint B (Chat)
|
||||
|
||||
#### TASK-CHAT-001 à TASK-CHAT-005
|
||||
- Réactions emoji, mentions @user, typing indicator, read receipts, recherche messages
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 40h total
|
||||
|
||||
### P1 — Phase 3.5 Sprint C (Marketplace/Education)
|
||||
|
||||
#### TASK-EDU-001 : Frontend module Education
|
||||
- **Action** : Implémenter le frontend du module Education (backend existant)
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 24h
|
||||
|
||||
#### TASK-MKT-001 à TASK-MKT-003
|
||||
- Licence history, flow remboursement, email templates
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 20h total
|
||||
|
||||
### P1 — Phase 3.5 Sprint D (Cleanup)
|
||||
|
||||
#### TASK-DEBT-001 : Supprimer soundcloud/ (~4K LOC)
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 2h
|
||||
|
||||
#### TASK-DEBT-002 : Supprimer webrtc.rs (~500 LOC)
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 1h
|
||||
|
||||
#### TASK-DEBT-003 : Supprimer k8s/chat-server/
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 1h
|
||||
|
||||
#### TASK-DEBT-004 à TASK-DEBT-010
|
||||
- Supprimer dossiers orphelins, uniformiser error handling, secret manager, CSP, pagination, onCreateProduct, features.go
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 30h total
|
||||
|
||||
#### TASK-ARCH-001 : Migration JWT HS256 → RS256
|
||||
- **Priorité** : P1
|
||||
- **Effort** : 16h
|
||||
|
||||
---
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Complétude
|
||||
|
|
@ -39992,6 +40121,7 @@ Documentation complète fonctionnalités playlists: API docs, user guide, develo
|
|||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 7.0.0 | 2026-03-04 | Révision éthique : suppression tâches AI/ML (F456-F470), Web3/Blockchain (F491-F500), Gamification (F536-F550). Ajout tâches audit P0 (TASK-SEC-001 à 006) et P1 (TASK-QA, TASK-CHAT, TASK-EDU, TASK-MKT, TASK-DEBT, TASK-ARCH) |
|
||||
| 6.0.0 | 2025-01-XX | T0211-T0240 marquées complétées (240 tâches complétées au total). T0241-T0270 créées (30 nouvelles tâches: Role Management et Track Upload Backend) |
|
||||
| 5.0.0 | 2025-01-XX | T0131-T0150 marquées complétées (150 tâches complétées au total). T0001-T0130 archivées dans ORIGIN_IMPLEMENTATION_TASKS_ARCHIVE.md. T0151-T0180 créées (30 nouvelles tâches d'authentification prêtes) |
|
||||
| 4.0.0 | 2025-01-XX | T0051-T0072 marquées complétées (72 tâches complétées au total) + T0073-T0100 détaillées (28 nouvelles tâches prêtes) |
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# ORIGIN_IMPLEMENTATION_TASKS_ARCHIVE.md
|
||||
|
||||
> **Note de révision (2026-03-04)** : Les tâches T0051-T0065 concernant le chat server Rust sont archivées comme « complétées mais obsolètes » suite à la migration du chat server vers Go (voir ADR-002). Le chat server Rust n'est plus utilisé — seul le stream server reste en Rust.
|
||||
|
||||
## 📋 ARCHIVE DES TÂCHES COMPLÉTÉES
|
||||
|
||||
Ce document archive les tâches T0001 à T0130 qui ont été complétées et déplacées du fichier principal pour réduire sa taille.
|
||||
|
|
@ -177,3 +179,12 @@ Les détails complets de chaque tâche (code snippets, tests, DoD) sont disponib
|
|||
|
||||
**Note**: Ces tâches sont toutes complétées et validées. Elles servent de référence pour l'historique du projet.
|
||||
|
||||
---
|
||||
|
||||
## 📜 HISTORIQUE DES VERSIONS
|
||||
|
||||
| Version | Date | Changements |
|
||||
|---------|------------|-------------------------------------------------------------------------------------------------|
|
||||
| 1.0.0 | 2025-01-XX | Version initiale — archivage des tâches T0001-T0130 |
|
||||
| 2.0.0 | 2026-03-04 | Note de révision T0051-T0065 (chat server Rust obsolète, migration vers Go — voir ADR-002) |
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit les objectifs de performance mesurables et définitifs pour tous les composants de la plateforme Veza. Il spécifie targets précis pour latence (< 100ms p95), throughput (10K req/s), database (< 10ms queries), frontend (Lighthouse 100), avec monitoring (Prometheus), alerting (PagerDuty), et optimization strategies garantissant expérience utilisateur fluide et scalabilité production.
|
||||
Ce document définit les objectifs de performance mesurables et réalistes pour tous les composants de la plateforme Veza. Il spécifie targets précis pour latence API (p95 < 100ms, p99 < 200ms), database (p95 < 10ms), frontend (Lighthouse Performance ≥ 90, Accessibility ≥ 95), audio streaming (start < 500ms, rebuffering < 0.5%), avec monitoring (Prometheus), plan de mesure (Lighthouse CI, k6, pg_stat_statements), et optimization strategies garantissant expérience utilisateur fluide et scalabilité production.
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ Garantir performance optimale avec latence API < 100ms (p95), temps chargement <
|
|||
3. **Frontend Load**: First Contentful Paint < 1.5s, Time to Interactive < 3.5s
|
||||
4. **Bundle Size**: Initial JS bundle < 200KB gzipped
|
||||
5. **Memory Leaks**: Zero memory leaks tolérés (CI/CD checks)
|
||||
6. **Audio Streaming**: Zero buffering, latency < 50ms
|
||||
6. **Audio Streaming**: Rebuffering < 0.5%, stream start < 500ms
|
||||
7. **Throughput**: Min 10K req/s sustained (backend)
|
||||
8. **Resource Usage**: CPU < 70%, Memory < 80% (average)
|
||||
9. **Cache Hit Rate**: > 90% for frequently accessed data
|
||||
|
|
@ -143,11 +143,11 @@ stream-server:
|
|||
|
||||
### 3.1 Core Web Vitals
|
||||
|
||||
**Lighthouse Scores** (Target: 100):
|
||||
- **Performance**: ≥ 95
|
||||
- **Accessibility**: ≥ 100
|
||||
- **Best Practices**: ≥ 100
|
||||
- **SEO**: ≥ 100
|
||||
**Lighthouse Scores** :
|
||||
- **Performance**: ≥ 90
|
||||
- **Accessibility**: ≥ 95
|
||||
- **Best Practices**: ≥ 90
|
||||
- **SEO**: ≥ 90
|
||||
|
||||
**Detailed Metrics**:
|
||||
|
||||
|
|
@ -345,8 +345,8 @@ location /api/ {
|
|||
|
||||
**Buffering**:
|
||||
- **Initial Buffer**: 2 seconds
|
||||
- **Rebuffering**: Zero (target)
|
||||
- **Rebuffering Events**: < 0.1% of plays
|
||||
- **Rebuffering rate**: < 0.5% des sessions de lecture
|
||||
- **Rebuffering Events**: < 0.5% of plays
|
||||
|
||||
### 6.2 Audio Quality
|
||||
|
||||
|
|
@ -575,6 +575,69 @@ jobs:
|
|||
run: cp bench-new.txt bench-baseline.txt
|
||||
```
|
||||
|
||||
### 8.4 Plan de Mesure en Production
|
||||
|
||||
**Prometheus** (métriques actives en production) :
|
||||
```yaml
|
||||
monitoring:
|
||||
prometheus:
|
||||
status: actif en production
|
||||
scrape_interval: 15s
|
||||
retention: 30 jours
|
||||
métriques:
|
||||
- http_request_duration_seconds (histogram, par endpoint)
|
||||
- http_requests_total (counter, par status code)
|
||||
- audio_stream_start_duration_seconds (histogram)
|
||||
- audio_rebuffering_events_total (counter)
|
||||
- db_query_duration_seconds (histogram)
|
||||
- active_connections (gauge)
|
||||
```
|
||||
|
||||
**Lighthouse CI** (GitHub Actions, bloquant) :
|
||||
```yaml
|
||||
lighthouse_ci:
|
||||
déclencheur: chaque PR + chaque merge sur main
|
||||
urls_testées:
|
||||
- / (landing)
|
||||
- /dashboard
|
||||
- /tracks/{id}
|
||||
- /upload
|
||||
seuils_bloquants:
|
||||
performance: 90
|
||||
accessibility: 95
|
||||
action: gh-actions (lhci autorun)
|
||||
rapport: commentaire automatique sur PR
|
||||
```
|
||||
|
||||
**k6 Load Tests** (CD nightly) :
|
||||
```yaml
|
||||
k6_load_tests:
|
||||
fréquence: nightly (CD pipeline, 02:00 UTC)
|
||||
scénarios:
|
||||
- smoke: 10 VUs, 1 min (sanity check)
|
||||
- load: 500 VUs, 10 min (charge normale)
|
||||
- stress: 2000 VUs, 5 min (pic de charge)
|
||||
seuils:
|
||||
http_req_duration_p95: < 100ms
|
||||
http_req_duration_p99: < 200ms
|
||||
http_req_failed: < 1%
|
||||
rapport: Grafana dashboard + Slack notification si échec
|
||||
```
|
||||
|
||||
**pg_stat_statements** (activé en production) :
|
||||
```yaml
|
||||
pg_stat_statements:
|
||||
status: activé
|
||||
paramètres:
|
||||
pg_stat_statements.max: 10000
|
||||
pg_stat_statements.track: all
|
||||
monitoring:
|
||||
- requêtes > 10ms p95 signalées automatiquement
|
||||
- top 20 requêtes par temps cumulé (dashboard Grafana)
|
||||
- reset hebdomadaire des statistiques
|
||||
alerte: requête > 100ms exécutée > 100 fois/min → Slack
|
||||
```
|
||||
|
||||
## 9. OPTIMIZATION STRATEGIES
|
||||
|
||||
### 9.1 Backend Optimizations
|
||||
|
|
@ -786,21 +849,23 @@ endpoints:
|
|||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Performance Targets
|
||||
- [ ] API latency p95 < 100ms for all critical endpoints
|
||||
- [ ] API latency p95 < 100ms, p99 < 200ms
|
||||
- [ ] Database queries p95 < 10ms
|
||||
- [ ] Frontend Lighthouse Performance score ≥ 95
|
||||
- [ ] Frontend Lighthouse Performance score ≥ 90
|
||||
- [ ] Frontend Lighthouse Accessibility score ≥ 95
|
||||
- [ ] Initial JS bundle < 200KB gzipped
|
||||
- [ ] First Contentful Paint < 1.5s
|
||||
- [ ] Time to Interactive < 3.5s
|
||||
- [ ] Audio streaming start < 500ms
|
||||
- [ ] Zero buffering during playback
|
||||
- [ ] Rebuffering rate < 0.5%
|
||||
|
||||
### Monitoring
|
||||
- [ ] Prometheus metrics configured
|
||||
- [ ] Grafana dashboards created
|
||||
- [ ] Alerting rules configured (critical + warning)
|
||||
- [ ] Performance testing in CI/CD
|
||||
- [ ] Regression detection automated
|
||||
### Plan de Mesure
|
||||
- [ ] Prometheus actif en production (scrape 15s)
|
||||
- [ ] Lighthouse CI dans GitHub Actions (bloquant sur régression)
|
||||
- [ ] k6 load tests en CD nightly (smoke + load + stress)
|
||||
- [ ] pg_stat_statements activé en production
|
||||
- [ ] Grafana dashboards created (API, DB, Frontend, Streaming)
|
||||
- [ ] Alerting rules configured (critical → PagerDuty, warning → Slack)
|
||||
|
||||
### Optimization
|
||||
- [ ] Database indexes optimized
|
||||
|
|
@ -815,8 +880,15 @@ endpoints:
|
|||
|
||||
### Performance Metrics
|
||||
- **API Latency (p95)**: < 100ms
|
||||
- **API Latency (p99)**: < 200ms
|
||||
- **DB Query (p95)**: < 10ms
|
||||
- **Frontend Load (FCP)**: < 1.5s
|
||||
- **Lighthouse Performance**: ≥ 95
|
||||
- **Frontend Load (TTI)**: < 3.5s
|
||||
- **Lighthouse Performance**: ≥ 90
|
||||
- **Lighthouse Accessibility**: ≥ 95
|
||||
- **Audio Stream Start**: < 500ms
|
||||
- **Rebuffering Rate**: < 0.5%
|
||||
- **Bundle JS initial gzip**: < 200KB
|
||||
- **Uptime**: > 99.9%
|
||||
|
||||
### Resource Efficiency
|
||||
|
|
@ -826,7 +898,7 @@ endpoints:
|
|||
- **Database Connection Utilization**: < 80%
|
||||
|
||||
### User Experience
|
||||
- **Zero Buffering**: > 99.9% of plays
|
||||
- **Rebuffering rate**: < 0.5% des sessions
|
||||
- **Error Rate**: < 0.1%
|
||||
- **Time to First Play**: < 3s
|
||||
|
||||
|
|
@ -835,6 +907,7 @@ endpoints:
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Performance targets complets |
|
||||
| 2.0.0 | 2026-03-04 | Audit : targets Lighthouse réalistes (Perf ≥ 90, A11y ≥ 95), rebuffering < 0.5%, ajout plan de mesure complet (Prometheus, Lighthouse CI, k6 nightly, pg_stat_statements), suppression targets ML/inférence |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -846,7 +919,8 @@ endpoints:
|
|||
|
||||
**Document créé par**: Performance Team + SRE
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Quarterly (2026-02-01)
|
||||
**Dernière révision**: 2026-03-04 (v2.0.0)
|
||||
**Prochaine révision**: Quarterly (2026-06-01)
|
||||
**Propriétaire**: Performance Lead
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit toutes les métriques de qualité de la plateforme Veza. Il couvre les indicateurs de qualité du code, performance, sécurité, UX, et business avec leurs seuils, méthodes de mesure, et actions correctives. Ces métriques garantissent le maintien d'un standard de qualité élevé pendant 24 mois.
|
||||
Ce document définit toutes les métriques de qualité de la plateforme Veza. Il couvre les indicateurs de qualité du code, performance, sécurité, UX, et business avec leurs seuils actuels, trajectoires cibles par phase, quality gates CI/CD, et plan de réduction de la dette technique (DT-001 à DT-017). Ces métriques garantissent le maintien d'un standard de qualité élevé et mesurable.
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
|
|
@ -47,12 +47,20 @@ Ce document définit toutes les métriques de qualité de la plateforme Veza. Il
|
|||
|
||||
**Metric**: Percentage of code covered by tests
|
||||
|
||||
**Targets**:
|
||||
**État actuel et trajectoire cible** :
|
||||
|
||||
| Stack | Actuel (mars 2026) | Phase 3.5 | Phase 4R | Phase 5R |
|
||||
|-------|-------------------|-----------|----------|----------|
|
||||
| **Frontend (TypeScript/React)** | ~50% | 70% | 75% | **80%** |
|
||||
| **Backend Go** | Non mesuré | 70% | **80%** | 80% |
|
||||
| **Backend Rust** | Non mesuré | **60%** | 70% | 75% |
|
||||
|
||||
**Seuils d'alerte** :
|
||||
```
|
||||
🔴 Red: < 70% (unacceptable)
|
||||
🟡 Yellow: 70-79% (needs improvement)
|
||||
🟢 Green: ≥ 80% (acceptable)
|
||||
🌟 Goal: ≥ 90% (excellent)
|
||||
🔴 Red: < 60% (bloquant en CI à partir de Phase 3.5)
|
||||
🟡 Yellow: 60-69% (needs improvement)
|
||||
🟢 Green: ≥ 70% (acceptable)
|
||||
🌟 Goal: ≥ 80% (cible Phase 5R)
|
||||
```
|
||||
|
||||
**Measurement**:
|
||||
|
|
@ -74,6 +82,7 @@ Tool: Codecov or Coveralls
|
|||
Frequency: Every commit (CI/CD)
|
||||
Dashboard: Grafana panel "Test Coverage Trend"
|
||||
Alert: Coverage drops > 5% → Slack notification
|
||||
CI Gate: Coverage < seuil phase → PR bloquée (à partir de Phase 3.5)
|
||||
```
|
||||
|
||||
**Action if Below Target**:
|
||||
|
|
@ -81,7 +90,7 @@ Alert: Coverage drops > 5% → Slack notification
|
|||
1. Identify untested code (coverage report)
|
||||
2. Write missing tests (priority: critical paths)
|
||||
3. Code review: Reject PRs that decrease coverage
|
||||
4. Goal: Return to ≥ 80% within 2 sprints
|
||||
4. Goal: Return to target within 2 sprints
|
||||
```
|
||||
|
||||
### 1.2 Cyclomatic Complexity
|
||||
|
|
@ -305,12 +314,12 @@ Alert: Query > 100ms executed > 100 times/min → Slack
|
|||
|
||||
**Metric**: Google Lighthouse score (0-100)
|
||||
|
||||
**Targets**:
|
||||
**Targets** :
|
||||
```
|
||||
Performance Accessibility Best Practices SEO
|
||||
🟢 Green: ≥ 90 ≥ 90 ≥ 90 ≥ 90
|
||||
🟡 Yellow: 80-89 80-89 80-89 80-89
|
||||
🔴 Red: < 80 < 80 < 80 < 80
|
||||
🟢 Green: ≥ 90 ≥ 95 ≥ 90 ≥ 90
|
||||
🟡 Yellow: 80-89 90-94 80-89 80-89
|
||||
🔴 Red: < 80 < 90 < 80 < 80
|
||||
```
|
||||
|
||||
**Measurement**:
|
||||
|
|
@ -926,36 +935,46 @@ Visualization: Debt heat map (by module)
|
|||
5. Set debt reduction goals (quarterly)
|
||||
```
|
||||
|
||||
### 6.2 TODO Comments
|
||||
### 6.2 TODO/FIXME Comments
|
||||
|
||||
**Metric**: Number of TODO comments in code
|
||||
**Metric**: Number of TODO/FIXME comments in code
|
||||
|
||||
**Targets**:
|
||||
**État actuel** : **356** TODO/FIXME (audit mars 2026)
|
||||
|
||||
**Trajectoire cible** :
|
||||
|
||||
| Métrique | Actuel | Phase 3.5 | Phase 4R | Phase 5R |
|
||||
|----------|--------|-----------|----------|----------|
|
||||
| **TODO/FIXME** | 356 | < 200 | **< 50** | < 30 |
|
||||
|
||||
**Seuils d'alerte** :
|
||||
```
|
||||
🟢 Green: < 50 TODOs
|
||||
🟡 Yellow: 50-100 TODOs
|
||||
🔴 Red: > 100 TODOs
|
||||
🔴 Red: > 100 TODOs (situation actuelle : 356 🔴)
|
||||
```
|
||||
|
||||
**Measurement**:
|
||||
```bash
|
||||
# Count TODO comments
|
||||
grep -r "TODO" --include="*.go" --include="*.rs" --include="*.ts" . | wc -l
|
||||
# Count TODO/FIXME comments
|
||||
rg -c "TODO|FIXME" --include="*.go" --include="*.rs" --include="*.ts" --include="*.tsx" | awk -F: '{s+=$2} END {print s}'
|
||||
```
|
||||
|
||||
**Reporting**:
|
||||
```
|
||||
Tool: SonarQube
|
||||
Tool: SonarQube + script CI dédié
|
||||
Dashboard: "Code Debt Indicators"
|
||||
Review: Monthly tech debt review
|
||||
CI: Tendance trackée, alerte si augmentation > 10 en une semaine
|
||||
```
|
||||
|
||||
**Action if Above Target**:
|
||||
**Action plan** :
|
||||
```
|
||||
1. Convert TODOs to Jira tickets
|
||||
2. Prioritize and schedule fixes
|
||||
3. Remove completed TODOs
|
||||
4. Add context to remaining TODOs (why, when)
|
||||
1. Triage initial : convertir chaque TODO/FIXME en issue GitHub avec label "tech-debt"
|
||||
2. Prioriser par criticité (sécurité > correctness > clean-up)
|
||||
3. Allouer 20% du temps de sprint à la réduction des TODOs
|
||||
4. Interdire les nouveaux TODOs sans issue associée
|
||||
5. Cible Phase 4R : < 50 (réduction de 86%)
|
||||
```
|
||||
|
||||
### 6.3 Deprecated Code
|
||||
|
|
@ -983,6 +1002,70 @@ grep -r "@deprecated" --include="*.go" --include="*.rs" --include="*.ts" . | wc
|
|||
4. Remove after grace period (6 months)
|
||||
```
|
||||
|
||||
### 6.4 Plan de réduction de la dette technique (DT-001 à DT-017)
|
||||
|
||||
Les éléments suivants ont été identifiés lors de l'audit technique de mars 2026. Chaque item a un identifiant unique, une priorité et une échéance cible.
|
||||
|
||||
| ID | Description | Priorité | Phase cible | Effort estimé |
|
||||
|----|-------------|----------|-------------|---------------|
|
||||
| **DT-001** | Coverage frontend : 50% → 70% (ajouter tests composants critiques) | 🔴 Haute | Phase 3.5 | 3 sprints |
|
||||
| **DT-002** | Coverage Go : mettre en place mesure + atteindre 70% | 🔴 Haute | Phase 3.5 | 2 sprints |
|
||||
| **DT-003** | Coverage Rust : mettre en place tarpaulin + atteindre 60% | 🟡 Moyenne | Phase 3.5 | 2 sprints |
|
||||
| **DT-004** | Réduction TODO/FIXME : 356 → < 200 (triage + conversion en issues) | 🔴 Haute | Phase 3.5 | 2 sprints |
|
||||
| **DT-005** | Réduction TODO/FIXME : < 200 → < 50 | 🟡 Moyenne | Phase 4R | 3 sprints |
|
||||
| **DT-006** | Fichiers > 500 lignes : 139 → < 100 (découpage des plus gros fichiers) | 🟡 Moyenne | Phase 3.5 | 3 sprints |
|
||||
| **DT-007** | Fichiers > 500 lignes : < 100 → < 50 | 🟢 Basse | Phase 5R | 4 sprints |
|
||||
| **DT-008** | Implémenter Lighthouse CI dans GitHub Actions | 🔴 Haute | Phase 3.5 | 1 sprint |
|
||||
| **DT-009** | Implémenter k6 load tests nightly | 🔴 Haute | Phase 3.5 | 1 sprint |
|
||||
| **DT-010** | Activer pg_stat_statements en production | 🔴 Haute | Phase 3.5 | 0.5 sprint |
|
||||
| **DT-011** | Implémenter coverage enforcement CI (bloquant) | 🔴 Haute | Phase 3.5 | 0.5 sprint |
|
||||
| **DT-012** | Supprimer code mort et dépendances inutilisées | 🟡 Moyenne | Phase 4R | 2 sprints |
|
||||
| **DT-013** | Migrer valeurs arbitraires Tailwind vers design tokens | 🟡 Moyenne | Phase 4R | 2 sprints |
|
||||
| **DT-014** | Standardiser gestion d'erreurs (Go + Rust) | 🟡 Moyenne | Phase 4R | 2 sprints |
|
||||
| **DT-015** | Documenter API interne (Go handlers, Rust services) | 🟢 Basse | Phase 5R | 2 sprints |
|
||||
| **DT-016** | Refactorer composants UI > 300 lignes | 🟡 Moyenne | Phase 4R | 3 sprints |
|
||||
| **DT-017** | Implémenter bundle size check CI (< 200KB gzip) | 🔴 Haute | Phase 3.5 | 0.5 sprint |
|
||||
|
||||
**Règles de gestion** :
|
||||
- Chaque item DT-xxx est tracké comme issue GitHub avec le label `tech-debt`
|
||||
- 20% du temps de sprint est alloué à la réduction de dette technique
|
||||
- Les items 🔴 Haute priorité sont traités en premier
|
||||
- Revue mensuelle de la progression par l'équipe engineering
|
||||
- Aucun nouvel item de dette ne peut être introduit sans issue associée
|
||||
|
||||
### 6.5 Fichiers > 500 lignes
|
||||
|
||||
**Metric**: Number of source files exceeding 500 lines
|
||||
|
||||
**État actuel** : **139 fichiers** > 500 lignes (audit mars 2026)
|
||||
|
||||
**Trajectoire cible** :
|
||||
|
||||
| Métrique | Actuel | Phase 3.5 | Phase 4R | Phase 5R |
|
||||
|----------|--------|-----------|----------|----------|
|
||||
| **Fichiers > 500 lignes** | 139 | < 100 | < 75 | **< 50** |
|
||||
|
||||
**Seuils d'alerte** :
|
||||
```
|
||||
🟢 Green: < 50 fichiers
|
||||
🟡 Yellow: 50-100 fichiers
|
||||
🔴 Red: > 100 fichiers (situation actuelle : 139 🔴)
|
||||
```
|
||||
|
||||
**Measurement**:
|
||||
```bash
|
||||
rg --files --type ts --type go --type rust | xargs wc -l | awk '$1 > 500 {count++} END {print count " files > 500 lines"}'
|
||||
```
|
||||
|
||||
**Action plan** :
|
||||
```
|
||||
1. Identifier les fichiers les plus longs (top 20)
|
||||
2. Planifier le découpage en sous-modules/composants
|
||||
3. Appliquer la règle cursorrules : > 300 lignes = découpage obligatoire
|
||||
4. Chaque sprint : découper au minimum 5 fichiers
|
||||
5. Nouveaux fichiers : hard limit 300 lignes en code review
|
||||
```
|
||||
|
||||
## 7. QUALITY GATES
|
||||
|
||||
### 7.1 CI/CD Quality Gates
|
||||
|
|
@ -990,11 +1073,12 @@ grep -r "@deprecated" --include="*.go" --include="*.rs" --include="*.ts" . | wc
|
|||
**Pre-Merge Checks** (blocking):
|
||||
```
|
||||
✅ All tests pass (unit, integration)
|
||||
✅ Test coverage ≥ 80%
|
||||
✅ Test coverage ≥ seuil de la phase courante (bloquant à partir de Phase 3.5)
|
||||
✅ No linter errors
|
||||
✅ No security vulnerabilities (critical/high)
|
||||
✅ Code review approved (2+ reviewers)
|
||||
✅ Code review approved (1+ reviewer)
|
||||
✅ No merge conflicts
|
||||
✅ Lighthouse CI : pas de régression Performance ou Accessibility (bloquant)
|
||||
```
|
||||
|
||||
**Pre-Deployment Checks** (blocking):
|
||||
|
|
@ -1015,6 +1099,59 @@ grep -r "@deprecated" --include="*.go" --include="*.rs" --include="*.ts" . | wc
|
|||
✅ No critical alerts (30 min observation)
|
||||
```
|
||||
|
||||
### 7.1bis Quality Gates à implémenter
|
||||
|
||||
Les quality gates suivants doivent être ajoutés au pipeline CI/CD selon le calendrier indiqué :
|
||||
|
||||
| Quality Gate | Type | Statut | Échéance |
|
||||
|-------------|------|--------|----------|
|
||||
| **Coverage enforcement CI** | Bloquant | À implémenter | Phase 3.5 |
|
||||
| **Lighthouse CI (Performance ≥ 90)** | Bloquant sur régression | À implémenter | Phase 3.5 |
|
||||
| **Lighthouse CI (Accessibility ≥ 95)** | Bloquant sur régression | À implémenter | Phase 3.5 |
|
||||
| **k6 performance baseline** | Informatif | À implémenter | Phase 3.5 |
|
||||
| **k6 performance baseline** | Bloquant | Migration | Phase 4R |
|
||||
| **Bundle size check (< 200KB gzip)** | Bloquant | À implémenter | Phase 3.5 |
|
||||
| **TODO/FIXME count trend** | Informatif | À implémenter | Phase 3.5 |
|
||||
|
||||
**Détail d'implémentation** :
|
||||
|
||||
**Coverage enforcement CI (bloquant)** :
|
||||
```yaml
|
||||
# .github/workflows/coverage.yml
|
||||
- name: Check coverage threshold
|
||||
run: |
|
||||
THRESHOLD=70 # Phase 3.5, sera incrémenté par phase
|
||||
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||||
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
|
||||
echo "Coverage $COVERAGE% below threshold $THRESHOLD%"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**Lighthouse CI (bloquant sur régression)** :
|
||||
```yaml
|
||||
# .github/workflows/lighthouse.yml
|
||||
- name: Lighthouse CI
|
||||
uses: treosh/lighthouse-ci-action@v10
|
||||
with:
|
||||
urls: |
|
||||
https://staging.veza.app/
|
||||
https://staging.veza.app/dashboard
|
||||
budgetPath: ./lighthouse-budget.json
|
||||
uploadArtifacts: true
|
||||
# Bloque si Performance < 90 ou Accessibility < 95
|
||||
```
|
||||
|
||||
**k6 performance baseline** :
|
||||
```yaml
|
||||
# Phase 3.5 : informatif (rapport uniquement)
|
||||
# Phase 4R : bloquant (échec si p95 > 100ms)
|
||||
- name: k6 load test
|
||||
run: |
|
||||
k6 run --out json=results.json tests/load/smoke.js
|
||||
# Analyse results.json, fail si seuils dépassés (Phase 4R+)
|
||||
```
|
||||
|
||||
### 7.2 Release Quality Gates
|
||||
|
||||
**Criteria for Production Release**:
|
||||
|
|
@ -1198,6 +1335,11 @@ Timeline:
|
|||
- [ ] Pre-merge checks automated
|
||||
- [ ] Pre-deployment checks automated
|
||||
- [ ] Post-deployment monitoring active
|
||||
- [ ] Coverage enforcement CI (bloquant, Phase 3.5)
|
||||
- [ ] Lighthouse CI intégré (bloquant sur régression, Phase 3.5)
|
||||
- [ ] k6 performance baseline (informatif Phase 3.5, bloquant Phase 4R)
|
||||
- [ ] Bundle size check (< 200KB gzip, Phase 3.5)
|
||||
- [ ] pg_stat_statements activé en production
|
||||
|
||||
### Review Process
|
||||
- [ ] Code review checklist documented
|
||||
|
|
@ -1222,6 +1364,7 @@ Timeline:
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Métriques de qualité complètes |
|
||||
| 2.0.0 | 2026-03-04 | Audit : ajout état actuel vs cibles par phase (coverage frontend 50%→80%, Go/Rust non mesuré→70-80%), TODO/FIXME 356→<50, fichiers >500 lignes 139→<50, quality gates CI à implémenter (coverage bloquant, Lighthouse CI, k6, bundle size), plan dette technique DT-001 à DT-017 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1242,7 +1385,8 @@ Les métriques de qualité définies ici sont **VERROUILLÉES**. Toute modificat
|
|||
|
||||
**Document créé par**: Engineering Leadership + DevOps
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Trimestrielle
|
||||
**Dernière révision**: 2026-03-04 (v2.0.0)
|
||||
**Prochaine révision**: Trimestrielle (2026-06-01)
|
||||
**Propriétaire**: VP Engineering
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
|
|
|||
231
veza-docs/ORIGIN/ORIGIN_REVISION_SUMMARY.md
Normal file
231
veza-docs/ORIGIN/ORIGIN_REVISION_SUMMARY.md
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
# ORIGIN_REVISION_SUMMARY.md
|
||||
|
||||
## Résumé de la Révision Éthique — 2026-03-04
|
||||
|
||||
**Version** : 2.0.0
|
||||
**Date** : 4 mars 2026
|
||||
**Auteur** : Architecte principal Veza
|
||||
**Périmètre** : 20 fichiers ORIGIN révisés
|
||||
**Raison** : Réaligner la documentation ORIGIN sur la vision réelle du projet et son éthique fondatrice
|
||||
|
||||
---
|
||||
|
||||
## 1. FEATURES SUPPRIMÉES
|
||||
|
||||
### Module 15 : IA & Fonctionnalités Avancées (F456-F470) — 15 features, ~480h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F456 | AI mastering | Déshumanise le processus créatif |
|
||||
| F457 | Stem separation | Questions éthiques sur la propriété artistique |
|
||||
| F458 | Auto BPM detection (ML) | Remplacé par déclaration manuelle du créateur |
|
||||
| F459 | Auto key detection (ML) | Remplacé par déclaration manuelle du créateur |
|
||||
| F460 | Genre detection ML | Biais de classification à grande échelle |
|
||||
| F461 | Vocal removal AI | Tromperie des audiences |
|
||||
| F462 | Audio denoising AI | Remplacé par outils tiers au choix du créateur |
|
||||
| F463 | Audio upscaling AI | Remplacé par outils tiers au choix du créateur |
|
||||
| F464 | Auto-tags ML | Remplacé par tags déclaratifs du créateur |
|
||||
| F465 | Content ID (ML) | Remplacé par audio fingerprinting déterministe (ACRCloud) |
|
||||
| F466 | Similarity detection ML | Optimise la rétention, pas la découverte |
|
||||
| F467 | Recommendations ML | Remplacé par découverte éthique |
|
||||
| F468 | Voice synthesis | Tromperie des audiences |
|
||||
| F469 | Lyrics transcription auto | Remplacé par saisie manuelle |
|
||||
| F470 | AI mixing assistant | Déshumanise le processus créatif |
|
||||
|
||||
### Module 18 : Blockchain & Web3 (F491-F500) — 10 features, ~400h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F491 | NFT minting | Fraudes, spéculation, détournement d'œuvres |
|
||||
| F492 | Smart contracts | Complexité disproportionnée |
|
||||
| F493 | Token economy | Spéculation |
|
||||
| F494 | Staking rewards | Mécanisme spéculatif |
|
||||
| F495 | NFT marketplace | Impact négatif sur artistes indépendants |
|
||||
| F496 | Wallet integration | Complexité UX, barrière à l'entrée |
|
||||
| F497 | IPFS storage | Consommation énergétique disproportionnée |
|
||||
| F498 | DAO governance | Gouvernance biaisée par le capital |
|
||||
| F499 | Crypto payments | Impact environnemental, volatilité |
|
||||
| F500 | Royalty smart contracts | Remplacé par Hyperswitch |
|
||||
|
||||
### Module 21 : Gamification (F536-F550) — 15 features, ~280h
|
||||
|
||||
| ID | Feature | Raison éthique |
|
||||
|----|---------|----------------|
|
||||
| F536 | XP system | Transforme l'art en compétition |
|
||||
| F537 | Level progression | Normalise les métriques de performance |
|
||||
| F538 | Achievement system (XP) | Social validation loop addictive |
|
||||
| F539 | Streaks | Habitude compulsive |
|
||||
| F540 | Leaderboards popularité | Favorise les artistes établis |
|
||||
| F541 | Points system | Gamification addictive |
|
||||
| F542 | Challenges quotidiens | Obligation de connexion (FOMO) |
|
||||
| F543 | Reward shop | Rétention artificielle |
|
||||
| F544 | Social badges (followers) | Social validation loop |
|
||||
| F545 | Performance badges | Normalise les métriques de performance |
|
||||
| F546 | Streak notifications | FOMO, pression sociale |
|
||||
| F547 | Progress bars | Mécanisme de compulsion |
|
||||
| F548 | Daily login rewards | Habitude compulsive |
|
||||
| F549 | Referral gamification | Marketing viral |
|
||||
| F550 | Season pass | Rétention artificielle |
|
||||
|
||||
**Total supprimé** : 40 features, ~1 160 heures d'effort estimé
|
||||
|
||||
---
|
||||
|
||||
## 2. FEATURES MODIFIÉES
|
||||
|
||||
| Feature / Concept | Avant | Après | Raison |
|
||||
|-------------------|-------|-------|--------|
|
||||
| Algorithme de découverte | ML collaborative/content-based filtering | Règles explicites + curation éditoriale humaine | Optimiser la singularité, pas la rétention |
|
||||
| Trending / Featured | Basé sur les plays/likes/engagement | Supprimé ou remplacé par curation éditoriale | Anti social validation loop |
|
||||
| Analytics créateur | Métriques d'engagement plateforme | Données agrégées et anonymisées pour le créateur | Données au service du créateur, pas de la plateforme |
|
||||
| Modération contenu | AI detection (NSFW, hate speech) | Règles déterministes + modération humaine | La décision finale est toujours humaine |
|
||||
| Paiements | Stripe + PayPal + Crypto (futur) | Hyperswitch (open source, multi-provider) | Open source, pas de crypto |
|
||||
| Relance panier | Emails agressifs (1h, 24h, 7j avec discounts) | Un seul email optionnel après 7j (si opt-in) | Anti dark patterns, anti FOMO |
|
||||
| Notifications marketing | Recommandations produit, achievements | Digest hebdo, summary mensuel (opt-in) | Pas de recommandations comportementales |
|
||||
| Badges profil | Badges de performance (plays, followers) | Badges de compétence déclaratifs uniquement | Seul le créateur définit ses compétences |
|
||||
| Feed utilisateur | Algorithme feed basé sur l'engagement | Chronologique + curation + tags déclarés | Pas d'optimisation pour la rétention |
|
||||
| Auto-modération | AI auto-detection | Règles déterministes (mots-clés, patterns) | Pas d'IA dans la modération |
|
||||
| Recherche | Recherche par similarité audio (ML) | Elasticsearch fulltext + tags déclarés | Technologie, pas ML |
|
||||
|
||||
---
|
||||
|
||||
## 3. NOUVELLES SECTIONS AJOUTÉES
|
||||
|
||||
### Sections récurrentes (ajoutées dans plusieurs documents)
|
||||
|
||||
| Section | Documents concernés |
|
||||
|---------|-------------------|
|
||||
| **EXCLUSIONS ET RAISONS ÉTHIQUES** | BUSINESS_LOGIC, FEATURES_REGISTRY, DEVELOPMENT_PHASES, MASTER_ARCHITECTURE, TECHNICAL_STACK, DATABASE_SCHEMA, API_SPECIFICATION |
|
||||
| **Principes d'architecture éthique** | MASTER_ARCHITECTURE |
|
||||
| **Algorithme de découverte éthique** | FEATURES_REGISTRY, MASTER_ARCHITECTURE, API_SPECIFICATION |
|
||||
|
||||
### Sections spécifiques par document
|
||||
|
||||
| Document | Nouvelles sections |
|
||||
|----------|-------------------|
|
||||
| **ORIGIN_BUSINESS_LOGIC.md** | §0 Principes éthiques et modèle économique, §11 Exclusions, §12 Gouvernance |
|
||||
| **ORIGIN_FEATURES_REGISTRY.md** | §29 Features exclues et raisons éthiques, §30 Algorithme de découverte éthique |
|
||||
| **ORIGIN_DEVELOPMENT_PHASES.md** | §6 Phase 3.5 Consolidation & Sécurité, §7 Phase 4R Social & Live, §8 Phase 5R Analytics & Recherche Éthique, §9 Phase 6R Premium & Infrastructure, §10 Phases supprimées, §14 Exclusions |
|
||||
| **ORIGIN_MASTER_ARCHITECTURE.md** | §1 Principes d'architecture éthique, §4 Découverte éthique, §13 Exclusions et raisons éthiques. ADR-011 (Hyperswitch), ADR-012 (Elasticsearch) |
|
||||
| **ORIGIN_TECHNICAL_STACK.md** | §17 Stack de découverte musicale éthique, §18 Exclusions et raisons éthiques |
|
||||
| **ORIGIN_SECURITY_FRAMEWORK.md** | §0 Corrections critiques (VEZA-SEC-001/002), §10 Sécurité et éthique des données, §12.4 Plan pentest externe, JWT RS256 migration |
|
||||
| **ORIGIN_DATABASE_SCHEMA.md** | §17 Exclusions et raisons éthiques, §18 Politique de rétention des données, §19 Conformité GDPR |
|
||||
| **ORIGIN_API_SPECIFICATION.md** | §7.9 Découverte éthique (6 endpoints), §7.10 Portabilité des données, §11 API Éthique, §12 Exclusions |
|
||||
| **ORIGIN_CODE_STANDARDS.md** | §2 Standards éthiques du code, §9.3 Architecture Decision Records (ADR), §3.7 API Standards (pagination, context, error handling) |
|
||||
| **ORIGIN_UI_UX_SYSTEM.md** | §13 Anti-patterns UX interdits, §14 Patterns UX positifs |
|
||||
| **ORIGIN_PERFORMANCE_TARGETS.md** | §8.4 Plan de mesure consolidé (Prometheus, Lighthouse CI, k6, pg_stat_statements) |
|
||||
| **ORIGIN_QUALITY_METRICS.md** | §6.4 Plan de réduction dette technique (DT-001 à DT-017), §7.1bis Quality gates à implémenter |
|
||||
| **ORIGIN_TESTING_STRATEGY.md** | §13 Tests post-déploiement (smoke tests), §14 Tests algorithme de découverte, §15 Stratégie de test éthique (biais, accessibilité, GDPR) |
|
||||
| **ORIGIN_DEPLOYMENT_GUIDE.md** | §13 Correctifs de sécurité prioritaires, §14 Checklist de déploiement éthique, §15 Plan migration JWT RS256 |
|
||||
| **ORIGIN_ERROR_PATTERNS.md** | PAT-024 à PAT-028 (JWT mismatch, context propagation, goroutine leaks, pagination, error handling) |
|
||||
| **ORIGIN_ERROR_PREVENTION_GUIDE.md** | §2.6 Audit prevention patterns (JWT validation, context propagation, goroutine lifecycle, pagination, error standardization) |
|
||||
| **ORIGIN_ERROR_RESOLUTION_STRATEGY.md** | §8.3 Discovery bias, §8.4 JWT mismatch, §8.5 Error handling migration |
|
||||
| **ORIGIN_FEATURE_VALIDATION_STRATEGY.md** | Phase 7 Validation éthique (checklist obligatoire), Métriques éthiques de succès |
|
||||
| **ORIGIN_IMPLEMENTATION_TASKS.md** | Marquage ⛔ des tâches AI/Web3/Gamification, 30+ nouvelles tâches P0/P1 issues de l'audit |
|
||||
| **ORIGIN_IMPLEMENTATION_TASKS_ARCHIVE.md** | Note de révision T0051-T0065 (Rust chat → Go obsolescence) |
|
||||
|
||||
---
|
||||
|
||||
## 4. COMPTE DE FEATURES RÉVISÉ
|
||||
|
||||
| Métrique | Avant (v1.0) | Après (v2.0) |
|
||||
|----------|-------------|-------------|
|
||||
| Features totales au registre | 600 | 560 |
|
||||
| Features supprimées (éthique) | 0 | 40 |
|
||||
| Features actives ciblées (roadmap) | 600 | ~490 |
|
||||
| Heures estimées (total) | ~8 590h | ~7 430h |
|
||||
| Heures économisées | — | ~1 160h |
|
||||
| Phases de développement | 8 | 6 (P0-P3 + P3.5-P6R) |
|
||||
| Modules actifs | 24 | 21 |
|
||||
| Modules supprimés | 0 | 3 (AI, Web3, Gamification) |
|
||||
|
||||
---
|
||||
|
||||
## 5. CROSS-REFERENCES VÉRIFIÉES
|
||||
|
||||
Les cross-references suivantes ont été vérifiées et corrigées :
|
||||
|
||||
| Source | Référence | Action |
|
||||
|--------|-----------|--------|
|
||||
| DEVELOPMENT_PHASES → FEATURES_REGISTRY | Compteur features | Mis à jour 600 → 560 |
|
||||
| DEVELOPMENT_PHASES → FEATURES_REGISTRY | Modules M15, M18, M21 | Marqués comme supprimés |
|
||||
| MASTER_ARCHITECTURE → TECHNICAL_STACK | Chat Server Rust → Go | Corrigé (Go, pas Rust) |
|
||||
| MASTER_ARCHITECTURE → TECHNICAL_STACK | Stripe → Hyperswitch | Corrigé |
|
||||
| MASTER_ARCHITECTURE → TECHNICAL_STACK | Traefik → HAProxy | Corrigé |
|
||||
| SECURITY_FRAMEWORK → IMPLEMENTATION_TASKS | VEZA-SEC-001/002 | Tâches correspondantes ajoutées |
|
||||
| API_SPECIFICATION → FEATURES_REGISTRY | Endpoints AI/Web3/Gamification | Supprimés |
|
||||
| DATABASE_SCHEMA → FEATURES_REGISTRY | Tables AI/Web3/Gamification | Supprimées |
|
||||
| QUALITY_METRICS → AUDIT_TECHNIQUE | DT-001 à DT-017 | Plan de réduction documenté |
|
||||
| IMPLEMENTATION_TASKS → AUDIT_TECHNIQUE | TASK-SEC-001 à 006, TASK-QA, TASK-DEBT | Ajoutés |
|
||||
| DEPLOYMENT_GUIDE → SECURITY_FRAMEWORK | JWT RS256 migration | Documenté des deux côtés |
|
||||
| TESTING_STRATEGY → ERROR_PATTERNS | Patterns audit PAT-024 à PAT-028 | Tests correspondants documentés |
|
||||
| IMPLEMENTATION_TASKS_ARCHIVE → MASTER_ARCHITECTURE | ADR-002 Chat Go | Note ajoutée |
|
||||
|
||||
---
|
||||
|
||||
## 6. INCOHÉRENCES DÉTECTÉES
|
||||
|
||||
Les problèmes suivants ont été identifiés mais ne sont pas couverts par cette révision documentaire et nécessitent une validation humaine :
|
||||
|
||||
| # | Incohérence | Impact | Action recommandée |
|
||||
|---|-------------|--------|-------------------|
|
||||
| 1 | **Spotify OAuth pour import goûts musicaux (F007)** importe les préférences pour "recommandations" — le mot "recommandations" reste dans la description mais le mécanisme ML est supprimé | Faible | Clarifier que l'import Spotify sert à initialiser les genres/tags suivis, pas à alimenter un moteur ML |
|
||||
| 2 | **Module 20 (Native Apps, F521-F535)** reste au registre mais Electron est abandonné d'après l'audit. La PWA est la stratégie mobile. | Moyen | Décider si ces features restent ou sont converties en features PWA |
|
||||
| 3 | **F210 "Algorithme feed"** est listé comme Complexité 5/5 mais avec la curation humaine + chronologique, la complexité devrait être réduite | Faible | Réévaluer la complexité à 3/5 |
|
||||
| 4 | **Module 9 (Hardware Mgmt, F306-F330)** reste au registre mais n'est dans aucune phase révisée | Faible | Planifier explicitement dans P6R ou reporter post-v1.0 |
|
||||
| 5 | **Ancienne Phase 4 référençait "Recommandations personnalisées"** dans les objectifs Social — cette référence existait dans le document original et a été retirée | — | Résolu |
|
||||
| 6 | **Revenue projections** ne chiffrent pas l'impact de la suppression des features AI/Web3 sur le MRR cible | Moyen | Ajuster les projections business avec le Product Owner |
|
||||
| 7 | **Volume Discounts API** (§1.2 BUSINESS_LOGIC) fait référence à des tarifs enterprise qui ne sont pas dans la roadmap révisée | Faible | Confirmer si l'offre enterprise reste planifiée pour P6R |
|
||||
|
||||
---
|
||||
|
||||
## 7. PROCHAINES ÉTAPES RECOMMANDÉES
|
||||
|
||||
### Immédiat (semaine 1-2)
|
||||
|
||||
1. **Exécuter TASK-SEC-001 et TASK-SEC-002** — vulnérabilités critiques JWT ouvertes
|
||||
2. **Protéger les routes /metrics** (TASK-SEC-006)
|
||||
3. **Créer `.nvmrc` et `rust-toolchain.toml`** (TASK-QA-006)
|
||||
4. **Review humaine** des incohérences listées en §6
|
||||
|
||||
### Phase 3.5 (Mars-Avril 2026)
|
||||
|
||||
5. **Implémenter les quality gates CI** (TASK-QA-001 à QA-005)
|
||||
6. **Supprimer le code mort** (soundcloud/, webrtc.rs, k8s/chat-server/)
|
||||
7. **Compléter le chat** (réactions, mentions, recherche)
|
||||
8. **Migration JWT HS256 → RS256** (TASK-ARCH-001)
|
||||
9. **Planifier le pentest externe** avant Phase 4R
|
||||
|
||||
### Continu
|
||||
|
||||
10. **Audit UX trimestriel** anti-dark-patterns
|
||||
11. **Tests de biais algorithmique** dans la CI pour la découverte
|
||||
12. **Mise à jour incrémentale** des documents ORIGIN au fil des livraisons
|
||||
13. **ADR systématiques** pour tout changement architectural
|
||||
|
||||
### Post-révision documentaire
|
||||
|
||||
14. **Communiquer les changements** à l'équipe engineering
|
||||
15. **Mettre à jour le README principal** du monorepo
|
||||
16. **Créer le CONTRIBUTING.md** avec les standards éthiques
|
||||
17. **Décider du sort du Module 20** (Native Apps → PWA ?)
|
||||
|
||||
---
|
||||
|
||||
## MÉTADONNÉES
|
||||
|
||||
| Champ | Valeur |
|
||||
|-------|--------|
|
||||
| **Documents révisés** | 20/20 |
|
||||
| **Features supprimées** | 40 (F456-F470, F491-F500, F536-F550) |
|
||||
| **Nouvelles sections ajoutées** | ~45 sections réparties sur 20 documents |
|
||||
| **Tâches P0 ajoutées** | 6 (TASK-SEC-001 à 006) |
|
||||
| **Tâches P1 ajoutées** | ~25 (TASK-QA, TASK-CHAT, TASK-EDU, TASK-MKT, TASK-DEBT, TASK-ARCH) |
|
||||
| **Incohérences identifiées** | 7 (nécessitent validation humaine) |
|
||||
| **Prochaines étapes** | 17 actions concrètes |
|
||||
|
||||
---
|
||||
|
||||
**Document créé par** : Architecte principal Veza
|
||||
**Date** : 2026-03-04
|
||||
**Ce document est la preuve d'audit de la révision éthique v2.0.0 de la documentation ORIGIN.**
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit le framework de sécurité complet et définitif de la plateforme Veza. Il couvre tous les aspects de la sécurité applicative, infrastructure, et conformité réglementaire (GDPR, CCPA, SOC2). Le framework suit les meilleures pratiques OWASP, NIST, et CIS Benchmarks pour garantir la protection des données utilisateurs, la résilience aux attaques, et la conformité légale pendant 24 mois.
|
||||
Ce document définit le framework de sécurité de la plateforme Veza. Il couvre la sécurité applicative, infrastructure, et conformité réglementaire (GDPR). Le framework suit les pratiques OWASP et CIS Benchmarks pour protéger les données utilisateurs et résister aux menaces courantes. Révisé le 2026-03-04 suite à un audit de sécurité ayant identifié deux vulnérabilités critiques JWT (voir section 0).
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
|
|
@ -18,6 +18,7 @@ Construire une plateforme sécurisée par conception (Security by Design) qui pr
|
|||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
0. [Corrections critiques — Audit 2026-03-04](#corrections-critiques--audit-2026-03-04)
|
||||
1. [Security Philosophy](#1-security-philosophy)
|
||||
2. [Threat Model](#2-threat-model)
|
||||
3. [Authentication Systems](#3-authentication-systems)
|
||||
|
|
@ -27,8 +28,9 @@ Construire une plateforme sécurisée par conception (Security by Design) qui pr
|
|||
7. [Application Security](#7-application-security)
|
||||
8. [Infrastructure Security](#8-infrastructure-security)
|
||||
9. [Compliance (GDPR, CCPA, SOC2)](#9-compliance-gdpr-ccpa-soc2)
|
||||
10. [Incident Response](#10-incident-response)
|
||||
11. [Security Testing](#11-security-testing)
|
||||
10. [Sécurité et éthique des données](#10-sécurité-et-éthique-des-données)
|
||||
11. [Incident Response](#11-incident-response)
|
||||
12. [Security Testing](#12-security-testing)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
|
|
@ -43,6 +45,39 @@ Construire une plateforme sécurisée par conception (Security by Design) qui pr
|
|||
9. **Security headers OBLIGATOIRES** (CSP, HSTS, X-Frame-Options, etc.)
|
||||
10. **Secrets JAMAIS dans le code** (environment variables ou Vault)
|
||||
|
||||
## CORRECTIONS CRITIQUES — AUDIT 2026-03-04
|
||||
|
||||
Deux vulnérabilités critiques identifiées lors de l'audit du 2026-03-04. Priorité P0 — à corriger avant tout autre travail.
|
||||
|
||||
### VEZA-SEC-001 : Secret JWT par défaut en dur (P0)
|
||||
|
||||
**Fichier** : `veza-common/src/config_rust.rs:234`
|
||||
|
||||
Le secret JWT est défini avec une valeur par défaut en dur. Si la variable d'environnement `JWT_SECRET` est absente, le service démarre avec un secret prévisible, ce qui permet la forge de tokens arbitraires.
|
||||
|
||||
**Correction requise** :
|
||||
- Supprimer la valeur par défaut du secret JWT dans `config_rust.rs:234`
|
||||
- Le service DOIT refuser de démarrer si `JWT_SECRET` n'est pas défini
|
||||
- Ajouter un test d'intégration qui vérifie le refus de démarrage sans secret
|
||||
|
||||
```rust
|
||||
// AVANT (vulnérable) — config_rust.rs:234
|
||||
let jwt_secret = env::var("JWT_SECRET").unwrap_or_else(|_| "default-secret".to_string());
|
||||
|
||||
// APRÈS (corrigé)
|
||||
let jwt_secret = env::var("JWT_SECRET")
|
||||
.expect("JWT_SECRET must be set — refusing to start with no secret");
|
||||
```
|
||||
|
||||
### VEZA-SEC-002 : Désalignement issuer/audience JWT entre Go et Rust (P0)
|
||||
|
||||
Les services Go et Rust utilisent des valeurs différentes pour les champs `iss` (issuer) et `aud` (audience) des tokens JWT. Un token émis par le backend Go peut être rejeté par un service Rust (ou inversement), ou pire, accepté sans vérification de ces champs.
|
||||
|
||||
**Correction requise** :
|
||||
- Définir une constante partagée pour `iss` et `aud` dans `veza-common`
|
||||
- Les deux backends DOIVENT valider `iss` et `aud` à chaque vérification de token
|
||||
- Valeurs à utiliser : `iss: "veza-api"`, `aud: "veza-platform"`
|
||||
|
||||
## 1. SECURITY PHILOSOPHY
|
||||
|
||||
### 1.1 Principes Fondamentaux
|
||||
|
|
@ -244,6 +279,19 @@ AND created_at > NOW() - INTERVAL '90 days'
|
|||
}
|
||||
```
|
||||
|
||||
**Migration HS256 → RS256 (Phase 3.5 — planifiée)** :
|
||||
|
||||
L'algorithme actuel (HS256, secret symétrique) est fonctionnel mais présente des limites :
|
||||
- Un même secret est partagé entre tous les services qui vérifient les tokens
|
||||
- La rotation du secret nécessite un redéploiement synchronisé
|
||||
- Pas de distinction entre capacité d'émission et capacité de vérification
|
||||
|
||||
La migration vers RS256 (clé asymétrique) est planifiée pour la Phase 3.5 :
|
||||
- Seul le service d'authentification détient la clé privée (émission)
|
||||
- Les autres services ne reçoivent que la clé publique (vérification)
|
||||
- Rotation facilitée via JWKS endpoint
|
||||
- Période de transition : les deux algorithmes acceptés pendant 30 jours
|
||||
|
||||
**Token Lifecycle**:
|
||||
- **Access Token**: 15 minutes (short-lived)
|
||||
- **Refresh Token**: 7 days (long-lived, stored in DB)
|
||||
|
|
@ -744,10 +792,12 @@ func DeleteUserData(userID uuid.UUID) error {
|
|||
|
||||
**Retention Policy**:
|
||||
```
|
||||
Account data: Until account deletion
|
||||
Audit logs: 7 years (legal requirement)
|
||||
Analytics: 24 months (aggregated, anonymized)
|
||||
Backups: 30 days
|
||||
Données de compte : jusqu'à demande de suppression par l'utilisateur
|
||||
Logs applicatifs : 90 jours (anonymisés après expiration)
|
||||
Sessions : 30 jours
|
||||
Analytics : 12 mois (agrégées, anonymisées)
|
||||
Backups : 30 jours
|
||||
Audit logs : 24 mois
|
||||
```
|
||||
|
||||
## 6. NETWORK SECURITY
|
||||
|
|
@ -1233,6 +1283,25 @@ loginAttempts.WithLabelValues("failed", "password").Inc()
|
|||
// Alert if > 100 failed logins/min from same IP
|
||||
```
|
||||
|
||||
**Protection des routes Prometheus `/metrics`** :
|
||||
|
||||
Les endpoints `/metrics` Prometheus sont actuellement exposés publiquement. Cela permet à un attaquant d'observer les patterns de trafic, les taux d'erreur, et la topologie interne des services. Correction requise :
|
||||
|
||||
- Les routes `/metrics` DOIVENT être accessibles uniquement depuis le réseau interne (subnet monitoring)
|
||||
- En environnement Kubernetes : utiliser un `ServiceMonitor` sur un port dédié non exposé par l'Ingress
|
||||
- En environnement Docker Compose : ne pas mapper le port metrics sur l'hôte, utiliser le réseau interne Docker
|
||||
- Alternative : protéger avec authentification Basic Auth sur un reverse proxy dédié
|
||||
|
||||
```go
|
||||
// Exposer /metrics sur un port séparé, non public
|
||||
go func() {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
// Port 9090 : accessible uniquement depuis le réseau interne
|
||||
http.ListenAndServe(":9090", mux)
|
||||
}()
|
||||
```
|
||||
|
||||
## 9. COMPLIANCE (GDPR, CCPA, SOC2)
|
||||
|
||||
### 9.1 GDPR Compliance
|
||||
|
|
@ -1349,9 +1418,72 @@ func OptOutOfDataSale(userID uuid.UUID) error {
|
|||
|
||||
**Audit Trail**: All access to production systems logged
|
||||
|
||||
## 10. INCIDENT RESPONSE
|
||||
## 10. SÉCURITÉ ET ÉTHIQUE DES DONNÉES
|
||||
|
||||
### 10.1 Incident Response Plan
|
||||
Veza collecte le minimum de données nécessaire au fonctionnement de la plateforme. Ce principe s'applique à tous les services.
|
||||
|
||||
### 10.1 Minimisation des données collectées
|
||||
|
||||
Seules les données strictement nécessaires au service sont collectées :
|
||||
- Compte : email, nom d'affichage, mot de passe hashé, rôle
|
||||
- Contenu : métadonnées des tracks (titre, artiste, genre, BPM), fichiers audio
|
||||
- Transactions : historique d'achats (montant, date, identifiant produit)
|
||||
|
||||
Ne sont PAS collectées :
|
||||
- Localisation précise (pas de géolocalisation)
|
||||
- Contacts ou carnet d'adresses
|
||||
- Données biométriques
|
||||
- Historique de navigation hors plateforme
|
||||
|
||||
### 10.2 Durées de rétention explicites
|
||||
|
||||
| Type de donnée | Durée de rétention | Action à expiration |
|
||||
|---|---|---|
|
||||
| Logs applicatifs | 90 jours | Anonymisation automatique |
|
||||
| Sessions utilisateur | 30 jours | Suppression |
|
||||
| Analytics | 12 mois | Agrégation puis suppression des données brutes |
|
||||
| Données de compte | Jusqu'à demande de suppression | Suppression complète sous 30 jours |
|
||||
| Audit trail | 24 mois | Archivage anonymisé |
|
||||
|
||||
### 10.3 Droits GDPR implémentés
|
||||
|
||||
- **Export** : endpoint `GET /api/v1/users/me/export` — retourne toutes les données personnelles en JSON
|
||||
- **Suppression** : endpoint `DELETE /api/v1/users/me` — suppression complète (hard delete) avec anonymisation des contenus associés, exécutée sous 30 jours
|
||||
- **Rectification** : endpoint `PATCH /api/v1/users/me` — modification des données personnelles
|
||||
- **Portabilité** : l'export JSON est dans un format standard réutilisable
|
||||
|
||||
### 10.4 Pas de tracking comportemental tiers
|
||||
|
||||
Aucun service de tracking tiers n'est intégré :
|
||||
- Pas de Google Analytics, Facebook Pixel, ou équivalent
|
||||
- Pas de fingerprinting navigateur
|
||||
- Pas de revente ou partage de données avec des tiers
|
||||
- Les analytics internes sont agrégées et anonymisées (voir section 5.3)
|
||||
|
||||
### 10.5 Anonymisation des logs
|
||||
|
||||
Les logs applicatifs sont anonymisés automatiquement après 90 jours :
|
||||
- Adresses IP remplacées par des hashes non réversibles
|
||||
- Identifiants utilisateur supprimés
|
||||
- Seuls les patterns agrégés sont conservés (compteurs, métriques de performance)
|
||||
|
||||
### 10.6 Audit trail pour les actions sensibles
|
||||
|
||||
Toutes les actions suivantes génèrent une entrée d'audit immuable :
|
||||
- Connexion / déconnexion (succès et échecs)
|
||||
- Modification de mot de passe ou d'email
|
||||
- Activation / désactivation MFA
|
||||
- Suppression de compte
|
||||
- Modification de rôle
|
||||
- Suppression de contenu (tracks, commentaires)
|
||||
- Accès aux données d'export utilisateur
|
||||
- Actions de modération
|
||||
|
||||
L'audit trail est conservé 24 mois et accessible aux administrateurs via le panneau d'administration.
|
||||
|
||||
## 11. INCIDENT RESPONSE
|
||||
|
||||
### 11.1 Incident Response Plan
|
||||
|
||||
**Phase 1: Detection** (< 15 minutes)
|
||||
- SIEM alerts (unusual patterns)
|
||||
|
|
@ -1381,7 +1513,7 @@ func OptOutOfDataSale(userID uuid.UUID) error {
|
|||
- User notification (if required)
|
||||
- Regulatory notification (GDPR 72h)
|
||||
|
||||
### 10.2 Security Incident Categories
|
||||
### 11.2 Security Incident Categories
|
||||
|
||||
| Severity | Examples | Response Time | Escalation |
|
||||
|----------|----------|---------------|------------|
|
||||
|
|
@ -1390,7 +1522,7 @@ func OptOutOfDataSale(userID uuid.UUID) error {
|
|||
| **Medium** | DDoS, brute-force, CSRF | < 4 hours | DevOps Team |
|
||||
| **Low** | Informational leaks, outdated software | < 24 hours | Developer |
|
||||
|
||||
### 10.3 Communication Plan
|
||||
### 11.3 Communication Plan
|
||||
|
||||
**Internal**:
|
||||
- Slack #security-incidents channel
|
||||
|
|
@ -1401,9 +1533,9 @@ func OptOutOfDataSale(userID uuid.UUID) error {
|
|||
- Email notifications (affected users)
|
||||
- Press release (if public breach)
|
||||
|
||||
## 11. SECURITY TESTING
|
||||
## 12. SECURITY TESTING
|
||||
|
||||
### 11.1 Static Application Security Testing (SAST)
|
||||
### 12.1 Static Application Security Testing (SAST)
|
||||
|
||||
**Go** (Gosec):
|
||||
```bash
|
||||
|
|
@ -1438,7 +1570,7 @@ plugins: ['security'],
|
|||
extends: ['plugin:security/recommended'],
|
||||
```
|
||||
|
||||
### 11.2 Dynamic Application Security Testing (DAST)
|
||||
### 12.2 Dynamic Application Security Testing (DAST)
|
||||
|
||||
**OWASP ZAP**:
|
||||
```bash
|
||||
|
|
@ -1454,7 +1586,7 @@ docker run -t owasp/zap2docker-stable zap-baseline.py \
|
|||
- Test authentication flows
|
||||
- Test session management
|
||||
|
||||
### 11.3 Dependency Scanning
|
||||
### 12.3 Dependency Scanning
|
||||
|
||||
**Go** (Dependabot + govulncheck):
|
||||
```bash
|
||||
|
|
@ -1475,16 +1607,24 @@ cargo audit --deny warnings
|
|||
npm audit --audit-level=high
|
||||
```
|
||||
|
||||
### 11.4 Penetration Testing
|
||||
### 12.4 Penetration Testing
|
||||
|
||||
**Schedule**: Quarterly + after major releases
|
||||
**Schedule**: Avant chaque release majeure + audit externe annuel
|
||||
|
||||
**Pentest externe obligatoire avant Phase 4R** :
|
||||
|
||||
Un audit de sécurité externe (pentest) par un prestataire indépendant est requis avant le passage en Phase 4R (release publique). Conditions :
|
||||
- Prestataire certifié (OSCP, CREST, ou équivalent)
|
||||
- Périmètre : authentification, API, upload, WebSocket, RBAC
|
||||
- Rapport avec scores CVSS pour chaque vulnérabilité
|
||||
- Toutes les vulnérabilités critiques et hautes doivent être corrigées avant la release
|
||||
- Le rapport de pentest est archivé et accessible à l'équipe sécurité
|
||||
|
||||
**Scope**:
|
||||
- Web application (frontend + backend)
|
||||
- API endpoints
|
||||
- WebSocket connections
|
||||
- File upload functionality
|
||||
- Payment integration
|
||||
- Authentication flows
|
||||
|
||||
**Methodology**: OWASP Testing Guide
|
||||
|
|
@ -1495,7 +1635,7 @@ npm audit --audit-level=high
|
|||
- Proof of concept exploits
|
||||
- Remediation recommendations
|
||||
|
||||
### 11.5 Bug Bounty Program
|
||||
### 12.5 Bug Bounty Program
|
||||
|
||||
**Platform**: HackerOne or Bugcrowd
|
||||
|
||||
|
|
@ -1591,6 +1731,7 @@ npm audit --audit-level=high
|
|||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique — Corrections P0 JWT (VEZA-SEC-001, VEZA-SEC-002), migration RS256 planifiée (Phase 3.5), section éthique des données, protection routes Prometheus, pentest externe avant Phase 4R, durées de rétention révisées |
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Framework sécurité complet |
|
||||
|
||||
---
|
||||
|
|
@ -1612,6 +1753,7 @@ Les contrôles de sécurité définis ici sont **OBLIGATOIRES**. Toute modificat
|
|||
|
||||
**Document créé par**: Security Team + Architecture
|
||||
**Date de création**: 2025-11-02
|
||||
**Dernière révision**: 2026-03-04 (révision éthique post-audit)
|
||||
**Prochaine révision**: Trimestrielle
|
||||
**Propriétaire**: CISO / Lead Security Engineer
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit la stack technique complète et définitive de la plateforme Veza. Chaque technologie, framework, et dépendance est spécifiée avec sa version exacte verrouillée pour les 24 prochains mois. Les choix sont justifiés, les alternatives rejetées documentées, et la stratégie de mise à jour définie (LTS only). Cette stack est **IMMUABLE** sauf changement critique de sécurité ou EOL forcé.
|
||||
Ce document définit la stack technique de la plateforme Veza, une plateforme audio open source pour musiciens indépendants. Les choix technologiques sont guidés par trois contraintes architecturales : performance, souveraineté des données, et respect éthique des utilisateurs. Toute technologie reposant sur l'extraction comportementale (ML/IA), la spéculation financière (blockchain/NFT), ou la manipulation attentionnelle (gamification addictive) est exclue par principe.
|
||||
|
||||
Les versions sont verrouillées, les alternatives rejetées documentées, et la stratégie de mise à jour définie (LTS only).
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
### Objectif Principal
|
||||
Verrouiller l'intégralité de la stack technique pour garantir stabilité, compatibilité, et prévisibilité sur 24 mois de développement sans déviations technologiques.
|
||||
Définir une stack technique stable, éthique et maintenable pour une plateforme audio qui sert les musiciens sans les exploiter.
|
||||
|
||||
### Objectifs Secondaires
|
||||
- Éliminer les débats technologiques récurrents
|
||||
|
|
@ -15,12 +17,13 @@ Verrouiller l'intégralité de la stack technique pour garantir stabilité, comp
|
|||
- Faciliter l'onboarding des nouveaux développeurs
|
||||
- Minimiser la dette technique liée aux upgrades
|
||||
- Garantir le support long terme (LTS)
|
||||
- Documenter les exclusions éthiques comme contraintes architecturales
|
||||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
1. [Vue d'Ensemble](#1-vue-densemble)
|
||||
2. [Backend Stack](#2-backend-stack)
|
||||
3. [Rust Services Stack](#3-rust-services-stack)
|
||||
3. [Rust Stream Server Stack](#3-rust-stream-server-stack)
|
||||
4. [Frontend Stack](#4-frontend-stack)
|
||||
5. [Mobile Stack](#5-mobile-stack)
|
||||
6. [Desktop Stack](#6-desktop-stack)
|
||||
|
|
@ -34,6 +37,8 @@ Verrouiller l'intégralité de la stack technique pour garantir stabilité, comp
|
|||
14. [Development Tools](#14-development-tools)
|
||||
15. [Stratégie de Mise à Jour](#15-stratégie-de-mise-à-jour)
|
||||
16. [Matrice de Compatibilité](#16-matrice-de-compatibilité)
|
||||
17. [Stack de Découverte Musicale Éthique](#17-stack-de-découverte-musicale-éthique)
|
||||
18. [Exclusions et Raisons Éthiques](#18-exclusions-et-raisons-éthiques)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
|
|
@ -54,28 +59,33 @@ Verrouiller l'intégralité de la stack technique pour garantir stabilité, comp
|
|||
|
||||
| Domain | Technology | Version | Justification | Support Until |
|
||||
|--------|-----------|---------|---------------|---------------|
|
||||
| **Backend API** | Go | 1.23.8 | Performance, simplicité, concurrence | Feb 2027 |
|
||||
| **Chat Server** | Rust | 1.75+ | Sécurité mémoire, perf temps réel | Rolling |
|
||||
| **Stream Server** | Rust | 1.75+ | Zero-cost abstractions, streaming | Rolling |
|
||||
| **Backend API** | Go | 1.24 | Performance, simplicité, concurrence | Feb 2028 |
|
||||
| **Chat Server** | Go | 1.24 | Même stack que l'API, WebSocket natif | Feb 2028 |
|
||||
| **Stream Server** | Rust | stable | HLS/FFmpeg, zero-cost abstractions | Rolling |
|
||||
| **Frontend Web** | React | 18.2.0 | Écosystème, Concurrent Mode | Ongoing |
|
||||
| **Mobile** | React Native | 0.73.x | Code sharing, performance native | Rolling |
|
||||
| **Desktop** | Electron | 28.x | Cross-platform, web stack reuse | Rolling |
|
||||
| **Database** | PostgreSQL | 15.x | ACID, relations, performance | Nov 2027 |
|
||||
| **Database** | PostgreSQL | 16 | ACID, relations, performance | Nov 2028 |
|
||||
| **Cache** | Redis | 7.x | In-memory, pub/sub | Jul 2026 |
|
||||
| **Message Queue** | RabbitMQ | 3.12.x | Mature, routing flexible | Dec 2025 |
|
||||
| **Message Queue** | RabbitMQ | 3.x | Mature, routing flexible | Rolling |
|
||||
| **Search** | Elasticsearch | 8.x | Recherche musicale déterministe | Rolling |
|
||||
| **Payment** | Hyperswitch | latest | Open source, multi-provider | Rolling |
|
||||
| **Container** | Docker | 24.x | Standard industrie | Rolling |
|
||||
| **Orchestration** | Kubernetes | 1.28+ (future) | Scalabilité, ecosystem | 1 year |
|
||||
| **Load Balancer** | HAProxy | 2.x | Blue-green deployments | Rolling |
|
||||
|
||||
### 1.2 Language Versions
|
||||
|
||||
```
|
||||
Go: 1.23.8 (Released: Feb 2024, Support: Feb 2027)
|
||||
Rust: 1.75.0+ (Rolling releases, stable channel)
|
||||
Go: 1.24 (Released: Feb 2025, Support: Feb 2028)
|
||||
Rust: stable (Rolling releases, stable channel, stream server only)
|
||||
TypeScript: 5.3.3 (Latest stable)
|
||||
Node.js: 20.11.0 (LTS - Iron, Support: Apr 2026)
|
||||
Python: 3.12.x (Scripts only, Support: Oct 2028)
|
||||
```
|
||||
|
||||
#### Fichiers de version à créer
|
||||
- `rust-toolchain.toml` : fixer le channel Rust stable pour le stream server
|
||||
- `.nvmrc` : fixer la version Node.js pour le frontend
|
||||
|
||||
### 1.3 Architecture Stack Summary
|
||||
|
||||
```
|
||||
|
|
@ -87,35 +97,37 @@ Python: 3.12.x (Scripts only, Support: Oct 2028)
|
|||
│ HTTPS/WSS
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ API GATEWAY TIER │
|
||||
│ Traefik 2.10+ (Load Balancer) │
|
||||
│ LOAD BALANCER TIER │
|
||||
│ HAProxy 2.x (Blue-Green Deployments) │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
│
|
||||
↓
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ APPLICATION TIER │
|
||||
│ Go API 1.23 | Rust Chat | Rust Stream | Workers │
|
||||
│ Go API 1.24 | Go Chat | Rust Stream (HLS) | Workers │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────┴───────────┐
|
||||
↓ ↓
|
||||
┌─────────────────────┐ ┌────────────────────────┐
|
||||
│ DATA TIER │ │ MESSAGE TIER │
|
||||
│ PostgreSQL 15 │ │ RabbitMQ 3.12 │
|
||||
│ Redis 7 │ │ (Event Bus) │
|
||||
│ S3 (Object Storage) │ └────────────────────────┘
|
||||
└─────────────────────┘
|
||||
┌───────────┼───────────┐
|
||||
↓ ↓ ↓
|
||||
┌────────────────────┐ ┌─────────┐ ┌────────────────────┐
|
||||
│ DATA TIER │ │ SEARCH │ │ MESSAGE TIER │
|
||||
│ PostgreSQL 16 │ │ Elastic │ │ RabbitMQ 3 │
|
||||
│ Redis 7 │ │ search │ │ (Event Bus) │
|
||||
│ S3 (Object Storage)│ │ 8.x │ └────────────────────┘
|
||||
└────────────────────┘ └─────────┘
|
||||
```
|
||||
|
||||
## 2. BACKEND STACK
|
||||
|
||||
### 2.1 Core
|
||||
|
||||
**Language**: Go 1.23.8
|
||||
**Release**: February 2024
|
||||
**Support**: Until February 2027
|
||||
**Language**: Go 1.24
|
||||
**Release**: February 2025
|
||||
**Support**: Until February 2028
|
||||
**Official Site**: https://go.dev/
|
||||
|
||||
> Le backend Go couvre l'API REST **et** le Chat Server (WebSocket). Le Chat Server était initialement prévu en Rust mais reste en Go pour maintenir une stack backend unifiée.
|
||||
|
||||
#### Justification
|
||||
- **Performance**: Compiled, garbage collected, excellent concurrency
|
||||
- **Simplicité**: Simple syntax, fast compilation, single binary
|
||||
|
|
@ -198,6 +210,9 @@ require github.com/golang-jwt/jwt/v5 v5.3.0
|
|||
- Token parsing et verification
|
||||
- Keyfunc support
|
||||
|
||||
#### Migration en cours
|
||||
- **HS256 → RS256** : migration planifiée pour séparer les clés de signature (privée) et de vérification (publique), nécessaire pour la communication inter-services sécurisée.
|
||||
|
||||
### 2.5 Validation
|
||||
|
||||
**Library**: go-playground/validator
|
||||
|
|
@ -232,6 +247,9 @@ require github.com/spf13/viper v1.18.2
|
|||
- Hot reload
|
||||
- Default values
|
||||
|
||||
#### Migration prévue : `dotenv` → `dotenvy`
|
||||
Le package `github.com/joho/godotenv` est en maintenance minimale. Migration vers `github.com/joeshaw/dotenvy` ou intégration directe via Viper à planifier.
|
||||
|
||||
### 2.7 Logging
|
||||
|
||||
**Library**: uber-go/zap
|
||||
|
|
@ -291,7 +309,7 @@ require (
|
|||
```go
|
||||
module veza-backend-api
|
||||
|
||||
go 1.23.8
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
// Web Framework
|
||||
|
|
@ -317,7 +335,7 @@ require (
|
|||
|
||||
// Configuration
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/joho/godotenv v1.5.1 // TODO: migrer vers dotenvy
|
||||
|
||||
// Logging
|
||||
go.uber.org/zap v1.27.0
|
||||
|
|
@ -327,9 +345,11 @@ require (
|
|||
|
||||
// External Services
|
||||
github.com/aws/aws-sdk-go-v2 v1.24.0 // S3
|
||||
github.com/stripe/stripe-go/v76 v76.16.0 // Payments
|
||||
github.com/sendgrid/sendgrid-go v3.14.0 // Email
|
||||
|
||||
// Payments (open source, multi-provider)
|
||||
// Hyperswitch — appel via API REST, pas de SDK Go natif
|
||||
|
||||
// Monitoring
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
|
||||
|
|
@ -343,26 +363,32 @@ require (
|
|||
)
|
||||
```
|
||||
|
||||
## 3. RUST SERVICES STACK
|
||||
## 3. RUST STREAM SERVER STACK
|
||||
|
||||
> **Périmètre** : Rust est utilisé **uniquement** pour le Stream Server (HLS/FFmpeg). Il n'est pas prévu d'étendre Rust à d'autres services. Le Chat Server, initialement prévu en Rust, est implémenté en Go (voir section 2).
|
||||
|
||||
### 3.1 Core
|
||||
|
||||
**Language**: Rust 1.75.0+
|
||||
**Channel**: Stable
|
||||
**Language**: Rust stable
|
||||
**Channel**: Stable (fixé via `rust-toolchain.toml`)
|
||||
**Edition**: 2021
|
||||
**Official Site**: https://www.rust-lang.org/
|
||||
|
||||
#### Justification
|
||||
#### Justification pour le streaming
|
||||
- **Sécurité mémoire**: Ownership model, zero-cost abstractions
|
||||
- **Performance**: Proche du C/C++, sans garbage collection
|
||||
- **Concurrence**: Fearless concurrency avec ownership
|
||||
- **Type safety**: Strong type system, zero runtime errors
|
||||
- **Tooling**: Cargo, rustfmt, clippy excellents
|
||||
- **Latence prévisible**: Pas de GC pauses, critique pour le streaming audio
|
||||
- **Intégration FFmpeg**: Bindings natifs performants pour le transcodage HLS
|
||||
|
||||
#### Alternatives Rejetées
|
||||
- **C++**: Pas de sécurité mémoire, complexité
|
||||
- **Go**: Garbage collection (latence imprévisible pour streaming)
|
||||
- **Elixir**: Performance inférieure pour audio processing
|
||||
- **Go**: Garbage collection (latence imprévisible pour streaming temps réel)
|
||||
|
||||
#### Fichier requis : `rust-toolchain.toml`
|
||||
```toml
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
```
|
||||
|
||||
### 3.2 Async Runtime
|
||||
|
||||
|
|
@ -390,44 +416,32 @@ tokio = { version = "1.35", features = ["full", "tracing"] }
|
|||
### 3.3 Web Framework
|
||||
|
||||
**Framework**: Axum
|
||||
**Version**: 0.8.x (chat), 0.7.x (stream)
|
||||
**Version**: 0.7.x
|
||||
**Repo**: https://github.com/tokio-rs/axum
|
||||
|
||||
```toml
|
||||
axum = { version = "0.8", features = ["macros", "ws"] }
|
||||
axum = { version = "0.7", features = ["macros"] }
|
||||
```
|
||||
|
||||
#### Features
|
||||
- Built on tower (middleware)
|
||||
- Type-safe routing
|
||||
- WebSocket support
|
||||
- Multipart forms
|
||||
- JSON/MessagePack
|
||||
- Low overhead
|
||||
- Adapté au streaming HLS
|
||||
|
||||
#### Alternatives Rejetées
|
||||
- **Actix-web**: Moins idiomatique, unsafe en interne
|
||||
- **Rocket**: Compilation lente, async moins mature
|
||||
- **Warp**: Complexité types, courbe apprentissage
|
||||
|
||||
### 3.4 WebSocket
|
||||
|
||||
**Library**: tokio-tungstenite
|
||||
**Version**: 0.21.x
|
||||
|
||||
```toml
|
||||
tokio-tungstenite = "0.21"
|
||||
tungstenite = "0.21"
|
||||
```
|
||||
|
||||
### 3.5 Database (Async)
|
||||
### 3.4 Database (Async)
|
||||
|
||||
**ORM**: SQLx
|
||||
**Version**: 0.8.6 (chat), 0.7.x (stream)
|
||||
**Version**: 0.7.x
|
||||
|
||||
```toml
|
||||
sqlx = {
|
||||
version = "0.8.6",
|
||||
version = "0.7",
|
||||
features = [
|
||||
"postgres",
|
||||
"runtime-tokio-native-tls",
|
||||
|
|
@ -452,7 +466,7 @@ sqlx = {
|
|||
- **SeaORM**: Moins mature
|
||||
- **tokio-postgres**: Trop bas niveau
|
||||
|
||||
### 3.6 Serialization
|
||||
### 3.5 Serialization
|
||||
|
||||
**Libraries**:
|
||||
- **JSON**: serde_json 1.0
|
||||
|
|
@ -466,23 +480,7 @@ rmp-serde = "1.1"
|
|||
toml = "0.9"
|
||||
```
|
||||
|
||||
### 3.7 Authentication & Security
|
||||
|
||||
**Libraries**:
|
||||
- **JWT**: jsonwebtoken 9.2
|
||||
- **Password hashing**: bcrypt 0.17, argon2 0.5
|
||||
- **Crypto**: ring 0.17
|
||||
- **2FA**: totp-rs 5.4
|
||||
|
||||
```toml
|
||||
jsonwebtoken = "9.2"
|
||||
bcrypt = "0.17"
|
||||
argon2 = "0.5"
|
||||
ring = "0.17"
|
||||
totp-rs = { version = "5.4", features = ["qr"] }
|
||||
```
|
||||
|
||||
### 3.8 Logging & Tracing
|
||||
### 3.6 Logging & Tracing
|
||||
|
||||
**Framework**: tracing
|
||||
**Version**: 0.1.x
|
||||
|
|
@ -496,7 +494,7 @@ tracing-subscriber = {
|
|||
tracing-appender = "0.2"
|
||||
```
|
||||
|
||||
### 3.9 Error Handling
|
||||
### 3.7 Error Handling
|
||||
|
||||
**Libraries**:
|
||||
- **Macros**: thiserror 2.0
|
||||
|
|
@ -507,7 +505,7 @@ thiserror = "2.0"
|
|||
anyhow = "1.0"
|
||||
```
|
||||
|
||||
### 3.10 Concurrency
|
||||
### 3.8 Concurrency
|
||||
|
||||
**Libraries**:
|
||||
- **HashMap concurrent**: dashmap 6.1
|
||||
|
|
@ -520,49 +518,43 @@ parking_lot = "0.12"
|
|||
flume = "0.11"
|
||||
```
|
||||
|
||||
### 3.11 Audio Processing (Stream Server)
|
||||
### 3.9 Streaming HLS & Audio
|
||||
|
||||
**Approche** : Le stream server utilise FFmpeg comme outil externe pour le transcodage et la segmentation HLS. Les libraries Rust gèrent le pilotage de FFmpeg et la lecture des formats audio.
|
||||
|
||||
**Libraries**:
|
||||
- **Codec universal**: symphonia 0.5
|
||||
- **WAV**: hound 3.5
|
||||
- **MP3**: minimp3 0.5
|
||||
- **Resampling**: rubato 0.15
|
||||
- **FFT**: rustfft 6.2
|
||||
- **Codec**: symphonia 0.5 (lecture multi-format)
|
||||
- **FFmpeg** : appelé via `std::process::Command` ou bindings
|
||||
|
||||
```toml
|
||||
symphonia = { version = "0.5", features = ["all"] }
|
||||
hound = "3.5"
|
||||
minimp3 = "0.5"
|
||||
rubato = "0.15"
|
||||
rustfft = "6.2"
|
||||
```
|
||||
|
||||
### 3.12 Complete Rust Cargo.toml (Chat Server)
|
||||
> FFmpeg est une dépendance système, pas une crate Rust. Il doit être installé dans l'image Docker du stream server.
|
||||
|
||||
### 3.10 Complete Rust Cargo.toml (Stream Server)
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "chat_server"
|
||||
name = "stream_server"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Runtime
|
||||
tokio = { version = "1.35", features = ["full", "tracing"] }
|
||||
axum = { version = "0.8", features = ["macros", "ws"] }
|
||||
tokio-tungstenite = "0.21"
|
||||
axum = { version = "0.7", features = ["macros"] }
|
||||
|
||||
# Database & Cache
|
||||
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "uuid", "chrono", "json", "migrate", "macros"] }
|
||||
redis = { version = "0.32", features = ["tokio-comp", "connection-manager"] }
|
||||
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls", "uuid", "chrono", "json", "migrate", "macros"] }
|
||||
redis = { version = "0.25", features = ["tokio-comp", "connection-manager"] }
|
||||
|
||||
# Serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
# Security
|
||||
jsonwebtoken = "9.2"
|
||||
bcrypt = "0.17"
|
||||
ring = "0.17"
|
||||
# Audio
|
||||
symphonia = { version = "0.5", features = ["all"] }
|
||||
|
||||
# Logging
|
||||
tracing = "0.1"
|
||||
|
|
@ -1005,44 +997,37 @@ thiserror = "2.0"
|
|||
version: '3.8'
|
||||
```
|
||||
|
||||
### 7.2 Orchestration (Future)
|
||||
### 7.2 Load Balancer & Reverse Proxy
|
||||
|
||||
**Tool**: Kubernetes
|
||||
**Version**: 1.28+ (when needed, Phase 7)
|
||||
**Distribution**: Amazon EKS or Google GKE
|
||||
|
||||
### 7.3 Load Balancer
|
||||
|
||||
**Tool**: Traefik
|
||||
**Version**: 2.10.x
|
||||
**Tool**: HAProxy
|
||||
**Version**: 2.x
|
||||
**Stratégie de déploiement**: Blue-green
|
||||
|
||||
```yaml
|
||||
image: traefik:v2.10
|
||||
image: haproxy:2.9
|
||||
```
|
||||
|
||||
#### Features
|
||||
- Automatic HTTPS (Let's Encrypt)
|
||||
- Docker labels configuration
|
||||
- Dashboard
|
||||
- Metrics
|
||||
- Blue-green deployments (zero-downtime)
|
||||
- Health checks
|
||||
- SSL termination
|
||||
- Connection draining
|
||||
|
||||
#### Justification
|
||||
HAProxy gère le routage entre environnements blue et green pour les déploiements sans interruption. Configuration statique et prévisible, pas besoin de service discovery dynamique.
|
||||
|
||||
#### Alternatives Rejetées
|
||||
- **NGINX**: Configuration moins dynamique
|
||||
- **HAProxy**: Pas de service discovery automatique
|
||||
- **Traefik**: Service discovery automatique non nécessaire à cette échelle
|
||||
- **Envoy**: Trop complexe pour nos besoins
|
||||
|
||||
### 7.4 Reverse Proxy (Prod)
|
||||
|
||||
**Tool**: NGINX
|
||||
**Version**: 1.25.x (mainline)
|
||||
- **NGINX**: Moins adapté au blue-green natif
|
||||
|
||||
## 8. DATABASE STACK
|
||||
|
||||
### 8.1 Primary Database
|
||||
|
||||
**Database**: PostgreSQL
|
||||
**Version**: 15.x (LTS)
|
||||
**Support**: Until November 2027
|
||||
**Version**: 16
|
||||
**Support**: Until November 2028
|
||||
**Official Site**: https://www.postgresql.org/
|
||||
|
||||
#### Justification
|
||||
|
|
@ -1084,14 +1069,14 @@ default_pool_size = 25
|
|||
|
||||
### 8.4 Database Migrations
|
||||
|
||||
**Backend**: GORM Auto-Migrate + SQL files
|
||||
**Rust**: SQLx migrations
|
||||
**Backend (Go)**: GORM Auto-Migrate + SQL files
|
||||
**Stream Server (Rust)**: SQLx migrations
|
||||
|
||||
```bash
|
||||
# GORM
|
||||
# GORM (Go API + Chat Server)
|
||||
db.AutoMigrate(&User{}, &Track{}, &Playlist{})
|
||||
|
||||
# SQLx
|
||||
# SQLx (Stream Server)
|
||||
sqlx migrate run
|
||||
```
|
||||
|
||||
|
|
@ -1147,15 +1132,18 @@ listeners.tcp.default = 5672
|
|||
- **AWS SQS**: Vendor lock-in
|
||||
- **NATS**: Moins mature pour persistence
|
||||
|
||||
### 9.3 Search Engine (Future)
|
||||
### 9.3 Search Engine
|
||||
|
||||
**Tool**: Elasticsearch
|
||||
**Version**: 8.x (Phase 5)
|
||||
**Version**: 8.x
|
||||
|
||||
```yaml
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
|
||||
```
|
||||
|
||||
#### Rôle
|
||||
Moteur de recherche déterministe pour la découverte musicale (voir section 17). Indexation par tags, genres, artistes. Pas de scoring ML — la pertinence repose sur des critères déclarés par les artistes et des filtres explicites des utilisateurs.
|
||||
|
||||
## 10. SERVICES EXTERNES
|
||||
|
||||
### 10.1 Object Storage
|
||||
|
|
@ -1182,18 +1170,23 @@ require github.com/aws/aws-sdk-go-v2 v1.24.0
|
|||
|
||||
### 10.3 Payments
|
||||
|
||||
**Provider**: Stripe
|
||||
**SDK**: stripe-go v76.16.0
|
||||
|
||||
```go
|
||||
require github.com/stripe/stripe-go/v76 v76.16.0
|
||||
```
|
||||
**Provider**: Hyperswitch (open source, multi-provider)
|
||||
**Repo**: https://github.com/juspay/hyperswitch
|
||||
**Intégration**: API REST (pas de SDK Go natif)
|
||||
|
||||
**Features**:
|
||||
- Checkout
|
||||
- Subscriptions
|
||||
- Stripe Connect (marketplace)
|
||||
- Routage multi-processeur de paiement (Stripe, Adyen, etc.)
|
||||
- Checkout unifié
|
||||
- Webhooks
|
||||
- Dashboard open source
|
||||
- Pas de vendor lock-in
|
||||
|
||||
#### Justification
|
||||
Hyperswitch est un orchestrateur de paiements open source. Il permet de router les paiements vers plusieurs processeurs sans dépendance à un fournisseur unique. Aligné avec les principes de souveraineté du projet.
|
||||
|
||||
#### Alternatives Rejetées
|
||||
- **Stripe direct**: Vendor lock-in, commission non-négociable
|
||||
- **PayPal**: UX inférieure, frais élevés
|
||||
|
||||
### 10.4 Email
|
||||
|
||||
|
|
@ -1238,7 +1231,8 @@ require github.com/getsentry/sentry-go v0.27.0
|
|||
|
||||
### 11.2 CI/CD
|
||||
|
||||
**Tool**: GitHub Actions
|
||||
**Tool**: GitHub Actions
|
||||
**Workflows actifs**: 14
|
||||
|
||||
```yaml
|
||||
# .github/workflows/backend-ci.yml
|
||||
|
|
@ -1249,14 +1243,14 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15
|
||||
image: postgres:16
|
||||
redis:
|
||||
image: redis:7
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23.8'
|
||||
go-version: '1.24'
|
||||
- run: go test ./...
|
||||
```
|
||||
|
||||
|
|
@ -1275,21 +1269,25 @@ jobs:
|
|||
- backend-api
|
||||
```
|
||||
|
||||
**Future**: Terraform (Phase 7, Kubernetes)
|
||||
**Future**: Terraform (si besoin d'infrastructure multi-serveurs)
|
||||
|
||||
### 11.4 Secret Management
|
||||
|
||||
**Tool**: Environment Variables (.env)
|
||||
**Production**: AWS Secrets Manager ou HashiCorp Vault (Phase 7)
|
||||
**Production**: AWS Secrets Manager ou HashiCorp Vault (future)
|
||||
|
||||
```bash
|
||||
# .env.example
|
||||
DATABASE_URL=postgres://...
|
||||
REDIS_URL=redis://...
|
||||
JWT_SECRET=...
|
||||
STRIPE_SECRET_KEY=...
|
||||
JWT_PRIVATE_KEY_PATH=...
|
||||
JWT_PUBLIC_KEY_PATH=...
|
||||
HYPERSWITCH_API_KEY=...
|
||||
HYPERSWITCH_BASE_URL=...
|
||||
```
|
||||
|
||||
> Migration `godotenv` → `dotenvy` planifiée (voir section 2.6).
|
||||
|
||||
### 11.5 Container Registry
|
||||
|
||||
**Registry**: GitHub Container Registry (ghcr.io)
|
||||
|
|
@ -1308,7 +1306,8 @@ image: prom/prometheus:v2.48.0
|
|||
|
||||
**Client Libraries**:
|
||||
- **Go**: prometheus/client_golang v1.18.0
|
||||
- **Rust**: prometheus 0.13
|
||||
|
||||
> Le stack de monitoring en production : **Prometheus** (métriques) + **Grafana** (visualisation) + **Alertmanager** (alertes) + **Sentry** (error tracking).
|
||||
|
||||
### 12.2 Visualization
|
||||
|
||||
|
|
@ -1360,12 +1359,12 @@ image: prom/alertmanager:v0.26.0
|
|||
### 13.1 SSL/TLS
|
||||
|
||||
**Certificates**: Let's Encrypt
|
||||
**ACME Client**: Traefik built-in
|
||||
**Terminaison SSL**: HAProxy
|
||||
|
||||
### 13.2 Secrets Management
|
||||
|
||||
**Development**: dotenv files
|
||||
**Production**: AWS Secrets Manager (Phase 6+)
|
||||
**Development**: dotenv files (migration vers dotenvy prévue, voir section 2.6)
|
||||
**Production**: AWS Secrets Manager ou HashiCorp Vault (future)
|
||||
|
||||
### 13.3 Vulnerability Scanning
|
||||
|
||||
|
|
@ -1491,11 +1490,11 @@ tokio = "=1.35.0" # NOT "1.35" or "^1.35"
|
|||
|
||||
| Component | Version | EOL Date | Action Plan |
|
||||
|-----------|---------|----------|-------------|
|
||||
| Go | 1.23.x | Feb 2027 | Upgrade to 1.24 in Q4 2026 |
|
||||
| PostgreSQL | 15.x | Nov 2027 | Upgrade to 16.x in Q3 2027 |
|
||||
| Node.js | 20.x | Apr 2026 | Upgrade to 22 LTS in Q1 2026 |
|
||||
| Redis | 7.2.x | Jul 2026 | Upgrade to 7.4 in Q2 2026 |
|
||||
| RabbitMQ | 3.12.x | Dec 2025 | Upgrade to 3.13 in Q4 2025 |
|
||||
| Go | 1.24 | Feb 2028 | Évaluer 1.25 en Q4 2027 |
|
||||
| PostgreSQL | 16 | Nov 2028 | Évaluer 17 en Q3 2028 |
|
||||
| Node.js | 20.x | Apr 2026 | Upgrade to 22 LTS prévu |
|
||||
| Redis | 7.x | Jul 2026 | Upgrade to 7.4+ en Q2 2026 |
|
||||
| RabbitMQ | 3.x | Rolling | Suivre releases stables |
|
||||
|
||||
**Monitoring**: Automated tracking avec endoflife.date API
|
||||
|
||||
|
|
@ -1505,10 +1504,12 @@ tokio = "=1.35.0" # NOT "1.35" or "^1.35"
|
|||
|
||||
| Component A | Version | Component B | Version | Compatible | Notes |
|
||||
|-------------|---------|-------------|---------|------------|-------|
|
||||
| Go API | 1.23.8 | PostgreSQL | 15.x | ✅ Yes | lib/pq 1.10.9 |
|
||||
| Go API | 1.23.8 | Redis | 7.2.x | ✅ Yes | go-redis 9.16.0 |
|
||||
| Rust Chat | 1.75 | PostgreSQL | 15.x | ✅ Yes | SQLx 0.8.6 |
|
||||
| Rust Stream | 1.75 | Redis | 7.2.x | ✅ Yes | redis-rs 0.25 |
|
||||
| Go API | 1.24 | PostgreSQL | 16 | ✅ Yes | lib/pq 1.10.9 |
|
||||
| Go API | 1.24 | Redis | 7.x | ✅ Yes | go-redis 9.16.0 |
|
||||
| Go Chat | 1.24 | PostgreSQL | 16 | ✅ Yes | GORM |
|
||||
| Rust Stream | stable | PostgreSQL | 16 | ✅ Yes | SQLx 0.7.x |
|
||||
| Rust Stream | stable | Redis | 7.x | ✅ Yes | redis-rs 0.25 |
|
||||
| Go API | 1.24 | Hyperswitch | latest | ✅ Yes | API REST |
|
||||
| React | 18.2 | Vite | 7.1.5 | ✅ Yes | @vitejs/plugin-react 4.2.1 |
|
||||
| Electron | 28.x | React | 18.2 | ✅ Yes | Electron React Boilerplate |
|
||||
|
||||
|
|
@ -1531,28 +1532,122 @@ tokio = "=1.35.0" # NOT "1.35" or "^1.35"
|
|||
| Opera | 85+ | ⚠️ Partial | Not officially tested |
|
||||
| IE11 | N/A | ❌ No | Deprecated |
|
||||
|
||||
## 17. STACK DE DÉCOUVERTE MUSICALE ÉTHIQUE
|
||||
|
||||
La découverte musicale sur Veza repose sur des mécanismes déterministes et transparents. Aucun algorithme de recommandation basé sur le machine learning n'est utilisé.
|
||||
|
||||
### 17.1 Principes
|
||||
|
||||
- **Pas de ML/IA** : aucun modèle de recommandation, aucun profiling comportemental
|
||||
- **Transparence** : l'utilisateur comprend pourquoi un résultat apparaît
|
||||
- **Contrôle artiste** : les métadonnées de découverte sont déclarées par les artistes, pas inférées
|
||||
|
||||
### 17.2 Composants techniques
|
||||
|
||||
| Composant | Technologie | Rôle |
|
||||
|-----------|-------------|------|
|
||||
| **Recherche** | Elasticsearch 8.x | Full-text search sur titres, artistes, descriptions |
|
||||
| **Taxonomie** | PostgreSQL 16 | Tags et genres déclarés par les artistes, stockés en base relationnelle |
|
||||
| **Curation humaine** | Go API + interface admin | Outils pour curateurs : playlists éditoriales, mises en avant manuelles |
|
||||
| **Filtres utilisateur** | Frontend React | Filtres explicites : genre, instrument, langue, durée, licence |
|
||||
|
||||
### 17.3 Recherche Elasticsearch
|
||||
|
||||
```yaml
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
|
||||
```
|
||||
|
||||
- Index par : titre, artiste, tags, genre, description, langue
|
||||
- Scoring basé sur la pertinence textuelle (BM25), pas sur un modèle entraîné
|
||||
- Pas de tracking de clics pour pondérer les résultats
|
||||
- Autocomplétion et suggestions basées sur les données déclarées
|
||||
|
||||
### 17.4 Curation humaine
|
||||
|
||||
Les curateurs disposent d'outils dans l'interface d'administration pour :
|
||||
- Créer des playlists éditoriales thématiques
|
||||
- Mettre en avant des artistes ou morceaux
|
||||
- Organiser des sélections par contexte (nouveautés, géographie, instrument)
|
||||
|
||||
Aucune automatisation ML dans le processus de curation. Les décisions éditoriales sont humaines et traçables.
|
||||
|
||||
### 17.5 Ce qui est explicitement exclu
|
||||
|
||||
- Modèles de recommandation (collaborative filtering, content-based filtering)
|
||||
- Analyse audio automatique (fingerprinting ML, extraction de features)
|
||||
- Scoring de popularité opaque
|
||||
- A/B testing sur les recommandations
|
||||
- Boucles de rétroaction comportementale (« les gens qui ont écouté X écoutent aussi Y »)
|
||||
|
||||
## 18. EXCLUSIONS ET RAISONS ÉTHIQUES
|
||||
|
||||
Les technologies suivantes ont été évaluées et **exclues par principe architectural**. Ces exclusions ne sont pas provisoires — elles reflètent les valeurs fondamentales du projet.
|
||||
|
||||
### 18.1 Intelligence Artificielle / Machine Learning
|
||||
|
||||
| Technologie exclue | Catégorie | Raison de l'exclusion |
|
||||
|--------------------|-----------|-----------------------|
|
||||
| TensorFlow | ML Framework | Recommandation algorithmique = manipulation attentionnelle |
|
||||
| PyTorch | ML Framework | Même raison que TensorFlow |
|
||||
| Hugging Face Transformers | NLP/ML | Aucun cas d'usage NLP qui ne puisse être résolu par Elasticsearch |
|
||||
| librosa | Analyse audio ML | Extraction de features audio = profiling du contenu sans consentement artiste |
|
||||
| essentia | Analyse audio ML | Même raison que librosa |
|
||||
| scikit-learn | ML classique | Pas de modèle prédictif dans une plateforme éthique |
|
||||
| ONNX Runtime | Inférence ML | Pas de modèle à exécuter |
|
||||
|
||||
**Principe** : La découverte musicale doit être un choix conscient de l'utilisateur, pas le résultat d'un algorithme optimisant le temps d'écoute.
|
||||
|
||||
### 18.2 Blockchain / Web3 / NFT / Crypto
|
||||
|
||||
| Technologie exclue | Catégorie | Raison de l'exclusion |
|
||||
|--------------------|-----------|-----------------------|
|
||||
| Ethereum / Solidity | Smart contracts | Spéculation financière incompatible avec le soutien aux musiciens |
|
||||
| IPFS | Stockage décentralisé | Complexité sans bénéfice réel — S3/MinIO suffit |
|
||||
| Web3.js / ethers.js | Blockchain SDK | Pas de blockchain = pas de SDK blockchain |
|
||||
| Metamask / Wallets | Wallet crypto | Pas de tokens, pas de NFT |
|
||||
| Polygon / L2 | Scaling blockchain | Pas de blockchain à scaler |
|
||||
|
||||
**Principe** : Les musiciens sont payés en monnaie réelle via des processeurs de paiement réels (Hyperswitch). La spéculation sur des tokens n'aide pas les artistes indépendants.
|
||||
|
||||
### 18.3 Gamification Addictive
|
||||
|
||||
| Mécanisme exclu | Raison de l'exclusion |
|
||||
|----------------|-----------------------|
|
||||
| Streaks / séries consécutives | Crée une obligation artificielle, pas un engagement réel |
|
||||
| Points / XP / niveaux | Transforme l'écoute musicale en jeu, détourne de la musique |
|
||||
| Classements compétitifs | Met les artistes en compétition sur des métriques qui ne reflètent pas la qualité |
|
||||
| Badges de complétion | Encourage la consommation quantitative au détriment de l'écoute attentive |
|
||||
| Notifications push de rétention | Manipulation attentionnelle, dark pattern |
|
||||
|
||||
**Principe** : L'engagement doit venir de la qualité de la musique et de l'expérience, pas de mécanismes psychologiques exploitant les biais cognitifs.
|
||||
|
||||
### 18.4 Règle générale
|
||||
|
||||
Toute technologie dont le but principal est d'**augmenter le temps passé sur la plateforme** au détriment du **choix conscient de l'utilisateur** est exclue. Cette règle s'applique aux choix futurs comme aux choix actuels.
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Backend Stack
|
||||
- [ ] Go 1.23.8 installed
|
||||
- [ ] Go 1.24 installed
|
||||
- [ ] All go.mod dependencies locked exact versions
|
||||
- [ ] PostgreSQL 15.x accessible
|
||||
- [ ] PostgreSQL 16 accessible
|
||||
- [ ] Redis 7.x accessible
|
||||
- [ ] RabbitMQ 3.12.x accessible
|
||||
- [ ] RabbitMQ 3.x accessible
|
||||
- [ ] S3-compatible storage configured
|
||||
- [ ] Stripe API keys configured
|
||||
- [ ] Hyperswitch instance configured
|
||||
- [ ] SendGrid API key configured
|
||||
- [ ] JWT RS256 keys generated (migration depuis HS256)
|
||||
|
||||
### Rust Services Stack
|
||||
- [ ] Rust 1.75+ installed (stable channel)
|
||||
### Rust Stream Server
|
||||
- [ ] Rust stable installed (via rust-toolchain.toml)
|
||||
- [ ] All Cargo.toml dependencies locked
|
||||
- [ ] FFmpeg installé dans l'image Docker
|
||||
- [ ] SQLx CLI installed
|
||||
- [ ] Database migrations tested
|
||||
- [ ] WebSocket server compiles
|
||||
- [ ] Stream server compiles
|
||||
- [ ] Stream server compiles et sert du HLS
|
||||
|
||||
### Frontend Stack
|
||||
- [ ] Node.js 20.11 LTS installed
|
||||
- [ ] Node.js 20.11 LTS installed (via .nvmrc)
|
||||
- [ ] All package.json dependencies exact versions
|
||||
- [ ] TypeScript 5.3.3
|
||||
- [ ] Vite build successful
|
||||
|
|
@ -1562,10 +1657,10 @@ tokio = "=1.35.0" # NOT "1.35" or "^1.35"
|
|||
### Infrastructure
|
||||
- [ ] Docker 24.x installed
|
||||
- [ ] Docker Compose 2.23.x installed
|
||||
- [ ] Traefik configured
|
||||
- [ ] Let's Encrypt certificates working
|
||||
- [ ] Prometheus + Grafana accessible
|
||||
- [ ] Loki logging working
|
||||
- [ ] HAProxy configured (blue-green)
|
||||
- [ ] Prometheus + Grafana + Alertmanager accessible
|
||||
- [ ] Sentry configured
|
||||
- [ ] Elasticsearch 8.x accessible
|
||||
|
||||
## 📊 MÉTRIQUES DE SUCCÈS
|
||||
|
||||
|
|
@ -1592,22 +1687,22 @@ tokio = "=1.35.0" # NOT "1.35" or "^1.35"
|
|||
|
||||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Stack technique verrouillée |
|
||||
| 1.0.0 | 2025-11-02 | Version initiale — stack technique verrouillée |
|
||||
| 2.0.0 | 2026-03-04 | Révision éthique : suppression ML/IA, blockchain/NFT, gamification addictive. Go 1.24, PostgreSQL 16, Chat Server migré de Rust vers Go, Stripe remplacé par Hyperswitch, Traefik remplacé par HAProxy blue-green, ajout sections découverte musicale éthique et exclusions éthiques, Rust scopé au stream server uniquement |
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ AVERTISSEMENT
|
||||
|
||||
**CE DOCUMENT EST IMMUABLE**
|
||||
**CE DOCUMENT DÉFINIT DES CONTRAINTES ARCHITECTURALES**
|
||||
|
||||
La stack technique définie ici est **VERROUILLÉE POUR 24 MOIS**. Toute modification nécessite:
|
||||
La stack technique et les exclusions éthiques définies ici sont des contraintes architecturales, pas des suggestions. Toute modification nécessite :
|
||||
|
||||
1. **RFC technique** avec justification (security, EOL, performance critique)
|
||||
2. **Impact analysis** complet (migration effort, breaking changes, testing)
|
||||
3. **Approval CTO** + Tech Lead
|
||||
3. **Vérification éthique** : la technologie proposée ne contrevient-elle pas aux exclusions de la section 18 ?
|
||||
4. **Migration plan** détaillé
|
||||
5. **Update** tous documents ORIGIN impactés
|
||||
6. **Team training** si nouveau tech
|
||||
|
||||
**Seules exceptions autorisées**:
|
||||
- **Security patches** (CVE critiques)
|
||||
|
|
@ -1615,17 +1710,20 @@ La stack technique définie ici est **VERROUILLÉE POUR 24 MOIS**. Toute modific
|
|||
- **Impossibilité technique** (bug bloquant non-résolu)
|
||||
|
||||
**Interdictions absolues**:
|
||||
- Changement de langage (Go → Node, Rust → Go, etc.)
|
||||
- Ajout de composants ML/IA, blockchain/NFT, ou gamification addictive
|
||||
- Changement de langage principal (Go → Node, etc.)
|
||||
- Changement de framework principal (React → Vue, etc.)
|
||||
- Ajout stack non-approuvée (nouvelle BDD, nouveau langage)
|
||||
- Extension de Rust au-delà du stream server
|
||||
- Ajout stack non-approuvée sans RFC
|
||||
- Downgrade de version (sauf rollback urgence)
|
||||
|
||||
---
|
||||
|
||||
**Document créé par**: CTO + Architecture Team
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Après Phase 4 (Q3 2026)
|
||||
**Dernière révision**: 2026-03-04 (v2.0.0 — révision éthique)
|
||||
**Prochaine révision**: Q3 2026
|
||||
**Propriétaire**: CTO
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
**Statut**: ✅ **APPROUVÉ — v2.0.0**
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ Ce document définit la stratégie de testing complète et définitive pour la p
|
|||
10. [CI/CD Pipeline Testing](#10-cicd-pipeline-testing)
|
||||
11. [Test Automation](#11-test-automation)
|
||||
12. [Quality Gates](#12-quality-gates)
|
||||
13. [Tests Post-Déploiement (Smoke Tests)](#13-tests-post-déploiement-smoke-tests)
|
||||
14. [Tests de l'Algorithme de Découverte](#14-tests-de-lalgorithme-de-découverte)
|
||||
15. [Stratégie de Test Éthique](#15-stratégie-de-test-éthique)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
|
|
@ -453,6 +456,9 @@ func TestUserAPI_CreateUser_Integration(t *testing.T) {
|
|||
|
||||
### 4.2 Database Integration Tests (Rust)
|
||||
|
||||
Tous les services Rust (chat-server, stream-server) doivent être testés avec une base de données réelle via `sqlx::test`. Les tests utilisent une base PostgreSQL temporaire créée et détruite automatiquement par le macro `#[sqlx::test]`.
|
||||
|
||||
**Test CRUD de base** :
|
||||
```rust
|
||||
use sqlx::PgPool;
|
||||
|
||||
|
|
@ -480,7 +486,6 @@ async fn test_create_user(pool: PgPool) -> sqlx::Result<()> {
|
|||
// ASSERT
|
||||
assert_eq!(result.rows_affected(), 1);
|
||||
|
||||
// Verify user exists
|
||||
let fetched_user = sqlx::query_as!(
|
||||
User,
|
||||
"SELECT id, email, username, password_hash, created_at FROM users WHERE id = $1",
|
||||
|
|
@ -496,6 +501,58 @@ async fn test_create_user(pool: PgPool) -> sqlx::Result<()> {
|
|||
}
|
||||
```
|
||||
|
||||
**Tests transactionnels et contraintes d'intégrité** :
|
||||
```rust
|
||||
#[sqlx::test]
|
||||
async fn test_unique_email_constraint(pool: PgPool) -> sqlx::Result<()> {
|
||||
let id1 = Uuid::new_v4();
|
||||
let id2 = Uuid::new_v4();
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO users (id, email, username, password_hash) VALUES ($1, $2, $3, $4)",
|
||||
id1, "duplicate@example.com", "user1", "hash1"
|
||||
)
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
|
||||
let result = sqlx::query!(
|
||||
"INSERT INTO users (id, email, username, password_hash) VALUES ($1, $2, $3, $4)",
|
||||
id2, "duplicate@example.com", "user2", "hash2"
|
||||
)
|
||||
.execute(&pool)
|
||||
.await;
|
||||
|
||||
assert!(result.is_err(), "Duplicate email must be rejected");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn test_cascade_delete_user_tracks(pool: PgPool) -> sqlx::Result<()> {
|
||||
let user_id = Uuid::new_v4();
|
||||
let track_id = Uuid::new_v4();
|
||||
|
||||
sqlx::query!("INSERT INTO users (id, email, username, password_hash) VALUES ($1, $2, $3, $4)",
|
||||
user_id, "artist@example.com", "artist", "hash")
|
||||
.execute(&pool).await?;
|
||||
|
||||
sqlx::query!("INSERT INTO tracks (id, user_id, title, genre, duration_seconds) VALUES ($1, $2, $3, $4, $5)",
|
||||
track_id, user_id, "My Song", "electronic", 240)
|
||||
.execute(&pool).await?;
|
||||
|
||||
sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
|
||||
.execute(&pool).await?;
|
||||
|
||||
let track = sqlx::query!("SELECT id FROM tracks WHERE id = $1", track_id)
|
||||
.fetch_optional(&pool).await?;
|
||||
|
||||
assert!(track.is_none(), "Tracks must be cascade-deleted with user");
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**CI Integration** : Les tests Rust avec DB tournent dans le job `integration-tests` du workflow GitHub Actions, avec un service PostgreSQL dédié (cf. section 10.1).
|
||||
```
|
||||
|
||||
### 4.3 API Contract Testing
|
||||
|
||||
**OpenAPI Schema Validation**:
|
||||
|
|
@ -1264,6 +1321,363 @@ vitest run --coverage
|
|||
- [ ] Security scan passed (OWASP ZAP)
|
||||
- [ ] Smoke tests passed in staging
|
||||
|
||||
## 13. TESTS POST-DÉPLOIEMENT (SMOKE TESTS)
|
||||
|
||||
### 13.1 Smoke Tests Automatisés
|
||||
|
||||
Après chaque déploiement en staging ou production, un ensemble de smoke tests automatisés doit s'exécuter pour valider que les services principaux fonctionnent correctement.
|
||||
|
||||
**Script de smoke tests** :
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# scripts/smoke-tests.sh
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${1:-https://api.veza.app}"
|
||||
FAILURES=0
|
||||
|
||||
check() {
|
||||
local name="$1" url="$2" expected_status="$3"
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
|
||||
if [ "$status" != "$expected_status" ]; then
|
||||
echo "FAIL: $name — expected $expected_status, got $status"
|
||||
FAILURES=$((FAILURES + 1))
|
||||
else
|
||||
echo "PASS: $name"
|
||||
fi
|
||||
}
|
||||
|
||||
check "Health endpoint" "$BASE_URL/health" "200"
|
||||
check "API version" "$BASE_URL/v1/version" "200"
|
||||
check "Tracks listing" "$BASE_URL/v1/tracks" "200"
|
||||
check "Auth (no token)" "$BASE_URL/v1/me" "401"
|
||||
check "Discovery endpoint" "$BASE_URL/v1/discover" "200"
|
||||
check "Stream health" "$BASE_URL/v1/stream/health" "200"
|
||||
|
||||
if [ "$FAILURES" -gt 0 ]; then
|
||||
echo "SMOKE TESTS FAILED: $FAILURES failure(s)"
|
||||
exit 1
|
||||
fi
|
||||
echo "ALL SMOKE TESTS PASSED"
|
||||
```
|
||||
|
||||
### 13.2 Intégration CI/CD
|
||||
|
||||
Les smoke tests s'exécutent automatiquement :
|
||||
- **Post-deploy staging** : bloquant — échec = rollback automatique
|
||||
- **Post-deploy production** : bloquant — échec = rollback + alerte PagerDuty
|
||||
|
||||
```yaml
|
||||
# Extrait du workflow deploy-production.yml
|
||||
- name: Run post-deployment smoke tests
|
||||
run: |
|
||||
./scripts/smoke-tests.sh https://api.veza.app
|
||||
timeout-minutes: 5
|
||||
|
||||
- name: Rollback on smoke test failure
|
||||
if: failure()
|
||||
run: |
|
||||
kubectl rollout undo deployment/veza-backend -n veza-production
|
||||
echo "ROLLBACK TRIGGERED — smoke tests failed"
|
||||
```
|
||||
|
||||
### 13.3 Smoke Tests WebSocket (Chat Server)
|
||||
|
||||
```typescript
|
||||
import WebSocket from 'ws';
|
||||
|
||||
async function smokeTestWebSocket(url: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = new WebSocket(`${url}/ws/health`);
|
||||
const timeout = setTimeout(() => {
|
||||
ws.close();
|
||||
reject(new Error('WebSocket health check timed out'));
|
||||
}, 5000);
|
||||
|
||||
ws.on('open', () => {
|
||||
clearTimeout(timeout);
|
||||
ws.close();
|
||||
resolve();
|
||||
});
|
||||
|
||||
ws.on('error', (err) => {
|
||||
clearTimeout(timeout);
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 14. TESTS DE L'ALGORITHME DE DÉCOUVERTE
|
||||
|
||||
### 14.1 Objectif
|
||||
|
||||
L'algorithme de découverte de Veza est un élément éthique fondamental : il ne doit **jamais** favoriser les artistes populaires au détriment des artistes émergents. Les tests doivent vérifier cette propriété de manière automatisée.
|
||||
|
||||
### 14.2 Tests de Distribution (Go)
|
||||
|
||||
```go
|
||||
func TestDiscovery_DoesNotFavorPopularArtists(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
|
||||
// Seed : 10 artistes populaires (>10k plays) et 40 artistes émergents (<100 plays)
|
||||
for i := 0; i < 10; i++ {
|
||||
seedArtist(t, db, fmt.Sprintf("popular-%d", i), 10000+rand.Intn(50000))
|
||||
}
|
||||
for i := 0; i < 40; i++ {
|
||||
seedArtist(t, db, fmt.Sprintf("emerging-%d", i), rand.Intn(100))
|
||||
}
|
||||
|
||||
service := NewDiscoveryService(db)
|
||||
results, err := service.Discover(context.Background(), DiscoveryParams{
|
||||
Limit: 20,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 20)
|
||||
|
||||
popularCount := 0
|
||||
emergingCount := 0
|
||||
for _, track := range results {
|
||||
if track.PlayCount > 1000 {
|
||||
popularCount++
|
||||
} else {
|
||||
emergingCount++
|
||||
}
|
||||
}
|
||||
|
||||
// Les artistes émergents (80% du catalogue) doivent représenter
|
||||
// au moins 50% des résultats de découverte
|
||||
emergingRatio := float64(emergingCount) / float64(len(results))
|
||||
assert.GreaterOrEqual(t, emergingRatio, 0.5,
|
||||
"Discovery must not under-represent emerging artists: got %.0f%% emerging", emergingRatio*100)
|
||||
|
||||
// Les artistes populaires ne doivent pas dépasser leur proportion dans le catalogue
|
||||
popularRatio := float64(popularCount) / float64(len(results))
|
||||
assert.LessOrEqual(t, popularRatio, 0.5,
|
||||
"Discovery must not over-represent popular artists: got %.0f%% popular", popularRatio*100)
|
||||
}
|
||||
|
||||
func TestDiscovery_GenreDiversity(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
|
||||
genres := []string{"electronic", "rock", "jazz", "hip-hop", "classical"}
|
||||
for _, genre := range genres {
|
||||
for i := 0; i < 10; i++ {
|
||||
seedTrackWithGenre(t, db, genre)
|
||||
}
|
||||
}
|
||||
|
||||
service := NewDiscoveryService(db)
|
||||
results, err := service.Discover(context.Background(), DiscoveryParams{Limit: 20})
|
||||
require.NoError(t, err)
|
||||
|
||||
genreSet := map[string]bool{}
|
||||
for _, track := range results {
|
||||
genreSet[track.Genre] = true
|
||||
}
|
||||
|
||||
assert.GreaterOrEqual(t, len(genreSet), 3,
|
||||
"Discovery results must include at least 3 different genres, got %d", len(genreSet))
|
||||
}
|
||||
```
|
||||
|
||||
### 14.3 Tests de Non-Régression
|
||||
|
||||
```go
|
||||
func TestDiscovery_NoPlayCountBias(t *testing.T) {
|
||||
db := setupTestDB(t)
|
||||
|
||||
// Deux tracks identiques sauf play count
|
||||
track1 := seedTrack(t, db, "Hidden Gem", 5)
|
||||
track2 := seedTrack(t, db, "Viral Hit", 1_000_000)
|
||||
|
||||
service := NewDiscoveryService(db)
|
||||
scores := map[string]int{track1.ID: 0, track2.ID: 0}
|
||||
|
||||
// Run discovery 100 times, count appearances
|
||||
for i := 0; i < 100; i++ {
|
||||
results, _ := service.Discover(context.Background(), DiscoveryParams{Limit: 10})
|
||||
for _, r := range results {
|
||||
if _, ok := scores[r.ID]; ok {
|
||||
scores[r.ID]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ratio := float64(scores[track2.ID]) / float64(scores[track1.ID]+1)
|
||||
assert.Less(t, ratio, 3.0,
|
||||
"Viral track must not appear >3x more than hidden gem in discovery")
|
||||
}
|
||||
```
|
||||
|
||||
### 14.4 Exécution CI
|
||||
|
||||
Les tests de l'algorithme de découverte font partie du job `integration-tests` et s'exécutent à chaque PR et nightly build. Un échec est bloquant.
|
||||
|
||||
## 15. STRATÉGIE DE TEST ÉTHIQUE
|
||||
|
||||
### 15.1 Principes
|
||||
|
||||
Veza refuse l'IA/ML, le Web3/NFT, la gamification addictive, et le tracking publicitaire. Les tests éthiques garantissent ces engagements de manière vérifiable et automatisée.
|
||||
|
||||
### 15.2 Tests de Biais Algorithmique
|
||||
|
||||
Tous les algorithmes exposant du contenu (découverte, recherche, suggestions) doivent être testés contre les biais suivants :
|
||||
|
||||
| Biais | Critère | Seuil |
|
||||
|-------|---------|-------|
|
||||
| **Popularité** | Les artistes émergents (<100 plays) doivent apparaître proportionnellement | ≥ 50% des résultats |
|
||||
| **Ancienneté** | Les nouveaux artistes (<30 jours) doivent apparaître | ≥ 20% des résultats |
|
||||
| **Genre** | Au moins 3 genres dans chaque page de découverte | Minimum 3 genres |
|
||||
| **Géographie** | Pas de biais pays (si donnée disponible) | Aucun pays > 40% |
|
||||
|
||||
Ces tests sont exécutés nightly et à chaque PR modifiant les services de découverte ou de recherche.
|
||||
|
||||
### 15.3 Tests d'Accessibilité Automatisés (axe-core)
|
||||
|
||||
L'accessibilité est testée automatiquement dans le pipeline CI via `@axe-core/playwright` :
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
|
||||
const CRITICAL_PAGES = ['/', '/discover', '/login', '/register', '/upload', '/settings'];
|
||||
|
||||
for (const path of CRITICAL_PAGES) {
|
||||
test(`accessibility audit: ${path}`, async ({ page }) => {
|
||||
await page.goto(path);
|
||||
|
||||
const results = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
|
||||
.analyze();
|
||||
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
}
|
||||
|
||||
test('accessibility: audio player controls', async ({ page }) => {
|
||||
await page.goto('/tracks/test-track');
|
||||
|
||||
const results = await new AxeBuilder({ page })
|
||||
.include('.audio-player')
|
||||
.withTags(['wcag2a', 'wcag2aa'])
|
||||
.analyze();
|
||||
|
||||
expect(results.violations).toEqual([]);
|
||||
|
||||
// Keyboard navigation verification
|
||||
await page.keyboard.press('Tab');
|
||||
const playButton = page.locator('.audio-player button[aria-label="Play"]');
|
||||
await expect(playButton).toBeFocused();
|
||||
});
|
||||
```
|
||||
|
||||
**CI Integration** :
|
||||
```yaml
|
||||
# Extrait du workflow test.yml
|
||||
- name: Run accessibility tests (axe-core)
|
||||
run: |
|
||||
cd apps/web
|
||||
npx playwright test tests/accessibility/ --project=chromium
|
||||
```
|
||||
|
||||
**Critère bloquant** : Zéro violation WCAG 2.1 AA sur les pages critiques. Les violations sont bloquantes en CI.
|
||||
|
||||
### 15.4 Tests de Conformité RGPD
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('GDPR Compliance', () => {
|
||||
test('user can export all personal data', async ({ request }) => {
|
||||
const token = await getAuthToken(request, 'gdpr-test-user@example.com');
|
||||
|
||||
const exportResponse = await request.post('/api/v1/me/data-export', {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
expect(exportResponse.status()).toBe(200);
|
||||
|
||||
const data = await exportResponse.json();
|
||||
expect(data).toHaveProperty('user');
|
||||
expect(data).toHaveProperty('tracks');
|
||||
expect(data).toHaveProperty('playlists');
|
||||
expect(data).toHaveProperty('listening_history');
|
||||
expect(data.user.email).toBe('gdpr-test-user@example.com');
|
||||
});
|
||||
|
||||
test('user can delete account and all associated data', async ({ request }) => {
|
||||
const token = await getAuthToken(request, 'delete-test-user@example.com');
|
||||
|
||||
// Request deletion
|
||||
const deleteResponse = await request.delete('/api/v1/me', {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
expect(deleteResponse.status()).toBe(200);
|
||||
|
||||
// Verify account is gone
|
||||
const profileResponse = await request.get('/api/v1/me', {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
expect(profileResponse.status()).toBe(401);
|
||||
|
||||
// Verify associated data is deleted (admin endpoint for test)
|
||||
const adminToken = await getAdminToken(request);
|
||||
const dataCheck = await request.get('/api/v1/admin/user-data-check/delete-test-user@example.com', {
|
||||
headers: { Authorization: `Bearer ${adminToken}` },
|
||||
});
|
||||
const remaining = await dataCheck.json();
|
||||
expect(remaining.tracks).toBe(0);
|
||||
expect(remaining.playlists).toBe(0);
|
||||
expect(remaining.messages).toBe(0);
|
||||
});
|
||||
|
||||
test('exported data does not contain other users data', async ({ request }) => {
|
||||
const token = await getAuthToken(request, 'gdpr-test-user@example.com');
|
||||
|
||||
const exportResponse = await request.post('/api/v1/me/data-export', {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
const data = await exportResponse.json();
|
||||
|
||||
const allEmails = JSON.stringify(data);
|
||||
expect(allEmails).not.toContain('other-user@example.com');
|
||||
expect(allEmails).not.toContain('admin@example.com');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Exécution** : Les tests RGPD s'exécutent dans le job E2E, à chaque PR et en nightly build. Un échec est bloquant pour le merge et le déploiement.
|
||||
|
||||
### 15.5 Tests Anti-Tracking
|
||||
|
||||
```go
|
||||
func TestAPI_NoTrackingHeaders(t *testing.T) {
|
||||
router := setupRouter(setupTestDB(t))
|
||||
|
||||
endpoints := []string{"/v1/tracks", "/v1/discover", "/v1/users/profile"}
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
t.Run(endpoint, func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", endpoint, nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
// No tracking/fingerprinting headers
|
||||
assert.Empty(t, w.Header().Get("X-Request-Fingerprint"))
|
||||
assert.Empty(t, w.Header().Get("X-Device-ID"))
|
||||
|
||||
// No third-party tracking cookies
|
||||
for _, cookie := range w.Result().Cookies() {
|
||||
assert.NotContains(t, cookie.Name, "_ga")
|
||||
assert.NotContains(t, cookie.Name, "_fbp")
|
||||
assert.NotContains(t, cookie.Name, "tracker")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Test Coverage
|
||||
|
|
@ -1322,6 +1736,7 @@ vitest run --coverage
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Stratégie de testing complète |
|
||||
| 2.0.0 | 2026-03-04 | Audit sécurité : ajout tests post-déploiement (smoke tests), tests algorithme de découverte, stratégie de test éthique (biais algorithmique, accessibilité axe-core, conformité RGPD, anti-tracking). Enrichissement tests d'intégration Rust avec DB. |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1353,7 +1768,8 @@ La stratégie de testing définie ici est **VERROUILLÉE**. Toute modification n
|
|||
|
||||
**Document créé par**: QA Team + Tech Leads
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Quarterly (2026-02-01)
|
||||
**Dernière révision**: 2026-03-04 (audit sécurité)
|
||||
**Prochaine révision**: Quarterly (2026-06-01)
|
||||
**Propriétaire**: QA Lead
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
|
|
|||
|
|
@ -2,19 +2,20 @@
|
|||
|
||||
## 📋 RÉSUMÉ EXÉCUTIF
|
||||
|
||||
Ce document définit le système de design UI/UX complet et définitif pour la plateforme Veza. Il spécifie 200+ composants réutilisables, design tokens (couleurs, typographie, spacing), patterns d'interaction, responsive breakpoints, accessibility WCAG AAA, animations, et user flows assurant cohérence visuelle, expérience utilisateur fluide et maintenabilité design sur 24 mois.
|
||||
Ce document définit le système de design UI/UX complet et définitif pour la plateforme Veza. Il spécifie 200+ composants réutilisables, design tokens (couleurs, typographie, spacing), patterns d'interaction, responsive breakpoints, accessibility WCAG AA minimum (WCAG AAA pour les fonctions critiques), animations, anti-patterns UX interdits, et user flows assurant cohérence visuelle, expérience utilisateur éthique et maintenabilité design sur 24 mois.
|
||||
|
||||
## 🎯 OBJECTIFS
|
||||
|
||||
### Objectif Principal
|
||||
Établir un design system cohérent, accessible (WCAG AAA), responsive (mobile-first), et maintenable avec 200+ composants documentés, garantissant expérience utilisateur premium et réduction 50% temps développement UI.
|
||||
Établir un design system cohérent, accessible (WCAG AA minimum, WCAG AAA pour les fonctions critiques), responsive (mobile-first), éthique (aucun dark pattern, aucune gamification), et maintenable avec 200+ composants documentés, garantissant expérience utilisateur respectueuse et réduction 50% temps développement UI.
|
||||
|
||||
### Objectifs Secondaires
|
||||
- Cohérence visuelle absolue (zero inconsistencies)
|
||||
- Accessibility WCAG AAA (keyboard navigation, screen readers)
|
||||
- Accessibility WCAG AA minimum, WCAG AAA pour les fonctions critiques (navigation, lecture audio, upload, inscription)
|
||||
- Responsive design (mobile, tablet, desktop)
|
||||
- Dark mode support natif
|
||||
- Performance (60 FPS animations)
|
||||
- Éthique UX : aucun dark pattern, aucune gamification, aucun mécanisme addictif
|
||||
|
||||
## 📖 TABLE DES MATIÈRES
|
||||
|
||||
|
|
@ -30,11 +31,13 @@ Ce document définit le système de design UI/UX complet et définitif pour la p
|
|||
10. [Animations & Transitions](#10-animations--transitions)
|
||||
11. [User Flows](#11-user-flows)
|
||||
12. [Figma & Prototyping](#12-figma--prototyping)
|
||||
13. [Anti-patterns UX interdits](#13-anti-patterns-ux-interdits)
|
||||
14. [Patterns UX positifs](#14-patterns-ux-positifs)
|
||||
|
||||
## 🔒 RÈGLES IMMUABLES
|
||||
|
||||
1. **Mobile-First**: Toujours designer mobile d'abord, desktop après
|
||||
2. **Accessibility First**: WCAG AAA obligatoire (not AAA où infeasible, then AA)
|
||||
2. **Accessibility First**: WCAG AA minimum obligatoire, WCAG AAA pour les fonctions critiques (navigation, lecture audio, upload, inscription)
|
||||
3. **Design Tokens Only**: Jamais de valeurs hardcodées (use CSS variables)
|
||||
4. **Component Reuse**: Aucun composant custom si équivalent existe dans DS
|
||||
5. **Spacing System**: Utiliser échelle 4px (4, 8, 12, 16, 24, 32, 48, 64)
|
||||
|
|
@ -315,10 +318,14 @@ Ce document définit le système de design UI/UX complet et définitif pour la p
|
|||
|
||||
### 4.2 Color Contrast
|
||||
|
||||
**WCAG AAA Requirements**:
|
||||
**WCAG AA Requirements (toute la plateforme)** :
|
||||
- **Normal Text**: Contrast ratio ≥ 4.5:1
|
||||
- **Large Text** (18pt+ or 14pt+ bold): Contrast ratio ≥ 3:1
|
||||
- **UI Components**: Contrast ratio ≥ 3:1
|
||||
|
||||
**WCAG AAA Requirements (fonctions critiques)** :
|
||||
- **Normal Text**: Contrast ratio ≥ 7:1
|
||||
- **Large Text** (18pt+ or 14pt+ bold): Contrast ratio ≥ 4.5:1
|
||||
- **UI Components**: Contrast ratio ≥ 3:1
|
||||
|
||||
**Color Contrast Checker**:
|
||||
```
|
||||
|
|
@ -672,11 +679,15 @@ Text on Background:
|
|||
|
||||
## 9. ACCESSIBILITY
|
||||
|
||||
### 9.1 WCAG AAA Compliance
|
||||
### 9.1 WCAG AA/AAA Compliance
|
||||
|
||||
**Checklist**:
|
||||
- [ ] Color contrast ≥ 7:1 (normal text)
|
||||
- [ ] Color contrast ≥ 4.5:1 (large text)
|
||||
**Niveaux d'accessibilité** :
|
||||
- **WCAG AA** : Obligatoire pour l'ensemble de la plateforme (niveau minimum)
|
||||
- **WCAG AAA** : Obligatoire pour les fonctions critiques (navigation principale, lecture audio, upload de tracks, inscription/connexion, gestion de profil)
|
||||
|
||||
**Checklist AA (toute la plateforme)** :
|
||||
- [ ] Color contrast ≥ 4.5:1 (normal text)
|
||||
- [ ] Color contrast ≥ 3:1 (large text, composants UI)
|
||||
- [ ] Keyboard navigation (Tab, Shift+Tab, Enter, Space, Arrow keys)
|
||||
- [ ] Screen reader support (ARIA labels, roles, states)
|
||||
- [ ] Focus indicators visible
|
||||
|
|
@ -686,6 +697,14 @@ Text on Background:
|
|||
- [ ] Captions for audio/video
|
||||
- [ ] Form labels and error messages
|
||||
|
||||
**Checklist AAA (fonctions critiques)** :
|
||||
- [ ] Color contrast ≥ 7:1 (normal text)
|
||||
- [ ] Color contrast ≥ 4.5:1 (large text)
|
||||
- [ ] Alternatives textuelles étendues
|
||||
- [ ] Navigation au clavier complète sans piège de focus
|
||||
- [ ] Identification cohérente des composants
|
||||
- [ ] Aide contextuelle disponible
|
||||
|
||||
### 9.2 ARIA Labels
|
||||
|
||||
```tsx
|
||||
|
|
@ -936,6 +955,100 @@ Veza Design System (Figma)
|
|||
- Consistent spacing
|
||||
- Easy maintenance
|
||||
|
||||
## 13. ANTI-PATTERNS UX INTERDITS
|
||||
|
||||
Les patterns suivants sont **strictement interdits** dans toute l'interface Veza. Ils contreviennent aux principes éthiques fondamentaux du projet.
|
||||
|
||||
### 13.1 Gamification addictive
|
||||
|
||||
| Pattern interdit | Description | Raison |
|
||||
|-----------------|-------------|--------|
|
||||
| **Barres d'XP / points** | Systèmes de points d'expérience, niveaux, progression gamifiée | Mécanisme addictif, pression psychologique |
|
||||
| **Badges de niveau** | Badges, rangs, tiers hiérarchiques entre utilisateurs | Crée des hiérarchies artificielles néfastes |
|
||||
| **Compteurs de streak** | "X jours consécutifs", séries, streaks | FOMO et culpabilisation si rupture |
|
||||
| **Classements publics** | Leaderboards, rankings entre artistes | Compétition toxique, découragement |
|
||||
| **Récompenses variables** | Loot boxes, récompenses aléatoires | Mécanismes de jeu de hasard |
|
||||
|
||||
### 13.2 Notifications push agressives
|
||||
|
||||
- Interdit : notifications non sollicitées à haute fréquence
|
||||
- Interdit : notifications de type "Vous nous manquez" / re-engagement
|
||||
- Interdit : notifications qui ne correspondent pas à une action explicite de l'utilisateur
|
||||
- Interdit : empilement de notifications pour forcer l'ouverture de l'app
|
||||
|
||||
### 13.3 FOMO (Fear Of Missing Out)
|
||||
|
||||
- Interdit : "X personnes regardent ceci en ce moment"
|
||||
- Interdit : "Dernière chance", "Offre limitée", compteurs de temps artificiels
|
||||
- Interdit : "Y personnes ont acheté ceci aujourd'hui"
|
||||
- Interdit : fausse rareté ou urgence artificielle
|
||||
|
||||
### 13.4 Social proof anxiogène
|
||||
|
||||
- Interdit : compteurs publics de followers/abonnés visibles par tous
|
||||
- Interdit : affichage public du nombre d'écoutes en temps réel comme métrique de valeur
|
||||
- Interdit : comparaisons entre artistes ("X a plus d'écoutes que vous")
|
||||
- Les métriques d'audience sont **privées**, visibles uniquement par le créateur concerné
|
||||
|
||||
### 13.5 Dark patterns dans les flows de paiement
|
||||
|
||||
- Interdit : cases pré-cochées pour abonnements ou options payantes
|
||||
- Interdit : désabonnement plus difficile que l'abonnement
|
||||
- Interdit : frais cachés révélés tardivement dans le flow
|
||||
- Interdit : "confirm-shaming" ("Non merci, je ne veux pas soutenir les artistes")
|
||||
- Interdit : renouvellement automatique sans rappel préalable clair
|
||||
|
||||
### 13.6 Auto-play et infinite scroll
|
||||
|
||||
- Interdit : auto-play de contenu audio/vidéo non sollicité
|
||||
- Interdit : lecture automatique du track suivant sans consentement explicite
|
||||
- Interdit : infinite scroll sans contrôle utilisateur (pagination ou bouton "Charger plus" requis)
|
||||
- Interdit : pré-chargement agressif de contenu pour forcer la consommation
|
||||
|
||||
## 14. PATTERNS UX POSITIFS
|
||||
|
||||
Ces patterns sont **recommandés et encouragés** pour garantir une expérience respectueuse de l'utilisateur.
|
||||
|
||||
### 14.1 Contrôle utilisateur total sur les notifications
|
||||
|
||||
- L'utilisateur choisit exactement quelles notifications il reçoit (opt-in granulaire)
|
||||
- Paramètres de fréquence configurables (immédiat, résumé quotidien, résumé hebdomadaire, désactivé)
|
||||
- Un bouton "Tout désactiver" toujours accessible
|
||||
- Respect du mode "Do Not Disturb" de l'OS : aucune notification ne doit contourner les paramètres système
|
||||
|
||||
### 14.2 Métriques privées et bienveillantes
|
||||
|
||||
- Les statistiques d'écoute, revenus et audience sont **visibles uniquement par le créateur concerné**
|
||||
- Présentation des métriques sous forme de tendances (progression personnelle) plutôt que de valeurs absolues compétitives
|
||||
- Pas de comparaison avec d'autres artistes
|
||||
- Option de masquer ses propres statistiques si le créateur le souhaite
|
||||
|
||||
### 14.3 Confirmation explicite pour actions irréversibles
|
||||
|
||||
- Dialogue de confirmation clair pour : suppression de track, suppression de compte, publication publique
|
||||
- Possibilité d'annulation (undo) pendant un délai raisonnable quand techniquement possible
|
||||
- Wording explicite décrivant les conséquences de l'action ("Cette action supprimera définitivement votre track et toutes ses statistiques")
|
||||
|
||||
### 14.4 Mode hors-ligne et faible connectivité
|
||||
|
||||
- Les tracks téléchargées restent accessibles hors-ligne
|
||||
- Indicateur clair de l'état de connectivité
|
||||
- Les actions effectuées hors-ligne sont synchronisées automatiquement au retour de la connexion
|
||||
- Dégradation gracieuse : l'interface reste fonctionnelle même avec une connexion lente (affichage progressif, placeholders)
|
||||
|
||||
### 14.5 Respect du mode "Do Not Disturb" OS
|
||||
|
||||
- L'application détecte et respecte le mode DND de l'OS
|
||||
- Aucune notification sonore ou visuelle envoyée pendant le DND
|
||||
- Les notifications en attente sont délivrées silencieusement à la fin du DND
|
||||
|
||||
### 14.6 Transparence et honnêteté
|
||||
|
||||
- Pricing affiché clairement dès le départ, sans frais cachés
|
||||
- Processus de désabonnement aussi simple que l'abonnement (max 2 clics)
|
||||
- Explication claire de l'utilisation des données personnelles
|
||||
- Aucun tracking publicitaire, aucune revente de données
|
||||
|
||||
## ✅ CHECKLIST DE VALIDATION
|
||||
|
||||
### Design System
|
||||
|
|
@ -946,11 +1059,21 @@ Veza Design System (Figma)
|
|||
- [ ] Responsive breakpoints defined
|
||||
|
||||
### Accessibility
|
||||
- [ ] WCAG AAA compliance (or AA where AAA infeasible)
|
||||
- [ ] WCAG AA compliance sur toute la plateforme
|
||||
- [ ] WCAG AAA compliance sur les fonctions critiques (navigation, lecture, upload, inscription)
|
||||
- [ ] Keyboard navigation functional
|
||||
- [ ] Screen reader tested (NVDA, JAWS, VoiceOver)
|
||||
- [ ] Focus indicators visible
|
||||
- [ ] Color contrast validated
|
||||
- [ ] Color contrast validated (AA : 4.5:1 normal, AAA : 7:1 fonctions critiques)
|
||||
|
||||
### Éthique UX
|
||||
- [ ] Aucun pattern de gamification (XP, badges, streaks, leaderboards)
|
||||
- [ ] Aucun dark pattern dans les flows de paiement/abonnement
|
||||
- [ ] Notifications opt-in uniquement, granulaires
|
||||
- [ ] Métriques privées (visibles uniquement par le créateur)
|
||||
- [ ] Aucun auto-play non sollicité
|
||||
- [ ] Aucun infinite scroll sans contrôle
|
||||
- [ ] Confirmation explicite pour actions irréversibles
|
||||
|
||||
### Performance
|
||||
- [ ] 60 FPS animations
|
||||
|
|
@ -973,7 +1096,8 @@ Veza Design System (Figma)
|
|||
- **Development Time Reduction**: > 50%
|
||||
|
||||
### Accessibility
|
||||
- **WCAG AAA Compliance**: 100% (or 95% AAA + 5% AA)
|
||||
- **WCAG AA Compliance**: 100% de la plateforme
|
||||
- **WCAG AAA Compliance**: 100% des fonctions critiques (navigation, lecture, upload, inscription)
|
||||
- **Keyboard Navigation**: 100% functional
|
||||
- **Screen Reader Support**: 100% labeled
|
||||
|
||||
|
|
@ -987,6 +1111,7 @@ Veza Design System (Figma)
|
|||
| Version | Date | Changements |
|
||||
|---------|------|-------------|
|
||||
| 1.0.0 | 2025-11-02 | Version initiale - Design system complet |
|
||||
| 2.0.0 | 2026-03-04 | Audit éthique : ajout anti-patterns UX interdits (gamification, FOMO, dark patterns), patterns UX positifs (contrôle notifications, métriques privées, mode hors-ligne), révision accessibilité WCAG AA minimum / AAA fonctions critiques |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -998,7 +1123,8 @@ Veza Design System (Figma)
|
|||
|
||||
**Document créé par**: Design Team + UX Lead
|
||||
**Date de création**: 2025-11-02
|
||||
**Prochaine révision**: Quarterly (2026-02-01)
|
||||
**Dernière révision**: 2026-03-04 (v2.0.0)
|
||||
**Prochaine révision**: Quarterly (2026-06-01)
|
||||
**Propriétaire**: Design Lead
|
||||
|
||||
**Statut**: ✅ **APPROUVÉ ET VERROUILLÉ**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
# Security (required, min 32 chars)
|
||||
SECRET_KEY=your-secret-key-minimum-32-characters-long
|
||||
# v0.9.1 RS256: path to public key (preferred); or JWT_SECRET for HS256
|
||||
# JWT_PUBLIC_KEY_PATH=/path/to/jwt-public.pem
|
||||
JWT_SECRET=your-jwt-secret-minimum-32-characters-long
|
||||
|
||||
# Internal API key for stream-events callbacks to backend (must match STREAM_SERVER_INTERNAL_API_KEY on backend)
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ impl Default for AudioProcessor {
|
|||
},
|
||||
security: crate::config::SecurityConfig {
|
||||
jwt_secret: None,
|
||||
jwt_public_key_path: None,
|
||||
jwt_expiration: Duration::from_secs(3600),
|
||||
bcrypt_cost: 10,
|
||||
rate_limit_requests_per_minute: 60,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use axum::{
|
|||
};
|
||||
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
// Note: Use tracing::debug! macro directly instead of importing
|
||||
|
|
@ -120,9 +121,13 @@ pub struct TokenValidationResult {
|
|||
|
||||
pub struct AuthManager {
|
||||
config: Arc<Config>,
|
||||
encoding_key: EncodingKey,
|
||||
decoding_key: DecodingKey,
|
||||
validation: Validation,
|
||||
encoding_key: Option<EncodingKey>,
|
||||
/// v0.9.1 RS256: verify tokens signed by backend with RSA
|
||||
decoding_key_rs256: Option<DecodingKey>,
|
||||
validation_rs256: Validation,
|
||||
/// HS256 fallback (dev / transition)
|
||||
decoding_key_hs256: Option<DecodingKey>,
|
||||
validation_hs256: Validation,
|
||||
revocation_store: Arc<dyn SessionRevocationStore>,
|
||||
}
|
||||
|
||||
|
|
@ -135,27 +140,54 @@ impl AuthManager {
|
|||
config: Arc<Config>,
|
||||
store: Arc<dyn SessionRevocationStore>,
|
||||
) -> Result<Self, AuthError> {
|
||||
let jwt_secret =
|
||||
config
|
||||
.security
|
||||
.jwt_secret
|
||||
.as_ref()
|
||||
.ok_or(AuthError::ConfigurationError(
|
||||
"JWT_SECRET not configured".to_string(),
|
||||
))?;
|
||||
let mut validation_rs256 = Validation::new(Algorithm::RS256);
|
||||
validation_rs256.set_audience(&["veza-services"]);
|
||||
validation_rs256.set_issuer(&["veza-platform"]);
|
||||
|
||||
let encoding_key = EncodingKey::from_secret(jwt_secret.as_bytes());
|
||||
let decoding_key = DecodingKey::from_secret(jwt_secret.as_bytes());
|
||||
let mut validation_hs256 = Validation::new(Algorithm::HS256);
|
||||
validation_hs256.set_audience(&["veza-services"]);
|
||||
validation_hs256.set_issuer(&["veza-platform"]);
|
||||
|
||||
let mut validation = Validation::new(Algorithm::HS256);
|
||||
validation.set_audience(&["veza-services"]);
|
||||
validation.set_issuer(&["veza-platform"]);
|
||||
let decoding_key_rs256 = config
|
||||
.security
|
||||
.jwt_public_key_path
|
||||
.as_ref()
|
||||
.map(|path| {
|
||||
let pem = fs::read_to_string(path).map_err(|e| {
|
||||
AuthError::ConfigurationError(format!(
|
||||
"Failed to read JWT public key from {}: {}",
|
||||
path, e
|
||||
))
|
||||
})?;
|
||||
DecodingKey::from_rsa_pem(pem.as_bytes()).map_err(|e| {
|
||||
AuthError::ConfigurationError(format!("Invalid RSA public key: {}", e))
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let (encoding_key, decoding_key_hs256) = if let Some(ref secret) = config.security.jwt_secret
|
||||
{
|
||||
(
|
||||
Some(EncodingKey::from_secret(secret.as_bytes())),
|
||||
Some(DecodingKey::from_secret(secret.as_bytes())),
|
||||
)
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
if decoding_key_rs256.is_none() && decoding_key_hs256.is_none() {
|
||||
return Err(AuthError::ConfigurationError(
|
||||
"JWT_PUBLIC_KEY_PATH or JWT_SECRET must be configured".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
config,
|
||||
encoding_key,
|
||||
decoding_key,
|
||||
validation,
|
||||
decoding_key_rs256,
|
||||
validation_rs256,
|
||||
decoding_key_hs256,
|
||||
validation_hs256,
|
||||
revocation_store: store,
|
||||
})
|
||||
}
|
||||
|
|
@ -202,7 +234,13 @@ impl AuthManager {
|
|||
session_id: session_id.clone(),
|
||||
};
|
||||
|
||||
let access_token = encode(&Header::default(), &claims, &self.encoding_key)
|
||||
let enc_key = self
|
||||
.encoding_key
|
||||
.as_ref()
|
||||
.ok_or(AuthError::ConfigurationError(
|
||||
"JWT_SECRET required for token generation (use RS256 for validation only)".to_string(),
|
||||
))?;
|
||||
let access_token = encode(&Header::default(), &claims, enc_key)
|
||||
.map_err(|e| AuthError::TokenGenerationError(e.to_string()))?;
|
||||
|
||||
// Refresh token avec une durée plus longue
|
||||
|
|
@ -211,50 +249,82 @@ impl AuthManager {
|
|||
..claims.clone()
|
||||
};
|
||||
|
||||
let refresh_token = encode(&Header::default(), &refresh_claims, &self.encoding_key)
|
||||
let refresh_token = encode(&Header::default(), &refresh_claims, enc_key)
|
||||
.map_err(|e| AuthError::TokenGenerationError(e.to_string()))?;
|
||||
|
||||
Ok((access_token, refresh_token))
|
||||
}
|
||||
|
||||
pub async fn validate_token(&self, token: &str) -> TokenValidationResult {
|
||||
match decode::<Claims>(token, &self.decoding_key, &self.validation) {
|
||||
Ok(token_data) => {
|
||||
let claims = token_data.claims;
|
||||
|
||||
// Vérifier si le token est révoqué
|
||||
if self.revocation_store.is_revoked(&claims.session_id).await {
|
||||
// v0.9.1: try RS256 first, then HS256 fallback
|
||||
let mut last_err = None;
|
||||
if let Some(ref key) = self.decoding_key_rs256 {
|
||||
match decode::<Claims>(token, key, &self.validation_rs256) {
|
||||
Ok(token_data) => {
|
||||
let claims = token_data.claims;
|
||||
if self.revocation_store.is_revoked(&claims.session_id).await {
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has been revoked".to_string()),
|
||||
};
|
||||
}
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
if claims.exp < now {
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has expired".to_string()),
|
||||
};
|
||||
}
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has been revoked".to_string()),
|
||||
valid: true,
|
||||
claims: Some(claims),
|
||||
error: None,
|
||||
};
|
||||
}
|
||||
|
||||
// Vérifier l'expiration
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
if claims.exp < now {
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has expired".to_string()),
|
||||
};
|
||||
}
|
||||
|
||||
TokenValidationResult {
|
||||
valid: true,
|
||||
claims: Some(claims),
|
||||
error: None,
|
||||
}
|
||||
Err(e) => last_err = Some(e.to_string()),
|
||||
}
|
||||
Err(e) => TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some(e.to_string()),
|
||||
},
|
||||
}
|
||||
if let Some(ref key) = self.decoding_key_hs256 {
|
||||
match decode::<Claims>(token, key, &self.validation_hs256) {
|
||||
Ok(token_data) => {
|
||||
let claims = token_data.claims;
|
||||
|
||||
if self.revocation_store.is_revoked(&claims.session_id).await {
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has been revoked".to_string()),
|
||||
};
|
||||
}
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
if claims.exp < now {
|
||||
return TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: Some("Token has expired".to_string()),
|
||||
};
|
||||
}
|
||||
return TokenValidationResult {
|
||||
valid: true,
|
||||
claims: Some(claims),
|
||||
error: None,
|
||||
};
|
||||
}
|
||||
Err(e) => last_err = Some(e.to_string()),
|
||||
}
|
||||
}
|
||||
TokenValidationResult {
|
||||
valid: false,
|
||||
claims: None,
|
||||
error: last_err.or_else(|| Some("No JWT verification key configured".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,8 +405,10 @@ impl Clone for AuthManager {
|
|||
Self {
|
||||
config: self.config.clone(),
|
||||
encoding_key: self.encoding_key.clone(),
|
||||
decoding_key: self.decoding_key.clone(),
|
||||
validation: self.validation.clone(),
|
||||
decoding_key_rs256: self.decoding_key_rs256.clone(),
|
||||
validation_rs256: self.validation_rs256.clone(),
|
||||
decoding_key_hs256: self.decoding_key_hs256.clone(),
|
||||
validation_hs256: self.validation_hs256.clone(),
|
||||
revocation_store: self.revocation_store.clone(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ pub struct CacheConfig {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SecurityConfig {
|
||||
pub jwt_secret: Option<String>,
|
||||
/// v0.9.1 RS256: path to RSA public key for token verification (preferred over jwt_secret)
|
||||
pub jwt_public_key_path: Option<String>,
|
||||
pub jwt_expiration: Duration,
|
||||
pub bcrypt_cost: u32,
|
||||
pub rate_limit_requests_per_minute: u32,
|
||||
|
|
@ -245,6 +247,7 @@ impl Default for Config {
|
|||
},
|
||||
security: SecurityConfig {
|
||||
jwt_secret: Some("test_jwt_secret_minimum_32_characters_long".to_string()),
|
||||
jwt_public_key_path: None,
|
||||
jwt_expiration: Duration::from_secs(3600),
|
||||
bcrypt_cost: 12,
|
||||
rate_limit_requests_per_minute: 60,
|
||||
|
|
@ -421,8 +424,17 @@ impl Config {
|
|||
},
|
||||
|
||||
security: SecurityConfig {
|
||||
// SECURITY: JWT_SECRET est REQUIS - pas de valeur par défaut
|
||||
jwt_secret: Some(require_env_min_length("JWT_SECRET", 32)),
|
||||
// v0.9.1 RS256: prefer JWT_PUBLIC_KEY_PATH; else require JWT_SECRET
|
||||
jwt_public_key_path: env::var("JWT_PUBLIC_KEY_PATH").ok().filter(|s| !s.is_empty()),
|
||||
jwt_secret: {
|
||||
let has_rs256 =
|
||||
env::var("JWT_PUBLIC_KEY_PATH").ok().filter(|s| !s.is_empty()).is_some();
|
||||
if has_rs256 {
|
||||
env::var("JWT_SECRET").ok().filter(|s| s.len() >= 32)
|
||||
} else {
|
||||
Some(require_env_min_length("JWT_SECRET", 32))
|
||||
}
|
||||
},
|
||||
jwt_expiration: Duration::from_secs(
|
||||
env::var("JWT_EXPIRATION")
|
||||
.unwrap_or_else(|_| "3600".to_string())
|
||||
|
|
@ -615,7 +627,8 @@ impl Config {
|
|||
return Err(ConfigError::WeakSecretKey);
|
||||
}
|
||||
|
||||
if self.security.jwt_secret.is_none() {
|
||||
// v0.9.1: require JWT_PUBLIC_KEY_PATH (RS256) OR JWT_SECRET (HS256)
|
||||
if self.security.jwt_public_key_path.is_none() && self.security.jwt_secret.is_none() {
|
||||
return Err(ConfigError::MissingJwtSecret);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,137 +1,842 @@
|
|||
# 🔍 AUDIT COMPLET DU MONOREPO VEZA
|
||||
# 🎯 VEZA - LISTE EXHAUSTIVE DES 300+ FONCTIONNALITÉS
|
||||
|
||||
Tu es un architecte logiciel senior spécialisé en applications web full-stack (Go, React/TypeScript, Rust). Tu dois réaliser un audit exhaustif de ce monorepo et produire un rapport structuré en deux parties.
|
||||
Liste complète et détaillée de toutes les features prévues, organisée par modules.
|
||||
|
||||
---
|
||||
|
||||
## CONTEXTE
|
||||
## 🔐 **MODULE 1 : AUTHENTIFICATION & SÉCURITÉ** (30 features)
|
||||
|
||||
Veza est une plateforme audio collaborative pour musiciens indépendants (type SoundCloud/Bandcamp + communauté + marketplace). Le monorepo contient :
|
||||
- **Backend API** : Go
|
||||
- **Frontend** : React / TypeScript
|
||||
- **Services Rust** : Chat temps réel, streaming audio
|
||||
- **Infrastructure** : Docker, éventuellement Nginx/Caddy, base(s) de données
|
||||
### 1.1 Inscription & Connexion (10)
|
||||
1. Inscription email/mot de passe
|
||||
2. Validation email après inscription
|
||||
3. Connexion email/mot de passe
|
||||
4. Connexion OAuth Google
|
||||
5. Connexion OAuth GitHub
|
||||
6. Connexion OAuth Discord
|
||||
7. Connexion OAuth Spotify
|
||||
8. Remember me (session persistante)
|
||||
9. Logout (déconnexion)
|
||||
10. Logout all devices (déconnexion globale)
|
||||
|
||||
L'objectif immédiat est d'atteindre une **version stable v0.101** (proof of concept fonctionnel). L'objectif long terme est la feature list complète de 600 fonctionnalités (document joint).
|
||||
### 1.2 Gestion Mot de Passe (8)
|
||||
11. Réinitialisation mot de passe par email
|
||||
12. Changement mot de passe (authentifié)
|
||||
13. Historique des mots de passe (empêcher réutilisation)
|
||||
14. Force du mot de passe (indicateur visuel)
|
||||
15. Politique de mots de passe configurables
|
||||
16. Expiration mot de passe (optionnel)
|
||||
17. Blocage après X tentatives échouées
|
||||
18. Notification changement mot de passe
|
||||
|
||||
### 1.3 Sécurité Avancée (12)
|
||||
19. Authentification 2FA TOTP (Google Authenticator)
|
||||
20. Authentification 2FA SMS
|
||||
21. Codes de backup 2FA
|
||||
22. Passkeys/WebAuthn support
|
||||
23. Session management (liste devices actifs)
|
||||
24. Notifications connexion inhabituelle
|
||||
25. Géolocalisation connexions
|
||||
26. Historique des connexions
|
||||
27. IP whitelisting (optionnel)
|
||||
28. Rate limiting connexion
|
||||
29. CAPTCHA anti-bot
|
||||
30. Détection tentatives bruteforce
|
||||
|
||||
---
|
||||
|
||||
## PARTIE 1 — ÉTAT DE STABILITÉ : QUE MANQUE-T-IL POUR UNE VERSION STABLE ?
|
||||
## 👤 **MODULE 2 : PROFILS & UTILISATEURS** (35 features)
|
||||
|
||||
Analyse chaque couche du projet et produis un diagnostic précis.
|
||||
### 2.1 Profil Utilisateur (15)
|
||||
31. Avatar upload
|
||||
32. Bannière profil upload
|
||||
33. Nom d'utilisateur (username unique)
|
||||
34. Nom complet
|
||||
35. Bio/description
|
||||
36. Localisation (pays/ville)
|
||||
37. Date de naissance
|
||||
38. Genre
|
||||
39. Langue préférée
|
||||
40. Fuseau horaire
|
||||
41. URL profil personnalisée (veza.app/u/username)
|
||||
42. Profil public/privé
|
||||
43. Email de contact public (optionnel)
|
||||
44. Liens réseaux sociaux (Instagram, Twitter, etc.)
|
||||
45. Badges/achievements affichés
|
||||
|
||||
### 1.1 Santé du code
|
||||
### 2.2 Rôles & Permissions (10)
|
||||
46. Rôle User (par défaut)
|
||||
47. Rôle Artist (créateur)
|
||||
48. Rôle Producer (producteur)
|
||||
49. Rôle Label (maison de disques)
|
||||
50. Rôle Formateur (éducation)
|
||||
51. Rôle Modérateur
|
||||
52. Rôle Admin
|
||||
53. Permissions granulaires par rôle
|
||||
54. Système de vérification (badge vérifié)
|
||||
55. KYC (Know Your Customer) pour vendeurs
|
||||
|
||||
Pour **chaque service/package** du monorepo :
|
||||
- Le code **compile-t-il sans erreur** ? (Go : `go build ./...`, Rust : `cargo check`, TS : `tsc --noEmit`)
|
||||
- Y a-t-il des **warnings critiques** ignorés ?
|
||||
- Y a-t-il des **imports cassés**, des modules manquants, des dépendances non résolues ?
|
||||
- Les fichiers `.env.example` ou configs nécessaires sont-ils documentés et cohérents ?
|
||||
- Y a-t-il des **TODO/FIXME/HACK** critiques dans le code ? Liste-les tous avec fichier + ligne.
|
||||
### 2.3 Paramètres Compte (10)
|
||||
56. Changer email
|
||||
57. Changer username
|
||||
58. Changer langue interface
|
||||
59. Thème clair/sombre/auto
|
||||
60. Notifications email ON/OFF
|
||||
61. Notifications push ON/OFF
|
||||
62. Notifications navigateur ON/OFF
|
||||
63. Préférences de confidentialité
|
||||
64. Préférences de visibilité profil
|
||||
65. Supprimer compte (GDPR compliant)
|
||||
|
||||
### 1.2 Points bloquants fonctionnels
|
||||
---
|
||||
|
||||
Pour chaque module central, vérifie si le **happy path** fonctionne de bout en bout :
|
||||
- **Auth** : inscription → validation email → login → refresh token → logout. Le flow complet est-il implémenté et fonctionnel ?
|
||||
- **Profils** : création profil → édition → affichage public. Des champs manquants ? Des routes non connectées au frontend ?
|
||||
- **Upload & fichiers** : upload audio → stockage → métadonnées extraites → fichier jouable. La chaîne est-elle complète ?
|
||||
- **Streaming/Lecteur** : play → pause → seek → next → queue. Le lecteur est-il fonctionnel avec de vrais fichiers ?
|
||||
- **Playlists** : CRUD complet → ajout/retrait tracks → réorganisation. Quel est l'état ?
|
||||
- **Chat** : connexion WebSocket → envoi message → réception temps réel → historique. Le service Rust est-il opérationnel ?
|
||||
- **Marketplace** : création produit → affichage catalogue → achat (même simulé). Jusqu'où va l'implémentation ?
|
||||
- **Recherche** : la recherche globale retourne-t-elle des résultats pertinents ?
|
||||
## 📁 **MODULE 3 : GESTION DE FICHIERS** (40 features)
|
||||
|
||||
Pour chaque module, classe l'état : ✅ Fonctionnel | ⚠️ Partiel (précise ce qui manque) | ❌ Non implémenté | 🔴 Cassé (précise l'erreur)
|
||||
### 3.1 Upload & Stockage (15)
|
||||
66. Upload fichier unique
|
||||
67. Upload multiple fichiers (batch)
|
||||
68. Drag & drop upload
|
||||
69. Upload par URL (import depuis lien)
|
||||
70. Upload depuis cloud (Dropbox, Drive)
|
||||
71. Progress bar upload
|
||||
72. Pause/resume upload
|
||||
73. Validation taille fichiers
|
||||
74. Validation type MIME
|
||||
75. Scan antivirus automatique
|
||||
76. Compression automatique (images)
|
||||
77. Transcoding audio automatique
|
||||
78. Génération thumbnails automatique
|
||||
79. Extraction métadonnées automatique
|
||||
80. Watermarking automatique (si activé)
|
||||
|
||||
### 1.3 Points bloquants techniques
|
||||
### 3.2 Formats Supportés (10)
|
||||
81. Audio: MP3
|
||||
82. Audio: WAV
|
||||
83. Audio: FLAC
|
||||
84. Audio: OGG
|
||||
85. Audio: AIFF
|
||||
86. Audio: M4A/AAC
|
||||
87. Archives: ZIP
|
||||
88. Archives: RAR
|
||||
89. Documents: PDF
|
||||
90. Presets: VST (.fxp, .vstpreset)
|
||||
|
||||
- **Base de données** : les migrations sont-elles à jour ? Y a-t-il des incohérences schéma vs code (structs Go, types TS) ? Des migrations en conflit ?
|
||||
- **API** : y a-t-il des endpoints définis côté backend mais non consommés côté frontend (ou vice versa) ? Liste les routes orphelines.
|
||||
- **Sécurité** : les JWT sont-ils correctement validés ? Le CORS est-il configuré ? Y a-t-il des endpoints exposés sans authentification qui ne devraient pas l'être ? Des secrets hardcodés dans le code ?
|
||||
- **Services Rust** : compilent-ils ? Les dépendances Cargo sont-elles résolues ? La communication avec le backend Go (gRPC, HTTP, WebSocket) est-elle fonctionnelle ?
|
||||
- **Docker** : les Dockerfiles buildent-ils ? Le docker-compose lance-t-il tout le stack sans erreur ? Y a-t-il des volumes, networks ou dépendances inter-services mal configurés ?
|
||||
- **Frontend** : y a-t-il des pages/composants avec des erreurs runtime ? Des routes définies mais pointant vers des composants vides ou placeholder ? Des appels API vers des endpoints inexistants ?
|
||||
- **Tests** : quel est l'état des tests existants (unit, integration, E2E Playwright) ? Combien passent, combien échouent ? Y a-t-il des tests critiques manquants ?
|
||||
- **Logs & observabilité** : les erreurs sont-elles loguées de manière exploitable ? Y a-t-il un système de health check ?
|
||||
### 3.3 Métadonnées (15)
|
||||
91. Titre track
|
||||
92. Artiste(s)
|
||||
93. Album
|
||||
94. Genre musical
|
||||
95. BPM (beats per minute)
|
||||
96. Key musicale (tonalité)
|
||||
97. Durée
|
||||
98. Date de sortie
|
||||
99. Label
|
||||
100. ISRC code
|
||||
101. Copyright info
|
||||
102. Lyrics (paroles)
|
||||
103. Cover art upload
|
||||
104. Tags personnalisés (illimités)
|
||||
105. Tags suggérés (auto-completion)
|
||||
|
||||
### 1.4 Synthèse stabilité
|
||||
---
|
||||
|
||||
## 🎵 **MODULE 4 : STREAMING AUDIO** (45 features)
|
||||
|
||||
### 4.1 Lecteur Audio (20)
|
||||
106. Play/pause
|
||||
107. Next track
|
||||
108. Previous track
|
||||
109. Seek (barre de progression)
|
||||
110. Volume control
|
||||
111. Mute/unmute
|
||||
112. Shuffle mode
|
||||
113. Repeat (off/track/playlist)
|
||||
114. Playback speed (0.5x - 2x)
|
||||
115. Crossfade entre tracks
|
||||
116. Gapless playback
|
||||
117. Visualiseur waveform
|
||||
118. Visualiseur spectrogram
|
||||
119. Visualiseur bars (equalizer)
|
||||
120. Mini-player mode
|
||||
121. Picture-in-picture (PiP)
|
||||
122. Raccourcis clavier
|
||||
123. Media Session API (contrôles OS)
|
||||
124. Chromecast support
|
||||
125. AirPlay support
|
||||
|
||||
### 4.2 File d'Attente (10)
|
||||
126. Queue management (liste)
|
||||
127. Ajouter à la queue
|
||||
128. Retirer de la queue
|
||||
129. Réorganiser queue (drag & drop)
|
||||
130. Sauvegarder queue comme playlist
|
||||
131. Vider la queue
|
||||
132. Voir historique écoute
|
||||
133. Reprendre où on s'est arrêté
|
||||
134. Queue collaborative (en groupe)
|
||||
135. Autoplay (recommandations auto)
|
||||
|
||||
### 4.3 Playlists (15)
|
||||
136. Créer playlist
|
||||
137. Éditer playlist
|
||||
138. Supprimer playlist
|
||||
139. Ajouter tracks à playlist
|
||||
140. Retirer tracks de playlist
|
||||
141. Réorganiser tracks playlist
|
||||
142. Playlist publique/privée
|
||||
143. Playlist collaborative (multi-users)
|
||||
144. Cover playlist personnalisée
|
||||
145. Description playlist
|
||||
146. Partager playlist (lien)
|
||||
147. Dupliquer playlist
|
||||
148. Fusionner playlists
|
||||
149. Exporter playlist (M3U, etc.)
|
||||
150. Playlists intelligentes (auto-update)
|
||||
|
||||
---
|
||||
|
||||
## 💬 **MODULE 5 : CHAT & MESSAGERIE** (35 features)
|
||||
|
||||
### 5.1 Chat Temps Réel (15)
|
||||
151. Messages directs 1-to-1 (DM)
|
||||
152. Salons publics (rooms)
|
||||
153. Salons privés (sur invitation)
|
||||
154. Messages de groupe (3+ personnes)
|
||||
155. Envoi de messages texte
|
||||
156. Envoi d'emojis
|
||||
157. Réactions emoji sur messages
|
||||
158. Édition de messages
|
||||
159. Suppression de messages
|
||||
160. Réponses/threads
|
||||
161. Mentions (@username)
|
||||
162. Markdown support (gras, italique, code)
|
||||
163. Envoi d'images
|
||||
164. Envoi de GIFs (Giphy integration)
|
||||
165. Partage de tracks audio
|
||||
|
||||
### 5.2 Fonctionnalités Avancées (10)
|
||||
166. Recherche dans historique
|
||||
167. Filtres de recherche (date, user, etc.)
|
||||
168. Épingler messages importants
|
||||
169. Bookmarks/favoris messages
|
||||
170. Notifications temps réel
|
||||
171. Notifications push
|
||||
172. Son de notification personnalisable
|
||||
173. Badge messages non lus
|
||||
174. Indicateur "en train d'écrire..."
|
||||
175. Read receipts (vu à...)
|
||||
|
||||
### 5.3 Présence & Statuts (10)
|
||||
176. Statut en ligne/hors ligne
|
||||
177. Statut occupé/ne pas déranger
|
||||
178. Statut personnalisé (texte + emoji)
|
||||
179. Statut automatique (AFK)
|
||||
180. Dernière activité (last seen)
|
||||
181. Liste utilisateurs en ligne par salon
|
||||
182. Mode invisible
|
||||
183. Notifications de présence
|
||||
184. Statut "en train d'écouter..." (track actuel)
|
||||
185. Rich presence (Discord-like)
|
||||
|
||||
---
|
||||
|
||||
## 👥 **MODULE 6 : SOCIAL & COMMUNAUTÉ** (40 features)
|
||||
|
||||
### 6.1 Interactions Sociales (15)
|
||||
186. Suivre utilisateur (follow)
|
||||
187. Ne plus suivre (unfollow)
|
||||
188. Liste followers
|
||||
189. Liste following
|
||||
190. Bloquer utilisateur
|
||||
191. Signaler utilisateur
|
||||
192. Recommandations de profils similaires
|
||||
193. Suggestions de suivi
|
||||
194. Demande de collaboration
|
||||
195. Inviter des amis (referral)
|
||||
196. Partage profil (lien)
|
||||
197. QR code profil
|
||||
198. Notifications de nouveaux followers
|
||||
199. Liste d'amis proches (close friends)
|
||||
200. Abonnements notifications artiste
|
||||
|
||||
### 6.2 Mur & Publications (15)
|
||||
201. Créer post texte
|
||||
202. Créer post avec image
|
||||
203. Créer post avec audio
|
||||
204. Créer post avec video
|
||||
205. Liker post
|
||||
206. Commenter post
|
||||
207. Partager post (repost)
|
||||
208. Citer post (quote)
|
||||
209. Épingler post sur profil
|
||||
210. Supprimer post
|
||||
211. Éditer post
|
||||
212. Post privé (followers only)
|
||||
213. Hashtags dans posts
|
||||
214. Trending hashtags
|
||||
215. Page d'exploration/découverte
|
||||
|
||||
### 6.3 Groupes & Communautés (10)
|
||||
216. Créer groupe
|
||||
217. Rejoindre groupe public
|
||||
218. Demander à rejoindre groupe privé
|
||||
219. Quitter groupe
|
||||
220. Inviter membres dans groupe
|
||||
221. Rôles dans groupes (admin, modo, membre)
|
||||
222. Forum de discussion par groupe
|
||||
223. Événements de groupe
|
||||
224. Fichiers partagés groupe
|
||||
225. Statistiques groupe
|
||||
|
||||
---
|
||||
|
||||
## 🛒 **MODULE 7 : MARKETPLACE** (50 features)
|
||||
|
||||
### 7.1 Produits & Catalogue (15)
|
||||
226. Créer produit (sample/beat/preset)
|
||||
227. Éditer produit
|
||||
228. Supprimer produit
|
||||
229. Upload fichiers produit
|
||||
230. Upload fichiers preview (démo)
|
||||
231. Images produit (multi)
|
||||
232. Description produit (rich text)
|
||||
233. Prix fixe
|
||||
234. Prix variable (pay what you want)
|
||||
235. Gratuit avec option donation
|
||||
236. Catégories de produits
|
||||
237. Tags produits
|
||||
238. BPM/Key dans métadonnées
|
||||
239. Genre musical
|
||||
240. Formats de fichiers (WAV, MP3, etc.)
|
||||
|
||||
### 7.2 Licences & Droits (10)
|
||||
241. Licence écoute seule (streaming)
|
||||
242. Licence personnelle (usage non-commercial)
|
||||
243. Licence commerciale (usage pro)
|
||||
244. Licence exclusive (droits complets)
|
||||
245. Licence lease (location temporaire)
|
||||
246. Licence unlimited (usage illimité)
|
||||
247. Conditions d'utilisation par licence
|
||||
248. Contrat automatique généré
|
||||
249. Signature électronique
|
||||
250. Historique des licences achetées
|
||||
|
||||
### 7.3 Achats & Paiements (15)
|
||||
251. Ajouter au panier
|
||||
252. Panier multi-produits
|
||||
253. Wishlist (liste de souhaits)
|
||||
254. Calcul automatique taxes
|
||||
255. Codes promo/réductions
|
||||
256. Checkout Stripe
|
||||
257. Paiement carte bancaire
|
||||
258. Paiement PayPal
|
||||
259. Paiement crypto (optionnel)
|
||||
260. Facture automatique
|
||||
261. Historique d'achats
|
||||
262. Re-téléchargement illimité
|
||||
263. Remboursement (sous conditions)
|
||||
264. Dispute/réclamation
|
||||
265. Support SAV
|
||||
|
||||
### 7.4 Vendeur & Analytics (10)
|
||||
266. Dashboard vendeur
|
||||
267. Statistiques de ventes
|
||||
268. Revenus en temps réel
|
||||
269. Graphiques évolution ventes
|
||||
270. Meilleurs produits
|
||||
271. Taux de conversion
|
||||
272. Avis clients (reviews)
|
||||
273. Répondre aux reviews
|
||||
274. Promotions/flash sales
|
||||
275. Payout automatique (stripe connect)
|
||||
|
||||
---
|
||||
|
||||
## 🎓 **MODULE 8 : FORMATION & ÉDUCATION** (30 features)
|
||||
|
||||
### 8.1 Catalogue de Cours (15)
|
||||
276. Liste de cours
|
||||
277. Recherche de cours
|
||||
278. Filtres (niveau, durée, genre)
|
||||
279. Catégories de cours
|
||||
280. Cours vidéo
|
||||
281. Cours texte/articles
|
||||
282. Cours audio (podcasts)
|
||||
283. Projets pratiques
|
||||
284. Quiz/évaluations
|
||||
285. Certificats de complétion
|
||||
286. Prérequis entre cours
|
||||
287. Parcours d'apprentissage
|
||||
288. Cours gratuits
|
||||
289. Cours payants
|
||||
290. Abonnement mensuel (accès illimité)
|
||||
|
||||
### 8.2 Progression & Suivi (10)
|
||||
291. Tracking progression par cours
|
||||
292. Progression globale
|
||||
293. Badges de compétences
|
||||
294. Chapitres/modules
|
||||
295. Marquer comme complété
|
||||
296. Notes personnelles
|
||||
297. Bookmarks dans vidéos
|
||||
298. Historique d'apprentissage
|
||||
299. Temps passé par cours
|
||||
300. Statistiques d'engagement
|
||||
|
||||
### 8.3 Formateurs & Création (5)
|
||||
301. Rôle formateur
|
||||
302. Upload de cours
|
||||
303. Gestion séries de cours
|
||||
304. Dashboard formateur
|
||||
305. Monétisation cours
|
||||
|
||||
---
|
||||
|
||||
## 🧰 **MODULE 9 : GESTION DE MATÉRIEL** (25 features)
|
||||
|
||||
### 9.1 Inventaire Personnel (15)
|
||||
306. Ajouter matériel
|
||||
307. Éditer matériel
|
||||
308. Supprimer matériel
|
||||
309. Catégories (synthé, interface, micro, etc.)
|
||||
310. Marque et modèle
|
||||
311. Numéro de série
|
||||
312. Date d'achat
|
||||
313. Prix d'achat
|
||||
314. Valeur actuelle estimée
|
||||
315. Photos du matériel
|
||||
316. État (neuf, bon, usé)
|
||||
317. Localisation (studio, maison)
|
||||
318. Notes personnelles
|
||||
319. Tags personnalisés
|
||||
320. Recherche dans inventaire
|
||||
|
||||
### 9.2 Garantie & Documentation (10)
|
||||
321. Date de garantie
|
||||
322. Durée de garantie
|
||||
323. Notification fin de garantie
|
||||
324. Upload facture
|
||||
325. Upload manuel PDF
|
||||
326. Liens documentation constructeur
|
||||
327. Historique SAV/réparations
|
||||
328. Notes de réparation
|
||||
329. Coût des réparations
|
||||
330. Assurance matériel
|
||||
|
||||
---
|
||||
|
||||
## ☁️ **MODULE 10 : CLOUD & STOCKAGE** (20 features)
|
||||
|
||||
### 10.1 Intégration Nextcloud (10)
|
||||
331. Connexion compte Nextcloud
|
||||
332. Synchronisation automatique
|
||||
333. Upload vers cloud
|
||||
334. Download depuis cloud
|
||||
335. Partage fichiers cloud
|
||||
336. Gestion permissions
|
||||
337. Versioning fichiers
|
||||
338. Restauration versions
|
||||
339. Snapshots ZFS
|
||||
340. Quota de stockage
|
||||
|
||||
### 10.2 Backup & Récupération (10)
|
||||
341. Backup automatique projets
|
||||
342. Backup manuel
|
||||
343. Planning backup configurable
|
||||
344. Backup incrémental
|
||||
345. Backup complet
|
||||
346. Restauration point dans le temps
|
||||
347. Historique backups
|
||||
348. Export données (GDPR)
|
||||
349. Import données
|
||||
350. Migration de compte
|
||||
|
||||
---
|
||||
|
||||
## 🔍 **MODULE 11 : RECHERCHE & DÉCOUVERTE** (30 features)
|
||||
|
||||
### 11.1 Recherche Globale (15)
|
||||
351. Recherche fulltext
|
||||
352. Recherche par catégorie
|
||||
353. Recherche tracks
|
||||
354. Recherche artistes
|
||||
355. Recherche albums
|
||||
356. Recherche playlists
|
||||
357. Recherche utilisateurs
|
||||
358. Recherche groupes
|
||||
359. Recherche cours
|
||||
360. Autocomplete suggestions
|
||||
361. Recherche phonétique
|
||||
362. Correction orthographique
|
||||
363. Recherche avancée (opérateurs booléens)
|
||||
364. Historique de recherche
|
||||
365. Recherches sauvegardées
|
||||
|
||||
### 11.2 Filtres & Tri (10)
|
||||
366. Filtre par genre
|
||||
367. Filtre par BPM range
|
||||
368. Filtre par key musicale
|
||||
369. Filtre par durée
|
||||
370. Filtre par date
|
||||
371. Filtre par popularité
|
||||
372. Filtre par prix
|
||||
373. Tri par pertinence
|
||||
374. Tri par date (récent)
|
||||
375. Tri alphabétique
|
||||
|
||||
### 11.3 Recommandations (5)
|
||||
376. Algorithme de recommandation
|
||||
377. Basé sur historique d'écoute
|
||||
378. Basé sur artistes suivis
|
||||
379. Collaborative filtering
|
||||
380. Playlists auto-générées
|
||||
|
||||
---
|
||||
|
||||
## 📊 **MODULE 12 : ANALYTICS & STATISTIQUES** (30 features)
|
||||
|
||||
### 12.1 Analytics Créateur (15)
|
||||
381. Dashboard analytics
|
||||
382. Statistiques d'écoute globales
|
||||
383. Plays par track
|
||||
384. Plays par période
|
||||
385. Durée d'écoute moyenne
|
||||
386. Taux de complétion
|
||||
387. Skip rate
|
||||
388. Localisation auditeurs (carte)
|
||||
389. Démographie auditeurs
|
||||
390. Devices utilisés (desktop/mobile)
|
||||
391. Sources de trafic
|
||||
392. Peaks d'écoute (jours/heures)
|
||||
393. Engagement (likes, comments, shares)
|
||||
394. Croissance followers
|
||||
395. Export données analytics
|
||||
|
||||
### 12.2 Analytics Vendeur (10)
|
||||
396. Revenus totaux
|
||||
397. Revenus par produit
|
||||
398. Revenus par période
|
||||
399. Nombre de ventes
|
||||
400. Taux de conversion
|
||||
401. Valeur moyenne panier
|
||||
402. Top clients
|
||||
403. Géographie des ventes
|
||||
404. Comparaison périodes
|
||||
405. Projections revenus
|
||||
|
||||
### 12.3 Analytics Admin (5)
|
||||
406. Utilisateurs actifs (DAU/MAU)
|
||||
407. Nouveaux inscrits
|
||||
408. Taux de rétention
|
||||
409. Volume de transactions
|
||||
410. Performances infrastructure
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ **MODULE 13 : ADMINISTRATION** (25 features)
|
||||
|
||||
### 13.1 Gestion Utilisateurs (10)
|
||||
411. Liste complète utilisateurs
|
||||
412. Recherche utilisateurs
|
||||
413. Filtres avancés
|
||||
414. Édition profil utilisateur
|
||||
415. Ban utilisateur
|
||||
416. Suspension temporaire
|
||||
417. Reset password utilisateur
|
||||
418. Changement de rôle
|
||||
419. Historique des actions admin
|
||||
420. Notes internes sur utilisateur
|
||||
|
||||
### 13.2 Modération Contenu (10)
|
||||
421. Queue de signalements
|
||||
422. Modération uploads
|
||||
423. Suppression contenu
|
||||
424. Validation releases
|
||||
425. Blocage contenu
|
||||
426. Copyright strike system
|
||||
427. Appeal système
|
||||
428. Templates réponses modération
|
||||
429. Attribution tâches entre modos
|
||||
430. Statistiques modération
|
||||
|
||||
### 13.3 Configuration Plateforme (5)
|
||||
431. Paramètres généraux
|
||||
432. Limites upload/storage
|
||||
433. Feature flags
|
||||
434. Maintenance mode
|
||||
435. Annonces globales
|
||||
|
||||
---
|
||||
|
||||
## 🎨 **MODULE 14 : UX/UI** (20 features)
|
||||
|
||||
### 14.1 Thèmes & Personnalisation (10)
|
||||
436. Thème clair
|
||||
437. Thème sombre
|
||||
438. Thème auto (système)
|
||||
439. Mode contraste élevé
|
||||
440. Mode compact
|
||||
441. Mode confortable
|
||||
442. Couleurs d'accent personnalisables
|
||||
443. Palette de couleurs custom
|
||||
444. Layouts personnalisables
|
||||
445. Réorganisation modules (drag & drop)
|
||||
|
||||
### 14.2 Accessibilité (10)
|
||||
446. Navigation clavier complète
|
||||
447. Screen reader support
|
||||
448. ARIA labels complets
|
||||
449. Focus visible
|
||||
450. Contraste WCAG AA
|
||||
451. Tailles de police ajustables
|
||||
452. Réduction animations (prefers-reduced-motion)
|
||||
453. Transcriptions vidéos
|
||||
454. Sous-titres générés automatiquement
|
||||
455. Mode dyslexie-friendly (police adaptée)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **MODULE 15 : FONCTIONNALITÉS AVANCÉES (FUTURE)** (45 features)
|
||||
|
||||
### 15.1 Intelligence Artificielle (15)
|
||||
456. Mastering automatique
|
||||
457. Stem separation (isoler instruments)
|
||||
458. Genre detection automatique
|
||||
459. BPM detection avancée
|
||||
460. Key detection automatique
|
||||
461. Vocal removal
|
||||
462. Denoiser audio
|
||||
463. Upscaling qualité audio
|
||||
464. Génération de tags automatique
|
||||
465. Détection similarité audio
|
||||
466. Copyright detection (Content ID)
|
||||
467. Recommendation ML avancée
|
||||
468. Voice synthesis (TTS)
|
||||
469. Auto-transcription lyrics
|
||||
470. AI mixing assistant
|
||||
|
||||
### 15.2 Livestreaming (10)
|
||||
471. Live DJ sets
|
||||
472. Live concerts
|
||||
473. Live production sessions (DAW)
|
||||
474. Multi-camera support
|
||||
475. Chat live intégré
|
||||
476. Donations/tips live
|
||||
477. VOD replay
|
||||
478. Clipping moments
|
||||
479. Stream scheduling
|
||||
480. Viewer analytics
|
||||
|
||||
### 15.3 Collaboration Temps Réel (10)
|
||||
481. DAW collaboration (Splice-like)
|
||||
482. Version control projets audio
|
||||
483. Commentaires temporels
|
||||
484. Stems sharing pour remixes
|
||||
485. Co-édition playlists
|
||||
486. Whiteboard collaboratif
|
||||
487. Video chat intégré
|
||||
488. Screen sharing
|
||||
489. Project templates partagés
|
||||
490. Collaboration workflow (approval)
|
||||
|
||||
### 15.4 Blockchain & Web3 (10)
|
||||
491. NFT minting
|
||||
492. NFT marketplace
|
||||
493. Smart contracts royalties
|
||||
494. Token $VEZA
|
||||
495. Staking rewards
|
||||
496. DAO governance
|
||||
497. On-chain licensing
|
||||
498. Royalty splits automatiques
|
||||
499. Decentralized storage (IPFS)
|
||||
500. Wallet integration (MetaMask)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **MODULE 16 : INTÉGRATIONS EXTERNES** (20 features)
|
||||
|
||||
### 16.1 Intégrations DAW (10)
|
||||
501. Ableton Link sync
|
||||
502. FL Studio integration
|
||||
503. Logic Pro integration
|
||||
504. Bitwig integration
|
||||
505. Cubase integration
|
||||
506. Pro Tools integration
|
||||
507. Reaper integration
|
||||
508. Studio One integration
|
||||
509. AudioGridder distant
|
||||
510. Plugin host cloud
|
||||
|
||||
### 16.2 Services Tiers (10)
|
||||
511. Spotify sync
|
||||
512. Apple Music sync
|
||||
513. SoundCloud import
|
||||
514. Bandcamp import
|
||||
515. YouTube upload
|
||||
516. DistroKid export
|
||||
517. CD Baby export
|
||||
518. TuneCore export
|
||||
519. Zapier webhooks
|
||||
520. IFTTT integration
|
||||
|
||||
---
|
||||
|
||||
## 📱 **MODULE 17 : APPLICATIONS NATIVES** (15 features)
|
||||
|
||||
### 17.1 Mobile Apps (10)
|
||||
521. App iOS (Swift)
|
||||
522. App Android (Kotlin)
|
||||
523. Offline mode
|
||||
524. Background playback
|
||||
525. CarPlay support
|
||||
526. Android Auto support
|
||||
527. Widget iOS
|
||||
528. Widget Android
|
||||
529. Push notifications natives
|
||||
530. Biometric login (Face ID, Touch ID)
|
||||
|
||||
### 17.2 Desktop Apps (5)
|
||||
531. App Windows (Tauri)
|
||||
532. App macOS (Tauri)
|
||||
533. App Linux (Tauri)
|
||||
534. Tray icon/menu
|
||||
535. Global shortcuts
|
||||
|
||||
---
|
||||
|
||||
## 🎮 **MODULE 18 : GAMIFICATION** (15 features)
|
||||
|
||||
### 18.1 Système XP & Niveaux (8)
|
||||
536. Points d'expérience (XP)
|
||||
537. Niveaux utilisateur
|
||||
538. Barre de progression niveau
|
||||
539. XP par actions (upload, écoute, etc.)
|
||||
540. Bonus XP événements
|
||||
541. Multiplicateurs XP
|
||||
542. Leaderboards globaux
|
||||
543. Leaderboards par catégorie
|
||||
|
||||
### 18.2 Achievements & Récompenses (7)
|
||||
544. Système d'achievements
|
||||
545. Badges collectibles
|
||||
546. Trophées rares
|
||||
547. Challenges hebdomadaires
|
||||
548. Challenges mensuels
|
||||
549. Saisons compétitives
|
||||
550. Récompenses exclusives (avatar, badge)
|
||||
|
||||
---
|
||||
|
||||
## 📧 **MODULE 19 : NOTIFICATIONS & COMMUNICATIONS** (20 features)
|
||||
|
||||
### 19.1 Notifications In-App (10)
|
||||
551. Notifications temps réel
|
||||
552. Badge compteur notifications
|
||||
553. Centre de notifications
|
||||
554. Marquer comme lu
|
||||
555. Marquer tout comme lu
|
||||
556. Filtrer par type
|
||||
557. Regroupement notifications
|
||||
558. Notifications persistantes
|
||||
559. Actions rapides (quick actions)
|
||||
560. Historique notifications (30 jours)
|
||||
|
||||
### 19.2 Emails Transactionnels (10)
|
||||
561. Email de bienvenue
|
||||
562. Email confirmation email
|
||||
563. Email reset password
|
||||
564. Email nouvelle connexion
|
||||
565. Email nouveau follower
|
||||
566. Email nouveau commentaire
|
||||
567. Email nouvel achat
|
||||
568. Email nouvelle vente
|
||||
569. Newsletter hebdomadaire (opt-in)
|
||||
570. Rapports mensuels (opt-in)
|
||||
|
||||
---
|
||||
|
||||
## 🔒 **MODULE 20 : SÉCURITÉ AVANCÉE** (15 features)
|
||||
|
||||
### 20.1 Protection & Surveillance (10)
|
||||
571. Rate limiting global
|
||||
572. Rate limiting par endpoint
|
||||
573. DDoS protection
|
||||
574. SQL injection protection
|
||||
575. XSS protection
|
||||
576. CSRF protection
|
||||
577. Clickjacking protection
|
||||
578. Content Security Policy (CSP)
|
||||
579. HSTS headers
|
||||
580. Security headers complets
|
||||
|
||||
### 20.2 Audit & Compliance (5)
|
||||
581. Audit logs complets
|
||||
582. GDPR compliance
|
||||
583. CCPA compliance
|
||||
584. SOC 2 compliance
|
||||
585. Export données utilisateur (GDPR)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ **MODULE 21 : DÉVELOPPEURS & API** (15 features)
|
||||
|
||||
### 21.1 API Publique (10)
|
||||
586. API REST complète
|
||||
587. API GraphQL
|
||||
588. Authentication API keys
|
||||
589. OAuth2 server
|
||||
590. Rate limiting API
|
||||
591. Documentation OpenAPI/Swagger
|
||||
592. SDK JavaScript
|
||||
593. SDK Python
|
||||
594. SDK Go
|
||||
595. Webhooks
|
||||
|
||||
### 21.2 Outils Développeurs (5)
|
||||
596. Sandbox environment
|
||||
597. API playground
|
||||
598. Logs API calls
|
||||
599. Analytics API usage
|
||||
600. Developer dashboard
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **RÉCAPITULATIF PAR PRIORITÉ**
|
||||
|
||||
### ✅ **TIER 0 - V1 LAUNCH (40 features)** - 3 mois
|
||||
Features 1-10, 31-45, 66-90, 106-135, 151-175, 186-200, 226-250, 351-365, 411-425, 436-450
|
||||
|
||||
### 📋 **TIER 1 - V2-V5 (150 features)** - 6-12 mois
|
||||
Features 11-30, 46-65, 91-105, 136-150, 176-185, 201-225, 251-275, 276-305, 306-330, 366-410
|
||||
|
||||
### 🔮 **TIER 2 - V6-V12 (410 features)** - 12-24 mois
|
||||
Features 426-435, 451-600
|
||||
|
||||
---
|
||||
|
||||
## 📊 **STATISTIQUES FINALES**
|
||||
|
||||
Produis une **liste ordonnée par priorité** de tous les points bloquants pour atteindre la stabilité, au format :
|
||||
```
|
||||
PRIORITÉ CRITIQUE (bloque le lancement) :
|
||||
1. [Description] — Fichier(s) concerné(s) — Effort estimé (heures)
|
||||
2. ...
|
||||
|
||||
PRIORITÉ HAUTE (dégrade l'expérience) :
|
||||
1. ...
|
||||
|
||||
PRIORITÉ MOYENNE (acceptable pour un PoC) :
|
||||
1. ...
|
||||
┌──────────────────────────────────────┐
|
||||
│ TOTAL FEATURES: 600 │
|
||||
├──────────────────────────────────────┤
|
||||
│ V1 (Launch): 40 (6.7%) │
|
||||
│ V2-V5 (Short term): 150 (25.0%) │
|
||||
│ V6-V12 (Long term): 410 (68.3%) │
|
||||
├──────────────────────────────────────┤
|
||||
│ Backend heavy: 250 (41.7%) │
|
||||
│ Frontend heavy: 200 (33.3%) │
|
||||
│ Full stack: 150 (25.0%) │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PARTIE 2 — PROGRESSION VERS L'OBJECTIF FINAL (600 FEATURES)
|
||||
## 🚀 **PROCHAINE ÉTAPE**
|
||||
|
||||
En te basant sur le document de features joint (600 fonctionnalités, 21 modules), évalue la couverture actuelle du code.
|
||||
Veux-tu que je :
|
||||
1. 📋 **Génère le fichier feature-registry.ts** avec ces 600 features ?
|
||||
2. 🏗️ **Crée les prompts Cursor** pour scaffolder tout ça ?
|
||||
3. 📊 **Fasse un planning détaillé** (roadmap sprint par sprint) ?
|
||||
4. 🎯 **Aide à prioriser** les 40 features V1 exactes ?
|
||||
|
||||
### 2.1 Matrice de couverture par module
|
||||
|
||||
Pour **chaque module** (1 à 21), produis :
|
||||
```
|
||||
## Module [N] : [Nom] — [X/Y features] ([Z%])
|
||||
|
||||
### Implémentées (backend + frontend connectés) :
|
||||
- Feature #[N] : [Nom] ✅
|
||||
|
||||
### Partiellement implémentées (backend OU frontend, pas les deux) :
|
||||
- Feature #[N] : [Nom] ⚠️ — Manque : [détail]
|
||||
|
||||
### Non implémentées :
|
||||
- Feature #[N] : [Nom] ❌
|
||||
|
||||
### Hors scope v0.101 (TIER 2 / Future) :
|
||||
- Feature #[N] : [Nom] 🔮
|
||||
```
|
||||
|
||||
### 2.2 Tableau récapitulatif
|
||||
```
|
||||
| Module | Total | ✅ Done | ⚠️ Partiel | ❌ Missing | 🔮 Future | % Done |
|
||||
|-------------------------------|-------|---------|------------|-----------|-----------|--------|
|
||||
| 1. Auth & Sécurité | 30 | ? | ? | ? | ? | ?% |
|
||||
| 2. Profils & Utilisateurs | 35 | ? | ? | ? | ? | ?% |
|
||||
| ... | | | | | | |
|
||||
| TOTAL | 600 | ? | ? | ? | ? | ?% |
|
||||
```
|
||||
|
||||
### 2.3 Écart par rapport aux tiers de priorité
|
||||
|
||||
Évalue spécifiquement :
|
||||
- **TIER 0 (V1 Launch — 40 features)** : combien sont faites ? Combien restent ? Quel effort estimé pour finir ?
|
||||
- **TIER 1 (V2-V5 — 150 features)** : combien ont déjà été commencées en avance ?
|
||||
- **TIER 2 (V6-V12 — 410 features)** : y a-t-il du code qui anticipe ces features ?
|
||||
|
||||
### 2.4 Recommandations stratégiques
|
||||
|
||||
Sur la base de ton audit :
|
||||
1. Quelles sont les **5 actions les plus impactantes** pour avancer vers la stabilité ?
|
||||
2. Y a-t-il des **choix architecturaux** qui vont poser problème à l'échelle (dette technique structurelle) ?
|
||||
3. Y a-t-il des **modules surdéveloppés** par rapport à leur priorité (effort mal alloué) ?
|
||||
4. Y a-t-il des **modules sous-développés** qui sont critiques pour le PoC ?
|
||||
5. Quelle est ton **estimation réaliste** du temps restant pour atteindre la v0.101 stable ?
|
||||
|
||||
---
|
||||
|
||||
## FORMAT DE SORTIE
|
||||
|
||||
- Sois **exhaustif et factuel** : cite les fichiers, les lignes, les erreurs exactes.
|
||||
- Ne suppose rien : si tu ne peux pas vérifier quelque chose, dis-le explicitement.
|
||||
- Utilise les émojis de statut systématiquement : ✅ ⚠️ ❌ 🔴 🔮
|
||||
- Termine par un **score global de maturité** sur 100 et une phrase de synthèse.
|
||||
- Tous les chemins de fichiers doivent être relatifs à la racine du monorepo.
|
||||
|
||||
---
|
||||
|
||||
## DOCUMENTS DE RÉFÉRENCE
|
||||
|
||||
Le document joint "LISTE EXHAUSTIVE DES 600 FONCTIONNALITÉS" contient la feature list complète organisée par modules et tiers de priorité. Utilise-le comme référence absolue pour la Partie 2.
|
||||
Dis-moi et je continue ! 💪
|
||||
Loading…
Reference in a new issue