Se o teu app foi feito com IA e já tá no ar, ele provavelmente tem pelo menos um destes 5 vacilos. A IA sabe consertar todos.
Esse post acompanha a aula do canal:
Lá eu explico cada fundamento com calma.
Antes de colar qualquer prompt
Roda num branch separado. Nada direto na main.
Lê o plano que a IA propõe antes de aceitar. Todos os prompts mandam ela mostrar o plano primeiro.
Migration nova você revisa antes de rodar. Banco de produção a IA não toca sem você olhar.
Se você não entendeu o que o prompt faz, volta no resumo. Colar sem entender é deixar a IA te enrolar de novo.
A ordem que eu rodaria
Teste de integração (prompt 5), pra travar o comportamento antes de mexer em qualquer coisa
Nunca confie no cliente (prompt 3), que é a porta aberta
Race condition (prompt 1) e idempotência (prompt 2), que é dinheiro
Separação de responsabilidades (prompt 4), por último, com os testes já te protegendo
1. Race condition
O que é: duas requisições chegam juntas, as duas leem o mesmo valor e as duas gravam em cima dele.
Onde quebra: todo lugar que lê, decide e depois grava. Estoque, cupom, saldo, crédito, vaga, convite.
Sinal de que você tem: pedido duplicado no banco, estoque negativo, cupom usado mais de uma vez.
O erro caro: subir um Redis pra fazer lock, ou ler o estoque do cache pra ficar rápido.
O Martin Kleppmann escreveu um artigo conhecido sobre isso (How to do distributed locking), e a correção que ele propõe é um número de controle conferido pelo lugar onde você grava. Ou seja, o banco.
PROMPT:
Você é um engenheiro sênior revisando um app que eu construí com IA. Quero achar e corrigir race conditions (condições de corrida).
1. Varra o código e liste todo lugar que faz "ler, decidir e depois gravar": criação de pedido, baixa de estoque, uso de cupom, saldo, créditos, vagas, convites, contadores, qualquer recurso limitado.
2. Para cada ocorrência, explique em uma frase o que acontece se 2 requisições iguais chegarem no mesmo milissegundo (ex.: pedido duplicado, estoque negativo, cupom usado 2 vezes).
3. Proponha a correção mais simples que resolve no banco, nesta ordem de preferência:
a. constraint única (unique index) que impede o registro duplicado;
b. operação atômica no próprio banco (ex.: UPDATE estoque SET qtd = qtd - 1 WHERE id = X AND qtd > 0, conferindo as linhas afetadas);
c. transação com lock da linha (SELECT ... FOR UPDATE) quando a regra for mais complexa.
4. No front, desabilite o botão durante o envio, mas trate isso como conforto de UX. A proteção de verdade fica no servidor e no banco.
5. Para cada correção, escreva um teste que dispara 2 requisições simultâneas e prova que só uma tem efeito.
Regras: não proponha Redis, fila, lock em memória ou qualquer infraestrutura nova se o banco resolve; se achar que precisa, me explique por que o banco não basta antes. Me mostre a lista completa e o plano antes de alterar qualquer arquivo. Toda migration nova deve ser revisada por mim antes de rodar. Se já existirem dados duplicados que impeçam criar a constraint, me avise e proponha como limpar, sem apagar nada sozinho.
2. Idempotência
O que é: repetir a mesma operação quantas vezes for e o resultado ser o mesmo de fazer uma vez só.
Onde quebra: webhook de pagamento.
Sinal de que você tem: cliente recebendo e-mail repetido, crédito somado duas vezes, assinatura duplicada, requisições duplicadas em servidor de terceiros.
Como resolve: uma tabela de eventos processados com o ID do evento como chave única.
Você é um engenheiro sênior especialista em pagamentos. Quero que todo webhook e todo endpoint de pagamento do meu app aceite repetição sem efeito duplicado (idempotência).
1. Liste todos os webhooks recebidos (Stripe ou outro gateway) e todos os endpoints que cobram, liberam plano, creditam saldo ou mandam e-mail transacional.
2. Webhooks:
a. confirme que a assinatura do webhook é verificada com o corpo bruto da requisição antes de qualquer processamento;
b. crie uma tabela de eventos processados com o ID do evento como chave única;
c. ao receber um evento, tente gravar o ID primeiro; se já existir, responda 200 e não faça mais nada;
d. não dependa da ordem de chegada dos eventos: quando precisar do estado atual, busque o objeto na API do gateway;
e. responda 2xx rápido e mande o trabalho pesado para uma fila ou processamento assíncrono, se o projeto já tiver essa estrutura.
3. Chamadas que EU faço ao gateway (criar cobrança, assinatura, reembolso): envie uma idempotency key (UUID v4) gerada uma vez por operação de negócio e reaproveitada em caso de nova tentativa.
4. Endpoints do meu app que criam pedido ou pagamento: aceite um header Idempotency-Key do cliente e devolva a mesma resposta se a chave se repetir.
5. Escreva testes que enviam o mesmo evento 2 vezes, e 2 vezes ao mesmo tempo, e provam que o efeito acontece só uma vez.
Regras: mostre o plano antes de alterar código. Não mude valores, preços nem regras de cobrança. Não use dado pessoal (e-mail, CPF) como chave de idempotência.
3. Nunca confie no cliente
O que é: tudo que roda no navegador o usuário controla. Ele abre o DevTools, muda o que quiser e chama a tua API direto. Validação no front serve pra experiência ficar boa; quem decide é o servidor.
Onde quebra: preço, desconto, permissão ou limite de plano calculado só no front.
Sinal de que você tem: o Matt Palmer analisou 1.645 apps feitos no Lovable, olhando só a página inicial, e achou 170 com o RLS quebrado.
Como resolve: o servidor recalcula tudo e ignora o valor que veio do cliente.
PROMPT
Você é um auditor de segurança. Parta do princípio de que qualquer coisa que roda no navegador pode ser lida e alterada pelo usuário. Quero uma auditoria completa e um plano de correção.
1. Regras de negócio no front: liste todo cálculo de preço, desconto, frete, permissão, papel de admin, limite de plano ou validação que só existe no cliente. Para cada um, mova a regra para o servidor (API route, server action, edge function) e faça o servidor recalcular tudo, ignorando valores vindos do cliente.
2. Segredos: procure chaves e tokens no código do front e em variáveis que vão para o navegador (NEXT_PUBLIC_, VITE_, EXPO_PUBLIC_ ou equivalente). Classifique cada uma como pública por design (ex.: publishable/anon key do Supabase, publishable key do Stripe) ou secreta (service_role/secret key, chaves de OpenAI, Stripe secret, tokens de terceiros). Toda secreta sai do front, vai para o servidor, e me diga quais eu preciso rotacionar porque já foram publicadas.
3. Supabase (ou banco equivalente exposto por API):
a. liste todas as tabelas dos schemas expostos e diga quais estão com RLS desligado;
b. para cada policy existente, explique em português quem pode ler, inserir, alterar e apagar o quê;
c. aponte policies permissivas demais, como USING (true), WITH CHECK (true) ou regras que não comparam com auth.uid();
d. proponha policies mínimas: cada usuário só acessa as próprias linhas, e campos sensíveis (ex.: status de pagamento, papel, saldo) só mudam pelo servidor;
e. confirme que a chave secreta (service_role) nunca é usada no navegador.
4. Gere um relatório final com: achado, risco (alto, médio, baixo), arquivo e linha, correção proposta.
Regras: primeiro só o relatório, sem alterar nada. Depois aplique as correções uma por vez, com migration separada para as policies, esperando meu OK em cada uma. Não desligue nenhuma proteção existente para "fazer funcionar".
4. Separação de responsabilidades
O que é: cada coisa na sua gaveta. A tela numa, a regra de negócio em outra, e quem conversa com banco, gateway de pagamentos e APIs de fora numa terceira.
Onde quebra: naquele arquivo gigante onde você pede pra IA mexer numa coisa e quebra outra do outro lado.
Sinal de que você tem: um arquivo que você tem medo de abrir, e toda alteração nele vira efeito colateral.
Como resolve: dividir em passos pequenos, sem mudar comportamento, com testes registrando como o arquivo funciona hoje antes do primeiro passo.
PROMPT
Você é um engenheiro sênior especialista em refatoração segura. O arquivo [CAMINHO DO ARQUIVO] ficou grande demais e toda alteração quebra outra coisa. Quero dividir em camadas sem mudar comportamento.
1. Mapeie o arquivo: liste cada função, componente e trecho, e classifique em uma destas camadas:
a. UI (o que aparece na tela e captura evento do usuário);
b. regra de negócio (cálculos, validações, decisões);
c. acesso a dados e serviços externos (banco, Supabase, Stripe, APIs).
2. Aponte dependências cruzadas, código duplicado e estado global que dificultam a separação.
3. Proponha a nova estrutura de pastas e arquivos, seguindo o padrão que o projeto já usa. Nada de framework ou biblioteca nova.
4. Monte um plano em passos pequenos. Cada passo move um pedaço só, mantém os mesmos nomes públicos e deixa o app funcionando.
5. Antes do primeiro passo, confira se existem testes cobrindo o comportamento atual. Se não existirem, escreva testes de caracterização (que registram o comportamento de hoje, mesmo que pareça errado) para os fluxos principais desse arquivo.
6. Execute um passo por vez, rodando os testes ao final de cada um.
Regras: não corrija bugs nem mude regra de negócio durante a refatoração; se achar bug, anote numa lista separada. Não renomeie rotas, props públicas ou colunas do banco. Mostre o plano e espere meu OK antes do passo 1.
5. Teste de integração
O que é: um teste que chama a tua rota de verdade, com um banco de teste de verdade, e só finge o que é de fora (o webhook do gateway, o envio de e-mail).
Por que esse e não os outros: o agente de IA adora teste unitário porque mocka tudo, e aí o teste passa sem testar nada. O E2E (com Playwright, por exemplo) é lento e quebra à toa.
Como fica: no jeitão do RSpec, a frase do comportamento vem antes do teste. Em JS, com Vitest, é assim (exemplo ilustrativo):
describe('webhook de pagamento', () => {
it('quando o mesmo evento chega 2 vezes, libera o plano 1 vez só', async () => {
await post(webhook, eventoPago)
await post(webhook, eventoPago)
expect(await assinaturas(usuario)).toBe(1)
})
it('quando as 2 cópias chegam juntas, libera 1 vez só', async () => {
await Promise.all([post(webhook, eventoPago), post(webhook, eventoPago)])
expect(await assinaturas(usuario)).toBe(1)
})
})
Você não precisa escrever isso. Precisa ler a frase do it e concordar com ela; a IA escreve o resto.
Onde quebra: sem esses testes, a IA mexe num lugar, quebra outro e quem descobre é o cliente.
Cuidado: teste de RLS só vale com banco de verdade. Supabase local ou um projeto só de teste. Banco de produção, nunca.
PROMPT:
Você é um engenheiro de qualidade. Quero cobrir os fluxos críticos do meu app com testes de integração, no estilo request spec do RSpec: cada teste chama a rota de verdade, com banco de teste de verdade, e só simula o que é de fora (gateway de pagamento, envio de e-mail, APIs de terceiros).
1. Leia o projeto e liste os fluxos críticos: cadastro, login, checkout, webhooks de pagamento e qualquer rota que mexe com dinheiro, permissão ou dado de outro usuário.
2. Para cada fluxo, escreva em português as frases de comportamento no formato describe / it ("quando..., então..."), cobrindo:
a. o caminho feliz;
b. erros esperados (pagamento recusado, campo inválido, usuário sem permissão);
c. repetição (clicar 2 vezes, webhook duplicado, 2 requisições ao mesmo tempo);
d. limites (estoque zerado, plano expirado, valor zero ou negativo);
e. acesso indevido (usuário A tentando ler ou alterar dado do usuário B).
3. Me mostre as frases e espere eu confirmar ou corrigir. Eu sou a fonte da verdade sobre o comportamento esperado.
4. Configure o ambiente de teste com a ferramenta que o projeto já tem (se não tiver nenhuma, sugira a mais simples para a stack e espere meu OK). O banco de teste é separado: Supabase local, container ou projeto só de teste. Nunca aponte para o banco de produção.
5. Escreva os testes batendo nas rotas (API routes, server actions, edge functions). Mock só de serviço externo; banco, regras de negócio e policies rodam de verdade. Para repetição simultânea, dispare as requisições ao mesmo tempo (Promise.all ou equivalente).
6. Opcional, só se eu aprovar: um único teste E2E de fumaça (ex.: Playwright) para o caminho cadastro até checkout.
7. Rode tudo e me diga o que passa e o que falha. Teste que falha por bug real fica falhando e entra numa lista de bugs; não ajuste o teste para passar.
8. Me diga o comando único para rodar todos os testes, para eu rodar depois de toda alteração feita por IA.
Regras: é proibido apagar, pular (skip) ou afrouxar um teste para fazê-lo passar. Não mocke o banco nem a regra que está sendo testada. Se um teste parecer errado, pare e me pergunte.Prompt de auditoria (os 5 de uma vez, sem alterar nada)
Você é um engenheiro sênior fazendo uma auditoria de um app que eu construí com IA. Nesta tarefa você NÃO altera nenhum arquivo do projeto, não roda migration e não instala nada. Você só lê o código, roda comandos de leitura e escreve um relatório.
Siga esta ordem e, ao final de cada etapa, anote os achados antes de passar para a próxima:
1. Testes de integração
- Existe ferramenta de teste configurada? Existe banco de teste separado do de produção? Qual o comando para rodar tudo? Rode (só se não tocar em produção) e diga quantos passam e quantos falham.
- Liste os fluxos críticos (cadastro, login, checkout, assinatura, webhooks) e diga quais têm teste batendo na rota de verdade, quais só têm teste unitário com mock e quais não têm nada.
2. Confiança no cliente
- Regras de preço, desconto, permissão, papel de admin ou limite de plano que existem só no front.
- Chaves e tokens em código de front ou em variáveis que vão para o navegador (NEXT_PUBLIC_, VITE_, EXPO_PUBLIC_ ou equivalente). Classifique como pública por design ou secreta.
- Se houver Supabase (ou banco exposto por API): tabelas expostas com RLS desligado e policies permissivas demais (USING (true), WITH CHECK (true), regras que não comparam com auth.uid()). Explique cada policy em português.
3. Race condition
- Todo trecho que lê, decide e depois grava sobre recurso limitado (estoque, cupom, saldo, crédito, vaga, convite). Para cada um, diga o que acontece se 2 requisições iguais chegarem juntas e se existe constraint única, operação atômica ou lock de linha no banco protegendo.
- Aponte proteção que depende de lock em memória, lock no Redis com expiração ou leitura de cache, e diga se o banco sozinho resolveria.
4. Idempotência
- Webhooks recebidos: a assinatura é verificada com o corpo bruto? Existe registro de eventos processados com ID único? O que acontece se o mesmo evento chegar 2 vezes?
- Chamadas ao gateway de pagamento: usam idempotency key?
5. Separação de responsabilidades
- Os arquivos mais longos do projeto e, em cada um, se mistura tela, regra de negócio e acesso a banco ou serviço externo. Aponte o candidato número 1 para refatorar.
Entrega: crie AUDITORIA.md na raiz com uma tabela por etapa (achado, risco alto/médio/baixo, arquivo e linha, correção sugerida) e, no topo, os 5 achados de maior risco em ordem. Se não conseguir verificar algo, escreva "não verificado" e o motivo, sem chutar. Termine dizendo qual dos 5 prompts de correção eu devo rodar primeiro e por quê.
O canal existe pra trazer conhecimento através de resenha. Aqui não tem mentoria e não tem curso.
Esse vídeo, e todos os outros do canal, só foram roteirizados, gravados e editados graças aos nossos patrocinadores:
💰 Appmax: Pix com taxa zero pra quem integrar via API por este link
🚀 Hostinger: use o cupom MANODEYVIN e ganhe desconto na primeira compra
⭐ E aos membros do canal, que bancam o boteco todo mês.

