CREATE TABLE pages ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), space_id uuid REFERENCES spaces(id) ON DELETE SET NULL, slug text NOT NULL, title text NOT NULL, body_md text NOT NULL DEFAULT '', body_html text, parent_id uuid REFERENCES pages(id) ON DELETE SET NULL, embedding vector(1024), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE (space_id, slug) ); CREATE TABLE page_revisions ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), page_id uuid NOT NULL REFERENCES pages(id) ON DELETE CASCADE, body_md text NOT NULL, edited_by text, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE refs ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), space_id uuid REFERENCES spaces(id) ON DELETE SET NULL, kind text NOT NULL CHECK (kind IN ('url','video','pdf','image','file')), source_url text, title text, description text, summary text, body_text text, blob_path text, thumbnail text, metadata jsonb NOT NULL DEFAULT '{}'::jsonb, embedding vector(1024), status text NOT NULL DEFAULT 'ingested' CHECK (status IN ('ingested','indexed','enriched')), source_kind text, external_id text, captured_at timestamptz NOT NULL DEFAULT now(), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX idx_pages_space ON pages(space_id); CREATE INDEX idx_pages_parent ON pages(parent_id); CREATE INDEX idx_pages_fts ON pages USING GIN (to_tsvector('english', title || ' ' || body_md)); CREATE INDEX idx_pages_embed ON pages USING hnsw (embedding vector_cosine_ops); CREATE INDEX idx_refs_space ON refs(space_id); CREATE INDEX idx_refs_kind ON refs(kind); CREATE INDEX idx_refs_external ON refs(source_kind, external_id) WHERE source_kind IS NOT NULL; CREATE INDEX idx_refs_fts ON refs USING GIN ( to_tsvector('english', coalesce(title,'') || ' ' || coalesce(summary,'') || ' ' || coalesce(body_text,'')) ); CREATE INDEX idx_refs_embed ON refs USING hnsw (embedding vector_cosine_ops);