Files
scoreodonto.com/doc/DEPLOY-PRODUCAO.md
T
VPS 4 Builder 93bf37340f
build-and-promote / build (push) Successful in 56s
build-and-promote / promote (push) Has been skipped
docs: Passo 5 validado em produção (v1.0.16) — modelo Build Once completo
- VERDADE-HOJE.md e DEPLOY-PRODUCAO.md: produção v1.0.16 (commit 471c2c2);
  tag promove por re-tag SEM rebuild (digest :v1.0.16 == :471c2c2, provado);
  versão nasce da tag; constants.ts/update-version.js removidos. Passo 5 .

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:51:49 +02:00

5.5 KiB

Deploy & Versionamento — Runbook ScoreOdonto

Auditado contra o sistema em 17/jun/2026. Cada item carrega seu status real.

Legenda: EM PRODUÇÃO · 🧪 EM DEV (não promovido) · 🎯 ALVO (não implementado).

Produção AGORA: v1.0.16 · commit 471c2c2 · 2026-06-17 (curl https://scoreodonto.com/api/version). Modelo Build Once → Promote → Deploy completo — Passo 5 validado em v1.0.16. Tudo abaixo .


1. O modelo

Push na main builda uma vez e publica por commit; a tag vX.Y.Z re-tagueia esse mesmo artefato (sem rebuild) e deploya. Produção nunca builda — só executa imagens.

 PUSH main (commit C)                 TAG vX.Y.Z (no commit C)
        │                                     │
        ▼                                     ▼
   CI: build (1x)                       CI: promote (SEM build) ✅
   publica :C + :latest                 re-tag :C → :vX.Y.Z (MESMO digest) + deploy
        ▼                                     ▼
   registry                             VPS1: pull :vX.Y.Z + up --no-build
                                        APP_VERSION=tag injetada em runtime

Prova (v1.0.16): :v1.0.16 tem digest idêntico a :471c2c2 — a tag é só um rótulo sobre a imagem já testada.


2. Estado por componente (verificado)

Componente Status Detalhe
Infra VPS1/3/4 + Docker rootless Mapa na §3
Registry (git.clube67.com/ruicesar/...) Ver REGISTRY.md
CI: job build publica por commit em push (sem APP_VERSION) .gitea/workflows/build.yml (runner vps4-builder)
Job promote por tag: re-tag :<commit>→:vX.Y.Z (sem rebuild) + deploy validado em v1.0.16 (:v1.0.16 == :471c2c2)
Validação de integridade no promote (commit existe? digest igual? front+back mesmo commit) falha se o commit não foi pushado
Produção não builda (image: + pull + up --no-build) docker-compose.prod.yml
Banco DEV isolado em pgdev; prod no Postgres da VPS3 Ver BANCO-DEV-ESTRATEGIA.md
Versão em runtime (/api/version) → Configurações + telas públicas useAppVersion(); sem APP_VERSION manual
APP_VERSION/APP_ENV injetados no deploy em runtime compose.prod environment
Versão nasce da tag git (constants.ts/update-version.js removidos) Passo 5

3. Mapa de máquinas

Onde Host Papel Docker
VPS1 10.99.0.1 Produção (Traefik + apps) rootless
VPS3 10.99.0.3 Postgres (prod) + Gitea + registry
VPS4 10.99.0.4 Dev + Builder (código; runner CI; pgdev) rootless
  • Repo: ssh://git@10.99.0.3/ruicesar/scoreodonto.com.git. Project Compose: scoreodontocom.

4. De onde vem a versão (/api/version)

{ "name": "ScoreOdonto API", "version": "v1.0.16", "commit": "471c2c2",
  "build": "2026-06-17 10:35 UTC", "environment": "PROD" }
  • commit / build = carimbados no build (imutáveis — identidade do artefato).
  • version / environment = injetados no deploy em runtime (a partir da tag). A mesma imagem é promovida sob qualquer tag, sem rebuild.
  • Frontend lê tudo de /api/version (useAppVersion()); não embute versão. Fonte única = backend.

5. Runbook — subir um release

⚠️ Regra de ouro: confirme DEV ou PRODUÇÃO. dev.scoreodonto.com = VPS4 (banco pgdev). scoreodonto.com = VPS1 (real). Nunca git push --force na main. Push/tag exigem autorização explícita.

# 1) VPS4: validar em DEV
cd /home/deploy/stack/scoreodonto.com
node --check backend/server.js
docker compose build scoreodonto-backend scoreodonto-frontend
docker compose up -d --force-recreate scoreodonto-backend scoreodonto-frontend   # https://dev.scoreodonto.com

# 2) commit + push → CI builda 1x e publica :<commit> + :latest (NÃO deploya)
git add -A && git commit -m "feat: <descrição>"
git push origin main

# 3) tag = "aprovado p/ produção" → job PROMOTE re-tagueia :<commit>→:vX.Y.Z (SEM rebuild) + deploya
#    (o número da versão é livre — não precisa casar com nenhum arquivo)
git tag -a vX.Y.Z -m "release vX.Y.Z" && git push origin vX.Y.Z

# 4) verificar (sem SSH)
curl -s https://scoreodonto.com/api/version     # → vX.Y.Z · <commit> · PROD

Backup do banco de PRODUÇÃO antes de releases sensíveis (via container, pois não há shell na VPS3):

docker run --rm -e PGPASSWORD=<senha> -v /home/deploy/backups:/b postgres:18 \
  pg_dump -h 10.99.0.3 -U scoreodonto_user -d scoreodonto -Fc -f /b/scoreodonto_$(date +%Y%m%d_%H%M).dump

6. Rollback

Por imagem, sem rebuild — na VPS1:

/home/deploy/stack/scoreodonto.com/deploy-prod.sh <tag-ou-commit-anterior>   # pull + up --no-build

⚠️ A referência confiável é o commit (:<sha>). Tags :vX.Y.Z antigas (pré-Passo 5) podem ter sido republicadas com código diferente — a partir do Passo 5, :vX.Y.Z é sempre um alias imutável do commit. Migrações são aditivas (voltar o código é seguro). Dump em /home/deploy/backups/ só em extremo.


7. Follow-ups (não bloqueiam) 🎯

  • GET /api/health (monitoramento/diagnóstico).
  • Política de retenção do registry (uma imagem :<commit> por push acumula).
  • Reconciliar o repo na VPS1 (working tree sujo, não afeta o deploy por imagem).

Racional do modelo em deploy.md; histórico em project-cicd-tag-promove-nao-rebuilda (memória).