veza/veza-chat-server/migrations/archive/003_enhanced_schema.sql
2025-12-03 20:33:26 +01:00

270 lines
No EOL
9.6 KiB
PL/PgSQL

-- Migration 003: Schéma amélioré avec sécurité renforcée et séparation DM/salons
-- Extension pour UUID
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- ================================================
-- UTILISATEURS AVEC SÉCURITÉ RENFORCÉE
-- ================================================
CREATE TABLE IF NOT EXISTS users_enhanced (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
-- Rôles et permissions
role VARCHAR(20) NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'moderator', 'user', 'guest')),
-- Statut et sécurité
is_active BOOLEAN NOT NULL DEFAULT true,
is_banned BOOLEAN NOT NULL DEFAULT false,
is_verified BOOLEAN NOT NULL DEFAULT false,
-- Statut de présence
status VARCHAR(20) DEFAULT 'offline' CHECK (status IN ('online', 'away', 'busy', 'invisible', 'offline')),
status_message VARCHAR(100),
-- Modération
reputation_score INTEGER DEFAULT 100,
-- Métadonnées
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ================================================
-- SALONS AVEC GESTION AVANCÉE
-- ================================================
CREATE TABLE IF NOT EXISTS rooms_enhanced (
id VARCHAR(100) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
-- Propriétaire
owner_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
-- Configuration
is_public BOOLEAN NOT NULL DEFAULT true,
is_archived BOOLEAN DEFAULT false,
max_members INTEGER DEFAULT 1000,
-- Métadonnées
member_count INTEGER DEFAULT 0,
message_count INTEGER DEFAULT 0,
-- Timestamps
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ================================================
-- MESSAGES UNIFIÉS
-- ================================================
CREATE TABLE IF NOT EXISTS messages_enhanced (
id BIGSERIAL PRIMARY KEY,
-- Type et contenu
message_type VARCHAR(20) NOT NULL CHECK (message_type IN ('room_message', 'direct_message', 'system_message')),
content TEXT NOT NULL CHECK (LENGTH(content) <= 4000),
-- Auteur
author_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
author_username VARCHAR(50) NOT NULL,
-- Destination (exclusion mutuelle)
room_id VARCHAR(100) REFERENCES rooms_enhanced(id) ON DELETE CASCADE,
recipient_id INTEGER REFERENCES users_enhanced(id) ON DELETE CASCADE,
recipient_username VARCHAR(50),
-- Threading
parent_message_id BIGINT REFERENCES messages_enhanced(id) ON DELETE SET NULL,
thread_count INTEGER DEFAULT 0,
-- Statut
status VARCHAR(20) DEFAULT 'sent' CHECK (status IN ('sent', 'delivered', 'read', 'edited', 'deleted')),
is_pinned BOOLEAN DEFAULT false,
is_edited BOOLEAN DEFAULT false,
original_content TEXT,
-- Modération
is_flagged BOOLEAN DEFAULT false,
moderation_notes TEXT,
-- Timestamps
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ,
-- Contraintes logiques
CONSTRAINT message_destination_check CHECK (
(message_type = 'room_message' AND room_id IS NOT NULL AND recipient_id IS NULL) OR
(message_type = 'direct_message' AND room_id IS NULL AND recipient_id IS NOT NULL) OR
(message_type = 'system_message')
)
);
-- ================================================
-- RÉACTIONS AUX MESSAGES
-- ================================================
CREATE TABLE IF NOT EXISTS message_reactions_enhanced (
id BIGSERIAL PRIMARY KEY,
message_id BIGINT NOT NULL REFERENCES messages_enhanced(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
emoji VARCHAR(100) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (message_id, user_id, emoji)
);
-- ================================================
-- MENTIONS DANS LES MESSAGES
-- ================================================
CREATE TABLE IF NOT EXISTS message_mentions_enhanced (
id BIGSERIAL PRIMARY KEY,
message_id BIGINT NOT NULL REFERENCES messages_enhanced(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
is_read BOOLEAN DEFAULT false,
UNIQUE (message_id, user_id)
);
-- ================================================
-- MEMBRES DES SALONS
-- ================================================
CREATE TABLE IF NOT EXISTS room_members_enhanced (
room_id VARCHAR(100) NOT NULL REFERENCES rooms_enhanced(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
role VARCHAR(20) DEFAULT 'member' CHECK (role IN ('owner', 'admin', 'moderator', 'member')),
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_read_message_id BIGINT,
PRIMARY KEY (room_id, user_id)
);
-- ================================================
-- BLOCAGES UTILISATEURS
-- ================================================
CREATE TABLE IF NOT EXISTS user_blocks_enhanced (
id BIGSERIAL PRIMARY KEY,
blocker_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
blocked_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
reason VARCHAR(500),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (blocker_id, blocked_id),
CONSTRAINT no_self_block CHECK (blocker_id != blocked_id)
);
-- ================================================
-- SESSIONS SÉCURISÉES
-- ================================================
CREATE TABLE IF NOT EXISTS user_sessions_enhanced (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id INTEGER NOT NULL REFERENCES users_enhanced(id) ON DELETE CASCADE,
token_hash VARCHAR(128) NOT NULL UNIQUE,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_activity TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
is_active BOOLEAN DEFAULT true
);
-- ================================================
-- LOGS DE SÉCURITÉ
-- ================================================
CREATE TABLE IF NOT EXISTS security_events_enhanced (
id BIGSERIAL PRIMARY KEY,
event_type VARCHAR(50) NOT NULL,
severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('debug', 'info', 'warning', 'error', 'critical')),
user_id INTEGER REFERENCES users_enhanced(id) ON DELETE SET NULL,
ip_address INET,
user_agent TEXT,
details JSONB DEFAULT '{}'::jsonb,
success BOOLEAN,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- ================================================
-- INDEX POUR PERFORMANCE
-- ================================================
-- Messages
CREATE INDEX IF NOT EXISTS idx_messages_room_enhanced ON messages_enhanced (room_id, created_at DESC) WHERE message_type = 'room_message' AND status != 'deleted';
CREATE INDEX IF NOT EXISTS idx_messages_dm_enhanced ON messages_enhanced (author_id, recipient_id, created_at DESC) WHERE message_type = 'direct_message' AND status != 'deleted';
CREATE INDEX IF NOT EXISTS idx_messages_dm_reverse_enhanced ON messages_enhanced (recipient_id, author_id, created_at DESC) WHERE message_type = 'direct_message' AND status != 'deleted';
-- Réactions
CREATE INDEX IF NOT EXISTS idx_reactions_message_enhanced ON message_reactions_enhanced (message_id);
CREATE INDEX IF NOT EXISTS idx_reactions_user_enhanced ON message_reactions_enhanced (user_id);
-- Mentions
CREATE INDEX IF NOT EXISTS idx_mentions_user_enhanced ON message_mentions_enhanced (user_id, is_read);
-- Sessions
CREATE INDEX IF NOT EXISTS idx_sessions_user_enhanced ON user_sessions_enhanced (user_id, is_active);
CREATE INDEX IF NOT EXISTS idx_sessions_token_enhanced ON user_sessions_enhanced (token_hash);
-- ================================================
-- TRIGGERS
-- ================================================
-- Fonction pour mettre à jour updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Appliquer aux tables principales
CREATE TRIGGER update_users_enhanced_updated_at
BEFORE UPDATE ON users_enhanced
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_rooms_enhanced_updated_at
BEFORE UPDATE ON rooms_enhanced
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- ================================================
-- FONCTIONS UTILITAIRES
-- ================================================
-- Fonction pour nettoyer les sessions expirées
CREATE OR REPLACE FUNCTION cleanup_expired_sessions()
RETURNS void AS $$
BEGIN
DELETE FROM user_sessions_enhanced
WHERE expires_at < NOW() AND is_active = false;
END;
$$ LANGUAGE plpgsql;
-- ================================================
-- COMMENTAIRES
-- ================================================
COMMENT ON TABLE users_enhanced IS 'Utilisateurs avec sécurité renforcée';
COMMENT ON TABLE messages_enhanced IS 'Messages unifiés avec séparation logique DM/salons';
COMMENT ON TABLE message_reactions_enhanced IS 'Réactions aux messages';
COMMENT ON TABLE message_mentions_enhanced IS 'Mentions d''utilisateurs';
COMMENT ON TABLE user_blocks_enhanced IS 'Blocages entre utilisateurs';
COMMENT ON TABLE user_sessions_enhanced IS 'Sessions sécurisées';
COMMENT ON TABLE security_events_enhanced IS 'Journal de sécurité';