bba1df32cb
git-subtree-dir: cms/core git-subtree-split: 59b9e2075ac48cf017db38009d54dbe56a98fffc
100 lines
4.7 KiB
SQL
100 lines
4.7 KiB
SQL
-- dialog plugin schema — forums / threads / comments (+ comment_stats view).
|
|
--
|
|
-- Captured 2026-06-29 from the live openbureau dev DB (CT 134 → openbureau-db,
|
|
-- supabase/postgres 15.8) via `pg_dump --schema-only --no-owner --no-privileges`
|
|
-- of public.{forums,threads,comments,comment_stats}. Made idempotent (IF NOT
|
|
-- EXISTS / OR REPLACE / constraint guards) so it is a no-op against the existing
|
|
-- openbureau DB and safe to apply to a fresh instance.
|
|
--
|
|
-- Notes:
|
|
-- * gen_random_uuid() is built into Postgres 13+ — no pgcrypto extension needed.
|
|
-- * RLS is enabled with NO policies: every read/write is mediated by the CMS
|
|
-- using the Supabase service_role key (which bypasses RLS). The dialog plugin
|
|
-- therefore only makes sense with `auth: supabase`; kgva (local auth) omits it.
|
|
-- * `posts` exists in the live DB but the dialog code never touches it — NOT a
|
|
-- dialog table, intentionally excluded.
|
|
|
|
-- ── tables ──────────────────────────────────────────────────────────────────
|
|
CREATE TABLE IF NOT EXISTS public.forums (
|
|
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
|
slug text NOT NULL,
|
|
name text NOT NULL,
|
|
description text DEFAULT ''::text,
|
|
color text,
|
|
sort integer DEFAULT 0 NOT NULL,
|
|
kind text DEFAULT 'forum'::text NOT NULL,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS public.threads (
|
|
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
|
forum_id uuid,
|
|
key text NOT NULL,
|
|
title text NOT NULL,
|
|
url text,
|
|
kind text DEFAULT 'forum'::text NOT NULL,
|
|
author_name text,
|
|
user_id uuid,
|
|
locked boolean DEFAULT false NOT NULL,
|
|
deleted boolean DEFAULT false NOT NULL,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS public.comments (
|
|
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
|
thread text NOT NULL,
|
|
parent_id uuid,
|
|
user_id uuid,
|
|
author_name text,
|
|
author_avatar text,
|
|
body text NOT NULL,
|
|
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
deleted boolean DEFAULT false NOT NULL,
|
|
author_role text
|
|
);
|
|
|
|
-- ── constraints (guarded — Postgres has no ADD CONSTRAINT IF NOT EXISTS) ──────
|
|
DO $$ BEGIN
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'forums_pkey') THEN
|
|
ALTER TABLE ONLY public.forums ADD CONSTRAINT forums_pkey PRIMARY KEY (id);
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'forums_slug_key') THEN
|
|
ALTER TABLE ONLY public.forums ADD CONSTRAINT forums_slug_key UNIQUE (slug);
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'threads_pkey') THEN
|
|
ALTER TABLE ONLY public.threads ADD CONSTRAINT threads_pkey PRIMARY KEY (id);
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'threads_key_key') THEN
|
|
ALTER TABLE ONLY public.threads ADD CONSTRAINT threads_key_key UNIQUE (key);
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'comments_pkey') THEN
|
|
ALTER TABLE ONLY public.comments ADD CONSTRAINT comments_pkey PRIMARY KEY (id);
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'threads_forum_id_fkey') THEN
|
|
ALTER TABLE ONLY public.threads ADD CONSTRAINT threads_forum_id_fkey
|
|
FOREIGN KEY (forum_id) REFERENCES public.forums(id) ON DELETE CASCADE;
|
|
END IF;
|
|
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'comments_parent_id_fkey') THEN
|
|
ALTER TABLE ONLY public.comments ADD CONSTRAINT comments_parent_id_fkey
|
|
FOREIGN KEY (parent_id) REFERENCES public.comments(id) ON DELETE CASCADE;
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ── indexes ───────────────────────────────────────────────────────────────────
|
|
CREATE INDEX IF NOT EXISTS threads_forum_idx ON public.threads USING btree (forum_id);
|
|
CREATE INDEX IF NOT EXISTS comments_thread_idx ON public.comments USING btree (thread, created_at);
|
|
|
|
-- ── view: per-thread comment counts (used by dialog-store) ────────────────────
|
|
CREATE OR REPLACE VIEW public.comment_stats AS
|
|
SELECT comments.thread,
|
|
(count(*))::integer AS count,
|
|
max(comments.created_at) AS last
|
|
FROM public.comments
|
|
WHERE (NOT comments.deleted)
|
|
GROUP BY comments.thread;
|
|
|
|
-- ── row-level security (enabled, no policies — service_role-mediated) ─────────
|
|
ALTER TABLE public.forums ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.threads ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.comments ENABLE ROW LEVEL SECURITY;
|