AUDIT TECHNIQUE — VEZA MONOREPO
| Champ |
Valeur |
| Date |
2026-02-26 |
| Auditeur |
Claude 4.6 Opus — Architecte senior / Expert sécurité |
| Version analysée |
v0.803 (tag 2026-02-25) |
| Périmètre |
Go backend, Rust stream server, React frontend, Infrastructure |
| Méthodologie |
Audit statique exhaustif du code source, 6 passes parallèles |
| Classification |
Confidentiel — Usage interne |
EXECUTIVE SUMMARY
Verdict global
Veza est un projet techniquement ambitieux et remarquablement structuré pour ce qui semble être une petite équipe. Avec 435 833 LOC répartis sur 3 langages (Go, TypeScript, Rust), 26 versions taguées, ~353 features déclarées, et une infrastructure CI/CD complète, le volume de travail est impressionnant.
Cependant, l'audit révèle un décalage significatif entre l'ambition fonctionnelle et la maturité de production. Le produit n'est pas prêt pour un déploiement commercial en l'état — principalement en raison de vulnérabilités de sécurité identifiées, d'un flux OAuth cassé, et d'un ratio features/tests qui reflète une priorité donnée à la couverture fonctionnelle plutôt qu'à la robustesse.
Top 5 risques
- CRITIQUE — Le flux OAuth génère des JWT invalides qui ne passent pas l'auth middleware → OAuth login cassé
- ÉLEVÉ —
PasswordService.GenerateJWT crée des tokens sans issuer/audience/token_version → contournement potentiel si utilisé hors contexte
- ÉLEVÉ — Absence de PKCE dans le flux OAuth → vulnérable à l'interception de code d'autorisation
- ÉLEVÉ — Tokens OAuth providers stockés en clair en base → compromission des comptes liés si la DB fuite
- ÉLEVÉ — Vérification des webhooks Hyperswitch désactivable quand le secret est vide → forgery de webhooks de paiement possible
Top 5 forces
- Architecture backend exemplaire — Séparation handler/service/repository, middleware chain complète, configuration validée par environnement
- Sécurité proactive — httpOnly cookies, CSRF Redis-based, security headers complets, account lockout, bcrypt cost 12, CSP stricte
- Infrastructure CI/CD mature — 14 workflows GitHub Actions, Trivy, CodeQL, Gitleaks, govulncheck, cargo-audit, cosign signing
- Frontend bien structuré — Feature-based architecture, Zustand + TanStack Query, 306 Storybook stories, 196 MSW endpoints, Zod validation
- Ops-ready — Kubernetes manifests avec network policies, Prometheus/Grafana, External Secrets Operator, blue-green deployment
Recommandation GO / NO-GO
NO-GO pour production commerciale en l'état. GO conditionnel après correction des 5 vulnérabilités critiques/élevées (effort estimé : 2-3 jours) et validation du flux OAuth end-to-end.
1️⃣ CARTOGRAPHIE GLOBALE
1.1 Stack réelle
| Élément |
Valeur vérifiée |
Commentaire |
| Go |
1.24.0 (go.mod) |
Dernière stable, OK |
| Rust |
2021 edition, stable toolchain (rust-toolchain.toml) |
OK |
| TypeScript |
5.9.3 (package.json) |
Dernière stable, OK |
| React |
18.2.0 |
Stable, pas encore React 19 |
| Vite |
7.1.5 |
Dernière version |
| Gin |
1.11.0 |
Framework web Go, maintenu |
| Axum |
0.8 |
Framework web Rust, maintenu |
| GORM |
1.30.0 |
ORM Go, dernière version |
| SQLx |
0.8 |
Query builder Rust, runtime mode (pas offline) |
| PostgreSQL |
16-alpine |
Dernière LTS, extensions: pg_trgm, uuid-ossp |
| Redis |
7-alpine |
Dernière stable |
| RabbitMQ |
3-management-alpine |
Message queue, optionnel |
| MinIO |
S3-compatible storage |
Object storage |
| JWT |
golang-jwt/v5 (Go), jsonwebtoken 10 (Rust) |
HS256, 5 min access / 14 jours refresh |
| Paiement |
Hyperswitch (Juspay/hyper.js 2.1.0) |
SDK frontend, webhook HMAC-SHA512 |
| Streaming |
HLS réel (FFmpeg transcoding, m3u8-rs) |
Pas un stub |
| WebSocket |
coder/websocket (Go), tokio-tungstenite (Rust) |
Chat en Go, streaming en Rust |
| WebRTC |
Signalisation uniquement dans le chat store |
Pas de TURN/STUN configuré |
| CI/CD |
GitHub Actions, 14 workflows |
Complet |
| Docker |
Multi-stage, alpine, non-root |
Bonnes pratiques suivies |
| Monitoring |
Prometheus + Grafana + alerting |
Configuré et dashboardé |
1.2 Organisation du monorepo
| Dossier |
Rôle réel |
Fichiers estimés |
Couplage |
apps/web/ |
Frontend React SPA |
~2000+ |
Consomme l'API Go via REST |
veza-backend-api/ |
API REST Go — cœur du produit |
~1111 |
PostgreSQL, Redis, RabbitMQ, S3 |
veza-stream-server/ |
Serveur de streaming HLS + WebSocket |
~109 RS |
PostgreSQL, Redis, gRPC vers backend |
veza-common/ |
Bibliothèque Rust partagée |
~28 RS |
Importée par stream-server |
veza-docs/ |
Site Docusaurus |
- |
Indépendant |
packages/ |
Packages npm partagés |
- |
Workspace npm |
k8s/ |
Manifests Kubernetes |
~50+ |
Référence les images Docker |
config/ |
Configs Docker, Prometheus, Grafana |
~20 |
Référencé par docker-compose |
migrations/ |
Migrations SQL (racine) |
~90 |
Dupliqué dans veza-backend-api/migrations/ |
docs/ |
Documentation technique |
~50+ |
Indépendant |
make/ |
Modules Makefile |
~10 |
Orchestration build |
scripts/ |
Scripts utilitaires |
~10 |
Outillage |
fixtures/ |
Données de test |
- |
Tests uniquement |
loadtests/ |
Scripts de charge |
- |
Tests uniquement |
proto/ |
Définitions Protobuf |
~5 |
gRPC entre Go et Rust |
Packages orphelins identifiés :
veza-docs/ — Site Docusaurus, potentiellement non déployé (pas référencé dans CI/CD principal)
sub_task_agents/ — Documentation d'agents, pas du code
Packages fantômes identifiés :
veza-chat-server/ — ABSENT du repo malgré des mentions dans la documentation et les .cursorrules. Le chat a été migré vers le backend Go en v0.502 (confirmé dans PROJECT_STATE.md)
Duplications :
- Le dossier
migrations/ existe à la racine ET dans veza-backend-api/migrations/ — risque de désynchronisation
1.3 Métriques de taille
| Service |
LOC |
Test files |
Stories |
Ratio test/code |
| Go backend |
184 501 |
292 |
- |
~1:1.6 (élevé) |
| React frontend |
211 929 |
299 |
306 |
~1:1.4 (élevé) |
| Rust stream |
39 403 |
6 |
- |
~1:43 (faible) |
| TOTAL |
435 833 |
597 |
306 |
- |
1.4 Schémas de flux critiques
graph TB
subgraph "Auth Flow"
A[Frontend] -->|POST /auth/login| B[Go API]
B -->|Validate credentials| C[PostgreSQL]
B -->|Check lockout| D[Redis]
B -->|Set httpOnly cookies| A
A -->|Auto-send cookies| B
B -->|Verify JWT + Session| D
end
graph TB
subgraph "Upload & Playback Flow"
A[Frontend] -->|POST /uploads| B[Go API]
B -->|ClamAV scan| C[Virus Scanner]
B -->|Store file| D[MinIO S3]
B -->|Queue transcode| E[RabbitMQ]
E -->|Consume job| F[Go Worker]
F -->|FFmpeg transcode| G[HLS Segments]
G -->|Store segments| D
H[Frontend Player] -->|GET /stream/:id| I[Rust Stream Server]
I -->|Validate token| J[PostgreSQL]
I -->|Serve HLS| H
end
graph TB
subgraph "Payment Flow"
A[Frontend] -->|POST /commerce/cart/checkout| B[Go API]
B -->|Create payment| C[Hyperswitch]
C -->|Webhook| B
B -->|Verify HMAC-SHA512| D{Signature OK?}
D -->|Yes| E[Update Order]
D -->|No| F[Reject]
end
Points de défaillance unique (SPOF) identifiés :
- PostgreSQL — Pas de réplication configurée dans docker-compose. Single instance.
- Redis — Utilisé pour CSRF, rate limiting, sessions, cache, presence. Si Redis tombe, les utilisateurs sont déconnectés et ne peuvent plus faire de requêtes mutantes (CSRF fail-secure → 503).
- RabbitMQ — Optionnel (fallback in-process), bon design.
- MinIO — Storage des fichiers audio. Pas de réplication visible.
Timeouts :
- HTTP server : 30s read/write ✅
- Request middleware timeout : configuré ✅
exec.CommandContext : context-based ✅
- Redis operations : timeout configuré ✅
- External HTTP calls : à vérifier cas par cas
2️⃣ CE QUE LE PRODUIT PERMET RÉELLEMENT
2.1 Classification des features
✅ Fonctionnelles (backend + frontend + DB + MSW)
| Feature |
Backend |
Frontend |
DB |
Tests |
| Auth (register, login, JWT, refresh) |
✅ Complet |
✅ Complet |
✅ Migrations 010-020 |
✅ |
| 2FA (TOTP) |
✅ Complet |
✅ Complet |
✅ Migration MFA |
✅ |
| Sessions management |
✅ Complet |
✅ Complet |
✅ Migration 020 |
✅ |
| Track CRUD + upload |
✅ Complet |
✅ Complet |
✅ Migration 030-040 |
✅ |
| HLS Streaming |
✅ Réel (FFmpeg) |
✅ HLS.js |
✅ Migration 040 |
✅ |
| Playlists (CRUD, collab, share) |
✅ Complet |
✅ Complet |
✅ Migrations 044 |
✅ |
| Search (pg_trgm) |
✅ Complet |
✅ Complet |
✅ Migration 048-085 |
✅ |
| Notifications |
✅ Complet |
✅ Complet |
✅ Migration 047 |
✅ |
| Chat (WebSocket, Go) |
✅ Migré en Go |
✅ Complet |
✅ Migration 051+ |
✅ |
| Social (feed, posts, groups) |
✅ Complet |
✅ Complet |
✅ Migrations 069-070 |
✅ |
| Marketplace (products, orders) |
✅ Complet |
✅ Complet |
✅ Migrations + Hyperswitch |
✅ |
| Cloud Storage (files, folders, quota) |
✅ Complet |
✅ Complet |
✅ Migrations 105-106 |
✅ |
| Gear/Inventory |
✅ Complet |
✅ Complet |
✅ Migrations 076+ |
✅ |
| Analytics (creator dashboard) |
✅ Complet |
✅ Complet |
✅ Migration 081 |
✅ |
| Admin panel |
✅ Complet |
✅ Complet |
✅ |
✅ |
| Developer portal (API keys, webhooks) |
✅ Complet |
✅ Complet |
✅ Migrations 075, 082 |
✅ |
| RBAC (roles, permissions) |
✅ Complet |
✅ Complet |
✅ Migration 021 |
✅ |
| Audit logs |
✅ Complet |
✅ Admin UI |
✅ Migration 910 |
✅ |
| Feature flags (DB-backed) |
✅ Complet |
✅ Admin UI |
✅ Migration 935 |
✅ |
⚠️ Partiellement implémentées
| Feature |
État |
Détail |
| OAuth |
Backend ⚠️ |
generateJWT produit des tokens invalides (manque issuer/audience). Le flux OAuth callback est probablement cassé. |
| Live Streaming |
Backend ✅, Frontend ⚠️ |
Routes API complètes, UI existante, mais pas de serveur RTMP/WebRTC de diffusion réel |
| WebRTC Audio Calls |
Frontend store ✅ |
Signalisation dans le chat store, mais pas de TURN/STUN server configuré. P2P audio non fonctionnel en conditions réseau réelles. |
| Cloud file versioning |
✅ Backend + DB |
Frontend stories en cours (fichier modifié dans git status) |
| Stripe Connect |
Backend ✅ |
Seller onboarding, transfers, balance — mais Hyperswitch SDK côté frontend (pas Stripe Elements) |
👻 Features fantômes
| Feature |
Déclarée dans |
Réalité |
| Studio |
Anciennes versions |
Explicitement retiré du scope (FEATURE_STATUS.md) |
| Education |
Anciennes versions |
Explicitement retiré du scope |
| Gamification |
FEATURE_STATUS.md |
"MSW-only" — mocks existent, pas de backend |
| veza-chat-server (Rust) |
.cursorrules, docs |
Répertoire absent. Chat migré en Go v0.502. Documentation pas mise à jour. |
💀 Code mort identifié
| Élément |
Localisation |
LOC estimé |
PasswordService.GenerateJWT |
password_service.go:260-267 |
8 LOC — Jamais appelé hors tests |
Routes /internal/tracks/:id/stream-ready |
routes_core.go |
Marquées "deprecated" |
Routes /internal/stream-events |
routes_core.go |
Marquées "deprecated" |
TokenBlacklist service |
token_blacklist.go |
~100 LOC — Implémenté mais non connecté au middleware auth |
| Références au chat-server Rust |
.cursorrules, docs |
Documentation obsolète |
2.2 Incohérences produit/code
.cursorrules mentionne veza-chat-server avec des instructions de compilation (cargo build --release) — ce service n'existe plus depuis v0.502.
.cursorrules mentionne "Chat Server: ❌ Erreurs compilation SQLx" — service supprimé.
VERSION file dit 0.101.0 mais le projet est en v0.803 selon CHANGELOG et git tags — incohérence de versioning.
- Dockerfile dev utilise Go 1.23 mais
go.mod et Dockerfile.production utilisent Go 1.24 — incohérence de version.
3️⃣ VALIDATION FONCTIONNELLE
3.1 Couverture de tests
| Service |
Test files |
LOC test estimé |
Tests désactivés |
Commentaire |
| Go backend |
292 |
~55 000 |
~134 t.Skip |
Majorité conditionnels (infra-dependent), pas hard-disabled |
| React frontend |
299 |
~45 000 |
12 test.skip |
E2E principalement, conditionnels |
| Rust stream |
6 |
~3 000 |
0 |
Couverture très faible |
| Storybook |
306 stories |
- |
- |
Excellente couverture UI |
Points positifs :
- 897 artefacts de test au total
- Go : ratio test/code ~1:3.3 → bon
- Frontend : tests unitaires + E2E Playwright + Storybook + MSW → pipeline complet
- 196 endpoints MSW mockés → couverture quasi-totale des API calls
Points négatifs :
- Rust stream server : 6 fichiers de test pour 109 fichiers source → risque élevé de régressions
- 134 tests Go conditionnellement skippés → la couverture effective dépend de l'infrastructure de test
- Pas de tests de contrat API formalisés (pas d'OpenAPI validation automatique)
3.2 Points de rupture probables
| Scénario |
Risque |
Impact |
| Redis down |
ÉLEVÉ |
CSRF → 503 sur toutes les requêtes mutantes. Sessions non validables. Rate limiting dégradé (fallback in-memory). |
| 10K tracks pour un utilisateur |
MOYEN |
Pagination implémentée, mais ORDER BY dynamique + OFFSET peut devenir lent. Cursor-based pagination absente. |
| Fichier audio de 10GB uploadé |
FAIBLE |
Taille max validée par UploadValidator. ClamAV scanner en place. |
| 1000 WebSocket simultanées |
MOYEN |
Go chat: goroutines, devrait tenir. Rust stream: websocket.rs a un connection manager mais pas de test de charge prouvé. |
| Webhook Hyperswitch en triple |
FAIBLE |
Les orders ont des statuts idempotents. Pas de déduplication explicite par webhook ID visible. |
| Token expiré mid-session |
FAIBLE |
Refresh token flow implémenté. Axios interceptor pour auto-refresh. httpOnly cookies. |
| Migration qui échoue à moitié |
MOYEN |
Pas de transactions explicites visibles autour des migrations. Pas de BEGIN/COMMIT wrapper. |
4️⃣ AUDIT DE SÉCURITÉ
Registre des vulnérabilités
| ID |
Catégorie |
Gravité |
Fichier(s) |
Description |
Impact |
Correctif |
Effort |
| VEZA-SEC-001 |
A07 Auth |
CRITIQUE |
oauth_service.go:585-593 |
generateJWT crée un JWT sans iss, aud, token_version, session_id. Ce token échoue à la validation dans auth.go:191 (version mismatch) et possiblement auth.go:166 (claims parsing). |
OAuth login probablement non fonctionnel. Si un consommateur accepte ces tokens sans validation complète, contournement d'auth possible. |
Remplacer par un appel à JWTService.GenerateAccessToken() + GenerateRefreshToken() avec création de session. |
M |
| VEZA-SEC-002 |
A07 Auth |
ÉLEVÉ |
password_service.go:260-267 |
GenerateJWT crée un token 24h sans issuer/audience/token_version. Bien que non appelé en production (aucun appel trouvé hors tests), sa présence est un risque si un développeur l'utilise par erreur. |
Contournement potentiel des contrôles de sécurité si utilisé. |
Supprimer cette méthode ou la faire passer par JWTService. |
S |
| VEZA-SEC-003 |
A07 Auth |
ÉLEVÉ |
oauth_service.go:252 |
Pas de PKCE (Proof Key for Code Exchange) dans le flux OAuth. Authorization Code flow sans PKCE. |
Vulnérable à l'interception du code d'autorisation sur des clients publics (SPA). |
Implémenter PKCE (S256). Ajouter code_verifier / code_challenge. |
M |
| VEZA-SEC-004 |
A02 Crypto |
ÉLEVÉ |
oauth_service.go:577-579 |
access_token et refresh_token des providers OAuth stockés en clair dans federated_identities. |
Si la base est compromise, l'attaquant a accès aux comptes OAuth liés (Google, GitHub, etc.). |
Chiffrer les tokens au repos avec une clé de chiffrement séparée (AES-GCM). |
M |
| VEZA-SEC-005 |
A08 Integrity |
ÉLEVÉ |
hyperswitch/routes_webhooks.go:65-73 |
Si HyperswitchWebhookSecret est vide, la vérification de signature est sautée (log warn seulement). En dev/staging, un attaquant peut forger des webhooks de paiement. |
Création de commandes frauduleuses, confirmation de paiements non effectués. |
Rendre la vérification obligatoire dans tous les environnements, ou bloquer les webhooks si le secret n'est pas configuré. |
S |
| VEZA-SEC-006 |
A03 Injection |
MOYEN |
waveform_service.go:72,82 |
inputPath passé directement à exec.CommandContext sans appel à ValidateExecPath(). D'autres services (transcode, backup, export) l'appellent systématiquement. |
Si inputPath contient des caractères spéciaux, path traversal possible (pas command injection car pas de shell). |
Ajouter utils.ValidateExecPath(inputPath) avant les appels exec.CommandContext. |
S |
| VEZA-SEC-007 |
A04 Design |
MOYEN |
token_blacklist.go, auth.go |
Le TokenBlacklist service est implémenté (Redis-backed, SHA-256 hashed) mais n'est jamais appelé dans le middleware d'auth. La révocation repose uniquement sur TokenVersion. |
Impossible de révoquer un token spécifique — seule la révocation de tous les tokens d'un utilisateur (via token version increment) est possible. |
Connecter TokenBlacklist.IsBlacklisted() dans authenticate() après la validation JWT. |
S |
| VEZA-SEC-008 |
A04 Design |
MOYEN |
ratelimit.go:49-50 |
/auth/login et /auth/register sont exclus du rate limiter global (100 req/min par IP). Ils ont des rate limiters endpoint-spécifiques (5/15min login, 3/h register) mais pas le plafond global. |
Un attaquant peut potentiellement contourner la protection globale en ciblant ces endpoints. Les limites endpoint-spécifiques restent en place. |
Appliquer le rate limiter global en amont des rate limiters spécifiques, ou documenter le choix. |
S |
| VEZA-SEC-009 |
A02 Crypto |
FAIBLE |
config.go:293 |
CHAT_JWT_SECRET fallback au JWT_SECRET principal. Si non configuré séparément, un JWT crafté pour le chat pourrait être accepté par l'API principale (si les claims matchent). |
Escalade potentielle entre services. |
Documenter ou forcer des secrets séparés. |
S |
| VEZA-SEC-010 |
A07 Auth |
FAIBLE |
oauth_service.go |
Pas de validation whitelist pour l'URL de redirection OAuth post-callback. |
Open redirect potentiel après OAuth. |
Valider l'URL de redirection contre une whitelist de domaines autorisés. |
S |
Points de sécurité positifs (bonnes pratiques confirmées)
| Domaine |
Implémentation |
Fichier |
| Tokens |
httpOnly cookies, non accessibles depuis JS |
tokenStorage.ts (no-op class), backend sets cookies |
| Passwords |
bcrypt cost 12, min 12 chars, complexity rules, 72-byte limit enforced |
password_service.go:23,311 |
| JWT |
HS256 algorithm pinning, 5 min TTL, issuer/audience validation, token version |
jwt_service.go:126-131,37 |
| CSRF |
Redis-backed, 32-byte random, timing-safe comparison, fail-secure |
csrf.go:131,115-127 |
| CORS |
Wildcard blocked in production, credentials-aware, origin reflection |
cors.go:29,125 |
| Headers |
HSTS, CSP, X-Frame-Options DENY, COEP, COOP, CORP, Permissions-Policy |
security_headers.go |
| Rate limiting |
Multi-layer (global IP, per-endpoint, per-user), Redis with in-memory fallback |
ratelimit*.go, endpoint_limiter.go |
| Account lockout |
5 attempts / 15 min, 30 min lockout, fail-secure |
account_lockout_service.go |
| File upload |
ClamAV scanning, type validation, concurrent limiting, fail-secure (503) |
upload.go:182-197 |
| SQL |
Parameterized queries throughout, ORDER BY fields whitelisted |
user_service_search.go:147-155 |
| Exec |
ValidateExecPath() on most services, context-based exec |
utils/sanitizer.go:29-43 |
| Secrets |
No hardcoded secrets, env vars required, masking in logs |
config.go, secrets.go |
| Audit |
Comprehensive audit middleware for sensitive actions |
middleware/audit.go |
| Bypass protection |
validateNoBypassFlagsInProduction blocks CSRF_DISABLED, DISABLE_RATE_LIMIT |
config/validation.go |
| Frontend XSS |
No dangerouslySetInnerHTML, DOMPurify available, no localStorage for tokens |
Grep results |
| Docker |
Non-root users (UID 1001), minimal alpine bases, health checks |
All Dockerfiles |
5️⃣ DETTE TECHNIQUE
5.1 Registre de la dette
| Cat. |
Description |
Impact |
Fichier(s) |
Effort |
| 🔴 |
OAuth generateJWT produit des tokens invalides |
OAuth login cassé |
oauth_service.go:585 |
M |
| 🔴 |
TokenBlacklist déconnecté de l'auth |
Révocation granulaire impossible |
token_blacklist.go |
S |
| 🟠 |
Rust stream server : 6 fichiers de test pour 109 sources |
Régressions non détectées |
veza-stream-server/src/ |
L |
| 🟠 |
134 tests Go conditionnellement skippés (infra-dependent) |
Couverture effective incertaine sans CI complet |
*_test.go |
XL |
| 🟠 |
veza-chat-server référencé dans .cursorrules mais absent |
Confusion pour nouveaux développeurs |
.cursorrules |
S |
| 🟠 |
VERSION file (0.101.0) incohérent avec CHANGELOG (v0.803) |
Confusion de versioning |
VERSION |
S |
| 🟠 |
Migrations : 122 fichiers, numérotation non contiguë (001→122 puis 900→935) |
Consolidation nécessaire avant scaling de l'équipe |
migrations/ |
L |
| 🟠 |
40 fichiers Go > 500 lignes |
Complexité, maintenabilité réduite |
Voir liste section 3 |
L |
| 🟡 |
docs.go généré : 5482 lignes |
Swagger spec dans le code source, alourdit le repo |
docs/docs.go |
S |
| 🟡 |
Duplication migrations/ racine vs veza-backend-api/migrations/ |
Risque de désynchronisation |
Racine + backend |
S |
| 🟡 |
Go 1.23 dans Dockerfile dev vs 1.24 dans go.mod et Dockerfile.production |
Comportement différent dev/prod |
Dockerfiles |
S |
| 🟡 |
21 TODO/FIXME/HACK dans le codebase |
Minor mais à nettoyer |
Distribués |
S |
| 🟡 |
Pas de cursor-based pagination |
Performance dégradée sur grands datasets avec OFFSET |
Services de listing |
M |
| ⚪ |
soundcloud/ directory dans Rust stream server |
Purpose unclear, naming confusion with SoundCloud brand |
veza-stream-server/src/soundcloud/ |
S |
5.2 Quantification
| Métrique |
Go |
TypeScript |
Rust |
Total |
| LOC |
184 501 |
211 929 |
39 403 |
435 833 |
| LOC mort estimé |
~200 |
~500 (generated types) |
~3000 (generated protobuf + soundcloud) |
~3 700 |
| Fichiers de test |
292 |
299 |
6 |
597 |
| Stories |
- |
306 |
- |
306 |
| TODO/FIXME/HACK |
9 |
8 |
4 |
21 |
| Fichiers > 500 lignes |
40 (1 generated) |
20 (1 generated) |
19 (1 generated) |
79 |
| Dépendances directes |
~35 |
82 (35 prod + 47 dev) |
~60 |
177 |
5.3 Hétérogénéité Go + Rust
Le choix de Go pour le backend API et Rust pour le streaming est architecturalement justifié :
- Go excelle en HTTP/REST APIs avec GORM, handlers, middleware
- Rust est pertinent pour le traitement audio temps-réel et HLS
Cependant, le chat server Rust a été migré en Go (v0.502), validant que Rust n'était pas nécessaire pour le WebSocket chat. La réduction à 2 langages (Go + Rust stream) est rationnelle.
Le coût réel : deux toolchains, deux CI pipelines, deux sets de dépendances à maintenir. Pour une équipe < 3 devs, c'est un overhead significatif.
6️⃣ QUALITÉ ARCHITECTURALE
6.1 Monorepo
| Critère |
Évaluation |
| Outil |
Turbo 2.3.0 + npm workspaces |
| Build |
Parallélisable via Turbo, outputs cachés |
| Versioning |
Incohérent (VERSION file ≠ CHANGELOG tags) |
| Workspace |
npm workspaces, Cargo workspace partiel |
| Makefile |
Excellent — 10 modules, orchestration complète |
6.2 Frontend
| Critère |
Score |
Détail |
| Structure |
✅ |
Feature-based, clean separation |
| State |
✅ |
Zustand + TanStack Query, persist + broadcast sync |
| Data fetching |
✅ |
TanStack Query avec cache/invalidation |
| Routing |
✅ |
React Router 6.30, lazy loading, code splitting |
| Design system |
✅ |
SUMI v2.0, 207+ UI components, Tailwind + CSS tokens |
| TypeScript |
✅ |
Strict mode probable, minimal any usage |
| Storybook |
✅ |
306 stories, MSW addon, a11y addon |
| MSW |
✅ |
196 endpoints, 11 handler modules, catch-all |
| Security |
✅ |
httpOnly cookies, no dangerouslySetInnerHTML, DOMPurify, Zod validation |
| Env validation |
✅ |
Zod schema for env vars |
6.3 Backend Go
| Critère |
Score |
Détail |
| Architecture |
✅ |
Layered: handler → service → repository. Domain-driven (core/auth, core/track, core/marketplace) |
| Error handling |
✅ |
Wrapped errors, structured responses, recovery middleware |
| Middleware |
✅ |
26 middlewares, correct ordering, comprehensive coverage |
| Database |
✅ |
GORM with connection pooling, parameterized queries, 122 migrations |
| Concurrency |
✅ |
Context propagation, graceful shutdown manager, goroutine management |
| Config |
✅ |
Environment-based, validated at startup, production-specific checks |
| API versioning |
✅ |
/api/v1/ consistently |
| OpenAPI |
⚠️ |
Swagger generated (docs.go) but not validated against code automatically |
6.4 Rust Stream Server
| Critère |
Score |
Détail |
| Architecture |
✅ |
Modular (auth, streaming, transcoding, codecs, monitoring) |
| Error handling |
✅ |
Custom AppError enum, 30+ variants, IntoResponse |
| Safety |
✅ |
0 unsafe blocks, ~15 expect() only in initialization |
| Tests |
❌ |
6 test files for 109 source files — critical gap |
| Compilation |
⚠️ |
No sqlx-data.json — requires live DB for compilation check |
6.5 Base de données
| Critère |
Score |
Détail |
| Schema |
✅ |
Well-normalized, UUID primary keys, FK constraints |
| Indexes |
✅ |
pg_trgm, composite indexes, performance indexes (migration 920) |
| Migrations |
⚠️ |
122 migrations, non-contiguous numbering (1-122, 900-935), no consolidation |
| Relations |
✅ |
FK constraints, cascades in migration 930 |
| Redis usage |
✅ |
Cache, CSRF, sessions, rate limiting, presence, blacklist — well-defined roles |
6.6 Scorecard
| Dimension |
Score |
Justification |
| Architecture |
8/10 |
Excellente séparation des concerns, patterns cohérents, middleware chain exemplaire. -1 pour OAuth JWT bypass, -1 pour TokenBlacklist déconnecté. |
| Maintenabilité |
7/10 |
Code lisible, conventions respectées, 21 TODO seulement. -1 pour 79 fichiers > 500 lignes, -1 pour incohérences de version, -1 pour documentation obsolète (chat-server). |
| Sécurité |
7/10 |
Excellentes pratiques (httpOnly, bcrypt, CSRF, CSP, rate limiting). -1 pour OAuth cassé, -1 pour PKCE absent, -1 pour tokens OAuth en clair. |
| Scalabilité |
6/10 |
Architecture horizontalement scalable en théorie. -1 pour SPOF PostgreSQL/Redis, -1 pour OFFSET pagination, -1 pour 134 tests conditionnels, -1 pour Rust tests insuffisants. |
| Testabilité |
7/10 |
897 artefacts de test, pipeline complet. -1 pour Rust coverage, -1 pour tests infra-dependent, -1 pour pas de contrat API formel. |
| Opérabilité |
8/10 |
Prometheus, Grafana, alerting, structured logging, health checks, K8s manifests, blue-green. -1 pour monitoring chat non couvert, -1 pour pas de runbook opérationnel complet. |
| Vélocité dev |
7/10 |
Makefile complet, MSW, Storybook, hot reload. -1 pour 3 langages, -1 pour onboarding multi-toolchain, -1 pour documentation incohérente. |
| Maturité produit |
6/10 |
19 features opérationnelles, 5 partielles, 4 fantômes. -1 pour OAuth cassé, -1 pour WebRTC non fonctionnel, -1 pour live streaming partiel, -1 pour gamification fantôme. |
Score moyen : 7.0 / 10
7️⃣ INFRA & DEVOPS
7.1 Docker
| Critère |
Status |
| Multi-stage builds |
✅ Tous les services |
| Images de base |
✅ Alpine (Go, Rust, Node, Nginx) |
| Non-root |
✅ UID 1001 partout |
| Health checks |
✅ Configurés |
| Secrets en build args |
✅ Aucun — env vars au runtime |
| Taille optimisée |
✅ Static binaries, stripped |
| ClamAV |
⚠️ Installé dans l'image backend — augmente la taille |
7.2 CI/CD
| Critère |
Status |
| Lint |
✅ ESLint, Clippy, gofmt, go vet |
| Tests |
✅ Unit + integration + E2E + Storybook |
| Security scanning |
✅ Gitleaks, CodeQL, Trivy, govulncheck, cargo-audit, npm audit |
| Container scanning |
✅ Trivy CRITICAL/HIGH |
| SBOM |
✅ CycloneDX |
| Signing |
✅ Cosign (configurable) |
| Deployment |
✅ Blue-green via docker-compose.prod.yml |
| Environments |
✅ Dev, staging, production séparés |
| Secrets |
✅ GitHub Secrets + External Secrets Operator (Vault) |
| Pre-commit |
✅ Husky hooks (typecheck, lint, tests) |
7.3 Reproductibilité
| Critère |
Status |
| Single command build |
✅ make dev ou docker compose up |
| Lock files |
✅ go.sum, Cargo.lock, package-lock.json |
| Toolchain pinning |
✅ rust-toolchain.toml, Go version in go.mod |
| Onboarding doc |
✅ ONBOARDING.md existe |
8️⃣ PERFORMANCE & SCALABILITÉ
| Composant |
Risque |
Seuil estimé |
Mitigation |
| PostgreSQL |
N+1 queries possibles via GORM |
> 5K req/min |
GORM Preload utilisé, mais à profiler |
| Redis |
SPOF pour CSRF/sessions/rate-limit |
Si Redis down → 503 global |
Sentinelle ou cluster non configuré |
| Chat WebSocket (Go) |
Goroutine per connection |
> 5K connexions simultanées |
Goroutine-safe, mais backpressure à valider |
| Stream server |
HLS segment serving |
> 500 streams simultanés |
Rust + Tokio devrait tenir, mais 6 tests |
| File storage (MinIO) |
Single instance |
> 5TB |
Pas de réplication configurée |
| OFFSET pagination |
O(n) scan |
> 100K records |
Migrer vers cursor-based pagination |
Scalabilité horizontale :
- ✅ Backend Go : stateless (sessions en Redis), scalable
- ✅ Frontend : statique, CDN-ready
- ⚠️ Stream server : WebSocket = session affinity nécessaire
- ⚠️ Chat : WebSocket = session affinity nécessaire
- ❌ PostgreSQL : single instance, pas de sharding
- ❌ Redis : single instance
9️⃣ RISQUES BUSINESS
9.1 Verdict catégorique
| Question |
Réponse |
Justification |
| Peut-on lancer en production tel quel ? |
NON |
OAuth cassé, webhook verification optionnelle, TokenBlacklist déconnecté |
| Peut-on vendre/monétiser tel quel ? |
NON |
Flux de paiement dépend de Hyperswitch webhook non vérifié en staging. OAuth non fonctionnel empêche le social login. |
| Peut-on maintenir avec 2 devs ? |
Conditionnel |
Oui si Go + TS. Le Rust stream server est un risque si le dev Rust part. |
| Faut-il refactorer avant prod ? |
OUI |
Corriger les 5 vulnérabilités, consolider les migrations, connecter le TokenBlacklist |
| Faut-il réécrire certains services ? |
NON |
L'architecture est saine. Corrections ciblées suffisent. |
| La vélocité (353 features) est-elle un red flag ? |
Attention |
Le volume est impressionnant mais le ratio features/tests sur le Rust server et la présence de features fantômes suggèrent que certaines "features" sont des endpoints avec MSW mocks mais pas de validation E2E réelle. |
9.2 Point de vue investisseur
| Question |
Réponse |
| Le produit est-il fonctionnel ou une démo ? |
Fonctionnel pour 80% des features. Les 19 features opérationnelles ont du code backend réel, des migrations, des handlers, des services, des tests. Ce n'est pas un prototype Figma ni du mock-only. |
| Risques d'incident public ? |
Oui — les tokens OAuth providers en clair et le webhook payment non vérifié sont exploitables. Correctifs estimés à 2-3 jours. |
| Code repris par une autre équipe ? |
Oui avec 2-3 semaines d'onboarding. Architecture claire, conventions cohérentes, documentation existante. La multi-stack Go+Rust+TS nécessite des profils polyvalents. |
| Coût pour v1.0 production-ready ? |
4-8 semaines pour corrections sécurité + tests Rust + consolidation migrations + monitoring complet + load testing. |
| IP technique défendable ? |
Oui — le pipeline HLS complet (upload → transcode → streaming), le système de chat WebSocket intégré, le marketplace avec Hyperswitch, et le système d'analytics constituent une plateforme cohérente. |
| Ratio features/qualité ? |
Quantité priorisée sur la qualité pour le stream server Rust (6 tests). Backend Go et frontend React ont un bon équilibre. |
9.3 Score de rachetabilité
7/10 — Code bien structuré, architecture claire, documentation existante. Points de friction : multi-stack (3 langages), 122 migrations à comprendre, quelques incohérences documentaires.
🔟 PLAN D'ACTION PRIORISÉ
Phase 1 — Critique (semaines 1-2)
| # |
Action |
Pourquoi |
Fichiers |
Effort |
| 1 |
Corriger OAuth generateJWT — utiliser JWTService.GenerateAccessToken() + créer une session |
OAuth login cassé |
oauth_service.go:585-593, oauth_service.go:307 |
M (1-2j) |
| 2 |
Supprimer PasswordService.GenerateJWT |
Code mort à risque |
password_service.go:260-267 |
S (<1j) |
| 3 |
Rendre webhook Hyperswitch verification obligatoire dans tous les envs |
Forgery de paiement possible |
routes_webhooks.go:65-73 |
S (<1j) |
| 4 |
Connecter TokenBlacklist au middleware auth |
Révocation granulaire non fonctionnelle |
auth.go, token_blacklist.go |
S (<1j) |
| 5 |
Ajouter ValidateExecPath dans waveform_service.go |
Path traversal sur FFmpeg |
waveform_service.go:72,82 |
S (<1j) |
| 6 |
Chiffrer les tokens OAuth providers au repos |
Compromission DB = accès aux comptes liés |
oauth_service.go:577-579 |
M (1-2j) |
Phase 2 — Stabilisation (semaines 3-6)
| # |
Action |
Pourquoi |
Effort |
| 7 |
Implémenter PKCE dans le flux OAuth |
OWASP A07 compliance |
M |
| 8 |
Ajouter des tests au Rust stream server — objectif 50% coverage |
6 tests pour 109 fichiers = risque |
XL |
| 9 |
Valider l'URL de redirection OAuth contre whitelist |
Open redirect prevention |
S |
| 10 |
Harmoniser VERSION file avec les tags git |
Confusion de versioning |
S |
| 11 |
Mettre à jour .cursorrules — retirer les références au chat-server Rust |
Documentation obsolète |
S |
| 12 |
Harmoniser Go version dans tous les Dockerfiles (1.24) |
Comportement dev ≠ prod |
S |
| 13 |
Load testing du stream server sous charge (1000 connexions WebSocket) |
Pas de preuve de performance |
L |
Phase 3 — Consolidation (semaines 7-12)
| # |
Action |
Pourquoi |
Effort |
| 14 |
Consolider les migrations — squash 1-122 en un schéma initial |
122 migrations = lent au setup, risque d'erreur |
L |
| 15 |
Implémenter cursor-based pagination sur les listings à volume |
OFFSET O(n) ne scale pas |
L |
| 16 |
Configurer Redis Sentinel/Cluster pour HA |
Redis = SPOF pour auth/CSRF |
M |
| 17 |
Refactorer les 10 fichiers Go > 1000 lignes |
Complexité, maintenabilité |
L |
| 18 |
Tests de contrat API — valider OpenAPI spec contre le code |
Drift API documentation |
M |
| 19 |
Configurer PostgreSQL replication |
SPOF pour toutes les données |
L |
| 20 |
Déduplication des migrations racine vs backend |
Source unique de vérité |
S |
Phase 4 — Évolution (mois 4+)
| # |
Action |
Effort |
| 21 |
WebRTC avec TURN/STUN pour audio calls |
XL |
| 22 |
Live streaming réel (RTMP ingestion) |
XL |
| 23 |
Gamification (backend, pas juste MSW) |
L |
| 24 |
Multi-region deployment |
XL |
| 25 |
CDN pour assets audio |
M |
CONCLUSION STRATÉGIQUE
Veza est un projet techniquement solide dans sa conception mais qui souffre d'un déséquilibre classique des projets early-stage : trop de features, pas assez de profondeur sur chacune. L'architecture est saine, les patterns sont cohérents, la sécurité est proactive dans 90% des cas — mais les 10% restants contiennent des vulnérabilités exploitables.
Le backend Go est le point fort du projet : layered architecture, 292 test files, middleware chain exemplaire, configuration validée. Le frontend React est également bien structuré avec son approche Storybook-first et ses 306 stories. Le Rust stream server est le point faible : fonctionnel mais insuffisamment testé (6 fichiers de test).
Recommandation : Investir, mais conditionné à la correction des 6 actions Phase 1 (2-3 jours de travail). Le coût de mise en production complète est estimé à 4-8 semaines. Le rapport qualité/ambition est favorable pour un projet de cette taille. L'architecture ne nécessite pas de réécriture — des corrections ciblées suffisent.
La question stratégique n'est pas technique mais organisationnelle : cette vélocité est-elle soutenable ? 26 versions en quelques mois avec une petite équipe suggère soit une productivité exceptionnelle, soit une accumulation de dette invisible. L'audit montre que la dette est quantifiable et gérable (21 TODO, ~3700 LOC mortes, 79 fichiers volumineux) — ce n'est pas un projet en perdition technique, c'est un projet qui a besoin de passer du mode "sprint feature" au mode "hardening for production".