veza/docs/archive/V0_502_RELEASE_SCOPE.md
senke 40883aebea docs(v0.502): Sprint 6 -- finalization, docs, and tag
- 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
2026-02-22 20:51:55 +01:00

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