veza/CHAT_SERVER_UUID_MIGRATION.md
okinrev 1ef0e0d6d6 P0: stabilisation backend/chat/stream + nouvelle base migrations v1
Backend Go:
- Remplacement complet des anciennes migrations par la base V1 alignée sur ORIGIN.
- Durcissement global du parsing JSON (BindAndValidateJSON + RespondWithAppError).
- Sécurisation de config.go, CORS, statuts de santé et monitoring.
- Implémentation des transactions P0 (RBAC, duplication de playlists, social toggles).
- Ajout d’un job worker structuré (emails, analytics, thumbnails) + tests associés.
- Nouvelle doc backend : AUDIT_CONFIG, BACKEND_CONFIG, AUTH_PASSWORD_RESET, JOB_WORKER_*.

Chat server (Rust):
- Refonte du pipeline JWT + sécurité, audit et rate limiting avancé.
- Implémentation complète du cycle de message (read receipts, delivered, edit/delete, typing).
- Nettoyage des panics, gestion d’erreurs robuste, logs structurés.
- Migrations chat alignées sur le schéma UUID et nouvelles features.

Stream server (Rust):
- Refonte du moteur de streaming (encoding pipeline + HLS) et des modules core.
- Transactions P0 pour les jobs et segments, garanties d’atomicité.
- Documentation détaillée de la pipeline (AUDIT_STREAM_*, DESIGN_STREAM_PIPELINE, TRANSACTIONS_P0_IMPLEMENTATION).

Documentation & audits:
- TRIAGE.md et AUDIT_STABILITY.md à jour avec l’état réel des 3 services.
- Cartographie complète des migrations et des transactions (DB_MIGRATIONS_*, DB_TRANSACTION_PLAN, AUDIT_DB_TRANSACTIONS, TRANSACTION_TESTS_PHASE3).
- Scripts de reset et de cleanup pour la lab DB et la V1.

Ce commit fige l’ensemble du travail de stabilisation P0 (UUID, backend, chat et stream) avant les phases suivantes (Coherence Guardian, WS hardening, etc.).
2025-12-06 11:14:38 +01:00

29 KiB

Migration Chat-Server Rust : i64 → UUID — Rapport complet

Date : 2025-01-27
Service : veza-chat-server (Rust/Axum)
Objectif : Migrer tous les IDs de i64 vers Uuid pour cohérence avec le schéma DB et le backend Go


Résumé exécutif

  • Fichiers à modifier : ~25 fichiers
  • Structs à migrer : 8 structures principales
  • Requêtes SQL à mettre à jour : ~50+ requêtes SQLx
  • Messages WebSocket à migrer : 5+ types de messages
  • Estimation temps : 4-6 heures
  • Risque : Moyen (nécessite tests exhaustifs)

État actuel :

  • Schéma DB : Utilise UUID (colonnes uuid) mais aussi BIGSERIAL (colonnes id)
  • Code Rust : Utilise i64 pour la plupart des IDs
  • Frontend : Envoie déjà des UUID strings
  • ⚠️ Backend Go : Mixte (certains handlers utilisent encore int64)

Problème identifié : Le schéma DB a une cohabitation BIGSERIAL/UUID :

  • Colonnes id : BIGSERIAL (i64)
  • Colonnes uuid : UUID (Uuid)
  • Le code Rust utilise les colonnes id (i64) alors qu'il devrait utiliser uuid

1. Cartographie complète

1.1 Structures avec IDs à migrer

