Supabase: a espinha dorsal de dados
Quase tudo que a plataforma faz "sozinha" — resumo que chega de manhã, número que se atualiza, narrativa que aparece pronta — nasce de duas peças trabalhando juntas: Supabase (onde o dado mora) e Trigger.dev (onde o trabalho roda sem ninguém apertar botão). Este post explica como cada uma funciona, como elas se conectam e as pegadinhas que já nos morderam.
Supabase — mais que um banco
O Supabase é nosso PostgreSQL gerenciado, e ele segura bem mais que tabela:
- PostgreSQL com 50+ tabelas, acessadas pela aplicação via Drizzle ORM (TypeScript tipado de ponta a ponta).
- Auth com Google OAuth — login do time sai daqui.
- API automática (PostgREST) — e é exatamente isso que torna a próxima seção inegociável.
RLS é obrigatório — sem exceção
Como o Supabase expõe uma API sobre as tabelas, qualquer tabela sem Row Level Security vaza dado pra quem tiver a chave pública. Por isso a regra aqui é dura:
- Toda tabela nasce com
ENABLE ROW LEVEL SECURITYno mesmo migration que a cria. - Tabela exposta à API precisa de policy explícita; tabela interna (cache, log, job) liga RLS e fica sem policy de propósito (deny-all).
- PR que cria tabela sem RLS é barrado no review. Não existe "depois eu ligo".
Cuidado com o schema real
São 50+ tabelas e migrations SQL escritas à mão — há drift conhecido entre o banco e o schema Drizzle em TS. Nunca assuma que o .ts reflete o banco; confira o banco antes de criar dado. E jamais db:push em produção.
Trigger.dev — o piloto automático
É onde vivem os jobs agendados e workflows com retry e observabilidade. Exemplos reais nossos: resumos diários de conversa, sincronizações periódicas, geração de narrativas por IA das apresentações mensais. Coisas que precisam rodar no horário, sobreviver a falha e deixar rastro.
A vantagem sobre um "cron jogado num servidor": retry automático, log por execução, e o código do job versionado junto com a aplicação.
Como as duas se conectam
O padrão é simples e poderoso:
- Trigger.dev acorda no horário (ou por evento).
- Lê e escreve no Supabase via Drizzle.
- Opcionalmente chama IA (Claude) pra resumir/gerar.
- Grava o resultado numa tabela — que a aplicação lê na hora que o usuário abre a tela.
O usuário só vê o resultado pronto. O trabalho aconteceu enquanto ninguém olhava.
Pegadinhas que já nos custaram tempo
- Schedules só sincronizam no deploy. Mudou o cron e não fez deploy? O agendamento velho continua valendo.
- Pinar a CLI na versão do SDK:
npx trigger.dev@<versão> deploy. Versão da CLI diferente do SDK gera erro chato de diagnosticar. - Timezone no cron vai como objeto
{ pattern, timezone }— senão roda no fuso errado. - Migration é SQL à mão, o
_journal.jsonestá desatualizado;db:migratenão é o mecanismo. Saber disso evita "rodei o migrate e nada aconteceu".
Supabase guarda a verdade; Trigger.dev faz a verdade acontecer no horário certo. Juntos, transformam "alguém precisa rodar isso toda manhã" em "já rodou, está aqui o resultado".
Post-âncora do Módulo 3 da série Vibe Coding. (A parte de Trigger.dev deste post abre o Módulo 4.) Próximo da série: #19 — Modelagem com Drizzle ORM.