Files
aura-crm/production/backend/migrations/047_site_page_blocks.sql
T

39 lines
2.0 KiB
SQL

-- +goose Up
-- Content for the marketing site's (`/root/site`) drag-and-drop page
-- builder — an owner/manager (gated by the existing "settings" permission,
-- see internal/sitecontent) edits this from the CRM, and site/web renders
-- whatever is_visible=true holds via a public read endpoint. Deliberately a
-- flat ordered list per page, not a block tree — this is a single-page
-- marketing site, nested layout is over-engineering for what's actually
-- needed. `page` exists (rather than assuming one global list) so a second
-- page could be added later without a schema change, even though today
-- only 'home' is ever used.
--
-- `content` is a type-dependent JSONB blob (hero: heading/subheading/button
-- text+link; text: heading/body; cards: repeatable {icon,title,text,link};
-- faq: repeatable {question,answer}; cta: heading/body/button; custom_code:
-- a single raw HTML/script string) — no per-type columns, since the shape
-- genuinely varies per block type and every consumer (the CRM editor, the
-- public API, site/web's renderer) already has to switch on `type` anyway.
--
-- custom_code's content is rendered UNSANITIZED on the public site by
-- design (see internal/sitecontent's package doc) — that's what makes a
-- chat-widget embed snippet possible at all. The access control is "only a
-- settings-permission staff member can write a row here", not sanitization
-- of what they write.
CREATE TABLE site_page_blocks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
page TEXT NOT NULL DEFAULT 'home',
position INT NOT NULL,
type TEXT NOT NULL CHECK (type IN ('hero', 'text', 'cards', 'faq', 'cta', 'custom_code')),
content JSONB NOT NULL DEFAULT '{}',
is_visible BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX site_page_blocks_page_position_idx ON site_page_blocks (page, position);
-- +goose Down
DROP TABLE site_page_blocks;