Struct Fichier Champs i64 Champs déjà Uuid Action Priorité
Room src/hub/channels.rs id: i64, owner_id: i64 uuid: Uuid Supprimer id, renommer uuid→id, migrer owner_id 🔴 Haute
RoomMember src/hub/channels.rs id: i64, conversation_id: i64, user_id: i64 - Migrer tous vers Uuid 🔴 Haute
RoomMessage src/hub/channels.rs id: i64, author_id: i64, conversation_id: i64, parent_message_id: Option<i64> uuid: Uuid Supprimer id, renommer uuid→id, migrer autres 🔴 Haute
RoomStats src/hub/channels.rs room_id: i64 - Migrer vers Uuid 🟡 Moyenne
EnhancedRoomMessage src/hub/channels.rs id: i64, author_id: i32, room_id: Option<i32> - Migrer vers Uuid 🟡 Moyenne
AuditLog src/hub/audit.rs id: i64, user_id: Option<i64> - Migrer vers Uuid 🟡 Moyenne
SecurityEvent src/hub/audit.rs id: i64, user_id: Option<i64> - Migrer vers Uuid 🟡 Moyenne
UserActivity src/hub/audit.rs user_id: i64 - Migrer vers Uuid 🟡 Moyenne
RoomAuditSummary src/hub/audit.rs room_id: i64 - Migrer vers Uuid 🟡 Moyenne
Message src/models/message.rs - id: Uuid, conversation_id: Uuid, sender_id: Uuid Déjà migré OK
WsInbound src/messages.rs to_user_id: i32, with: i32 - Migrer vers Uuid (string) 🔴 Haute

Total : 10 structures à migrer (8 avec i64, 2 déjà OK)

1.2 Requêtes SQLx à mettre à jour

Fichier : src/hub/channels.rs

Fonction Ligne Requête Champs i64 concernés Modification
create_room 139-152 INSERT INTO conversations ... RETURNING id, uuid, ... id, owner_id Utiliser uuid au lieu de id, migrer owner_id
join_room 198-220 SELECT id, uuid, ... FROM conversations WHERE id = $1 room_id, user_id Utiliser uuid au lieu de id
leave_room 254-290 SELECT id, ... FROM conversations WHERE id = $1 room_id, user_id Utiliser uuid
send_room_message 347-412 INSERT INTO messages ... RETURNING id room_id, author_id, message_id, parent_message_id Utiliser uuid pour tous
pin_message 416-450 UPDATE messages ... WHERE id = $2 room_id, message_id, user_id Utiliser uuid
fetch_room_history 462-546 SELECT id, uuid, ... FROM messages WHERE conversation_id = $1 room_id, user_id, message_id Utiliser uuid
fetch_pinned_messages 548-593 SELECT ... FROM messages WHERE conversation_id = $1 room_id, user_id Utiliser uuid
get_room_stats 594-623 SELECT c.id as room_id, ... room_id Utiliser uuid
list_room_members 625-670 SELECT ... FROM conversation_members WHERE conversation_id = $1 room_id, user_id Utiliser uuid

Total dans channels.rs : ~20 requêtes à modifier

Fichier : src/hub/audit.rs

Fonction Ligne Requête Champs i64 concernés Modification
log_action 81-100 INSERT INTO audit_logs ... RETURNING id user_id: Option<i64> Migrer vers Option<Uuid>
log_security_event 112-137 INSERT INTO security_events ... RETURNING id user_id: Option<i64> Migrer vers Option<Uuid>
log_room_created 150-173 log_action(..., room_id: i64, owner_id: i64) room_id, owner_id Migrer vers Uuid
log_member_change 174-207 log_action(..., room_id: i64, target_user_id: i64, ...) room_id, user_ids Migrer vers Uuid
log_message_modified 207-244 log_action(..., message_id: i64, room_id: i64, ...) Tous les IDs Migrer vers Uuid
log_moderation_action 244-297 log_action(..., room_id: i64, ...) Tous les IDs Migrer vers Uuid
get_room_audit_logs 297-346 SELECT ... FROM audit_logs WHERE ... room_id, requesting_user_id Migrer vers Uuid
get_room_security_events 347-398 SELECT ... FROM security_events WHERE ... room_id, requesting_user_id Migrer vers Uuid
generate_room_activity_report 399-515 SELECT ... WHERE room_id = $1 room_id, requesting_user_id Migrer vers Uuid
get_room_audit_summary 516-551 SELECT c.id as room_id, ... room_id, requesting_user_id Migrer vers Uuid
detect_suspicious_patterns 552-590 SELECT ... WHERE room_id = $1 room_id Migrer vers Uuid

