CREATE TABLE messages ( id BYTEA NOT NULL CHECK(length(id) = 26), channel_id BYTEA NOT NULL CHECK(length(channel_id) = 26), guild_id BYTEA CHECK(length(guild_id) = 26), -- nullable for DMs author_id BYTEA NOT NULL CHECK(length(author_id) = 26), -- Message content and metadata content TEXT NOT NULL DEFAULT '', timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(), edited_timestamp TIMESTAMPTZ, tts BOOLEAN NOT NULL DEFAULT FALSE, -- Mentions and embeds (as JSON for flexibility) mentions BYTEA[], -- array of user IDs (could also be TEXT[] if using base58) mention_everyone BOOLEAN NOT NULL DEFAULT FALSE, embeds JSONB NOT NULL DEFAULT '[]'::jsonb, attachments BYTEA[], -- Reply/reference data (optional) reply_message_id BYTEA CHECK(length(reply_message_id) = 26), application_id BYTEA CHECK(length(application_id) = 26), -- for slash commands -- System/interaction message type message_type INTEGER NOT NULL DEFAULT 0, -- 0 = default, 1 = reply, 2 = gateway ping, etc. -- Thread support thread_name TEXT, auto_archive_duration INTEGER, -- minutes (360, 1440, 4320, 10080) -- Audit & integrity created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (id) ); -- Indexes for common query patterns CREATE INDEX idx_messages_channel_id ON messages (channel_id); CREATE INDEX idx_messages_channel_id_timestamp ON messages (channel_id, timestamp DESC); CREATE INDEX idx_messages_author_id ON messages (author_id); CREATE INDEX idx_messages_guild_id ON messages (guild_id) WHERE guild_id IS NOT NULL; CREATE INDEX idx_messages_reference_message_id ON messages (reply_message_id); CREATE INDEX idx_messages_timestamp ON messages (timestamp DESC);