AeThex-Connect/supabase/migrations/20260110120000_messaging_system.sql

158 lines
6.4 KiB
PL/PgSQL

-- Migration 002: Messaging System
-- Creates tables for conversations, messages, participants, reactions, calls, and files
-- ============================================================================
-- CONVERSATIONS
-- ============================================================================
CREATE TABLE IF NOT EXISTS conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
type VARCHAR(20) NOT NULL CHECK (type IN ('direct', 'group', 'channel')),
title VARCHAR(200),
description TEXT,
avatar_url VARCHAR(500),
created_by VARCHAR,
gameforge_project_id VARCHAR,
is_archived BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_conversations_type ON conversations(type);
CREATE INDEX IF NOT EXISTS idx_conversations_creator ON conversations(created_by);
CREATE INDEX IF NOT EXISTS idx_conversations_project ON conversations(gameforge_project_id);
CREATE INDEX IF NOT EXISTS idx_conversations_updated ON conversations(updated_at DESC);
-- ============================================================================
-- CONVERSATION PARTICIPANTS
-- ============================================================================
CREATE TABLE IF NOT EXISTS conversation_participants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
user_id UUID NOT NULL,
role VARCHAR(20) DEFAULT 'member' CHECK (role IN ('admin', 'moderator', 'member')),
joined_at TIMESTAMP DEFAULT NOW(),
last_read_at TIMESTAMP,
notification_settings JSONB DEFAULT '{"enabled": true, "mentions_only": false}'::jsonb,
UNIQUE(conversation_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_participants_conversation ON conversation_participants(conversation_id);
CREATE INDEX IF NOT EXISTS idx_participants_user ON conversation_participants(user_id);
-- ============================================================================
-- MESSAGES
-- ============================================================================
CREATE TABLE IF NOT EXISTS messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
sender_id UUID NOT NULL,
content_encrypted TEXT NOT NULL,
content_type VARCHAR(20) DEFAULT 'text' CHECK (content_type IN ('text', 'image', 'video', 'audio', 'file')),
metadata JSONB,
reply_to_id UUID REFERENCES messages(id) ON DELETE SET NULL,
edited_at TIMESTAMP,
deleted_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_messages_sender ON messages(sender_id);
CREATE INDEX IF NOT EXISTS idx_messages_reply_to ON messages(reply_to_id);
CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at DESC);
-- ============================================================================
-- MESSAGE REACTIONS
-- ============================================================================
CREATE TABLE IF NOT EXISTS message_reactions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
user_id UUID NOT NULL,
emoji VARCHAR(20) NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(message_id, user_id, emoji)
);
CREATE INDEX IF NOT EXISTS idx_reactions_message ON message_reactions(message_id);
CREATE INDEX IF NOT EXISTS idx_reactions_user ON message_reactions(user_id);
-- ============================================================================
-- MESSAGE ATTACHMENTS
-- ============================================================================
CREATE TABLE IF NOT EXISTS message_attachments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
file_name VARCHAR(500) NOT NULL,
file_url VARCHAR(1000) NOT NULL,
file_size INTEGER,
file_type VARCHAR(100),
uploaded_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_attachments_message ON message_attachments(message_id);
-- ============================================================================
-- CALLS
-- ============================================================================
CREATE TABLE IF NOT EXISTS calls (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL,
call_type VARCHAR(20) NOT NULL CHECK (call_type IN ('audio', 'video', 'screen_share')),
initiator_id UUID NOT NULL,
status VARCHAR(20) DEFAULT 'initiated' CHECK (status IN ('initiated', 'ringing', 'active', 'ended', 'missed', 'declined')),
started_at TIMESTAMP,
ended_at TIMESTAMP,
duration_seconds INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_calls_conversation ON calls(conversation_id);
CREATE INDEX IF NOT EXISTS idx_calls_initiator ON calls(initiator_id);
CREATE INDEX IF NOT EXISTS idx_calls_status ON calls(status);
CREATE INDEX IF NOT EXISTS idx_calls_created ON calls(created_at DESC);
-- ============================================================================
-- CALL PARTICIPANTS
-- ============================================================================
CREATE TABLE IF NOT EXISTS call_participants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
call_id UUID NOT NULL REFERENCES calls(id) ON DELETE CASCADE,
user_id UUID NOT NULL,
joined_at TIMESTAMP,
left_at TIMESTAMP,
is_muted BOOLEAN DEFAULT false,
is_camera_on BOOLEAN DEFAULT true,
UNIQUE(call_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_call_participants_call ON call_participants(call_id);
CREATE INDEX IF NOT EXISTS idx_call_participants_user ON call_participants(user_id);
-- ============================================================================
-- FUNCTIONS AND TRIGGERS
-- ============================================================================
-- Function to update conversation updated_at timestamp when messages are added
CREATE OR REPLACE FUNCTION update_conversation_timestamp()
RETURNS TRIGGER AS $$
BEGIN
UPDATE conversations
SET updated_at = NOW()
WHERE id = NEW.conversation_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger to update conversation timestamp on new message
DROP TRIGGER IF EXISTS trigger_update_conversation_timestamp ON messages;
CREATE TRIGGER trigger_update_conversation_timestamp
AFTER INSERT ON messages
FOR EACH ROW
EXECUTE FUNCTION update_conversation_timestamp();