Total dans audit.rs : ~15 requêtes à modifier

Autres fichiers

Fichier Fonctions impactées Requêtes Priorité
src/hub/direct_messages.rs Toutes fonctions DM ~10 requêtes 🔴 Haute
src/repository/room_repository.rs Toutes méthodes ~8 requêtes 🔴 Haute
src/repository/message_repository.rs Toutes méthodes ~8 requêtes 🔴 Haute
src/message_store.rs Store/retrieve ~5 requêtes 🟡 Moyenne
src/services/room_service.rs Service layer ~5 requêtes 🟡 Moyenne

Total estimé : ~60 requêtes SQLx à modifier

1.3 Conversions/parsing d'ID à migrer

Fichier Ligne Code actuel Code cible Contexte
src/messages.rs 21 to_user_id: i32 to_user_id: String (UUID string) WebSocket inbound
src/messages.rs 33 with: i32 with: String (UUID string) WebSocket inbound
src/hub/channels.rs 122 owner_id: i64 owner_id: Uuid Paramètre fonction
src/hub/channels.rs 189 room_id: i64, user_id: i64 room_id: Uuid, user_id: Uuid Paramètres fonction
src/hub/channels.rs 326 author_id: i64 author_id: Uuid Paramètre fonction
src/hub/channels.rs 339 author_id as i32 Supprimer conversion Rate limiting
src/hub/channels.rs 383 message.get("id")i64 message.get("uuid")Uuid Récupération ID
src/hub/audit.rs 81 user_id: Option<i64> user_id: Option<Uuid> Paramètre fonction
src/hub/audit.rs 150 room_id: i64, owner_id: i64 room_id: Uuid, owner_id: Uuid Paramètres fonction

Patterns de conversion à chercher :

  • as i64 / as i32 : Conversions explicites
  • .parse::<i64>() : Parsing depuis string
  • get::<i64, _>("id") : Récupération depuis SQLx Row
  • validate_user_id(user_id as i32) : Validation avec conversion

1.4 Messages/DTOs WebSocket à migrer

Struct Fichier Champs i64 Sérialisé en JSON Impact client Action
WsInbound::DirectMessage src/messages.rs to_user_id: i32 Oui Frontend envoie UUID string Migrer vers String (UUID)
WsInbound::DmHistory src/messages.rs with: i32 Oui Frontend envoie UUID string Migrer vers String (UUID)
RoomMessage src/hub/channels.rs id: i64, author_id: i64, conversation_id: i64 Oui ⚠️ Frontend attend UUID string Migrer vers Uuid (sérialisé en string)
Room src/hub/channels.rs id: i64, owner_id: i64 Oui ⚠️ Frontend attend UUID string Migrer vers Uuid
RoomMember src/hub/channels.rs id: i64, user_id: i64 Oui ⚠️ Frontend attend UUID string Migrer vers Uuid

Note importante : Le frontend envoie déjà des UUID strings (voir apps/web/src/features/chat/types/index.ts). Le problème est que le Rust attend des i32/i64.

1.5 Schéma DB (source de vérité)

Analyse du schéma : migrations/001_create_clean_database.sql

Table Colonne ID Type DB Colonne UUID Type DB Type Rust actuel Conforme Action
users id BIGSERIAL uuid UUID i64 Utiliser uuid
conversations id BIGSERIAL uuid UUID i64 Utiliser uuid
conversation_members id BIGSERIAL - - i64 PROBLÈME : Pas de colonne UUID
messages id BIGSERIAL uuid UUID i64 Utiliser uuid
audit_logs id BIGSERIAL - - i64 PROBLÈME : Pas de colonne UUID
security_events id BIGSERIAL - - i64 PROBLÈME : Pas de colonne UUID

