🔐 O salto de "protótipo" para "produto seguro"
Um app na sua máquina pode até ter a chave colada no código que ninguém vê. Mas no momento em que ele sobe para o GitHub e roda na nuvem, qualquer descuido com segredos vira um problema real — chave vazada gasta seu dinheiro, dado exposto vira incidente. Este módulo é o conjunto de hábitos que mantém isso sob controle: onde os segredos moram, como o código os lê, e quem consegue ver o quê.
Antes dos oito tópicos, veja a ideia que une todos: o código é público (vai para o GitHub), mas os segredos ficam fora dele, num cofre separado, e só são injetados na hora de rodar. Mais uma camada — o banco com RLS — garante que, mesmo com o app no ar, um usuário nunca vê os dados de outro.
Diagrama ilustrativo — segurança em camadas: nenhum segredo no código, chaves só no cofre injetadas em runtime, e o banco isolando dados com RLS independentemente de bugs no app.
🔑 Variáveis de ambiente
O que é
Uma variável de ambiente é um valor que fica armazenado fora do código e é injetado no programa só na hora de rodar (em runtime). O efeito é simples e poderoso: o código nunca contém a chave. Onde antes você escreveria const key = "sk-ant-abc123...", agora escreve const key = process.env.ANTHROPIC_API_KEY — o valor real vem do ambiente, não do arquivo.
O que é?Runtime — o momento em que o programa está de fato executando. Chave de API — uma senha que dá ao seu app acesso a um serviço (Anthropic, Firecrawl, Google). Hard-coded — valor escrito direto no código (o que queremos evitar para segredos).
Diagrama ilustrativo — o código vira uma referência ("dê-me a chave chamada ANTHROPIC_API_KEY"); o valor real vive no ambiente e nunca aparece no repositório.
Por que aprender
É o mecanismo que separa "o que é público" (o código) de "o que é secreto" (as chaves). Sem ele, todo segredo viaja junto com o código — e basta um git push para ele estar exposto no GitHub para sempre, mesmo que você apague depois. Variável de ambiente é a fundação de tudo que vem nos próximos tópicos: é a base de gerência de segredos.
Conceitos-chave
O segredo não mora no arquivo.
Injetado só na hora de rodar.
O código pede a chave pelo nome.
Chave nunca escrita à mão.
🗄️ Local (.env) vs nuvem (dashboard)
O que é
O mesmo segredo vive em dois lugares diferentes, dependendo de onde o código roda. No modelo local, ele fica num arquivo .env na sua máquina. No modelo nuvem, ele fica no painel de Environment Variables da plataforma (Trigger.dev, Vercel), que injeta os valores em runtime. O detalhe que pega todo mundo: o Trigger.dev não consegue ler o seu .env local — na nuvem, ele só conhece o que você cadastrou no dashboard.
O que é?Environment Variables (dashboard) — a tela da plataforma onde você adiciona cada segredo como par chave/valor. Ambiente de development — para testar; production — o que roda de verdade para os usuários.
🎯 Objetivo: guardar todos os segredos do projeto fora do código, num arquivo local.
# .env — NUNCA vai para o GitHub (precisa estar no .gitignore) ANTHROPIC_API_KEY=<sua-chave> FIRECRAWL_API_KEY=<sua-chave> # Google (acesso via OAuth — ver tópico 4) GOOGLE_CLIENT_ID=<seu-client-id> GOOGLE_CLIENT_SECRET=<seu-client-secret> GOOGLE_REFRESH_TOKEN=<seu-refresh-token> SHEET_ID=<id-da-sua-planilha>
✅ Como verificar: rode cat .gitignore e confirme que existe uma linha .env — se o arquivo aparece em git status como "a ser commitado", PARE e adicione ao .gitignore antes de qualquer push.
🎯 Dica prática
Ao subir para produção, cadastre cada chave do .env também no dashboard da nuvem — e marque tanto development quanto production. Esquecer de cadastrar uma chave em production é a origem clássica do bug que "só falha em prod": localmente tudo funciona, na nuvem o app quebra com "key is undefined".
Por que aprender
Porque "funcionou na minha máquina" não basta: o ambiente da nuvem é outro, com outro cofre de segredos. Entender que são dois lugares — e que precisam estar sincronizados — evita o erro mais frustrante do deploy. E reforça a regra do tópico 5: você pode (e às vezes deve) usar chaves distintas para local e produção.
Conceitos-chave
Arquivo na sua máquina.
Painel de env vars.
A nuvem ignora seu arquivo local.
Cadastre nos dois ambientes.
📄 .env.example e process.env
O que é
O .env.example é um template seguro de commitar: lista os nomes das chaves que o projeto precisa, mas sem nenhum valor. Ele documenta "o que esse projeto exige" sem expor um único segredo. Já o process.env é como o código lê esses valores em runtime — nunca os escreve direto. Na prática, você pede ao Claude Code para criar o .env, confirmar que está no .gitignore, gerar o .env.example e ajustar o código para ler de process.env.
🎯 Objetivo: documentar quais segredos o projeto precisa, sem expor nenhum — este arquivo PODE ir para o GitHub.
# .env.example — só os NOMES, nenhum valor. Seguro de commitar. # Copie para .env e preencha os valores reais. ANTHROPIC_API_KEY= FIRECRAWL_API_KEY= GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GOOGLE_REFRESH_TOKEN= SHEET_ID=
✅ Como verificar: abra o arquivo — nenhum valor depois do =. Quem clonar o repo entende o que precisa configurar, mas não recebe nenhum segredo seu.
🎯 Objetivo: ler o segredo em runtime, sem nunca escrevê-lo no código.
// lê o valor do ambiente — o código fica sem segredo
const key = process.env.ANTHROPIC_API_KEY;
// falha rápido e claro se a chave não foi configurada
if (!key) {
throw new Error("Faltou ANTHROPIC_API_KEY no ambiente (.env ou dashboard).");
}
✅ Como verificar: rode o código sem a chave no ambiente — ele deve falhar com a mensagem clara, não com um erro confuso lá na frente. Esse "falha rápido" economiza horas de debug.
🎯 Objetivo: deixar o Claude Code configurar todo o esquema de segredos de uma vez.
Configure as variáveis de ambiente do projeto para estas chaves: ANTHROPIC_API_KEY, FIRECRAWL_API_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, SHEET_ID. Faça, nesta ordem: 1. crie o arquivo .env (com placeholders <sua-chave>); 2. garanta que .env está no .gitignore; 3. crie um .env.example com as mesmas chaves SEM valores; 4. ajuste o código para ler tudo de process.env (nada hard-coded). Não cole nenhuma chave real no chat.
✅ Como verificar: ao final, git status mostra .env.example como novo arquivo, mas NÃO mostra .env. Faça uma busca por aspas com "sk-" no código para garantir que nenhuma chave ficou hard-coded.
Por que aprender
Porque um projeto sem .env.example é um quebra-cabeça: quem clona não sabe quais chaves precisa, e acaba descobrindo por tentativa e erro. O par .env.example + process.env resolve isso elegantemente — documenta o necessário e mantém o código limpo de segredos. É a prática padrão de qualquer projeto profissional.
Conceitos-chave
Só os nomes, sem valor.
O example pode subir; o .env não.
Leitura em runtime.
Diz o que o projeto precisa.
🔄 OAuth & refresh token
O que é
OAuth é o protocolo que permite delegar acesso a um serviço (por exemplo, o Google) sem expor a sua senha. Em vez de dar sua senha ao app, você autoriza o app a agir em seu nome e ele recebe tokens. O refresh token é o token de longa duração que renova o acesso sozinho quando o acesso temporário expira — é o que mantém um agente hospedado funcionando sem você logar de novo toda vez.
O que é?Client ID / Client secret — a "identidade" do seu app no Google Cloud Console. Access token — acesso curto, expira rápido. Refresh token — acesso longo, gera novos access tokens. Service account — uma conta-robô alternativa (aqui usamos OAuth do usuário, mais simples para Sheets/Drive pessoais).
Por que aprender
Porque é assim que agentes na nuvem acessam Google Sheets, Drive e Gmail sem você abrir o navegador toda execução. O caminho concreto: criar credenciais OAuth (client ID + secret) no Google Cloud Console e obter um refresh token. O fluxo padrão pelo OAuth Playground às vezes falha com "access blocked" ou "request is invalid"; a alternativa que funciona é um script de terminal que imprime uma URL de autorização e, no fim, devolve o refresh token para você colar no .env e nas env vars do Trigger.dev.
✓ Acesso delegado (OAuth)
- ✓Autorizar o app sem entregar a senha.
- ✓Refresh token renova o acesso sozinho.
- ✓Se o Playground falhar, gerar o token via script no terminal.
✗ Atalhos perigosos
- ✗Colar sua senha do Google direto no app.
- ✗Logar manualmente toda vez que o agente roda.
- ✗Commitar o refresh token no repositório.
🎯 Dica prática
Se o OAuth Playground travar com "access blocked / request is invalid", não insista nele. Peça ao Claude Code um pequeno script de terminal que usa seu GOOGLE_CLIENT_ID e GOOGLE_CLIENT_SECRET, imprime a URL de autorização, recebe o código que o Google devolve e cospe o GOOGLE_REFRESH_TOKEN no console — daí é só colar no .env (e no dashboard da nuvem).
Conceitos-chave
Autoriza sem dar senha.
Renova o acesso sozinho.
Identidade do app.
Script gera o token.
🏆 Regras de ouro
O que é
Três regras inegociáveis para tratar segredos. Um: nunca cole chaves de API no chat da IA — o chat não é o lugar de um segredo. Dois: nunca commite o .env no GitHub — uma vez no histórico, considere a chave vazada. Três: rotacione/regenere chaves periodicamente, e idealmente use chaves diferentes para local e produção. A imagem mental: trate uma chave de API como acesso a um cartão de crédito.
O ciclo de vida de um segredo seguro
Gerar a chave no painel do serviço (Anthropic, Firecrawl) e copiá-la direto para o .env — sem passar pelo chat.
Isolar: o .env no .gitignore; o valor cadastrado no dashboard da nuvem (dev e prod).
Usar via process.env — nunca hard-coded, nunca impresso em log.
Rotacionar: se desconfiar de vazamento, regenere a chave no painel — a antiga morre na hora. Chaves separadas dev/prod limitam o estrago.
⚠️ Chave = cartão de crédito
Uma chave vazada não dá só "acesso": ela permite que alguém rode chamadas de IA na sua conta, acumulando uso e custo no seu nome. Bots varrem o GitHub atrás de chaves expostas em minutos. Por isso a regra é dura: vazou, rotacione imediatamente.
Por que aprender
Porque a maioria dos incidentes de segurança com apps de IA não vem de hacker sofisticado — vem de uma chave colada no lugar errado. Internalizar estas três regras é o que separa um protótipo descuidado de um produto que você pode deixar rodando com tranquilidade.
Conceitos-chave
Chave fora da conversa com a IA.
.env sempre no .gitignore.
Regenere se desconfiar.
Vazou, alguém gasta por você.
🛡️ RLS — isolar dados no banco
O que é
RLS (Row-Level Security) são regras que vivem dentro do próprio banco de dados (no Supabase, por exemplo) e impedem um usuário de ver as linhas de outro — mesmo que exista um bug no frontend. É uma camada extra de defesa: o banco protege os dados independentemente do app. Se o seu código por engano pedir "todos os leads", o banco, com RLS, devolve apenas os leads daquele usuário.
O que é?Linha (row) — um registro na tabela (ex.: um lead). Policy — a regra que diz "quem pode ver/alterar quais linhas". Defesa em profundidade — não confiar numa única camada; se uma falha, a outra segura.
Diagrama ilustrativo — com RLS, a regra de isolamento mora no banco; um erro no frontend não consegue mais vazar os dados de outro usuário.
🎯 Objetivo: isolar os dados por usuário na própria base, com uma política RLS na tabela de leads.
-- liga o Row-Level Security na tabela alter table leads enable row level security; -- política: cada usuário só enxerga as próprias linhas -- (compara o dono da linha com o usuário autenticado) create policy "cada um vê só os seus leads" on leads for select using ( user_id = auth.uid() );
✅ Como verificar: logue como um usuário A e liste os leads — só aparecem os dele. Logue como B e tente ler os de A: o banco devolve vazio. Isolamento garantido na base, não no app.
🎯 Dica prática
Ao criar o projeto no Supabase: defina uma senha de banco distinta da senha de login da conta, escolha a região mais próxima dos usuários, habilite o RLS nas tabelas com dados de usuário e rode a migração SQL que cria a tabela. RLS desligado numa tabela exposta é a falha de segurança nº 1 em apps feitos rápido.
Por que aprender
Porque você vai construir rápido, e código rápido tem bugs. RLS é o cinto de segurança: ainda que o frontend escorregue, o banco não deixa um usuário ver dados de outro. É a diferença entre "um bug irritante" e "um vazamento de dados que vira notícia".
Conceitos-chave
A proteção mora na base.
Cada um só vê o seu.
Independe do frontend.
Se uma falha, a outra segura.
🔍 Auditoria de segurança
O que é
Antes de deixar o app em produção, você pede à IA que aja como especialista de segurança e revise o projeto contra um checklist de quatro pontos: rotas protegidas, nenhuma chave exposta no frontend, segredos só em variáveis de ambiente e RLS habilitado. Uma boa prática é limpar a conversa antes (contexto fresco audita melhor) e, depois, corrigir tudo que falhar.
🎯 Objetivo: fazer uma auditoria de segurança explícita antes do deploy.
Aja como especialista de segurança e audite este app. Verifique, item por item: 1. rotas protegidas (nada sensível acessível sem login); 2. nenhuma chave de API exposta no frontend / no bundle; 3. segredos APENAS em variáveis de ambiente (nada hard-coded); 4. RLS habilitado em todas as tabelas com dados de usuário. Liste o que FALHAR e, para cada falha, diga exatamente como corrigir. Não invente: se não der pra confirmar, diga.
✅ Como verificar: você recebe uma lista de achados acionáveis. Corrija cada falha e rode a auditoria de novo até a lista ficar vazia — só então faça o deploy para produção.
✓ Auditoria que funciona
- ✓Limpar o contexto antes, para uma análise fresca.
- ✓Checklist explícito de 4 pontos.
- ✓Corrigir o que falhar e re-auditar até zerar.
✗ O que dá errado
- ✗Achar que "compilou" = "está seguro".
- ✗Deixar a chave da API ir parar no frontend.
- ✗Subir para produção sem nunca revisar segurança.
Por que aprender
Porque no vibe coding você constrói depressa e é fácil deixar uma porta aberta sem perceber. Uma auditoria explícita, com checklist, é barata (um prompt) e pega justamente o que passou. É o "trust but verify" aplicado à segurança: não confie que ficou seguro — verifique.
Conceitos-chave
Peça à IA o papel.
Rotas, chaves, env, RLS.
Audite com conversa fresca.
Até a lista zerar.
⚠️ App aberto = risco
O que é
Um app aberto — sem autenticação — é um risco financeiro concreto: qualquer pessoa com a URL pode disparar o seu workflow e consumir os seus tokens de IA. Como você paga pelo uso, o uso de estranhos vira a sua conta. Por isso, não deixe um app sem login rodando em produção por muito tempo: antes de compartilhar, adicione autenticação (Supabase) e limites de uso.
O que é?Autenticação — exigir login antes de usar o app. Limite de uso (rate limit / quota) — um teto de quantas vezes alguém pode chamar o app. Token de IA — a unidade de consumo que você paga ao provedor a cada chamada do modelo.
⚠️ A conta que chega no fim do mês
Você publica um app legal, posta o link, vai dormir. Um bot acha a URL, dispara o workflow milhares de vezes, e cada disparo chama o modelo de IA. De manhã, a fatura do provedor explodiu — com uso que não foi seu. App aberto + chamada de IA paga = risco direto no seu bolso.
Por que aprender
Porque é o gatilho natural para o próximo módulo. Adicionar login com Supabase e limites de uso não é só segurança — é o primeiro passo de um modelo de negócio: se você vai controlar quem usa e quanto, está a um passo de cobrar por isso. Esse raciocínio motiva o modelo freemium com Stripe que você vê em 6.3.
Conceitos-chave
Quem tem o link, dispara.
Tokens de estranhos viram sua conta.
Login antes de usar (Supabase).
Teto por usuário → freemium.
Fixando: onde NUNCA se deve colocar uma chave de API?
📌 Resumo do Módulo
Próximo Módulo:
6.3 — Confiabilidade & Monetização