← back to Lawyer Directory Builder
migrations/015_community.sql
61 lines
-- Community + DM threads. Channels: client_public / lawyer_public /
-- dm_client_lawyer / dm_client_client / dm_lawyer_lawyer.
CREATE TABLE IF NOT EXISTS threads (
id BIGSERIAL PRIMARY KEY,
channel TEXT NOT NULL CHECK (channel IN (
'client_public','lawyer_public',
'dm_client_lawyer','dm_client_client','dm_lawyer_lawyer'
)),
topic TEXT,
organization_id BIGINT REFERENCES organizations(id) ON DELETE SET NULL,
professional_id BIGINT REFERENCES professionals(id) ON DELETE SET NULL,
participant_user_ids BIGINT[] NOT NULL DEFAULT '{}',
created_by BIGINT REFERENCES app_users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_message_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
message_count INT NOT NULL DEFAULT 0,
closed_at TIMESTAMPTZ
);
CREATE INDEX IF NOT EXISTS idx_threads_channel_recent ON threads (channel, last_message_at DESC);
CREATE INDEX IF NOT EXISTS idx_threads_participants ON threads USING GIN (participant_user_ids);
CREATE INDEX IF NOT EXISTS idx_threads_org ON threads (organization_id) WHERE organization_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS messages (
id BIGSERIAL PRIMARY KEY,
thread_id BIGINT NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
user_id BIGINT NOT NULL REFERENCES app_users(id) ON DELETE SET NULL,
body TEXT NOT NULL,
posted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
edited_at TIMESTAMPTZ,
hidden_at TIMESTAMPTZ,
hidden_reason TEXT
);
CREATE INDEX IF NOT EXISTS idx_messages_thread ON messages (thread_id, posted_at);
CREATE INDEX IF NOT EXISTS idx_messages_user ON messages (user_id, posted_at DESC);
-- Reads/seen tracker so we can show unread counts in UI.
CREATE TABLE IF NOT EXISTS thread_reads (
thread_id BIGINT NOT NULL REFERENCES threads(id) ON DELETE CASCADE,
user_id BIGINT NOT NULL REFERENCES app_users(id) ON DELETE CASCADE,
last_read_message_id BIGINT REFERENCES messages(id) ON DELETE SET NULL,
last_read_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (thread_id, user_id)
);
-- Bump thread metadata on each message insert
CREATE OR REPLACE FUNCTION bump_thread_on_message() RETURNS TRIGGER AS $$
BEGIN
UPDATE threads
SET last_message_at = NEW.posted_at,
message_count = message_count + 1
WHERE id = NEW.thread_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_bump_thread_on_message ON messages;
CREATE TRIGGER trg_bump_thread_on_message
AFTER INSERT ON messages
FOR EACH ROW EXECUTE FUNCTION bump_thread_on_message();