- Update PROJECT_STATE.md: v0.502 delivered, next version v0.503 - Update CHANGELOG.md: comprehensive v0.502 entry (Added/Changed/Removed/Infrastructure) - Create SMOKE_TEST_V0502.md: validation checklist for chat rewrite - Create RETROSPECTIVE_V0502.md: retrospective with metrics and action items - Archive V0_502_RELEASE_SCOPE.md to docs/archive/ - Create V0_503_RELEASE_SCOPE.md placeholder - Update SCOPE_CONTROL.md and .cursorrules to reference v0.503
336 lines
15 KiB
Markdown
336 lines
15 KiB
Markdown
# V0.502 Release Scope — Chat Server Rewrite (Rust → Go)
|
|
|
|
**Status** : En préparation
|
|
**Phase** : 5 — Streaming & Communication
|
|
**Prérequis** : v0.501 (taguée)
|
|
**ADR** : [ADR-002-chat-server.md](adr/ADR-002-chat-server.md)
|
|
|
|
---
|
|
|
|
## Objectif
|
|
|
|
Réécrire le chat server Rust (`veza-chat-server`) en Go, intégré directement dans le backend API (`veza-backend-api`). Conserver le protocole WebSocket JSON identique pour une migration transparente du frontend.
|
|
|
|
---
|
|
|
|
## État actuel (pré-v0.502)
|
|
|
|
| Composant | État |
|
|
|-----------|------|
|
|
| Chat server Rust (`veza-chat-server`) | Compile, **non intégré** (boot mode OFF) |
|
|
| Modèles Go (`Room`, `RoomMember`, `Message`) | ✅ Existants |
|
|
| Repositories Go (`RoomRepository`, `ChatRepository`) | ✅ Existants |
|
|
| Services Go (`RoomService`, `ChatService`) | ✅ Existants |
|
|
| Handlers REST Go (`/conversations/*`, `/chat/token`) | ✅ Existants |
|
|
| Frontend chat (`useChat`, `chatStore`, `ChatPage`) | ✅ Existe, utilise mocks MSW |
|
|
| Pattern WebSocket Go (`playback_websocket_handler.go`) | ✅ Référence |
|
|
| Tables DB (`rooms`, `room_members`, `messages`) | ✅ Migration 051 |
|
|
| Tables DB (`read_receipts`, `delivered_status`, `message_reactions`) | ❌ Manquantes en Go |
|
|
|
|
---
|
|
|
|
## Lots
|
|
|
|
### Lot CH1 : Chat Server Go — Backend (14 tâches)
|
|
|
|
#### CH1-01 : Migrations DB complémentaires
|
|
- **Migration 109** : `read_receipts` (user_id, message_id, read_at, index)
|
|
- **Migration 110** : `delivered_status` (user_id, message_id, delivered_at, index)
|
|
- **Migration 111** : `message_reactions` (user_id, message_id, emoji, created_at, unique constraint)
|
|
- **Migration 112** : Ajout colonnes manquantes sur `messages` : `edited_at TIMESTAMPTZ`, `status VARCHAR(20) DEFAULT 'sent'`
|
|
|
|
#### CH1-02 : Modèles Go complémentaires
|
|
- Modèle `ReadReceipt` (UserID, MessageID, ReadAt)
|
|
- Modèle `DeliveredStatus` (UserID, MessageID, DeliveredAt)
|
|
- Modèle `MessageReaction` (UserID, MessageID, Emoji, CreatedAt)
|
|
- Mise à jour modèle `Message` : ajout champs `EditedAt`, `Status`, `IsPinned`, `Metadata`
|
|
|
|
#### CH1-03 : Repository Chat GORM enrichi
|
|
- Créer `ChatMessageRepository` basé sur GORM (remplace `database/chat_repository.go` en raw SQL)
|
|
- Méthodes : `Create`, `GetByID`, `GetByRoomID` (paginé, avant/après curseur), `Update`, `SoftDelete`
|
|
- Méthodes : `Search` (ILIKE + to_tsvector), `GetSince` (pour sync)
|
|
- Méthodes : `Pin`, `Unpin`, `GetPinned`
|
|
|
|
#### CH1-04 : Repositories read/delivered/reactions
|
|
- `ReadReceiptRepository` : `MarkRead`, `GetByMessage`, `GetByConversation`
|
|
- `DeliveredStatusRepository` : `MarkDelivered`, `GetByMessage`
|
|
- `ReactionRepository` : `Add`, `Remove`, `GetByMessage`
|
|
|
|
#### CH1-05 : Service Redis PubSub
|
|
- Créer `ChatPubSubService` dans `internal/services/chat_pubsub.go`
|
|
- `Publish(roomID, message)` : publie un message JSON sur le canal `chat:room:{roomID}`
|
|
- `Subscribe(roomID)` : s'abonne au canal et retourne un channel Go
|
|
- `PublishPresence(event)` : publie sur `chat:presence`
|
|
- Fallback in-memory si Redis non disponible (dev sans Redis)
|
|
|
|
#### CH1-06 : WebSocket Hub (gestionnaire de connexions)
|
|
- Créer `internal/websocket/chat/hub.go`
|
|
- Structure `Hub` avec :
|
|
- `clients map[uuid.UUID]*Client` (userID → client)
|
|
- `rooms map[uuid.UUID]map[uuid.UUID]*Client` (roomID → userID → client)
|
|
- `register`, `unregister`, `broadcast` channels
|
|
- Goroutine `Run()` principale qui gère les événements
|
|
- Méthodes : `BroadcastToRoom(roomID, message, excludeUserID)`
|
|
- Méthodes : `SendToUser(userID, message)`
|
|
- Intégration Redis PubSub pour multi-instance
|
|
|
|
#### CH1-07 : Client WebSocket et pumps
|
|
- Créer `internal/websocket/chat/client.go`
|
|
- Structure `Client` :
|
|
- `conn *websocket.Conn`
|
|
- `userID uuid.UUID`, `username string`
|
|
- `hub *Hub`
|
|
- `send chan []byte`
|
|
- `rooms map[uuid.UUID]bool` (rooms auxquelles le client est abonné)
|
|
- Goroutine `readPump()` : lecture des messages, parsing JSON, dispatch
|
|
- Goroutine `writePump()` : écriture des messages depuis le channel `send`, ping/pong keepalive
|
|
- Timeouts : read 60s, write 10s, pong 60s
|
|
|
|
#### CH1-08 : Types de messages WebSocket Go
|
|
- Créer `internal/websocket/chat/messages.go`
|
|
- Structs Go pour chaque type de message entrant (IncomingMessage avec champ `Type` discriminant)
|
|
- Structs Go pour chaque type de message sortant (OutgoingMessage avec champ `Type` discriminant)
|
|
- Marshaling/unmarshaling JSON identique au protocole Rust existant
|
|
- Validation des messages entrants (champs requis selon le type)
|
|
|
|
#### CH1-09 : Handler WebSocket — Messages CRUD
|
|
- `handleSendMessage` : validation, persistence DB, broadcast room, Redis PubSub
|
|
- `handleEditMessage` : vérification ownership, update DB, broadcast `MessageEdited`
|
|
- `handleDeleteMessage` : vérification ownership, soft delete DB, broadcast `MessageDeleted`
|
|
|
|
#### CH1-10 : Handler WebSocket — Rooms
|
|
- `handleJoinConversation` : vérification membership, ajout au hub, broadcast présence
|
|
- `handleLeaveConversation` : retrait du hub, broadcast départ
|
|
|
|
#### CH1-11 : Handler WebSocket — Historique & Recherche
|
|
- `handleFetchHistory` : query DB paginée (before/after curseur, limit), réponse `HistoryChunk`
|
|
- `handleSearchMessages` : query ILIKE + FTS, réponse `SearchResults`
|
|
- `handleSyncMessages` : messages depuis un timestamp, réponse `SyncChunk`
|
|
|
|
#### CH1-12 : Handler WebSocket — Typing, Read, Delivered, Reactions
|
|
- `handleTyping` : broadcast `UserTyping` avec timeout 3s auto-clear
|
|
- `handleMarkAsRead` : persistence `read_receipts`, broadcast `MessageRead`
|
|
- `handleDelivered` : persistence `delivered_status`, broadcast `MessageDelivered`
|
|
- `handleAddReaction` : persistence, broadcast `ReactionAdded`
|
|
- `handleRemoveReaction` : suppression, broadcast `ReactionRemoved`
|
|
|
|
#### CH1-13 : Handler WebSocket — Signalisation WebRTC
|
|
- `handleCallOffer` : relay SDP offer au target_user_id
|
|
- `handleCallAnswer` : relay SDP answer au caller_user_id
|
|
- `handleICECandidate` : relay ICE candidate au target_user_id
|
|
- `handleCallHangup` : broadcast hangup
|
|
- `handleCallReject` : broadcast rejection
|
|
|
|
#### CH1-14 : Rate Limiting WebSocket
|
|
- Créer `internal/websocket/chat/rate_limiter.go`
|
|
- Rate limits par action et par utilisateur (Redis-backed, fallback mémoire) :
|
|
- `SendMessage` : 10/s
|
|
- `Typing` : 5/s
|
|
- `AddReaction` : 5/s
|
|
- `EditMessage` / `DeleteMessage` : 5/s
|
|
- `SearchMessages` : 2/s
|
|
- `CallSignaling` : 10/s
|
|
- Réponse `Error` si rate limit dépassé
|
|
|
|
---
|
|
|
|
### Lot CH2 : Intégration Routes & Docker (6 tâches)
|
|
|
|
#### CH2-01 : Endpoint WebSocket dans le router Go
|
|
- Ajouter route `GET /api/v1/ws` dans `router.go`
|
|
- Handler : upgrade HTTP → WebSocket avec `coder/websocket`
|
|
- Auth : extraire token du query param `?token=`, valider JWT
|
|
- Créer le client, l'enregistrer dans le Hub, lancer readPump/writePump
|
|
|
|
#### CH2-02 : Mise à jour ChatService
|
|
- Mettre à jour `GenerateToken` pour retourner le bon `WSUrl` (/api/v1/ws)
|
|
- Ajouter méthode `ValidateChatToken(tokenString) (*Claims, error)`
|
|
|
|
#### CH2-03 : Initialisation du Hub dans le backend
|
|
- Instancier le Hub au démarrage du serveur (dans `main.go` ou `router.go`)
|
|
- Injecter Redis PubSub si disponible
|
|
- Lancer `hub.Run()` en goroutine
|
|
|
|
#### CH2-04 : Suppression du chat server Rust de Docker
|
|
- Retirer le service `chat-server` de `docker-compose.yml`
|
|
- Retirer le service `chat-server` de `docker-compose.staging.yml`
|
|
- Retirer le service `chat-server` de `docker-compose.prod.yml`
|
|
- Supprimer les variables d'environnement `CHAT_SERVER_*` du backend
|
|
- Mettre à jour les healthchecks et depends_on
|
|
|
|
#### CH2-05 : Variables d'environnement
|
|
- Supprimer `VITE_WS_URL` (le WebSocket est maintenant sur le même host que l'API)
|
|
- Ou rediriger `VITE_WS_URL` vers `${VITE_API_URL}/ws` (même origin)
|
|
- Mettre à jour `.env.example`, `.env.development`
|
|
|
|
#### CH2-06 : Permissions et membership
|
|
- Créer `internal/websocket/chat/permissions.go`
|
|
- `CanRead(userID, roomID)` : vérifie membership via `room_members`
|
|
- `CanSend(userID, roomID)` : vérifie membership + non-muted + non-banned
|
|
- `CanJoin(userID, roomID)` : vérifie si room publique ou si invité
|
|
- `CanModerate(userID, roomID)` : vérifie rôle admin/moderator
|
|
|
|
---
|
|
|
|
### Lot CH3 : Frontend Migration (6 tâches)
|
|
|
|
#### CH3-01 : Mise à jour de l'URL WebSocket
|
|
- Modifier `useChat.ts` pour construire l'URL WS depuis `VITE_API_URL`
|
|
- Format : `ws(s)://{api_host}/api/v1/ws?token={token}`
|
|
- Supprimer la logique de `VITE_WS_URL` séparée
|
|
- Supprimer la vérification `127.0.0.1:8081` (dev hack)
|
|
|
|
#### CH3-02 : Mise à jour du flux d'authentification
|
|
- Modifier `useChatStore` : `setWsToken` n'a plus besoin de `wsUrl`
|
|
- Le hook `useChat` construit l'URL dynamiquement depuis le token et l'API URL
|
|
- Supprimer le champ `wsUrl` du store (ou le garder calculé)
|
|
|
|
#### CH3-03 : Mise à jour des handlers MSW
|
|
- Mettre à jour `handlers-misc.ts` : `POST /api/v1/chat/token` retourne le bon `ws_url`
|
|
- Ajouter mock pour `GET /api/v1/conversations/:id/history`
|
|
- S'assurer que le mock conversation list est compatible
|
|
|
|
#### CH3-04 : Vérification des composants Chat
|
|
- Vérifier `ChatPage.tsx`, `ChatInterface.tsx`, `ChatMessage.tsx`
|
|
- Vérifier `TypingIndicator.tsx`, `VirtualizedChatMessages`
|
|
- Vérifier que `useWebRTC.ts` (appels) fonctionne avec la nouvelle URL
|
|
- S'assurer que `EditMessage` et `DeleteMessage` sont gérés dans `handleMessage`
|
|
|
|
#### CH3-05 : Ajout types manquants
|
|
- Ajouter `EditMessage`, `DeleteMessage`, `FetchHistory`, `SearchMessages`, `SyncMessages` dans `OutgoingMessage`
|
|
- Ajouter `MessageEdited`, `MessageDeleted`, `SearchResults`, `SyncChunk` dans `IncomingMessage`
|
|
- Ajouter les handlers correspondants dans `useChat.ts` `handleMessage`
|
|
|
|
#### CH3-06 : Storybook & tests visuels
|
|
- Mettre à jour les stories chat si nécessaire
|
|
- Vérifier que `ChatPage.stories.tsx` fonctionne avec les nouveaux mocks
|
|
- Ajouter une story pour l'état "WebSocket connecting" et "WebSocket error"
|
|
|
|
---
|
|
|
|
### Lot CH4 : Tests & Validation (8 tâches)
|
|
|
|
#### CH4-01 : Tests unitaires Hub
|
|
- Test `Hub.Run()` : register/unregister clients
|
|
- Test `BroadcastToRoom` : message envoyé à tous les membres sauf l'expéditeur
|
|
- Test `SendToUser` : message ciblé
|
|
|
|
#### CH4-02 : Tests unitaires message handlers
|
|
- Test `handleSendMessage` : message persisté, broadcasté
|
|
- Test `handleEditMessage` : ownership vérifié, message mis à jour
|
|
- Test `handleDeleteMessage` : soft delete, broadcast
|
|
|
|
#### CH4-03 : Tests unitaires typing/read/reactions
|
|
- Test `handleTyping` : broadcast UserTyping
|
|
- Test `handleMarkAsRead` : read_receipt créé, broadcast
|
|
- Test `handleAddReaction` / `handleRemoveReaction`
|
|
|
|
#### CH4-04 : Tests E2E connexion WebSocket
|
|
- Test : connexion avec token valide → upgrade réussie
|
|
- Test : connexion sans token → refusée
|
|
- Test : connexion avec token expiré → refusée
|
|
- Test : ping/pong keepalive
|
|
|
|
#### CH4-05 : Tests E2E flux de messages
|
|
- Test : envoyer message → reçu par autre client dans la même room
|
|
- Test : join room → receive history
|
|
- Test : edit message → broadcast edit event
|
|
- Test : delete message → broadcast delete event
|
|
|
|
#### CH4-06 : Tests E2E real-time features
|
|
- Test : typing indicator envoyé → reçu par les autres
|
|
- Test : mark as read → broadcast read receipt
|
|
- Test : add reaction → broadcast reaction added
|
|
|
|
#### CH4-07 : Document de feature parity
|
|
- Créer `docs/CHAT_FEATURE_PARITY.md`
|
|
- Checklist : chaque feature du chat server Rust validée en Go
|
|
- Colonnes : Feature | Rust | Go | Status
|
|
|
|
#### CH4-08 : Tests de performance
|
|
- Benchmark : 100 connexions simultanées
|
|
- Benchmark : latence message delivery < 100ms
|
|
- Benchmark : mémoire par connexion
|
|
|
|
---
|
|
|
|
## Fichiers impactés
|
|
|
|
### Nouveaux fichiers Go
|
|
|
|
| Fichier | Contenu |
|
|
|---------|---------|
|
|
| `migrations/109_read_receipts.sql` | Table read_receipts |
|
|
| `migrations/110_delivered_status.sql` | Table delivered_status |
|
|
| `migrations/111_message_reactions.sql` | Table message_reactions |
|
|
| `migrations/112_messages_extra_columns.sql` | Colonnes edited_at, status sur messages |
|
|
| `internal/models/read_receipt.go` | Modèle ReadReceipt |
|
|
| `internal/models/delivered_status.go` | Modèle DeliveredStatus |
|
|
| `internal/models/message_reaction.go` | Modèle MessageReaction |
|
|
| `internal/repositories/chat_message_repository.go` | Repository GORM pour messages |
|
|
| `internal/repositories/read_receipt_repository.go` | Repository read receipts |
|
|
| `internal/repositories/delivered_status_repository.go` | Repository delivered status |
|
|
| `internal/repositories/reaction_repository.go` | Repository reactions |
|
|
| `internal/services/chat_pubsub.go` | Service Redis PubSub |
|
|
| `internal/websocket/chat/hub.go` | Hub WebSocket (gestionnaire de connexions) |
|
|
| `internal/websocket/chat/client.go` | Client WebSocket (readPump/writePump) |
|
|
| `internal/websocket/chat/messages.go` | Types de messages JSON |
|
|
| `internal/websocket/chat/handler.go` | Dispatch des messages |
|
|
| `internal/websocket/chat/handler_messages.go` | Send/Edit/Delete message |
|
|
| `internal/websocket/chat/handler_rooms.go` | Join/Leave conversation |
|
|
| `internal/websocket/chat/handler_history.go` | History/Search/Sync |
|
|
| `internal/websocket/chat/handler_realtime.go` | Typing/Read/Delivered/Reactions |
|
|
| `internal/websocket/chat/handler_calls.go` | WebRTC signaling |
|
|
| `internal/websocket/chat/permissions.go` | Permission checks |
|
|
| `internal/websocket/chat/rate_limiter.go` | Rate limiting |
|
|
|
|
### Fichiers modifiés
|
|
|
|
| Fichier | Modification |
|
|
|---------|-------------|
|
|
| `internal/models/message.go` | Ajout EditedAt, Status, IsPinned, Metadata |
|
|
| `internal/services/chat_service.go` | WSUrl mis à jour, ValidateChatToken |
|
|
| `internal/api/router.go` | Route /ws, initialisation Hub |
|
|
| `docker-compose.yml` | Suppression service chat-server |
|
|
| `docker-compose.staging.yml` | Suppression service chat-server |
|
|
| `docker-compose.prod.yml` | Suppression service chat-server |
|
|
|
|
### Fichiers frontend modifiés
|
|
|
|
| Fichier | Modification |
|
|
|---------|-------------|
|
|
| `apps/web/src/features/chat/hooks/useChat.ts` | URL WS, auth flow, types manquants |
|
|
| `apps/web/src/features/chat/types/index.ts` | Types Edit/Delete/Search/Sync |
|
|
| `apps/web/src/features/chat/store/chatStore.ts` | Suppression wsUrl, ajout handlers |
|
|
| `apps/web/src/mocks/handlers-misc.ts` | Mocks chat mis à jour |
|
|
|
|
---
|
|
|
|
## Critères d'acceptance
|
|
|
|
- [ ] Toutes les features du chat server Rust fonctionnent avec le server Go
|
|
- [ ] Protocole WebSocket JSON identique (0 changement frontend sémantique)
|
|
- [ ] Latence de livraison des messages < 100ms
|
|
- [ ] Rate limiting fonctionnel par utilisateur et par action
|
|
- [ ] Read receipts et delivered status persistés en DB
|
|
- [ ] Réactions persistées avec broadcast temps réel
|
|
- [ ] Typing indicators avec auto-clear 3s
|
|
- [ ] Signalisation WebRTC (appels 1-to-1) fonctionnelle
|
|
- [ ] Redis PubSub pour broadcasting multi-instance
|
|
- [ ] Chat server Rust supprimé de Docker Compose
|
|
- [ ] Tests E2E pour connexion, messages, typing, reactions
|
|
- [ ] Document de feature parity validé
|
|
- [ ] Go backend compile sans erreur
|
|
- [ ] Frontend TypeScript compile sans erreur
|
|
- [ ] Storybook sans erreur réseau/console
|
|
|
|
---
|
|
|
|
## Hors scope v0.502
|
|
|
|
- Chat groupé multi-room UI (refonte UX) → v0.503
|
|
- Fichier upload dans le chat (images, audio inline) → v0.503
|
|
- Notifications push pour messages chat → v0.503
|
|
- Modération avancée (sanctions, bans, mutes depuis UI) → v0.503
|
|
- Message threading UI (réponses imbriquées) → v0.503
|
|
- Recherche full-text avancée dans le chat → v0.503
|