-- +goose Up CREATE TABLE message_threads ( id BIGSERIAL PRIMARY KEY, created_by_user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, subject VARCHAR(255) NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT message_threads_subject_not_blank CHECK (length(btrim(subject)) > 0) ); CREATE TABLE message_thread_participants ( thread_id BIGINT NOT NULL REFERENCES message_threads(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_read_at TIMESTAMPTZ, archived_at TIMESTAMPTZ, PRIMARY KEY (thread_id, user_id) ); CREATE TABLE messages ( id BIGSERIAL PRIMARY KEY, thread_id BIGINT NOT NULL REFERENCES message_threads(id) ON DELETE CASCADE, sender_user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, body TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), CONSTRAINT messages_body_not_blank CHECK (length(btrim(body)) > 0) ); CREATE INDEX idx_message_threads_created_by_user_id ON message_threads(created_by_user_id); CREATE INDEX idx_message_threads_updated_at ON message_threads(updated_at DESC); CREATE INDEX idx_message_thread_participants_user_id ON message_thread_participants(user_id); CREATE INDEX idx_messages_thread_id_created_at ON messages(thread_id, created_at DESC); CREATE INDEX idx_messages_sender_user_id ON messages(sender_user_id); CREATE TRIGGER message_threads_updated_at BEFORE UPDATE ON message_threads FOR EACH ROW EXECUTE FUNCTION update_updated_at(); CREATE TRIGGER messages_updated_at BEFORE UPDATE ON messages FOR EACH ROW EXECUTE FUNCTION update_updated_at(); -- +goose Down DROP TRIGGER IF EXISTS messages_updated_at ON messages; DROP TRIGGER IF EXISTS message_threads_updated_at ON message_threads; DROP TABLE IF EXISTS messages; DROP TABLE IF EXISTS message_thread_participants; DROP TABLE IF EXISTS message_threads;