188 lines
8.6 KiB
SQL
188 lines
8.6 KiB
SQL
-- 010: Channel Kinds — text, voice, stage, forum, announcement
|
|
--
|
|
-- ALTER:
|
|
-- channel — add channel_kind + voice/forum/stage fields
|
|
-- message_thread — add forum post fields (title, tags, pinned, locked)
|
|
--
|
|
-- New tables:
|
|
-- forum_tag, voice_participant, stage,
|
|
-- message_poll, message_poll_option, message_poll_vote
|
|
|
|
-- ============================================================
|
|
-- 1. ALTER channel — add channel_kind + voice/forum/stage fields
|
|
-- ============================================================
|
|
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS channel_kind TEXT NOT NULL DEFAULT 'text';
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS position INTEGER NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS nsfw BOOLEAN NOT NULL DEFAULT FALSE;
|
|
|
|
-- Voice / Stage specific
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS bitrate INTEGER NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS user_limit INTEGER NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS rtc_region TEXT NULL;
|
|
|
|
-- Forum specific
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS default_auto_archive_duration INTEGER NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS default_reaction_emoji TEXT NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS default_sort_order TEXT NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS default_forum_layout TEXT NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS require_tag BOOLEAN NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS available_tags JSONB NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS default_thread_rate_limit INTEGER NULL;
|
|
|
|
-- General
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS rate_limit_per_user INTEGER NULL;
|
|
ALTER TABLE channel ADD COLUMN IF NOT EXISTS parent_channel_id UUID NULL REFERENCES channel(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_channel_channel_kind ON channel (channel_kind);
|
|
CREATE INDEX IF NOT EXISTS idx_channel_parent_channel_id ON channel (parent_channel_id);
|
|
|
|
-- ============================================================
|
|
-- 2. ALTER message_thread — add forum post fields
|
|
-- ============================================================
|
|
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS title TEXT NULL;
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS tags TEXT[] NOT NULL DEFAULT '{}';
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS pinned BOOLEAN NOT NULL DEFAULT FALSE;
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS locked BOOLEAN NOT NULL DEFAULT FALSE;
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS rate_limit_per_user INTEGER NULL;
|
|
ALTER TABLE message_thread ADD COLUMN IF NOT EXISTS auto_archive_at TIMESTAMPTZ NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_message_thread_pinned ON message_thread (pinned) WHERE pinned;
|
|
|
|
-- ============================================================
|
|
-- 3. Forum Tags
|
|
-- ============================================================
|
|
|
|
-- models/channels/forum_tags.rs → forum_tag
|
|
CREATE TABLE IF NOT EXISTS forum_tag (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
channel_id UUID NOT NULL REFERENCES channel(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
emoji_id TEXT NULL,
|
|
emoji_name TEXT NULL,
|
|
moderated BOOLEAN NOT NULL,
|
|
position INTEGER NOT NULL,
|
|
created_by UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMPTZ NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL,
|
|
CONSTRAINT uq_forum_tag_channel_name UNIQUE (channel_id, name)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_forum_tag_channel_id ON forum_tag (channel_id);
|
|
|
|
-- ============================================================
|
|
-- 4. Voice Participants
|
|
-- ============================================================
|
|
|
|
-- models/channels/voice_participants.rs → voice_participant
|
|
CREATE TABLE IF NOT EXISTS voice_participant (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
channel_id UUID NOT NULL REFERENCES channel(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
session_id TEXT NULL,
|
|
deafened BOOLEAN NOT NULL,
|
|
muted BOOLEAN NOT NULL,
|
|
self_deafened BOOLEAN NOT NULL,
|
|
self_muted BOOLEAN NOT NULL,
|
|
self_video BOOLEAN NOT NULL,
|
|
streaming BOOLEAN NOT NULL,
|
|
speaking BOOLEAN NOT NULL,
|
|
joined_at TIMESTAMPTZ NOT NULL,
|
|
left_at TIMESTAMPTZ NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_voice_participant_channel_id ON voice_participant (channel_id);
|
|
CREATE INDEX IF NOT EXISTS idx_voice_participant_user_id ON voice_participant (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_voice_participant_channel_user ON voice_participant (channel_id, user_id);
|
|
|
|
-- ============================================================
|
|
-- 5. Stages
|
|
-- ============================================================
|
|
|
|
-- models/channels/stages.rs → stage
|
|
CREATE TABLE IF NOT EXISTS stage (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
channel_id UUID NOT NULL REFERENCES channel(id) ON DELETE CASCADE,
|
|
topic TEXT NOT NULL,
|
|
privacy_level TEXT NOT NULL,
|
|
discoverable BOOLEAN NOT NULL,
|
|
started_by UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
started_at TIMESTAMPTZ NOT NULL,
|
|
ended_at TIMESTAMPTZ NULL,
|
|
created_at TIMESTAMPTZ NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL,
|
|
CONSTRAINT uq_stage_active_channel UNIQUE (channel_id, ended_at)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_stage_channel_id ON stage (channel_id);
|
|
CREATE INDEX IF NOT EXISTS idx_stage_channel_active ON stage (channel_id) WHERE ended_at IS NULL;
|
|
|
|
-- ============================================================
|
|
-- 6. Message Polls
|
|
-- ============================================================
|
|
|
|
-- models/channels/message_polls.rs → message_poll
|
|
CREATE TABLE IF NOT EXISTS message_poll (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
message_id UUID NOT NULL REFERENCES message(id) ON DELETE CASCADE,
|
|
channel_id UUID NOT NULL REFERENCES channel(id) ON DELETE CASCADE,
|
|
question TEXT NOT NULL,
|
|
description TEXT NULL,
|
|
layout TEXT NOT NULL,
|
|
allow_multiselect BOOLEAN NOT NULL,
|
|
duration_hours INTEGER NULL,
|
|
ends_at TIMESTAMPTZ NULL,
|
|
total_votes BIGINT NOT NULL,
|
|
metadata JSONB NULL,
|
|
created_at TIMESTAMPTZ NOT NULL,
|
|
updated_at TIMESTAMPTZ NOT NULL,
|
|
CONSTRAINT uq_message_poll_message_id UNIQUE (message_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_channel_id ON message_poll (channel_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_ends_at ON message_poll (ends_at) WHERE ends_at IS NOT NULL;
|
|
|
|
-- ============================================================
|
|
-- 7. Message Poll Options
|
|
-- ============================================================
|
|
|
|
-- models/channels/message_poll_options.rs → message_poll_option
|
|
CREATE TABLE IF NOT EXISTS message_poll_option (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
poll_id UUID NOT NULL REFERENCES message_poll(id) ON DELETE CASCADE,
|
|
position INTEGER NOT NULL,
|
|
text TEXT NOT NULL,
|
|
emoji_id TEXT NULL,
|
|
emoji_name TEXT NULL,
|
|
vote_count BIGINT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_option_poll_id ON message_poll_option (poll_id);
|
|
|
|
-- ============================================================
|
|
-- 8. Message Poll Votes
|
|
-- ============================================================
|
|
|
|
-- models/channels/message_poll_votes.rs → message_poll_vote
|
|
CREATE TABLE IF NOT EXISTS message_poll_vote (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
poll_id UUID NOT NULL REFERENCES message_poll(id) ON DELETE CASCADE,
|
|
option_id UUID NOT NULL REFERENCES message_poll_option(id) ON DELETE CASCADE,
|
|
user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
|
|
voted_at TIMESTAMPTZ NOT NULL,
|
|
CONSTRAINT uq_message_poll_vote_user_option UNIQUE (poll_id, option_id, user_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_vote_poll_id ON message_poll_vote (poll_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_vote_user_id ON message_poll_vote (user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_message_poll_vote_option_id ON message_poll_vote (option_id);
|
|
|
|
-- ============================================================
|
|
-- 9. Triggers — auto-refresh updated_at
|
|
-- ============================================================
|
|
|
|
DROP TRIGGER IF EXISTS trg_forum_tag_updated_at ON forum_tag;
|
|
CREATE TRIGGER trg_forum_tag_updated_at BEFORE UPDATE ON forum_tag FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
DROP TRIGGER IF EXISTS trg_stage_updated_at ON stage;
|
|
CREATE TRIGGER trg_stage_updated_at BEFORE UPDATE ON stage FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|
|
|
|
DROP TRIGGER IF EXISTS trg_message_poll_updated_at ON message_poll;
|
|
CREATE TRIGGER trg_message_poll_updated_at BEFORE UPDATE ON message_poll FOR EACH ROW EXECUTE FUNCTION set_updated_at();
|