-- ============================================================ -- saas_docs — Documentação dinâmica do sistema -- Exibida nas páginas do frontend via botão "Ajuda" -- ============================================================ -- ------------------------------------------------------------ -- 1. TABELA -- ------------------------------------------------------------ CREATE TABLE IF NOT EXISTS public.saas_docs ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), titulo text NOT NULL, conteudo text NOT NULL DEFAULT '', medias jsonb NOT NULL DEFAULT '[]'::jsonb, -- formato: [{ "tipo": "imagem"|"video", "url": "..." }, ...] tipo_acesso text NOT NULL DEFAULT 'usuario' CHECK (tipo_acesso IN ('usuario', 'admin')), -- 'usuario' → todos os autenticados -- 'admin' → clinic_admin, tenant_admin, saas_admin pagina_path text NOT NULL, -- path da rota do frontend, ex: '/therapist/agenda' pagina_label text, -- label amigável (informativo, não usado no match) docs_relacionados uuid[] NOT NULL DEFAULT '{}', -- IDs de outros saas_docs exibidos como "Veja também" ativo boolean NOT NULL DEFAULT true, ordem int NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); -- ------------------------------------------------------------ -- 2. ÍNDICE -- ------------------------------------------------------------ -- Query principal do frontend: filtra por path + ativo CREATE INDEX IF NOT EXISTS saas_docs_path_ativo_idx ON public.saas_docs (pagina_path, ativo); -- ------------------------------------------------------------ -- 3. RLS -- ------------------------------------------------------------ ALTER TABLE public.saas_docs ENABLE ROW LEVEL SECURITY; -- SaaS admin: acesso total (SELECT, INSERT, UPDATE, DELETE) -- Verificado via tabela saas_admins CREATE POLICY "saas_admin_full_access" ON public.saas_docs FOR ALL TO authenticated USING ( EXISTS ( SELECT 1 FROM public.saas_admins WHERE saas_admins.user_id = auth.uid() ) ) WITH CHECK ( EXISTS ( SELECT 1 FROM public.saas_admins WHERE saas_admins.user_id = auth.uid() ) ); -- Admins de clínica: leem todos os docs ativos (usuario + admin) CREATE POLICY "clinic_admin_read_all_docs" ON public.saas_docs FOR SELECT TO authenticated USING ( ativo = true AND EXISTS ( SELECT 1 FROM public.profiles WHERE profiles.id = auth.uid() AND profiles.role IN ('clinic_admin', 'tenant_admin') ) ); -- Demais usuários autenticados: leem apenas docs do tipo 'usuario' CREATE POLICY "users_read_usuario_docs" ON public.saas_docs FOR SELECT TO authenticated USING ( ativo = true AND tipo_acesso = 'usuario' ); -- ------------------------------------------------------------ -- 4. STORAGE — bucket saas-docs (imagens dos documentos) -- ------------------------------------------------------------ INSERT INTO storage.buckets (id, name, public) VALUES ('saas-docs', 'saas-docs', true) ON CONFLICT (id) DO NOTHING; -- SaaS admin: pode fazer upload CREATE POLICY "saas_admin_storage_upload" ON storage.objects FOR INSERT TO authenticated WITH CHECK ( bucket_id = 'saas-docs' AND EXISTS ( SELECT 1 FROM public.saas_admins WHERE saas_admins.user_id = auth.uid() ) ); -- SaaS admin: pode deletar CREATE POLICY "saas_admin_storage_delete" ON storage.objects FOR DELETE TO authenticated USING ( bucket_id = 'saas-docs' AND EXISTS ( SELECT 1 FROM public.saas_admins WHERE saas_admins.user_id = auth.uid() ) ); -- Leitura pública (bucket é público, mas policy explícita para clareza) CREATE POLICY "saas_docs_public_read" ON storage.objects FOR SELECT TO public USING (bucket_id = 'saas-docs');