-- Per-website AI prompt instances (editable copies) with their own public links. CREATE TABLE IF NOT EXISTS domain_ai_prompts ( id BIGSERIAL PRIMARY KEY, domain_id BIGINT NOT NULL REFERENCES domains (id) ON DELETE CASCADE, source_template_id BIGINT REFERENCES ai_prompt_templates (id) ON DELETE SET NULL, name VARCHAR(255) NOT NULL, body TEXT NOT NULL, public_id VARCHAR(32) NOT NULL, sort_order INT NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT domain_ai_prompts_public_id_unique UNIQUE (public_id) ); CREATE INDEX IF NOT EXISTS idx_domain_ai_prompts_domain_id ON domain_ai_prompts (domain_id, sort_order, id); CREATE INDEX IF NOT EXISTS idx_domain_ai_prompts_source_template_id ON domain_ai_prompts (source_template_id); CREATE OR REPLACE FUNCTION domain_ai_prompts_set_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS domain_ai_prompts_set_updated_at ON domain_ai_prompts; CREATE TRIGGER domain_ai_prompts_set_updated_at BEFORE UPDATE ON domain_ai_prompts FOR EACH ROW EXECUTE FUNCTION domain_ai_prompts_set_updated_at(); -- Copy existing assignments into editable instances (one public id each). DO $$ DECLARE r RECORD; pid TEXT; BEGIN IF EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_name = 'domain_ai_prompt_templates' ) THEN FOR r IN SELECT l.domain_id, l.template_id, l.sort_order, t.name, t.body FROM domain_ai_prompt_templates l JOIN ai_prompt_templates t ON t.id = l.template_id ORDER BY l.domain_id, l.sort_order, l.template_id LOOP LOOP pid := encode(gen_random_bytes(12), 'hex'); EXIT WHEN NOT EXISTS ( SELECT 1 FROM domain_ai_prompts WHERE public_id = pid ); END LOOP; INSERT INTO domain_ai_prompts ( domain_id, source_template_id, name, body, public_id, sort_order ) VALUES ( r.domain_id, r.template_id, r.name, r.body, pid, r.sort_order ); END LOOP; END IF; END $$; DROP TABLE IF EXISTS domain_ai_prompt_templates;