veza/veza-chat-server/docs/CHAT_MESSAGE_EDIT_DELETE.md
okinrev b7955a680c 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

12 KiB

Documentation : Édition et Suppression de Messages

Date de création : 2025-12-05
Version : 1.0.0
Statut : Implémenté

Vue d'ensemble

Ce document décrit l'implémentation complète de l'édition et de la suppression (soft delete) de messages dans le serveur de chat Veza. Ces fonctionnalités sont essentielles pour un système de chat moderne et respectent les meilleures pratiques de sécurité, permissions et cohérence temps réel.

Table des matières

  1. Architecture
  2. Événements WebSocket
  3. Permissions
  4. Base de données
  5. Services
  6. Exemples d'utilisation
  7. Conséquences UX
  8. Impact sur la recherche et pagination

Architecture

Composants principaux

  1. Migration SQL (migrations/005_message_edit_delete.sql)

    • Ajoute deleted_at pour la traçabilité
    • Index pour les requêtes de nettoyage
  2. PermissionService (src/security/permission.rs)

    • can_edit_message() : Vérifie les permissions d'édition
    • can_delete_message() : Vérifie les permissions de suppression
  3. MessageEditService (src/services/message_edit_service.rs)

    • edit_message() : Édite un message avec validation
    • delete_message() : Supprime un message (soft delete)
  4. MessageRepository (src/repository/message_repository.rs)

    • update() : Met à jour le contenu d'un message
    • delete() : Marque un message comme supprimé
    • get_by_id_including_deleted() : Récupère même les messages supprimés
  5. WebSocket Handlers (src/websocket/handler.rs)

    • Gère les événements EditMessage et DeleteMessage
    • Broadcast les événements MessageEdited et MessageDeleted

Événements WebSocket

Inbound Events (Client → Serveur)

EditMessage

Édite un message existant.

{
  "type": "EditMessage",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "new_content": "Nouveau contenu du message"
}

Règles de validation :

  • new_content doit être différent du contenu précédent
  • new_content ne peut pas être vide (après trim)
  • new_content ne peut pas dépasser 4000 caractères
  • Le message ne doit pas être supprimé
  • L'utilisateur doit avoir les permissions d'édition

DeleteMessage

Supprime un message (soft delete).

{
  "type": "DeleteMessage",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000"
}

Règles de validation :

  • L'utilisateur doit avoir les permissions de suppression
  • L'opération est idempotente (supprimer un message déjà supprimé retourne OK)

Outbound Events (Serveur → Client)

MessageEdited

Notifie tous les clients d'une conversation qu'un message a été édité.

{
  "type": "MessageEdited",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "editor_id": "770e8400-e29b-41d4-a716-446655440000",
  "edited_at": "2025-12-05T10:30:00Z",
  "new_content": "Nouveau contenu du message"
}

MessageDeleted

Notifie tous les clients d'une conversation qu'un message a été supprimé.

{
  "type": "MessageDeleted",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "deleter_id": "770e8400-e29b-41d4-a716-446655440000",
  "deleted_at": "2025-12-05T10:30:00Z"
}

Permissions

Règles d'édition

Un utilisateur peut éditer un message si :

  1. Il est l'auteur du message : L'auteur peut toujours éditer son propre message
  2. Il est admin/modérateur de la conversation : Les admins et modérateurs peuvent éditer n'importe quel message dans leur conversation
  3. Le message n'est pas supprimé : Un message supprimé ne peut jamais être édité

Règles de suppression

Un utilisateur peut supprimer un message si :

  1. Il est l'auteur du message : L'auteur peut toujours supprimer son propre message
  2. Il est admin/modérateur de la conversation : Les admins et modérateurs peuvent supprimer n'importe quel message dans leur conversation

Limitations de temps

Actuellement, il n'y a pas de limitation de temps pour l'édition ou la suppression. Un message peut être édité ou supprimé à tout moment tant que les permissions sont respectées.

