Corrija migrações de banco de dados quebradas em apps gerados por IA com segurança
Corrija migrações de banco de dados com um plano de recuperação seguro: audite o histórico, detecte drift entre ambientes, reconstrua uma cadeia limpa e proteja os dados ao aplicar.

Por que aplicativos gerados por IA acabam com migrações quebradas
Uma migração de banco de dados é um pequeno script que altera seu banco de dados de forma controlada. Pense nela como um “passo de receita” para suas tabelas: criar uma coluna, renomear um campo, adicionar um índice. Migrações devem rodar em ordem para que todos os ambientes terminem com o mesmo esquema.
Apps gerados por IA frequentemente quebram essa cadeia porque o código é produzido rapidamente, sem os hábitos cuidadosos que os humanos usam para manter o histórico limpo. Ferramentas podem gerar migrações automaticamente, regenerá‑las após um prompt ou copiar padrões de outro projeto. Isso pode criar arquivos que parecem válidos, mas não concordam entre si.
Causas comuns incluem:
- Duas migrações que tentam alterar a mesma tabela de maneiras diferentes
- Um arquivo de migração editado depois de já ter sido executado em algum lugar
- Nomes de migração duplicados ou timestamps que ordenam de forma diferente entre máquinas
- Migrações geradas contra um banco local que não corresponde ao staging ou prod
“Funciona na minha máquina” acontece quando o banco do seu laptop tem mudanças manuais extras, passos faltando ou uma ordem de migrações diferente. O código do app bate com o seu esquema local, então tudo parece ok — até que a produção execute a cadeia real de migrações e encontre uma tabela ausente, uma coluna duplicada ou uma foreign key que não pode ser criada.
Esse problema geralmente aparece no pior momento: no primeiro deploy, quando um novo colega executa a instalação do zero, ou quando o CI monta um banco limpo e executa migrações em ordem estrita.
Se você herdou um protótipo gerado por IA de ferramentas como Lovable, Bolt, v0, Cursor ou Replit, isso é uma das primeiras coisas que a FixMyMess verifica durante um diagnóstico de codebase, porque problemas de migração podem ficar escondidos até o dia do lançamento.
Sintomas e riscos a observar antes de tocar em qualquer coisa
Migrações quebradas geralmente aparecem quando você tenta fazer um deploy, mas o problema real começou antes. Apps gerados por IA podem criar migrações rapidamente e depois continuar editando modelos e esquema de maneiras que não correspondem ao que já foi executado em outros ambientes.
Os sinais óbvios são difíceis de perder: deploys falham com “table not found” ou “column already exists”, páginas travam porque uma query espera um campo que não existe, ou você vê tabelas ausentes que o código do app assume que existem. Outro padrão comum é colunas duplicadas (como user_id e userid) ou índices criados duas vezes com nomes diferentes.
Os sinais mais perigosos são silenciosos. Seu app pode continuar rodando, mas local, staging e produção já não concordam. Um ambiente pode ter um tipo de coluna mais novo, um valor default, ou uma constraint (como NOT NULL) que os outros não têm. Isso cria bugs do tipo “funciona na minha máquina”: uma feature passa nos testes locais, mas quebra em produção, ou pior, grava dados incorretos que só viram problema depois.
Antes de tentar consertar migrações quebradas, fique atento a estes riscos:
- Perda de dados ao executar migrações destrutivas em um esquema errado
- Longo downtime se uma migração travar tabelas grandes ou desencadear backfills lentos
- Rollbacks parciais onde o código reverte mas o banco não consegue desfazer mudanças limpas
- Bugs ocultos do app quando o código assume um esquema que existe apenas em um ambiente
Uma boa regra: se você não consegue responder claramente “quais migrações rodaram em prod, e em que ordem?”, pare. Não execute mais migrações às cegas para “ver se funciona.” Isso costuma ampliar a divergência entre ambientes e tornar a recuperação mais difícil. Se você herdou um protótipo gerado por IA e os erros estão se acumulando, times como o FixMyMess costumam começar com uma auditoria somente leitura para mapear o que é seguro rodar e o que precisa de uma reconstrução controlada.
Comece com um inventário rápido: o que existe e onde
Antes de tentar consertar migrações, obtenha uma imagem clara do que você realmente tem. A maioria dos desastres de migração acontece porque as pessoas presumem que local, staging e produção são iguais quando não são.
Primeiro, nomeie cada ambiente que existe hoje. Normalmente isso inclui pelo menos local (seu laptop), staging (um servidor de teste) e produção (usuários reais). Se você tem preview apps, bancos antigos de staging ou uma segunda região de produção, inclua esses também.
Em seguida, capture o esquema atual em cada ambiente como ele é agora, não como você gostaria que fosse. Use o que sua stack suportar: dump de esquema, comando de introspecção ou exportação somente leitura de tabelas, colunas, índices e constraints. Salve essas saídas com timestamps para poder comparar depois.
Depois reúna as fontes das migrações e o estado das migrações:
- A pasta completa de migrações do repositório (incluindo arquivos antigos)
- A tabela de rastreamento de migrações no banco (por exemplo, a tabela que registra quais migrações rodaram)
- Qualquer nota ou script manual que tenha sido usado para alterar o banco fora das migrações
- O comando exato que falha (e quem o executou)
- O texto completo do erro, além de quando acontece (instalação do zero vs após puxar atualizações)
Por fim, escreva a história da falha em palavras simples. Exemplo: "Local funciona, staging falha na migração 0042, produção tem uma coluna extra adicionada manualmente." Essa narrativa curta evita suposições e acelera os próximos passos, especialmente se você trouxer ajuda como a FixMyMess para uma auditoria.
Audite o histórico de migrações por conflitos e edições
Antes de tentar consertar migrações quebradas, entenda se sua cadeia de migrações é confiável. Apps gerados por IA costumam criar migrações rápido e depois sobrescrever arquivos ou gerar novas sem respeitar o que já rodou em produção.
Comece lendo a lista de migrações da mais antiga à mais nova e verifique se a ordem está limpa. Lacunas não são sempre fatais, mas são um indício de que arquivos foram renomeados, deletados ou regenerados. Também fique atento a IDs ou timestamps duplicados que podem fazer duas migrações reivindicarem o mesmo “slot” no histórico.
Em seguida, procure edições em migrações antigas. Se uma migração foi aplicada em algum lugar (staging ou prod) e depois seu arquivo foi alterado, você agora tem duas verdades: o banco tem uma versão e seu repositório outra. Um cheque rápido é comparar datas de modificação dos arquivos, histórico de commits ou até procurar comentários como “fix” adicionados a uma migração antiga.
Merges de branches são outra fonte comum de conflito. Dois branches podem adicionar cada um a “próxima migração”, então ao merge você acaba com migrações concorrentes que assumem ser a próxima. Isso costuma aparecer como dois novos arquivos de migração criados em minutos uns dos outros, mas com conteúdo diferente.
Por fim, presuma que algumas mudanças ocorreram manualmente em pelo menos um ambiente. Se alguém adicionou um índice em produção, hotfixou um tipo de coluna ou executou um snippet SQL, suas migrações não vão refletir isso.
Checklist rápido de auditoria:
- Confirme que IDs de migração são únicos e estritamente crescentes
- Marque qualquer arquivo de migração antigo que foi editado após a criação
- Identifique migrações “paralelas” criadas em branches separados
- Note alterações de esquema que existem no BD mas não nas migrações
- Escreva quais ambientes provavelmente divergem (local, staging, prod)
Se isso parecer bagunçado, é normal para protótipos vindos de ferramentas como Cursor ou Replit. Times como a FixMyMess costumam começar por essa auditoria antes de decidir reparar ou reconstruir a cadeia.
Detecte drift entre ambientes sem adivinhar
Drift de migração é quando dois ambientes (local, staging, prod) têm esquemas diferentes embora devessem ser iguais. Em apps gerados por IA, isso acontece frequentemente após “correções rápidas” feitas diretamente no banco ou após migrações terem sido editadas e reexecutadas.
Comece comparando o esquema em si, não apenas os arquivos de migração. Você quer um diff escrito claro do que existe em cada ambiente: tabelas, colunas, tipos de dados, índices e constraints (especialmente foreign keys e unique constraints). Essas são as diferenças que geralmente explicam por que um endpoint funciona localmente mas falha em prod.
Uma maneira prática e rápida é exportar um snapshot de esquema de cada ambiente (dump apenas do esquema ou a saída de introspecção do seu ORM) e compará‑los lado a lado. Ao revisar o diff, concentre‑se em objetos que mudam o comportamento:
- Colunas faltando ou extras que o código lê/escreve
- Diferente nullability ou valores default
- Constraints únicas ausentes (permitindo duplicatas)
- Foreign keys ausentes (ou regras de cascade diferentes)
- Diferenças de índices que causam timeouts sob tráfego real
Separe “diferenças esperadas” do drift real. Dados de seed, usuários de teste admin e flags de recurso de dev podem diferir sem ser um problema. Diferenças de esquema raramente são “esperadas”. Se o esquema difere, presuma que algo vai eventualmente quebrar.
Depois, escolha uma fonte da verdade. Isso é uma decisão, não um palpite. Geralmente a produção deve prevalecer se está atendendo usuários reais, mas às vezes prod é o bagunçado (por exemplo, colunas hotfixed manualmente durante um pânico). Se você está tentando consertar migrações quebradas, escolha o ambiente com o esquema mais correto e completo, e documente o porquê.
Exemplo: um protótipo construído no Replit funciona localmente, mas o cadastro falha em prod. O diff mostra que prod está sem um índice único em users.email, então contas duplicadas foram criadas e a autenticação ficou inconsistente. Esse único drift de esquema explica os bugs “aleatórios” de login e indica o que reparar primeiro.
Passo a passo: um plano de recuperação seguro que você pode seguir
Migrações quebradas parecem urgentes, mas apressar é a forma de transformar um problema de esquema em perda de dados. O plano mais seguro é propositalmente chato: pause mudanças, crie um ponto de restauração confiável e pratique o conserto antes de tocar em produção.
Primeiro, congele deployments. Pare auto-deploys, jobs em background que aplicam migrações na inicialização e quaisquer releases do tipo “só dê push”. Se o app atende clientes, escolha uma janela de manutenção e diga à equipe o que está bloqueado: esquema do banco, modelos do ORM e qualquer código que escreva nas tabelas afetadas.
Em seguida, faça um backup que você realmente testou. Não se contente com logs de “backup concluído”. Faça um pequeno restore em um banco separado, execute uma query simples para confirmar que tabelas-chave e linhas recentes existem, e verifique se o app consegue conectar. Se você não consegue restaurar, você não tem um backup.
Agora reproduza a falha em um lugar seguro usando uma cópia dos dados de produção (ou um snapshot anonimizados). Execute o comando completo de migração exatamente como a produção o faz. Capture o primeiro erro e o nome do arquivo de migração — porque a primeira falha costuma ser a pista real.
Depois escolha sua abordagem de recuperação. Se o problema é pequeno (uma coluna faltando, uma migração editada ou uma execução parcial), reconcilie: escreva uma migração corretiva que mova o esquema do estado atual para o esperado. Se o histórico está emaranhado (edições conflitantes, IDs duplicados, drift entre ambientes), reconstrua: crie uma baseline limpa a partir do esquema atual e reinicie a cadeia.
Antes de enviar à produção, faça uma execução completa de ponta a ponta: parta de um banco vazio, aplique todas as migrações, semeie dados mínimos e rode um smoke test. Esse é o momento de capturar o drift “funciona no meu laptop”.
Se você está tentando consertar migrações em uma codebase gerada por IA (Lovable, Bolt, v0, Cursor, Replit), times como o FixMyMess costumam iniciar exatamente por esse fluxo de ensaio para que a mudança em produção seja previsível, não heroica.
Reconstruir uma cadeia de migrações limpa (baseline, squash e reset)
Uma cadeia de migrações limpa é o que torna deploys entediantes novamente. Se você precisa consertar migrações quebradas, não comece deletando arquivos. Comece decidindo se você vai estabilizar o que existe ou criar uma baseline nova e bem documentada.
Baseline: quando criá‑la (e quando não)
Crie uma nova migração baseline quando o esquema do banco em produção estiver correto, mas o histórico de migrações estiver bagunçado, editado ou fora de ordem. O objetivo é capturar o esquema atual como o novo ponto de partida.
Não faça baseline se a produção não for confiável (mudanças manuais desconhecidas, tabelas faltando ou problemas de dados). Nesse caso, você precisa reparar o esquema primeiro e só então criar a baseline.
Squash e reset: manter o histórico seguro
Se migrações já foram aplicadas em produção, evite reescrever o histórico no lugar. Em vez disso, trate a cadeia antiga como “legado” e adicione um ponto de corte claro.
Um padrão seguro é:
- Congele o estado atual: faça backup dos dados e registre a versão do esquema em cada ambiente.
- Gere uma única migração “squash” que corresponda exatamente ao esquema atual.
- Marque‑a como a nova baseline (por exemplo, com uma nota no repositório e nos docs de deploy).
- Mantenha as migrações antigas em uma pasta separada ou seção claramente rotulada, mas pare de aplicá‑las.
- Para novos ambientes, execute baseline + novas migrações daqui pra frente.
Imagine um protótipo onde o local tem 42 migrações, staging 39, e prod tem tabelas hotfixed adicionadas manualmente. Squashar o local às cegas não vai corresponder à prod. O movimento correto é criar a baseline a partir do esquema que você escolheu como fonte da verdade (geralmente prod) e então aplicar mudanças futuras como migrações novas.
Documente a baseline em palavras simples: a data, o ambiente fonte, o snapshot exato do esquema e a regra para novos setups. Times como a FixMyMess costumam adicionar essa documentação como parte da remediação de apps gerados por IA, porque deploys futuros dependem disso.
Testar e aplicar a correção sem arriscar dados reais
Trate sua correção de migração como um release, não um patch rápido. O lugar mais seguro para provar que funciona é um ambiente de staging que corresponda à produção: mesmo engine de banco e versão, mesmas extensões, mesmas variáveis de ambiente e uma cópia do esquema de produção (e idealmente uma fatia pequena e anonimizadas dos dados).
Antes de testar qualquer coisa, faça um backup fresco que você possa realmente restaurar. Planos de rollback frequentemente falham porque presumem que down‑migrations vão desfazer mudanças perfeitamente. Na prática, o rollback mais realista é restaurar um snapshot.
Garanta que migrações são repetíveis
Uma migração que “funciona uma vez” ainda pode ser perigosa. Execute a cadeia completa de migrações no staging, depois resete esse banco de staging e execute novamente. Você quer o mesmo resultado ambas as vezes.
Fique atento a sinais de alerta como timestamps usados como valores default, backfills não determinísticos ou migrações que dependem do conteúdo atual da tabela.
Valide o app, não apenas o esquema
Após as migrações, inicie o app e teste os fluxos que importam: cadastro/login, criar e editar registros centrais, busca/filtragem e quaisquer telas administrativas. Depois dispare jobs em background e tarefas agendadas, porque elas frequentemente acessam colunas que foram renomeadas ou tornadas non-null.
Mantenha o rollout pequeno e controlado:
- Anuncie uma curta janela de manutenção (mesmo que espere zero downtime)
- Aplique migrações primeiro, depois faça deploy do código que espera o novo esquema
- Monitore erros e queries lentas logo após o release
- Esteja pronto para restaurar o banco se algo parecer errado
Se o app é gerado por IA, verifique duplamente por suposições ocultas de esquema no código. A FixMyMess frequentemente encontra protótipos onde a UI funciona localmente, mas a produção falha devido a migrações faltantes, arquivos de migração editados ou segredos que mudam o comportamento entre ambientes.
Erros comuns que pioram problemas de migração
A forma mais rápida de transformar uma bagunça de migrações em um outage real é “patchar até funcionar” sem saber o que rodou onde. Quando você tenta consertar migrações quebradas, o objetivo não é apenas fazer o app subir. É fazer todos os ambientes voltarem a uma história consistente e explicável.
Um erro comum é editar uma migração antiga que já rodou em produção. Seu código agora diz uma coisa, mas a prod já fez outra. Um colega roda um setup do zero, o staging roda uma cadeia diferente, e você criou duas linhas do tempo que nunca vão mais se alinhar.
Outro erro é “consertar o drift” mudando o banco manualmente primeiro. Por exemplo, alguém adiciona uma coluna faltante direto em prod para parar os erros, mas os arquivos de migração continuam divergentes. O app parece ok por um dia, então o próximo deploy tenta adicionar a coluna de novo, falha e bloqueia todas as migrações seguintes.
Aqui estão erros que aparecem repetidamente em apps gerados por IA:
- Tratar down‑migrations como rede de segurança, embora ninguém tenha testado rollback com dados reais
- Pular constraints e índices porque o app “funciona” sem eles, para depois enfrentar consultas lentas e dados errados
- Aplicar correções rápidas como deletar uma linha da tabela de migrações para silenciar erros
- Renomear tabelas ou colunas fora de migrações e depois se perguntar por que os modelos do ORM divergiram
- Misturar mudanças de esquema e backfills de dados em uma mesma migração, tornando falhas mais difíceis de recuperar
Correções rápidas frequentemente escondem o sintoma e mantêm o drift. Você pode passar pelo erro imediato, mas o próximo ambiente (ou o próximo laptop do desenvolvedor) quebra de uma nova forma.
Se você herdou um protótipo de ferramentas como Lovable, Bolt ou Replit, presuma que migrações foram geradas às pressas. Times como a FixMyMess costumam começar confirmando o que rodou em produção e reconstruindo um caminho limpo para frente sem reescrever o histórico no lugar.
Checklist rápido antes de apertar deploy
Se suas migrações foram geradas por uma ferramenta de IA, presuma que existem lacunas. Um checklist calmo ajuda a evitar o erro que mais dói: descobrir na produção.
Antes de tocar a produção
Faça um backup e prove que funciona. “Backup realizado” não é o mesmo que “restore testado.” Restaure em um banco fresco, abra o app e confirme que tabelas-chave e registros recentes aparecem.
Em seguida, faça um diff de esquema entre todos os ambientes que importam (local, staging, produção). Você quer saber o que é diferente antes de rodar qualquer coisa. Se a produção tem uma coluna extra ou um índice faltando, anote.
Escolha uma única fonte da verdade e seja explícito. Decida se o esquema de produção, um branch de migrações específico ou um ambiente conhecido‑bom é a referência. Coloque essa escolha nas suas notas para que ninguém “conserte” o lado errado durante o deploy.
Prove que a cadeia de migrações é segura
Execute a sequência completa de migrações em uma cópia parecida com produção. Isso significa uma cópia dos dados de prod (ou dados saneados com o mesmo formato), o mesmo engine e versão do banco, e o mesmo comando de migração que você usará no deploy. Fique de olho em locks longos, constraints que falham e diferenças “funciona na minha máquina”.
Antes de deploy, garanta que seu plano inclua validação e rollback:
- Validar: login básico, algumas leituras/escritas chave e checagem rápida de tabelas/contagens críticas
- Rollback: passos claros para reverter a versão do app e restaurar o banco se necessário
Exemplo: se o staging está “à frente” da prod porque uma ferramenta de IA criou uma migração extra localmente, pause e reconcilie essa diferença primeiro. Enviar com esse drift normalmente vira um deploy falho ou, pior, inconsistências silenciosas de dados.
Se você herdou uma codebase gerada por IA, a FixMyMess costuma começar aqui: uma auditoria gratuita que confirma a fonte da verdade, mapeia o drift e checa o plano de recuperação antes de qualquer mudança ir ao ar.
Exemplo: recuperar um protótipo que driftou entre local e prod
Um fundador envia um protótipo gerado por IA que funciona no laptop. Depois, o deploy em produção falha na migração 012 com erro “column already exists”. O app não inicia e todo re‑deploy repete a falha.
Após uma rápida análise, o problema não é “um arquivo ruim”. Dois branches introduziram mudanças ligeiramente diferentes na mesma tabela (por exemplo, ambos adicionaram um campo status em users, mas um deixou nullable e outro colocou um default). Localmente, o desenvolvedor aplicou a migração de um branch. Em produção, um deploy anterior aplicou a do outro. Agora o histórico de migrações e o esquema real divergem.
A forma mais segura de sair é tratar produção como fonte da verdade, criar uma baseline a partir do esquema de produção e só então seguir em frente.
Na prática isso é:
- Congelar deploys e fazer backup completo (confirmando que dá para restaurar)
- Inspecionar o esquema de produção e a tabela de migrações para ver o que realmente rodou
- Criar uma migração baseline que corresponda à produção hoje (sem mudanças, só alinhamento)
- Escrever uma nova cadeia limpa e progressiva que aplique as mudanças faltantes em passos pequenos e explícitos
Depois você valida o app usando fluxos reais, não apenas “migrações rodaram”. Nesse exemplo, testaria login (sessões, reset de senha), faturamento (webhooks, invoices) e dashboards que dependem da tabela alterada.
Esse padrão é comum quando você precisa consertar migrações em apps gerados por IA: não force a produção a bater com um histórico local bagunçado. Faça o histórico bater com a produção e então adicione migrações seguras, apenas para frente. Se não tiver certeza de qual esquema está correto, a FixMyMess pode auditar o codebase e o trilho de migrações primeiro para evitar aprender da pior maneira na produção.
Próximos passos: manter migrações estáveis e saber quando pedir ajuda
Depois de restaurar as migrações, o objetivo é consistência entediante. Comece decidindo se precisa de um conserto pequeno (uma migração ruim, um arquivo faltando, ordem errada) ou de uma reconstrução completa (histórico editado, ambientes discordantes e ninguém sabe o que “latest” significa). Se ainda houver surpresas após um teste limpo em um banco fresco, incline‑se para a reconstrução.
Uma forma simples de prevenir problemas repetidos é escrever um pequeno “contrato de esquema” que todos sigam. Guarde no repositório como uma nota simples. Não precisa ser sofisticado, mas precisa ser claro.
- Só criar novas migrações; nunca editar antigas depois de terem sido lançadas
- Cada migração deve ser reversível (ou explicar por que não é)
- Uma pessoa fica responsável pelo merge final quando múltiplos branches tocarem o banco
- Mudanças no esquema de produção acontecem apenas via migrações, não por edições manuais no console
- Uma instalação nova (DB vazio -> latest) deve funcionar no CI antes de você deployar
Se seu app foi gerado por ferramentas como Lovable, Bolt, v0, Cursor ou Replit, espere mais drift oculto do que o normal. O código pode criar tabelas na inicialização, semear dados em lugares inesperados ou divergir entre SQLite local e Postgres em produção. Trate o banco como parte de primeira classe do app, não como um detalhe.
Saiba quando chamar uma segunda opinião. Se você tem dados reais de clientes, múltiplos ambientes que discordam, ou não tem certeza se um “conserto” pode dropar colunas ou reescrever constraints, pare. A FixMyMess pode rodar uma auditoria gratuita no código para apontar problemas de migração e propor correções seguras antes de qualquer compromisso — frequentemente mais rápido do que chutar debaixo de pressão.