-- Migration 003: Schéma amélioré - VERSION CORRIGÉE BEGIN; -- Supprimer les fonctions qui pourraient être en conflit DROP FUNCTION IF EXISTS cleanup_expired_sessions(); DROP FUNCTION IF EXISTS cleanup_old_data(); -- Supprimer les vues qui pourraient être en conflit DROP VIEW IF EXISTS server_stats CASCADE; -- Extensions nécessaires CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Table des sessions utilisateur sécurisées CREATE TABLE IF NOT EXISTS user_sessions_secure ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash VARCHAR(255) NOT NULL UNIQUE, refresh_token_hash VARCHAR(255) UNIQUE, device_info JSONB DEFAULT '{}', ip_address INET NOT NULL, user_agent TEXT, is_active BOOLEAN DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() + INTERVAL '7 days'), last_used TIMESTAMPTZ DEFAULT NOW() ); -- Table des événements de sécurité CREATE TABLE IF NOT EXISTS security_events_secure ( id BIGSERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, event_type VARCHAR(50) NOT NULL, severity VARCHAR(20) DEFAULT 'info' CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')), description TEXT NOT NULL, ip_address INET, user_agent TEXT, additional_data JSONB DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), resolved_at TIMESTAMPTZ, resolved_by INTEGER REFERENCES users(id) ON DELETE SET NULL ); -- Table des mentions CREATE TABLE IF NOT EXISTS message_mentions_secure ( id BIGSERIAL PRIMARY KEY, message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, is_read BOOLEAN DEFAULT false, read_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE (message_id, user_id) ); -- Table des blocages utilisateur CREATE TABLE IF NOT EXISTS user_blocks_secure ( id BIGSERIAL PRIMARY KEY, blocker_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, blocked_id INTEGER NOT NULL REFERENCES users(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) ); -- Index pour les performances CREATE INDEX IF NOT EXISTS idx_sessions_secure_user ON user_sessions_secure (user_id, is_active); CREATE INDEX IF NOT EXISTS idx_sessions_secure_expires ON user_sessions_secure (expires_at); CREATE INDEX IF NOT EXISTS idx_security_events_user ON security_events_secure (user_id, created_at DESC); CREATE INDEX IF NOT EXISTS idx_mentions_secure_user ON message_mentions_secure (user_id, is_read); CREATE INDEX IF NOT EXISTS idx_blocks_secure_blocker ON user_blocks_secure (blocker_id); -- Fonction de nettoyage des sessions expirées (nom unique) CREATE OR REPLACE FUNCTION cleanup_expired_sessions_secure() RETURNS INTEGER AS $$ DECLARE deleted_count INTEGER; BEGIN DELETE FROM user_sessions_secure WHERE expires_at < NOW() OR last_used < NOW() - INTERVAL '30 days'; GET DIAGNOSTICS deleted_count = ROW_COUNT; RETURN deleted_count; END; $$ LANGUAGE plpgsql; -- Fonction de nettoyage général (nom unique) CREATE OR REPLACE FUNCTION cleanup_old_data_secure() RETURNS void AS $$ BEGIN -- Supprimer les sessions expirées PERFORM cleanup_expired_sessions_secure(); -- Nettoyer les événements de sécurité anciens DELETE FROM security_events_secure WHERE created_at < NOW() - INTERVAL '6 months' AND severity = 'info'; RAISE NOTICE 'Nettoyage terminé'; END; $$ LANGUAGE plpgsql; -- Trigger pour les mentions automatiques CREATE OR REPLACE FUNCTION handle_mentions_secure() RETURNS TRIGGER AS $$ BEGIN -- Extraire les mentions @username du contenu INSERT INTO message_mentions_secure (message_id, user_id) SELECT NEW.id, u.id FROM users u WHERE NEW.content ~* ('@' || u.username || '\M') AND u.id != NEW.from_user ON CONFLICT (message_id, user_id) DO NOTHING; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS trigger_handle_mentions_secure ON messages; CREATE TRIGGER trigger_handle_mentions_secure AFTER INSERT ON messages FOR EACH ROW EXECUTE FUNCTION handle_mentions_secure(); -- Permissions GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO veza; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO veza; GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO veza; COMMIT;