- Create ADR-002-chat-server.md: decision to rewrite Rust chat in Go - Rewrite V0_502_RELEASE_SCOPE.md with 4 detailed lots (34 tasks) - Create PLAN_V0_502_IMPLEMENTATION.md with 6 sprints and commit instructions - Update .cursorrules scope reference for v0.502
6 KiB
ADR-002 : Réécriture du Chat Server Rust → Go
Date : 2026-02-22 Statut : Accepté Décideurs : Équipe technique Veza Réf. scope : V0_502_RELEASE_SCOPE.md
Contexte
Le chat server actuel (veza-chat-server) est implémenté en Rust avec :
- Axum 0.8 pour le serveur HTTP et WebSocket
- SQLx 0.8 pour la persistence PostgreSQL
- Tokio-tungstenite pour les connexions WebSocket
- Lapin 2.3 pour RabbitMQ (non utilisé en production)
- Tonic 0.11 / Prost 0.12 pour gRPC (stub, jamais intégré)
Le serveur compile mais n'est pas intégré en production :
- Boot mode OFF dans Docker Compose
- Le frontend utilise des mocks MSW pour le chat
- L'authentification WebSocket est cassée (
TokenStorage.getAccessToken()retournenull) - gRPC et RabbitMQ ne sont pas utilisés
Par ailleurs, le backend Go possède déjà :
- Des modèles GORM pour
Room,RoomMember,Message - Un
RoomRepositoryet unChatRepository(raw SQL) - Un
RoomServiceavec CRUD complet - Un
RoomHandleravec routes REST/conversations/* - Un
ChatServiceavec génération de token JWT - Un pattern WebSocket fonctionnel (
playback_websocket_handler.goaveccoder/websocket)
Décision
Réécrire le chat server en Go, intégré directement dans le backend API existant (veza-backend-api).
Approche retenue
Ajouter un handler WebSocket Go au backend existant plutôt que de maintenir un service Rust séparé.
Justification
1. Complexité injustifiée
Le chat server Rust introduit un second langage, un second runtime, des dépendances séparées (SQLx vs GORM, Axum vs Gin) pour une fonctionnalité qui ne requiert pas les performances extrêmes de Rust. Le chat textuel est I/O-bound, pas CPU-bound.
2. Duplication de l'infrastructure
- Deux systèmes d'authentification JWT (Go + Rust) à maintenir en synchronisation
- Deux connexions PostgreSQL séparées pour les mêmes tables
- Deux systèmes de logging, monitoring et configuration
3. Pattern existant en Go
Le playback_websocket_handler.go démontre que Go avec coder/websocket gère efficacement les connexions WebSocket. Le pattern Client/Hub avec goroutines readPump/writePump est éprouvé.
4. Modèles et repositories existants
Les modèles Room, RoomMember, Message et les repositories GORM sont déjà implémentés côté Go. Le chat server Go peut les réutiliser directement.
5. Simplification opérationnelle
Un seul binaire à déployer, monitorer et scaler. Pas de coordination inter-services pour le chat.
Conséquences
Positives
- Un seul langage pour le backend (Go) — maintenance simplifiée
- Réutilisation des modèles, repositories, middleware auth existants
- Authentification unifiée — même JWT, même middleware
- Déploiement simplifié — un seul conteneur pour API + WebSocket
- Monitoring unifié — un seul jeu de métriques Prometheus
Négatives
- Effort de développement : réécriture complète du handler WebSocket (~1200 LOC Rust → Go)
- Migration frontend : changement d'URL WebSocket et potentiels ajustements de protocole
- Pas de séparation des responsabilités : le backend Go grossit
Risques mitigés
| Risque | Mitigation |
|---|---|
| Performance WebSocket Go | Benchmark : Go gère 10k+ connexions WS sans problème pour du chat textuel |
| Régression fonctionnelle | Feature parity checklist + tests E2E avant la migration |
| Downtime pendant migration | Frontend pointe vers la nouvelle URL via variable d'environnement |
Spécifications techniques
Protocole WebSocket
Le protocole JSON existant est conservé tel quel pour assurer la compatibilité frontend :
Messages entrants (client → serveur) :
SendMessage,EditMessage,DeleteMessageJoinConversation,LeaveConversationMarkAsRead,Delivered,TypingAddReaction,RemoveReactionFetchHistory,SearchMessages,SyncMessagesCallOffer,CallAnswer,ICECandidate,CallHangup,CallRejectPing
Messages sortants (serveur → client) :
NewMessage,MessageEdited,MessageDeletedUserTyping,MessageRead,MessageDeliveredReactionAdded,ReactionRemovedHistoryChunk,SearchResults,SyncChunkCallOffer,CallAnswer,ICECandidate,CallHangup,CallRejectedActionConfirmed,Error,Pong
Endpoint WebSocket
GET /api/v1/ws?token={jwt_token}
Authentification
- Token JWT généré via
POST /api/v1/chat/token(existant) - Validé par le même middleware JWT que le backend Go
- Claims :
sub(user_id),name(username),aud("veza-chat"),exp
Persistence
- GORM avec les modèles existants (
Room,RoomMember,Message) - Nouvelles tables :
read_receipts,delivered_status,message_reactions
Broadcasting multi-instance
- Redis PubSub pour synchroniser les messages entre instances Go
- Canal par room :
chat:room:{room_id} - Canal global :
chat:presence
Alternatives considérées
A. Corriger le chat server Rust existant
Rejeté : nécessiterait de résoudre l'intégration gRPC, la synchronisation JWT, et la maintenance d'un second langage. Effort comparable à la réécriture en Go avec un résultat moins maintenable.
B. Utiliser un service chat tiers (Stream, Ably)
Rejeté : coût récurrent, dépendance externe, données hors contrôle. Non aligné avec la philosophie self-hosted de Veza.
C. Garder Rust mais simplifier (supprimer gRPC, RabbitMQ)
Rejeté : reste un second langage à maintenir, duplication JWT et DB connections.
Références
- ADR-001-rust-services.md — Architecture initiale Go + Rust + React
- V0_502_RELEASE_SCOPE.md — Scope de la réécriture
veza-chat-server/src/websocket/handler.rs— Handler WebSocket Rust à remplacerveza-backend-api/internal/handlers/playback_websocket_handler.go— Pattern WebSocket Go de référence