Problème majeur identifié :

  • Les tables conversation_members, audit_logs, security_events n'ont PAS de colonne UUID
  • Elles utilisent uniquement BIGSERIAL pour les IDs
  • Solution : Soit ajouter des colonnes UUID (migration DB), soit utiliser les IDs BIGSERIAL mais les convertir en UUID côté application

Recommandation : Utiliser les colonnes uuid existantes et ajouter des migrations pour les tables sans UUID.


2. Impacts et dépendances

2.1 Communication avec le backend Go

Direction Endpoint/Event Format ID actuel (Rust) Format attendu (Go) Action
Go → Rust WebSocket token (JWT) user_id dans JWT : int64 user_id : uuid.UUID ⚠️ PROBLÈME : JWT contient int64
Go → Rust HTTP webhook (si existe) user_id: i64 user_id: string (UUID) Vérifier si webhooks existent
Rust → Go Webhook callback (si existe) user_id: i64 user_id: string (UUID) Migrer vers UUID

Problème identifié : Le backend Go génère des tokens JWT avec user_id en uuid.UUID, mais le chat-server Rust pourrait s'attendre à un int64. À vérifier dans src/auth.rs et src/jwt_manager.rs.

2.2 Communication avec le Frontend

Message WS Direction Champ Type actuel (Rust) Type Frontend Compatible Action
NewMessage Server→Client message_id i64 (number) string (UUID) Migrer vers Uuid (sérialisé en string)
NewMessage Server→Client sender_id i64 (number) string (UUID) Migrer vers Uuid
NewMessage Server→Client conversation_id i64 (number) string (UUID) Migrer vers Uuid
join_room Client→Server room String (nom) string (nom ou UUID) OK (utilise nom, pas ID)
direct_message Client→Server to_user_id i32 (number) string (UUID) Migrer vers String (UUID)
dm_history Client→Server with i32 (number) string (UUID) Migrer vers String (UUID)

Résultat : Incompatible - Le frontend envoie/reçoit des UUID strings, mais le Rust attend/envoie des i64.

2.3 Tests existants

Fichier test Test Utilise i64 Modification
src/hub/channels.rs (tests inline) test_room_creation Probable Changer en Uuid::new_v4()
tests/integration_test.rs (si existe) Tests d'intégration Probable Migrer vers UUID
Tests unitaires Tous Probable Migrer vers UUID

Action : Vérifier avec grep -r "#\[test\]" veza-chat-server/src/ et mettre à jour tous les tests.


3. Plan de migration détaillé

3.1 Ordre des modifications (bottom-up)

Étape 1 : Préparation (sans changement fonctionnel)

  1. Vérifier Cargo.toml : uuid avec features ["v4", "serde"] (déjà présent)
  2. Vérifier Cargo.toml : sqlx avec feature uuid (déjà présent)
  3. Créer branche : git checkout -b fix/chat-server-uuid-migration
  4. Tag de sauvegarde : git tag pre-uuid-migration-chat-server

Étape 2 : Migration des structs (du plus simple au plus complexe)

Ordre recommandé :

  1. src/models/message.rs - Déjà migré, vérifier seulement
  2. src/messages.rs - Migrer WsInbound (simple, pas de DB)
  3. src/hub/channels.rs - Migrer Room, RoomMember, RoomMessage (complexe)
  4. src/hub/audit.rs - Migrer structs d'audit
  5. Autres structs dans autres fichiers

Étape 3 : Migration des requêtes SQLx