Note : Pour une implémentation future, on pourrait ajouter :

  • Fenêtre d'édition limitée (ex: 15 minutes après l'envoi)
  • Fenêtre de suppression limitée (ex: 5 minutes après l'envoi)

Base de données

Schéma

La table messages contient les colonnes suivantes pour l'édition et la suppression :

CREATE TABLE messages (
    id UUID PRIMARY KEY,
    conversation_id UUID NOT NULL,
    sender_id UUID NOT NULL,
    content TEXT NOT NULL,
    -- ... autres colonnes ...
    is_edited BOOLEAN NOT NULL DEFAULT FALSE,
    is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
    edited_at TIMESTAMPTZ,
    deleted_at TIMESTAMPTZ,
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Migration

La migration 005_message_edit_delete.sql ajoute :

  • deleted_at : Timestamp de suppression (pour la traçabilité)
  • Index sur deleted_at pour les requêtes de nettoyage
  • Index sur edited_at pour les requêtes de recherche

Soft Delete

Les messages ne sont jamais supprimés physiquement de la base de données. Au lieu de cela :

  • is_deleted est mis à true
  • deleted_at est mis à NOW()
  • Le contenu reste dans la base de données (pour audit futur)

Note : Pour une implémentation future, on pourrait :

  • Créer une table message_archive pour stocker les messages supprimés
  • Vider le contenu du message après suppression (mettre content à NULL ou "")

Services

MessageEditService

Service centralisé pour l'édition et la suppression de messages.

edit_message(user_id, message_id, new_content) -> Result<Message>

Édite un message avec validation complète.

Validation :

  1. Contenu non vide (après trim)
  2. Longueur maximale (4000 caractères)
  3. Contenu différent de l'original
  4. Message non supprimé
  5. Permissions d'édition

Mise à jour DB :

  • content = nouveau contenu
  • is_edited = true
  • edited_at = NOW()
  • updated_at = NOW()

delete_message(user_id, message_id) -> Result<Message>

Supprime un message (soft delete).

Validation :

  1. Permissions de suppression

Mise à jour DB :

  • is_deleted = true
  • deleted_at = NOW()
  • updated_at = NOW()

Idempotence : Si le message est déjà supprimé, retourne le message tel quel sans erreur.


Exemples d'utilisation

Édition d'un message

Client :

{
  "type": "EditMessage",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "new_content": "Correction : Nouveau contenu"
}

Réponse (confirmation) :

{
  "type": "ActionConfirmed",
  "action": "message_edited",
  "success": true
}

Broadcast (tous les clients de la conversation) :

{
  "type": "MessageEdited",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "editor_id": "770e8400-e29b-41d4-a716-446655440000",
  "edited_at": "2025-12-05T10:30:00Z",
  "new_content": "Correction : Nouveau contenu"
}

Suppression d'un message

Client :

{
  "type": "DeleteMessage",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000"
}

Réponse (confirmation) :

{
  "type": "ActionConfirmed",
  "action": "message_deleted",
  "success": true
}

Broadcast (tous les clients de la conversation) :

{
  "type": "MessageDeleted",
  "message_id": "550e8400-e29b-41d4-a716-446655440000",
  "conversation_id": "660e8400-e29b-41d4-a716-446655440000",
  "deleter_id": "770e8400-e29b-41d4-a716-446655440000",
  "deleted_at": "2025-12-05T10:30:00Z"
}

Gestion des erreurs

Permission refusée :

{
  "type": "Error",
  "message": "Permissions insuffisantes pour edit_message dans la conversation 660e8400-e29b-41d4-a716-446655440000"
}

Message introuvable :

{
  "type": "Error",
  "message": "Message 550e8400-e29b-41d4-a716-446655440000 introuvable"
}

Message supprimé (tentative d'édition) :

{
  "type": "Error",
  "message": "Un message supprimé ne peut pas être édité"
}

Conséquences UX

Affichage des messages édités

Lorsqu'un message est édité, l'interface utilisateur doit :

  1. Afficher le nouveau contenu : Remplacer l'ancien contenu par le nouveau
  2. Indicateur visuel : Afficher un indicateur "Édité" (ex: "✏️ Édité")
  3. Timestamp d'édition : Optionnellement afficher edited_at au survol
  4. Historique : Pour une implémentation future, on pourrait afficher l'historique des éditions

Exemple d'affichage :

[Utilisateur] Message original ✏️ Édité

Affichage des messages supprimés

Lorsqu'un message est supprimé, l'interface utilisateur doit :

  1. Placeholder : Afficher un placeholder comme "Message supprimé" ou "Ce message a été supprimé"
  2. Style visuel : Utiliser un style atténué (gris, italique)
  3. Informations limitées : Ne pas afficher le contenu original
  4. Timestamp : Optionnellement afficher deleted_at

Exemple d'affichage :

[Utilisateur] Ce message a été supprimé

Cohérence multi-device

Les événements WebSocket garantissent que :

  • Tous les clients connectés à la conversation reçoivent les mises à jour en temps réel
  • Les modifications sont synchronisées instantanément
  • Pas besoin de rafraîchir la page

Impact sur la recherche et pagination

Recherche

Les messages supprimés sont exclus des résultats de recherche par défaut.

Requête SQL :

SELECT * FROM messages
WHERE conversation_id = $1
  AND is_deleted = false
  AND content ILIKE $2
ORDER BY created_at DESC;

Note : Pour une implémentation future, on pourrait :

  • Permettre aux admins de rechercher dans les messages supprimés
  • Créer une vue messages_active qui exclut automatiquement les messages supprimés

Pagination

Les messages supprimés sont exclus de la pagination par défaut.

Requête SQL :

SELECT * FROM messages
WHERE conversation_id = $1
  AND is_deleted = false
ORDER BY created_at DESC
LIMIT $2 OFFSET $3;

Placeholder dans la liste : Si un message est supprimé pendant qu'un utilisateur consulte l'historique, il peut être remplacé par un placeholder dans la liste.

Impact sur les métriques

  • Les messages supprimés ne sont pas comptés dans les statistiques de messages
  • Les messages édités sont comptés comme des messages normaux (pas de double comptage)

Tests

Les tests sont disponibles dans tests/chat_edit_delete.rs :

  • Édition par l'auteur
  • Édition interdite pour un non-auteur
  • Édition interdite pour un message supprimé
  • Édition avec contenu identique interdite
  • Édition avec contenu vide interdite
  • Suppression par l'auteur
  • Suppression par un admin
  • Suppression interdite pour un non-auteur
  • Suppression idempotente
  • Validation de la longueur maximale

Note : Les tests nécessitent une base de données de test et sont marqués avec #[ignore].


Améliorations futures

  1. Limitation de temps : Fenêtre d'édition/suppression limitée
  2. Historique d'édition : Stocker l'historique des modifications
  3. Archive de messages : Table séparée pour les messages supprimés
  4. Raison de suppression : Champ optionnel pour la raison de suppression (modération)
  5. Recherche dans les supprimés : Permettre aux admins de rechercher dans les messages supprimés
  6. Notifications : Notifier l'auteur lorsqu'un admin supprime son message

Références

  • Migration : migrations/005_message_edit_delete.sql
  • Service : src/services/message_edit_service.rs
  • Permissions : src/security/permission.rs
  • Repository : src/repository/message_repository.rs
  • WebSocket : src/websocket/handler.rs
  • Tests : tests/chat_edit_delete.rs