913 lines
58 KiB
Markdown
913 lines
58 KiB
Markdown
# 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.
|
|
|