Ordre recommandé :

  1. src/hub/channels.rs - Toutes les requêtes (fonctions principales)
  2. src/hub/audit.rs - Toutes les requêtes d'audit
  3. src/hub/direct_messages.rs - Requêtes DM
  4. src/repository/*.rs - Repositories
  5. Autres fichiers avec requêtes SQL

Étape 4 : Migration handlers/WebSocket

  1. src/websocket/handler.rs - Handlers WebSocket
  2. src/websocket/broadcast.rs - Broadcast messages
  3. src/message_handler.rs - Message handlers
  4. Autres handlers

Étape 5 : Tests

  1. Mettre à jour tous les tests unitaires
  2. Mettre à jour les tests d'intégration
  3. Ajouter des tests de conversion UUID

3.2 Modifications fichier par fichier

Fichier : src/messages.rs

Modification : Migrer WsInbound pour accepter des UUID strings

// AVANT
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum WsInbound {
    #[serde(rename = "direct_message")]
    DirectMessage {
        to_user_id: i32,  // ❌
        content: String,
    },
    #[serde(rename = "dm_history")]
    DmHistory {
        with: i32,  // ❌
        limit: i64,
    }
}

// APRÈS
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum WsInbound {
    #[serde(rename = "direct_message")]
    DirectMessage {
        to_user_id: String,  // ✅ UUID string depuis frontend
        content: String,
    },
    #[serde(rename = "dm_history")]
    DmHistory {
        with: String,  // ✅ UUID string depuis frontend
        limit: i64,
    }
}

Fonctions impactées : Aucune (juste parsing)


Fichier : src/hub/channels.rs

Modification 1 : Struct Room

// AVANT
#[derive(Debug, FromRow, Serialize, Deserialize)]
pub struct Room {
    pub id: i64,           // ❌
    pub uuid: Uuid,        // ✅ Existe déjà
    pub name: String,
    pub description: Option<String>,
    pub owner_id: i64,     // ❌
    pub is_public: bool,
    pub is_archived: bool,
    pub max_members: Option<i32>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

// APRÈS
#[derive(Debug, FromRow, Serialize, Deserialize)]
pub struct Room {
    pub id: Uuid,          // ✅ Renommé depuis uuid
    pub name: String,
    pub description: Option<String>,
    pub owner_id: Uuid,    // ✅ Migré
    pub is_public: bool,
    pub is_archived: bool,
    pub max_members: Option<i32>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

Modification 2 : Struct RoomMember

// AVANT
#[derive(Debug, FromRow, Serialize, Deserialize)]
pub struct RoomMember {
    pub id: i64,                // ❌
    pub conversation_id: i64,   // ❌
    pub user_id: i64,           // ❌
    pub role: String,
    pub joined_at: DateTime<Utc>,
    pub left_at: Option<DateTime<Utc>>,
    pub is_muted: bool,
}

// APRÈS
#[derive(Debug, FromRow, Serialize, Deserialize)]
pub struct RoomMember {
    pub id: Uuid,               // ✅
    pub conversation_id: Uuid,  // ✅
    pub user_id: Uuid,          // ✅
    pub role: String,
    pub joined_at: DateTime<Utc>,
    pub left_at: Option<DateTime<Utc>>,
    pub is_muted: bool,
}

Modification 3 : Struct RoomMessage

// AVANT
#[derive(Debug, FromRow, Serialize)]
pub struct RoomMessage {
    pub id: i64,                    // ❌
    pub uuid: Uuid,                 // ✅ Existe déjà
    pub author_id: i64,             // ❌
    pub author_username: String,
    pub conversation_id: i64,        // ❌
    pub content: String,
    pub parent_message_id: Option<i64>, // ❌
    // ...
}

// APRÈS
#[derive(Debug, FromRow, Serialize)]
pub struct RoomMessage {
    pub id: Uuid,                    // ✅ Renommé depuis uuid
    pub author_id: Uuid,             // ✅
    pub author_username: String,
    pub conversation_id: Uuid,       // ✅
    pub content: String,
    pub parent_message_id: Option<Uuid>, // ✅
    // ...
}

Modification 4 : Fonction create_room

// AVANT
pub async fn create_room(
    hub: &ChatHub,
    owner_id: i64,  // ❌
    name: &str,
    // ...
) -> Result<Room> {
    let room_uuid = Uuid::new_v4();
    
    let conversation = query_as::<_, Room>("
        INSERT INTO conversations (uuid, type, name, description, owner_id, is_public, max_members)
        VALUES ($1, 'public_room', $2, $3, $4, $5, $6)
        RETURNING id, uuid, name, description, owner_id, is_public, is_archived, max_members, created_at, updated_at
    ")
    .bind(room_uuid)
    .bind(owner_id)  // ❌ i64
    // ...
}

// APRÈS
pub async fn create_room(
    hub: &ChatHub,
    owner_id: Uuid,  // ✅
    name: &str,
    // ...
) -> Result<Room> {
    let room_uuid = Uuid::new_v4();
    
    let conversation = query_as::<_, Room>("
        INSERT INTO conversations (uuid, type, name, description, owner_id, is_public, max_members)
        VALUES ($1, 'public_room', $2, $3, $4, $5, $6)
        RETURNING uuid as id, name, description, owner_id, is_public, is_archived, max_members, created_at, updated_at
    ")
    .bind(room_uuid)
    .bind(owner_id)  // ✅ Uuid
    // ...
}

Note : La requête SQL doit utiliser uuid as id pour mapper la colonne uuid vers le champ id de la struct.

Modification 5 : Fonction send_room_message

// AVANT
pub async fn send_room_message(
    hub: &ChatHub,
    room_id: i64,           // ❌
    author_id: i64,         // ❌
    username: &str,
    content: &str,
    parent_message_id: Option<i64>,  // ❌
    metadata: Option<Value>
) -> Result<i64> {  // ❌ Retourne i64
    // ...
    let message = query("
        INSERT INTO messages (uuid, author_id, conversation_id, content, parent_message_id, metadata, status)
        VALUES ($1, $2, $3, $4, $5, $6, 'sent')
        RETURNING id, created_at
    ")
    .bind(message_uuid)
    .bind(author_id)        // ❌ i64
    .bind(room_id)          // ❌ i64
    .bind(parent_message_id) // ❌ Option<i64>
    // ...
    let message_id: i64 = message.get("id");  // ❌
    // ...
    Ok(message_id)  // ❌
}

// APRÈS
pub async fn send_room_message(
    hub: &ChatHub,
    room_id: Uuid,              // ✅
    author_id: Uuid,            // ✅
    username: &str,
    content: &str,
    parent_message_id: Option<Uuid>,  // ✅
    metadata: Option<Value>
) -> Result<Uuid> {  // ✅ Retourne Uuid
    // ...
    let message = query("
        INSERT INTO messages (uuid, author_id, conversation_id, content, parent_message_id, metadata, status)
        VALUES ($1, $2, $3, $4, $5, $6, 'sent')
        RETURNING uuid as id, created_at
    ")
    .bind(message_uuid)
    .bind(author_id)        // ✅ Uuid
    .bind(room_id)          // ✅ Uuid
    .bind(parent_message_id) // ✅ Option<Uuid>
    // ...
    let message_id: Uuid = message.get("id");  // ✅ (depuis uuid as id)
    // ...
    Ok(message_id)  // ✅
}

Toutes les autres fonctions : Même pattern - remplacer i64 par Uuid dans les paramètres et utiliser uuid as id dans les requêtes SQL.


Fichier : src/hub/audit.rs

Modification : Toutes les fonctions utilisent i64 pour les IDs. Migrer vers Uuid.

// AVANT
pub async fn log_action(
    hub: &ChatHub,
    action: &str,
    details: Value,
    user_id: Option<i64>,  // ❌
    // ...
) -> Result<i64> {  // ❌
    // ...
}

// APRÈS
pub async fn log_action(
    hub: &ChatHub,
    action: &str,
    details: Value,
    user_id: Option<Uuid>,  // ✅
    // ...
) -> Result<Uuid> {  // ✅
    // ...
}

Note : Les tables audit_logs et security_events n'ont pas de colonne uuid. Deux options :

  1. Option A (recommandée) : Ajouter une migration DB pour ajouter des colonnes uuid
  2. Option B : Garder BIGSERIAL pour ces tables (moins idéal)

3.3 Gestion de la sérialisation JSON

Configuration Serde : Avec uuid = { version = "1.6", features = ["v4", "serde"] }, les Uuid se sérialisent automatiquement en strings.

Vérification : Le JSON produit sera :

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "General"
}

Pas besoin de configuration spéciale - Serde gère automatiquement.

3.4 Gestion des requêtes SQLx

Pattern de migration :

// AVANT (i64)
let room = query_as::<_, Room>("
    SELECT id, uuid, name, description, owner_id, is_public, is_archived, max_members, created_at, updated_at
    FROM conversations 
    WHERE id = $1
")
.bind(room_id)  // i64
.fetch_one(&pool)
.await?;

// APRÈS (Uuid)
let room = query_as::<_, Room>("
    SELECT uuid as id, name, description, owner_id, is_public, is_archived, max_members, created_at, updated_at
    FROM conversations 
    WHERE uuid = $1
")
.bind(room_id)  // Uuid
.fetch_one(&pool)
.await?;

Points d'attention :

  1. Utiliser uuid as id dans les SELECT pour mapper vers le champ id de la struct
  2. Utiliser WHERE uuid = $1 au lieu de WHERE id = $1
  3. Les paramètres $1, $2, ... doivent être de type Uuid
  4. SQLx vérifie les types au compile-time - les erreurs seront explicites

4. Gestion des erreurs et rollback

4.1 Points de rollback

Stratégie de commits :

Commit 1 : Préparation

git commit -m "chore(chat-server): prepare UUID migration dependencies"
  • Vérifier/ajouter dépendances Cargo.toml (déjà présentes)
  • Créer types/ids.rs si nécessaire (optionnel)

Commit 2 : Migration des structs

git commit -m "refactor(chat-server): migrate structs from i64 to Uuid"
  • Modifier toutes les structs
  • Le code NE COMPILE PAS encore (c'est normal)

Commit 3 : Migration des requêtes DB

git commit -m "refactor(chat-server): migrate SQLx queries to Uuid"
  • Modifier toutes les requêtes SQLx
  • Le code devrait compiler maintenant

Commit 4 : Migration handlers/WebSocket

git commit -m "refactor(chat-server): migrate handlers and WS to Uuid"
  • Modifier les handlers
  • Modifier les messages WS

Commit 5 : Tests

git commit -m "test(chat-server): update tests for UUID migration"
  • Mettre à jour tous les tests
  • Tous les tests passent

Tag final

git tag chat-server-uuid-migration-complete

4.2 Erreurs attendues et solutions

Erreur 1 : Type mismatch dans query_as!

error: type mismatch: expected `i64`, found `Uuid`

Solution : Vérifier que la struct ET la requête utilisent le même type. Utiliser uuid as id dans le SELECT.

Erreur 2 : Cannot convert i64 to Uuid

error: the trait `From<i64>` is not implemented for `Uuid`

Solution : Il reste du code qui utilise i64 — chercher avec grep -r "i64" src/ | grep -v test

Erreur 3 : Serde désérialisation échoue

error: invalid type: integer, expected a string

Solution : Le client envoie un number au lieu d'un string UUID. Vérifier le frontend ou accepter les deux formats temporairement.

Erreur 4 : SQLx compile-time check échoue

error: column "id" is of type uuid but expression is of type bigint

Solution : La requête SQL utilise encore un paramètre i64. Migrer vers Uuid.


5. Validation et tests

5.1 Tests de non-régression

Tests unitaires Rust

cd veza-chat-server
cargo test

Test d'intégration DB

# Vérifier que les requêtes fonctionnent avec la vraie DB
DATABASE_URL="postgres://..." cargo test --features integration

Test WebSocket manuel

# Avec websocat ou wscat
wscat -c ws://localhost:8080/ws

# Envoyer un message avec UUID
{"type": "join_room", "room": "general"}
{"type": "direct_message", "to_user_id": "550e8400-e29b-41d4-a716-446655440000", "content": "test"}

# Vérifier la réponse (doit contenir des UUID strings, pas des numbers)

Test intégration Backend Go ↔ Chat Server

# Depuis le backend Go, obtenir un token
curl -X GET http://localhost:8080/api/v1/chat/token \
  -H "Authorization: Bearer <jwt_token>"

# Vérifier que le token contient un UUID (pas un int64)

Test Frontend

  1. Ouvrir l'app web
  2. Rejoindre un chat room
  3. Envoyer un message
  4. Vérifier dans la console réseau que les IDs sont des strings UUID

5.2 Checklist finale

Compilation

  • cargo build --release passe sans warning
  • cargo clippy passe sans erreur
  • cargo test — tous les tests passent

Cohérence des types

  • Aucun i64 pour des IDs dans src/ (vérifier avec grep -r "i64" src/ | grep -v test | grep -v limit | grep -v count)
  • Tous les champs ID sont de type Uuid
  • Toutes les requêtes SQLx utilisent Uuid

Sérialisation JSON

  • Les réponses JSON contiennent des UUID strings (pas des numbers)
  • Les requêtes JSON acceptent des UUID strings

Intégration

  • Le backend Go peut communiquer avec le chat-server
  • Le frontend peut se connecter et envoyer/recevoir des messages
  • Les IDs dans les messages WebSocket sont des strings

Documentation

  • README mis à jour si nécessaire
  • Commentaires de code à jour

6. Commandes d'exécution

# Étape 1 : Créer branche
git checkout -b fix/chat-server-uuid-migration

# Étape 2 : Tag de sauvegarde
git tag pre-uuid-migration-chat-server

# Étape 3 : Appliquer les modifications (voir sections 3.2)

# Étape 4 : Tester
cd veza-chat-server
cargo build --release
cargo test

# Étape 5 : Commit
git add .
git commit -m "refactor(chat-server): migrate all IDs from i64 to Uuid"

# Étape 6 : Tag final
git tag chat-server-uuid-migration-complete

7. Questions à clarifier

7.1 Schéma DB - Tables sans UUID

Problème : Les tables conversation_members, audit_logs, security_events n'ont pas de colonne uuid.

Options :

  1. Ajouter des colonnes UUID (migration DB) - Recommandé
  2. Garder BIGSERIAL et convertir en UUID côté application - Moins idéal

Recommandation : Créer une migration pour ajouter des colonnes uuid à ces tables.

7.2 Backend Go - Handlers avec int64

Problème : veza-backend-api/internal/api/handlers/chat_handlers.go utilise encore strconv.ParseInt pour les room_id.

Action : Migrer aussi le backend Go (hors scope de ce rapport, mais à noter).

7.3 JWT Tokens - Format user_id

Question : Le JWT généré par le backend Go contient-il user_id en UUID ou int64 ?

Action : Vérifier dans src/auth.rs et src/jwt_manager.rs comment le JWT est parsé.


8. Résumé des modifications

Fichiers à modifier (ordre de priorité)

  1. 🔴 Haute priorité :

    • src/messages.rs - WebSocket inbound messages
    • src/hub/channels.rs - Structures et fonctions principales
    • src/hub/direct_messages.rs - Direct messages
    • src/repository/room_repository.rs - Repository layer
    • src/repository/message_repository.rs - Repository layer
  2. 🟡 Moyenne priorité :

    • src/hub/audit.rs - Audit logs
    • src/services/room_service.rs - Service layer
    • src/message_store.rs - Message storage
    • src/websocket/handler.rs - WebSocket handlers
    • src/websocket/broadcast.rs - Broadcast messages
  3. 🟢 Basse priorité :

    • Tests unitaires
    • Documentation
    • Autres fichiers avec IDs

Statistiques

  • Structs à migrer : 10
  • Fonctions à modifier : ~40
  • Requêtes SQL à mettre à jour : ~60
  • Lignes de code à modifier : ~500-800
  • Temps estimé : 4-6 heures

Document généré le : 2025-01-27
Prochaine étape : Commencer la migration avec l'étape 1 (préparation)