-- ========================================================================== -- Agencia PSI — Migracao: Storage Bucket para midia de WhatsApp -- ========================================================================== -- Criado por: Leonardo Nohama -- Data: 2026-04-21 · Sao Carlos/SP — Brasil -- -- Cria bucket privado `whatsapp-media` para armazenar audio/imagem/video/ -- documentos recebidos via Evolution API. URLs do WhatsApp sao encriptadas -- com mediaKey da Meta — precisamos decriptar via Evolution getBase64 e -- subir pro nosso storage para playback no browser. -- -- Privacidade LGPD: -- - Bucket privado (public=false) -- - Upload apenas via service_role (edge function) -- - Leitura via signed URLs gerados on-demand pelo frontend (expiracao curta) -- - Paths tenant-scoped: ///. -- ========================================================================== -- Bucket whatsapp-media INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types) VALUES ( 'whatsapp-media', 'whatsapp-media', false, 26214400, -- 25 MB (WhatsApp aceita ate 16MB audio/video, margem extra) ARRAY[ -- Audio 'audio/ogg', 'audio/mpeg', 'audio/mp4', 'audio/aac', 'audio/wav', 'audio/webm', -- Imagem 'image/jpeg', 'image/png', 'image/webp', 'image/gif', -- Video 'video/mp4', 'video/3gpp', 'video/quicktime', 'video/webm', -- Documento 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'text/plain', 'application/zip', 'application/octet-stream' ] ) ON CONFLICT (id) DO NOTHING; -- -------------------------------------------------------------------------- -- Storage RLS Policies — whatsapp-media -- -------------------------------------------------------------------------- -- Politica: APENAS service_role faz upload (edge function). -- Usuarios autenticados leem se forem membros ativos do tenant no path[0]. -- -------------------------------------------------------------------------- -- Read: membro ativo do tenant cujo id e o primeiro segmento do path CREATE POLICY "whatsapp-media: read tenant members" ON storage.objects FOR SELECT TO authenticated USING ( bucket_id = 'whatsapp-media' AND ( -- SaaS admins leem qualquer tenant public.is_saas_admin() OR -- Membros ativos do tenant (tenant_id e o primeiro segmento do path) EXISTS ( SELECT 1 FROM public.tenant_members tm WHERE tm.user_id = auth.uid() AND tm.status = 'active' AND (storage.foldername(name))[1] = tm.tenant_id::text ) ) ); -- Insert: bloqueado para authenticated (apenas service_role sobe) -- Sem policy de INSERT para authenticated = bloqueado por default no RLS. -- Delete: SaaS admin pode deletar (retention policy futura) CREATE POLICY "whatsapp-media: delete saas admin" ON storage.objects FOR DELETE TO authenticated USING ( bucket_id = 'whatsapp-media' AND public.is_saas_admin() ); -- ========================================================================== -- FIM DA MIGRACAO -- ==========================================================================