From 40883aebea869b8776ed2b855796a22daed0be0e Mon Sep 17 00:00:00 2001 From: senke Date: Sun, 22 Feb 2026 20:51:55 +0100 Subject: [PATCH] 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 --- .cursorrules | 8 +- CHANGELOG.md | 37 +++ docs/PROJECT_STATE.md | 22 +- docs/RETROSPECTIVE_V0502.md | 41 ++++ docs/SCOPE_CONTROL.md | 12 +- docs/SMOKE_TEST_V0502.md | 44 ++++ docs/V0_503_RELEASE_SCOPE.md | 22 ++ docs/archive/V0_502_RELEASE_SCOPE.md | 336 +++++++++++++++++++++++++++ 8 files changed, 508 insertions(+), 14 deletions(-) create mode 100644 docs/RETROSPECTIVE_V0502.md create mode 100644 docs/SMOKE_TEST_V0502.md create mode 100644 docs/V0_503_RELEASE_SCOPE.md create mode 100644 docs/archive/V0_502_RELEASE_SCOPE.md diff --git a/.cursorrules b/.cursorrules index 99f86b7cd..c195402c8 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,10 +1,10 @@ # Règles de Développement UI - Projet SaaS -## 0. Scope v0.502 (priorité absolue) +## 0. Scope v0.503 (priorité absolue) -- **Référence** : `docs/V0_502_RELEASE_SCOPE.md` et `docs/SCOPE_CONTROL.md` -- Avant toute modification : vérifier si le changement est **dans le scope v0.502** -- **Autorisé v0.502** : lots CH1 (Chat Server Go — WebSocket hub, handlers, Redis PubSub, rate limiting), CH2 (Routes & Docker — endpoint WS, suppression Rust), CH3 (Frontend Migration — useChat, store, types, MSW), CH4 (Tests & Validation — E2E, feature parity) +- **Référence** : `docs/V0_503_RELEASE_SCOPE.md` et `docs/SCOPE_CONTROL.md` +- Avant toute modification : vérifier si le changement est **dans le scope v0.503** +- **Autorisé v0.503** : à définir (voir V0_503_RELEASE_SCOPE.md) - **Interdit** : nouvelles routes/pages hors scope, nouvelles dépendances (sauf correctif sécurité) - En cas de doute : ne pas ajouter. Créer une issue pour une version ultérieure. diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aca1bfca..1563f0d25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog - Veza +## [v0.502] - 2026-02-22 + +### Added +- **Chat Server (Go)**: Full WebSocket chat server integrated into veza-backend-api at `/api/v1/ws` +- **WebSocket Hub**: Client management with room-based broadcasting and user indexing +- **Message Handlers**: SendMessage, EditMessage, DeleteMessage with ownership checks +- **Room Handlers**: JoinConversation, LeaveConversation with permission enforcement +- **History/Search/Sync**: Cursor-based FetchHistory, ILIKE SearchMessages, SyncMessages +- **Real-time Features**: Typing indicators, read receipts, delivered status, message reactions +- **WebRTC Signaling**: CallOffer, CallAnswer, ICECandidate, CallHangup, CallReject relay +- **PermissionService**: CanRead, CanSend, CanJoin, CanModerate based on room_members +- **RateLimiter**: Per-user per-action sliding window (in-memory) +- **ChatPubSubService**: Redis PubSub for multi-instance broadcasting with in-memory fallback +- **4 database migrations** (109-112): read_receipts, delivered_status, message_reactions, messages extra columns +- **3 new GORM models**: ReadReceipt, DeliveredStatus, MessageReaction +- **ChatMessageRepository enriched**: cursor pagination, search, soft delete +- **ValidateChatToken**: JWT validation for WebSocket authentication +- **15 unit tests**: Hub, message handlers, real-time handlers +- **CHAT_FEATURE_PARITY.md**: 25-feature checklist (all OK or IMPROVED vs Rust) + +### Changed +- Frontend env.ts: WS_URL auto-derived from API_URL (no separate VITE_WS_URL needed) +- Frontend types/index.ts: Added EditMessage, DeleteMessage, FetchHistory, SearchMessages, SyncMessages, MessageEdited, MessageDeleted, SearchResults, SyncChunk +- MSW handler: chat/token returns ws_url: '/api/v1/ws' +- WSUrl in ChatService.GenerateToken changed from `/ws` to `/api/v1/ws` + +### Removed +- **Rust chat server** (`veza-chat-server`) removed from docker-compose.yml, staging.yml, prod.yml +- VITE_WS_URL environment variable from Docker frontend configs (auto-derived) +- Dev hack for `127.0.0.1:8081` in useChat.ts + +### Infrastructure +- Docker: Single backend binary serves both REST API and Chat WebSocket +- Redis PubSub: Enables horizontal scaling of chat (improvement over single-instance Rust) + +--- + ## [v0.501] - 2026-02-22 ### Added diff --git a/docs/PROJECT_STATE.md b/docs/PROJECT_STATE.md index dd0a99ee1..71025c99b 100644 --- a/docs/PROJECT_STATE.md +++ b/docs/PROJECT_STATE.md @@ -8,10 +8,10 @@ | Élément | Valeur | |---------|--------| -| **Dernier tag** | v0.501 | +| **Dernier tag** | v0.502 | | **Branche courante** | `main` | -| **Phase** | Phase 5 Streaming & Cloud — v0.501 livrée | -| **Prochaine version** | v0.502 | +| **Phase** | Phase 5 Streaming & Communication — v0.502 livrée | +| **Prochaine version** | v0.503 | --- @@ -73,6 +73,18 @@ - Infra : MinIO S3-compatible (dev, staging, prod), 6 migrations (103–108) - Sécurité : Trivy container scanning CI +### v0.502 (Phase 5 Communication — Chat Server Rewrite) +- Chat Server Rust → Go : WebSocket intégré dans veza-backend-api (`/api/v1/ws`) +- Hub/Client avec goroutines readPump/writePump, 30s ping keepalive +- 18 types messages entrants, 20 types sortants (protocole identique au Rust) +- Handlers : SendMessage, EditMessage, DeleteMessage, JoinConversation, LeaveConversation, FetchHistory, SearchMessages, SyncMessages, Typing, MarkAsRead, Delivered, AddReaction, RemoveReaction, WebRTC signaling (5 types) +- PermissionService (room_members), RateLimiter (per-user per-action) +- ChatPubSubService (Redis PubSub + fallback in-memory) +- 4 nouvelles migrations (109–112), 3 modèles GORM, 4 repositories enrichis +- Docker : suppression chat-server Rust de docker-compose.yml, staging.yml, prod.yml +- Frontend : dérivation WS_URL depuis API_URL, types TS mis à jour, MSW mis à jour +- 15 tests unitaires Go, E2E tests intégration, CHAT_FEATURE_PARITY.md (25/25 OK) + --- ## 3. Prochaines étapes @@ -137,7 +149,9 @@ | [PLAN_V0_402_IMPLEMENTATION.md](PLAN_V0_402_IMPLEMENTATION.md) | Plan d'implémentation v0.402 | | [V0_404_RELEASE_SCOPE.md](V0_404_RELEASE_SCOPE.md) | Scope v0.404 (stabilisation post-audit) | | [V0_501_RELEASE_SCOPE.md](archive/V0_501_RELEASE_SCOPE.md) | Scope v0.501 (Streaming & Cloud, archivé) | -| [V0_502_RELEASE_SCOPE.md](V0_502_RELEASE_SCOPE.md) | Scope v0.502 (Chat Server Rewrite) | +| [V0_502_RELEASE_SCOPE.md](archive/V0_502_RELEASE_SCOPE.md) | Scope v0.502 (Chat Server Rewrite, archivé) | +| [V0_503_RELEASE_SCOPE.md](V0_503_RELEASE_SCOPE.md) | Scope v0.503 (placeholder) | +| [CHAT_FEATURE_PARITY.md](CHAT_FEATURE_PARITY.md) | Feature parity Rust vs Go (25/25 OK) | | [V0_301_RELEASE_SCOPE.md](V0_301_RELEASE_SCOPE.md) | Scope détaillé v0.301 (Phase 3 Social) | | [V0_203_RELEASE_SCOPE.md](V0_203_RELEASE_SCOPE.md) | Scope v0.203 (archivé) | | [SCOPE_CONTROL.md](SCOPE_CONTROL.md) | Anti-scope-creep, workflow | diff --git a/docs/RETROSPECTIVE_V0502.md b/docs/RETROSPECTIVE_V0502.md new file mode 100644 index 000000000..0f0809e30 --- /dev/null +++ b/docs/RETROSPECTIVE_V0502.md @@ -0,0 +1,41 @@ +# Rétrospective v0.502 — Chat Server Rewrite (Rust → Go) + +**Date** : 2026-02-22 +**Durée** : 6 sprints + +--- + +## Ce qui a bien fonctionné + +1. **Architecture claire** : Le plan ADR-002 a fourni une décision architecturale bien documentée +2. **Modèle Hub/Client** : Le pattern existant (playback_websocket_handler.go) a servi de base solide +3. **Compatibilité protocole** : Les 19 types entrants et 20 types sortants sont identiques au Rust +4. **Tests unitaires** : 15 tests passent dès la première exécution avec SQLite in-memory +5. **Migration frontend transparente** : Dérivation automatique de WS_URL depuis API_URL + +## Ce qui pourrait être amélioré + +1. **Couverture E2E** : Les tests E2E sont taggés `integration` et nécessitent un setup complet +2. **Rate limiter** : Actuellement in-memory seulement, pas Redis (suffisant pour single-instance) +3. **Presence tracking** : Simplifié à `hub.IsUserOnline()`, pas de persistence +4. **Message search** : ILIKE basique, pas de full-text search PostgreSQL + +## Métriques + +| Métrique | Valeur | +|----------|--------| +| Fichiers Go créés | 15 | +| Fichiers Go modifiés | 3 | +| Migrations SQL | 4 | +| Tests unitaires | 15 | +| Tests E2E | 6 | +| Lignes de code Go (chat) | ~1500 | +| Types message protocole | 39 (19 in + 20 out) | + +## Points d'action pour v0.503+ + +- [ ] Ajouter Redis-backed rate limiter +- [ ] Implémenter presence tracking avec persistence +- [ ] Ajouter PostgreSQL full-text search pour messages +- [ ] Benchmark performance (100+ connexions simultanées) +- [ ] Supprimer le dossier `veza-chat-server/` du repo (archivage) diff --git a/docs/SCOPE_CONTROL.md b/docs/SCOPE_CONTROL.md index 1352cf780..e0bb30555 100644 --- a/docs/SCOPE_CONTROL.md +++ b/docs/SCOPE_CONTROL.md @@ -1,23 +1,23 @@ # Contrôle du scope — Anti-scope-creep **Objectif** : Éviter toute dérive de scope. Chaque modification doit être intentionnelle et traçable. -**Référence active** : [V0_502_RELEASE_SCOPE.md](V0_502_RELEASE_SCOPE.md) -**Version précédente** : [V0_501_RELEASE_SCOPE.md](archive/V0_501_RELEASE_SCOPE.md) +**Référence active** : [V0_503_RELEASE_SCOPE.md](V0_503_RELEASE_SCOPE.md) +**Version précédente** : [V0_502_RELEASE_SCOPE.md](archive/V0_502_RELEASE_SCOPE.md) --- ## 1. Règle d'or -> **Avant d'ajouter quoi que ce soit : vérifier si c'est dans le scope v0.502.** +> **Avant d'ajouter quoi que ce soit : vérifier si c'est dans le scope v0.503.** > Si non → ne pas ajouter. Créer un ticket pour une version ultérieure. --- -## 2. Pendant la phase v0.502 (jusqu'au tag) +## 2. Pendant la phase v0.503 (jusqu'au tag) ### 2.1 Autorisé -- **Corrections de bugs** sur les features IN SCOPE v0.502 +- **Corrections de bugs** sur les features IN SCOPE v0.503 - **Stabilisation** : tests, refactoring sans changement de comportement - **Nettoyage** : suppression de code mort, consolidation - **Documentation** : mise à jour des docs existantes @@ -26,7 +26,7 @@ ### 2.2 Interdit -- **Nouvelles features** hors scope v0.502 +- **Nouvelles features** hors scope v0.503 - **Nouvelles routes** ou pages hors scope - **Nouvelles dépendances** (sauf correctif sécurité) - **Changements de comportement** sur les features HORS SCOPE diff --git a/docs/SMOKE_TEST_V0502.md b/docs/SMOKE_TEST_V0502.md new file mode 100644 index 000000000..9a498c7fe --- /dev/null +++ b/docs/SMOKE_TEST_V0502.md @@ -0,0 +1,44 @@ +# Smoke Test — v0.502 Chat Server Rewrite + +## Pre-requisites +- [ ] `go build ./...` passes in veza-backend-api +- [ ] `go test ./internal/websocket/chat/... -v` passes (15 tests) +- [ ] Frontend builds without new errors (`npx tsc --noEmit`) + +## Backend Chat WebSocket +- [ ] Backend starts without errors (`go run ./cmd/server`) +- [ ] POST `/api/v1/chat/token` returns `{token, ws_url: "/api/v1/ws", expires_in}` +- [ ] WebSocket connects at `ws://localhost:8080/api/v1/ws?token=` +- [ ] Receives `{"type":"ActionConfirmed","action":"connected","success":true}` on connect +- [ ] Sending `{"type":"Ping"}` returns `{"type":"Pong"}` +- [ ] Missing/invalid token returns 401 + +## Message Flow +- [ ] JoinConversation -> ActionConfirmed +- [ ] SendMessage -> ActionConfirmed + NewMessage broadcast +- [ ] EditMessage -> ActionConfirmed + MessageEdited broadcast +- [ ] DeleteMessage -> ActionConfirmed + MessageDeleted broadcast +- [ ] FetchHistory -> HistoryChunk with messages array + +## Real-time Features +- [ ] Typing -> UserTyping broadcast to other room members +- [ ] MarkAsRead -> ActionConfirmed + MessageRead broadcast +- [ ] Delivered -> ActionConfirmed + MessageDelivered broadcast +- [ ] AddReaction -> ActionConfirmed + ReactionAdded broadcast +- [ ] RemoveReaction -> ActionConfirmed + ReactionRemoved broadcast + +## Call Signaling +- [ ] CallOffer relayed to target user +- [ ] CallAnswer relayed to caller +- [ ] ICECandidate relayed to target +- [ ] CallHangup relayed to target +- [ ] CallReject relayed to caller + +## Docker +- [ ] `docker-compose up` starts without chat-server service +- [ ] Backend still starts and serves WS endpoint + +## Frontend +- [ ] Chat connects to `/api/v1/ws` instead of old port 8081 +- [ ] Messages sent and received correctly +- [ ] Typing indicators work diff --git a/docs/V0_503_RELEASE_SCOPE.md b/docs/V0_503_RELEASE_SCOPE.md new file mode 100644 index 000000000..55b7cd946 --- /dev/null +++ b/docs/V0_503_RELEASE_SCOPE.md @@ -0,0 +1,22 @@ +# V0.503 Release Scope — Placeholder + +**Status** : En préparation +**Phase** : 5 — Streaming & Communication +**Prérequis** : v0.502 (taguée) + +--- + +## Objectif + +À définir. Candidats potentiels : + +- Stream server stabilisation (veza-stream-server) +- Chat améliorations (presence tracking, full-text search, Redis rate limiter) +- Performance benchmarks et optimisations +- Suppression / archivage du dossier veza-chat-server + +--- + +## Lots + +À définir lors de la planification v0.503. diff --git a/docs/archive/V0_502_RELEASE_SCOPE.md b/docs/archive/V0_502_RELEASE_SCOPE.md new file mode 100644 index 000000000..7388481ff --- /dev/null +++ b/docs/archive/V0_502_RELEASE_SCOPE.md @@ -0,0 +1,336 @@ +# 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