docs: aponta deploy/infra para documentos-unicos (fonte única); remove DEPLOY-PRODUCAO local
build-and-promote / build (push) Successful in 1m21s
build-and-promote / promote (push) Has been skipped

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-06-17 16:59:46 +02:00
parent fc006221de
commit 4e00e28bc2
2 changed files with 12 additions and 117 deletions
+12
View File
@@ -0,0 +1,12 @@
# LEIA
A documentação de **infra/deploy** deste projeto **NÃO fica aqui**. Fonte única em:
**`/home/deploy/stack/documentos-unicos/`** — comece pelo `LEIA-PRIMEIRO.md`.
- Deploy: `documentos-unicos/deploy/` (modelo, subir-release, rollback, versionamento)
- Infra: `documentos-unicos/infra/` (máquinas/rede, ambiente-dev)
Documentação **específica do ScoreOdonto** (produto, RX, banco-dev, registry) está em `doc/` deste projeto.
**Regra:** nunca criar documentação de deploy/infra solta no projeto; atualização vai na pasta única (reescrever; antigo → `desuso/`). Tudo em português.
-117
View File
@@ -1,117 +0,0 @@
# 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`)
```json
{ "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.
```bash
# 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):
```bash
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:
```bash
/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).