/* * Site Builder Migration * Tables: site_pages, site_settings, cms_posts, newsletter_subscriptions * Public read via anon + RLS */ -- ===================================================== -- 1. site_pages — Puck JSON per page -- ===================================================== CREATE TABLE IF NOT EXISTS public.site_pages ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE, slug text NOT NULL, title text NOT NULL, puck_data jsonb NOT NULL DEFAULT '{}'::jsonb, is_published boolean NOT NULL DEFAULT false, is_homepage boolean NOT NULL DEFAULT false, sort_order integer NOT NULL DEFAULT 0, meta_description text, meta_image text, created_by uuid REFERENCES auth.users(id), updated_by uuid REFERENCES auth.users(id), created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), published_at timestamptz, UNIQUE(account_id, slug) ); CREATE INDEX idx_site_pages_account ON public.site_pages(account_id); CREATE INDEX idx_site_pages_published ON public.site_pages(account_id, is_published); ALTER TABLE public.site_pages ENABLE ROW LEVEL SECURITY; REVOKE ALL ON public.site_pages FROM authenticated, service_role; GRANT SELECT, INSERT, UPDATE, DELETE ON public.site_pages TO authenticated; GRANT SELECT ON public.site_pages TO anon; GRANT ALL ON public.site_pages TO service_role; CREATE POLICY site_pages_public_read ON public.site_pages FOR SELECT TO anon USING (is_published = true); CREATE POLICY site_pages_auth_read ON public.site_pages FOR SELECT TO authenticated USING ( is_published = true OR public.has_role_on_account(account_id) ); CREATE POLICY site_pages_admin_write ON public.site_pages FOR ALL TO authenticated USING ( public.has_permission(auth.uid(), account_id, 'settings.manage'::public.app_permissions) ); CREATE TRIGGER trg_site_pages_updated BEFORE UPDATE ON public.site_pages FOR EACH ROW EXECUTE FUNCTION public.update_account_settings_timestamp(); -- ===================================================== -- 2. site_settings — Per-club branding -- ===================================================== CREATE TABLE IF NOT EXISTS public.site_settings ( account_id uuid PRIMARY KEY REFERENCES public.accounts(id) ON DELETE CASCADE, site_name text, site_logo text, primary_color text DEFAULT '#2563eb', secondary_color text DEFAULT '#64748b', font_family text DEFAULT 'Inter', custom_css text, navigation jsonb NOT NULL DEFAULT '[]'::jsonb, footer_text text, contact_email text, contact_phone text, contact_address text, social_links jsonb DEFAULT '{}'::jsonb, impressum text, datenschutz text, custom_domain text, is_public boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); ALTER TABLE public.site_settings ENABLE ROW LEVEL SECURITY; REVOKE ALL ON public.site_settings FROM authenticated, service_role; GRANT SELECT, INSERT, UPDATE ON public.site_settings TO authenticated; GRANT SELECT ON public.site_settings TO anon; GRANT ALL ON public.site_settings TO service_role; CREATE POLICY site_settings_public_read ON public.site_settings FOR SELECT TO anon USING (is_public = true); CREATE POLICY site_settings_auth_read ON public.site_settings FOR SELECT TO authenticated USING ( is_public = true OR public.has_role_on_account(account_id) ); CREATE POLICY site_settings_admin_write ON public.site_settings FOR ALL TO authenticated USING ( public.has_permission(auth.uid(), account_id, 'settings.manage'::public.app_permissions) ); CREATE TRIGGER trg_site_settings_updated BEFORE UPDATE ON public.site_settings FOR EACH ROW EXECUTE FUNCTION public.update_account_settings_timestamp(); -- ===================================================== -- 3. cms_posts — News/blog per club -- ===================================================== CREATE TABLE IF NOT EXISTS public.cms_posts ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE, title text NOT NULL, slug text NOT NULL, content text, excerpt text, cover_image text, author_id uuid REFERENCES auth.users(id), status text NOT NULL DEFAULT 'draft' CHECK (status IN ('draft','published','archived')), published_at timestamptz, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), UNIQUE(account_id, slug) ); CREATE INDEX idx_cms_posts_account ON public.cms_posts(account_id); CREATE INDEX idx_cms_posts_published ON public.cms_posts(account_id, status); ALTER TABLE public.cms_posts ENABLE ROW LEVEL SECURITY; REVOKE ALL ON public.cms_posts FROM authenticated, service_role; GRANT SELECT, INSERT, UPDATE, DELETE ON public.cms_posts TO authenticated; GRANT SELECT ON public.cms_posts TO anon; GRANT ALL ON public.cms_posts TO service_role; CREATE POLICY cms_posts_public_read ON public.cms_posts FOR SELECT TO anon USING (status = 'published'); CREATE POLICY cms_posts_auth_read ON public.cms_posts FOR SELECT TO authenticated USING ( status = 'published' OR public.has_role_on_account(account_id) ); CREATE POLICY cms_posts_admin_write ON public.cms_posts FOR ALL TO authenticated USING ( public.has_permission(auth.uid(), account_id, 'settings.manage'::public.app_permissions) ); CREATE TRIGGER trg_cms_posts_updated BEFORE UPDATE ON public.cms_posts FOR EACH ROW EXECUTE FUNCTION public.update_account_settings_timestamp(); -- ===================================================== -- 4. newsletter_subscriptions — Public signup -- ===================================================== CREATE TABLE IF NOT EXISTS public.newsletter_subscriptions ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), account_id uuid NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE, email text NOT NULL, name text, subscribed_at timestamptz NOT NULL DEFAULT now(), unsubscribed_at timestamptz, is_active boolean NOT NULL DEFAULT true, confirmation_token text, confirmed_at timestamptz, UNIQUE(account_id, email) ); CREATE INDEX idx_newsletter_subs_account ON public.newsletter_subscriptions(account_id); ALTER TABLE public.newsletter_subscriptions ENABLE ROW LEVEL SECURITY; REVOKE ALL ON public.newsletter_subscriptions FROM authenticated, service_role; GRANT SELECT, INSERT, UPDATE, DELETE ON public.newsletter_subscriptions TO authenticated; GRANT INSERT ON public.newsletter_subscriptions TO anon; GRANT ALL ON public.newsletter_subscriptions TO service_role; CREATE POLICY newsletter_sub_public_insert ON public.newsletter_subscriptions FOR INSERT TO anon WITH CHECK (true); CREATE POLICY newsletter_sub_admin ON public.newsletter_subscriptions FOR ALL TO authenticated USING (public.has_role_on_account(account_id));