feat(backend): implémentation complète du système de messagerie

Ajoute l'infrastructure backend complète pour les conversations et messages :

## Entités
- Conversation : conversations individuelles, groupes, broadcast, annonces
- Message : messages avec statut, priorité, pièces jointes, soft delete

## Repositories
- ConversationRepository : findByParticipant, findByIdAndParticipant (sécurité)
- MessageRepository : findByConversation, countUnread, markAsRead

## Services
- ConversationService : CRUD conversations, archive, mute, pin
- MessageService : send, edit, delete, getMessages

## REST Endpoints (12 total)
- GET /api/conversations - Lister mes conversations
- GET /api/conversations/{id} - Récupérer une conversation
- POST /api/conversations - Créer conversation
- PUT /api/conversations/{id}/archive - Archiver
- PUT /api/conversations/{id}/mark-read - Marquer comme lu
- PUT /api/conversations/{id}/toggle-mute - Activer/désactiver son
- PUT /api/conversations/{id}/toggle-pin - Épingler
- GET /api/messages?conversationId=X - Lister messages
- POST /api/messages - Envoyer message
- PUT /api/messages/{id} - Éditer message
- DELETE /api/messages/{id} - Supprimer message

## Database
- Migration V6 : tables conversations, messages, conversation_participants
- Indexes sur organisation, type, archived, deleted pour performance

## Sécurité
- SecuriteHelper.resolveMembreId() : résolution membre depuis JWT
- Vérification accès conversation avant toute opération
- @RolesAllowed sur tous les endpoints

Débloquer la fonctionnalité Communication mobile (actuellement 100% stubs).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dahoud
2026-03-16 06:39:39 +00:00
parent f5271cc29e
commit 3be01e28a7
10 changed files with 1226 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
-- ============================================================================
-- Migration V6: Tables Communication (Conversations + Messages)
-- Date: 2026-03-16
-- Description: Création du système de messagerie UnionFlow
-- ============================================================================
-- Table conversations
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
description VARCHAR(1000),
type VARCHAR(20) NOT NULL CHECK (type IN ('INDIVIDUAL', 'GROUP', 'BROADCAST', 'ANNOUNCEMENT')),
organisation_id UUID,
avatar_url VARCHAR(500),
is_muted BOOLEAN NOT NULL DEFAULT FALSE,
is_pinned BOOLEAN NOT NULL DEFAULT FALSE,
is_archived BOOLEAN NOT NULL DEFAULT FALSE,
metadata TEXT,
updated_at TIMESTAMP,
-- Colonnes BaseEntity
date_creation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
date_modification TIMESTAMP,
cree_par VARCHAR(255),
modifie_par VARCHAR(255),
actif BOOLEAN DEFAULT TRUE,
version INTEGER NOT NULL DEFAULT 0,
CONSTRAINT fk_conversation_organisation FOREIGN KEY (organisation_id)
REFERENCES organisations(id) ON DELETE SET NULL
);
-- Index pour conversations
CREATE INDEX idx_conversation_organisation ON conversations(organisation_id);
CREATE INDEX idx_conversation_type ON conversations(type);
CREATE INDEX idx_conversation_archived ON conversations(is_archived);
CREATE INDEX idx_conversation_created ON conversations(date_creation);
-- Table de jointure conversation_participants (many-to-many)
CREATE TABLE conversation_participants (
conversation_id UUID NOT NULL,
membre_id UUID NOT NULL,
joined_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (conversation_id, membre_id),
CONSTRAINT fk_conv_participant_conversation FOREIGN KEY (conversation_id)
REFERENCES conversations(id) ON DELETE CASCADE,
CONSTRAINT fk_conv_participant_membre FOREIGN KEY (membre_id)
REFERENCES membres(id) ON DELETE CASCADE
);
-- Index pour conversation_participants
CREATE INDEX idx_conv_participants_membre ON conversation_participants(membre_id);
CREATE INDEX idx_conv_participants_conversation ON conversation_participants(conversation_id);
-- Table messages
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL,
sender_id UUID NOT NULL,
sender_name VARCHAR(255) NOT NULL,
sender_avatar VARCHAR(500),
content TEXT NOT NULL,
type VARCHAR(20) NOT NULL CHECK (type IN ('INDIVIDUAL', 'BROADCAST', 'TARGETED', 'SYSTEM')),
status VARCHAR(20) NOT NULL CHECK (status IN ('SENT', 'DELIVERED', 'READ', 'FAILED')),
priority VARCHAR(20) NOT NULL DEFAULT 'NORMAL' CHECK (priority IN ('NORMAL', 'HIGH', 'URGENT')),
recipient_ids VARCHAR(2000),
recipient_roles VARCHAR(500),
organisation_id UUID,
read_at TIMESTAMP,
metadata TEXT,
attachments VARCHAR(2000),
is_edited BOOLEAN NOT NULL DEFAULT FALSE,
edited_at TIMESTAMP,
is_deleted BOOLEAN NOT NULL DEFAULT FALSE,
-- Colonnes BaseEntity
date_creation TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
date_modification TIMESTAMP,
cree_par VARCHAR(255),
modifie_par VARCHAR(255),
actif BOOLEAN DEFAULT TRUE,
version INTEGER NOT NULL DEFAULT 0,
CONSTRAINT fk_message_conversation FOREIGN KEY (conversation_id)
REFERENCES conversations(id) ON DELETE CASCADE,
CONSTRAINT fk_message_sender FOREIGN KEY (sender_id)
REFERENCES membres(id) ON DELETE SET NULL,
CONSTRAINT fk_message_organisation FOREIGN KEY (organisation_id)
REFERENCES organisations(id) ON DELETE SET NULL
);
-- Index pour messages
CREATE INDEX idx_message_conversation ON messages(conversation_id);
CREATE INDEX idx_message_sender ON messages(sender_id);
CREATE INDEX idx_message_organisation ON messages(organisation_id);
CREATE INDEX idx_message_status ON messages(status);
CREATE INDEX idx_message_created ON messages(date_creation);
CREATE INDEX idx_message_deleted ON messages(is_deleted);
-- Commentaires
COMMENT ON TABLE conversations IS 'Conversations (fils de discussion) du système de messagerie';
COMMENT ON TABLE conversation_participants IS 'Association many-to-many entre conversations et membres participants';
COMMENT ON TABLE messages IS 'Messages individuels dans les conversations';
COMMENT ON COLUMN conversations.type IS 'Type: INDIVIDUAL (1-1), GROUP (groupe), BROADCAST (diffusion), ANNOUNCEMENT (annonces)';
COMMENT ON COLUMN messages.status IS 'Statut: SENT (envoyé), DELIVERED (livré), READ (lu), FAILED (échec)';
COMMENT ON COLUMN messages.priority IS 'Priorité: NORMAL, HIGH (élevée), URGENT (urgente)';