-- 050_legacy_chat.sql -- Legacy Chat (Aligned with ORIGIN "Module Chat" for Public Schema) -- Note: Origin specifies 'rooms', 'messages', 'room_members' fully. -- === ROOMS === CREATE TABLE public.rooms ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Room Info name VARCHAR(255), slug VARCHAR(100), -- Origin UNIQUE, nullable description TEXT, -- Type room_type VARCHAR(50) NOT NULL, -- public, private, dm -- Visibility is_private BOOLEAN NOT NULL DEFAULT false, password_hash VARCHAR(255), -- Limits max_members INTEGER, -- Creator creator_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, -- Counts member_count INTEGER NOT NULL DEFAULT 0, message_count INTEGER NOT NULL DEFAULT 0, -- Legacy fields owner_id UUID, -- Maps to creator_id is_active BOOLEAN DEFAULT true, -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ ); CREATE INDEX idx_rooms_creator_id ON public.rooms(creator_id); CREATE INDEX idx_rooms_room_type ON public.rooms(room_type); CREATE UNIQUE INDEX idx_rooms_slug ON public.rooms(slug) WHERE slug IS NOT NULL; CREATE INDEX idx_rooms_created_at_desc ON public.rooms(created_at DESC); -- === ROOM MEMBERS === CREATE TABLE public.room_members ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), room_id UUID NOT NULL REFERENCES public.rooms(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, -- Role role VARCHAR(50) NOT NULL DEFAULT 'member', -- owner, admin, moderator, member -- Status is_banned BOOLEAN NOT NULL DEFAULT false, is_muted BOOLEAN NOT NULL DEFAULT false, -- Read Status last_read_at TIMESTAMPTZ, -- Timestamps joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Legacy created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, deleted_at TIMESTAMPTZ, CONSTRAINT uq_room_members_room_user UNIQUE (room_id, user_id) ); CREATE INDEX idx_room_members_room_id ON public.room_members(room_id); CREATE INDEX idx_room_members_user_id ON public.room_members(user_id); CREATE INDEX idx_room_members_role ON public.room_members(role); -- === MESSAGES === CREATE TABLE public.messages ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), room_id UUID NOT NULL REFERENCES public.rooms(id) ON DELETE CASCADE, sender_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE, -- Message Content content TEXT NOT NULL, message_type public.message_type NOT NULL DEFAULT 'text', -- Attachments attachment_file_id UUID REFERENCES public.files(id) ON DELETE SET NULL, -- Threading reply_to_id UUID REFERENCES public.messages(id) ON DELETE SET NULL, -- Status is_edited BOOLEAN NOT NULL DEFAULT false, edited_at TIMESTAMPTZ, is_deleted BOOLEAN NOT NULL DEFAULT false, is_pinned BOOLEAN NOT NULL DEFAULT false, -- Metadata metadata JSONB, -- Legacy user_id UUID, -- Maps to sender_id parent_id UUID, -- Maps to reply_to_id -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), deleted_at TIMESTAMPTZ, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Added for triggers CONSTRAINT chk_messages_content_length CHECK (LENGTH(content) >= 1 AND LENGTH(content) <= 10000) ); CREATE INDEX idx_messages_room_id_created_at ON public.messages(room_id, created_at DESC); CREATE INDEX idx_messages_sender_id ON public.messages(sender_id); CREATE INDEX idx_messages_reply_to_id ON public.messages(reply_to_id) WHERE reply_to_id IS NOT NULL; CREATE INDEX idx_messages_is_pinned ON public.messages(room_id, is_pinned) WHERE is_pinned = true; CREATE INDEX idx_messages_content_gin ON public.messages USING GIN(to_tsvector('english', content));