Você já parou pra pensar no risco de manter uma esteira onde qualquer merge na branch principal vai direto pra produção sem nenhum gate de segurança?
Por muito tempo, o nosso fluxo aqui era aquele clássico script que quase todo mundo já usou na vida: merge na main disparando SSH com git pull e pm2 restart
Funcionava no dia a dia, mas era aquela falsa sensação de estabilidade kkkk
A ficha caiu de verdade quando encontrei um ponto cego crítico na automação: os scripts remotos rodavam sem tratamento estrito de erro. Ou seja, se um git pull gerasse conflito ou uma migração de banco falhasse no meio do processo, o script ignorava o erro, executava até o final e o GitHub Actions marcava o pipeline como sucesso
O pior cenário para quem monitora: a esteira reportava que tudo tinha corrido bem, enquanto a aplicação em produção já estava fora do ar
Além disso, a ordem de execução estava invertida: a migração de banco rodava antes do build da aplicação. Se o TypeScript acusasse um erro de tipagem logo depois, o banco já tinha sido alterado e o código novo nem subia. Como o Prisma não possui down migrations nativas, reverter o estado virava uma intervenção manual de alto risco
Decidi parar e redesenhar toda a nossa arquitetura de entrega do zero, partindo de uma premissa clara: tag é release, merge não é
Hoje, nada toca o servidor sem uma tag SemVer anotada, atravessando 6 estágios encadeados:
- Validação estrita da tag: só aceita tag anotada no padrão vX.Y.Z, garantindo autor, data e o registro auditável de cada release
- Gates de qualidade em PR e Release: testes automatizados com Vitest, typecheck rigoroso, build e validação de migrações em banco limpo via workflow_call
- Backup desacoplado: rotina diária agendada somada a um snapshot obrigatório antes de qualquer alteração de infraestrutura
- Ensaio real de migração: o gate de maior valor, onde o pipeline restaura o dump de produção num banco descartável dentro da própria VPS, executa a migração cronometrada e checa drift de schema antes de tocar a base oficial
- Deploy determinístico: checkout direto na tag imutável, build antes da migração e trava de concorrência pra evitar deploys simultâneos
- Smoke tests: validação ativa das portas HTTP e varredura de processos no PM2 pra garantir que nada entrou em loop de erro
O impacto dessa mudança na operação é brutal: conquistamos previsibilidade real nas migrações, rastreabilidade de cada versão e a certeza de que pipeline verde significa sistema íntegro no ar
Pra quem também gerencia aplicações Node e TypeScript em VPS ou servidores dedicados e quer sair do deploy cego, estruturei toda essa arquitetura em um template modular de GitHub Actions
Deixei o repositório aberto pra quem quiser usar de base nos seus projetos: https://github.com/victor-lis-bronzo/tag-release-template
Como vocês costumam desenhar os gates de deploy e migração de banco por aí?
Top comments (0)