1
Deploy V.1.0.3
VPS 4 Deploy Agent edited this page 2026-05-31 00:09:24 +02:00

🚀 Deploy V.1.0.3 — GitOps + Modelo A + Publicação do Cliente Windows

Versão 1.0.3 — inclui tudo da 1.0.2 (Modelo A, Wasabi, versionamento do servidor) e detalha o ciclo completo do Cliente Windows (Electron): build → publicação → auto-update, com a armadilha mais comum: versão buildada no dist/ mas nunca publicada na VPS1.


📋 Índice

  1. Arquitetura Multi-VPS
  2. Pipeline GitOps (Servidor — Modelo A)
  3. O Listener do Webhook
  4. Versionamento — Servidor
  5. Cliente Windows — Build, Publicação e Auto-Update
  6. Erros comuns e soluções
  7. Troubleshooting
  8. Changelog

1. Arquitetura Multi-VPS

Servidor IP (VPN) Função
VPS 1 — App 10.99.0.1 Produção (Docker rootless) + serve /updates/ do cliente
VPS 3 — Data/Git 10.99.0.3 Gitea + PostgreSQL
VPS 4 — Builder 10.99.0.4 Build do servidor e do cliente Windows (cross-compile)
Wasabi S3-compatível Storage de imagens (não no disco)

2. Pipeline GitOps (Modelo A)

git push origin main (rx.scoreodonto.com)
    ↓
Gitea dispara webhook → VPS4:9003/webhook
    ↓
listener-rx.js → deploy-prod.sh
    ↓
VPS4: build React (Vite) → docker compose build app → docker save → app.tar.gz
    ↓
VPS4: rsync app.tar.gz + docker-compose.yml + version.txt → VPS1
    ↓
VPS1: docker load + docker compose up -d --no-deps app
    ↓
✅ Deploy concluído (~30-40 s)

⚠️ O build do React roda com NODE_ENV=development npm install --include=dev porque o vite é devDependency e o listener roda com NODE_ENV=production (que pula devDeps).


3. O Listener do Webhook

Arquivo: /home/deploy/stack/webhook-listener/listener-rx.js (porta 9003)

  • Valida token (x-gitea-token ou ?token=...)
  • Trava de concorrência (isBuilding) + anti-loop (ignora chore(deploy): bump version)
  • Dispara deploy-prod.sh e reporta status ao Gitea (pending → success/failure)

📌 O cliente Windows NÃO tem webhook. O deploy-client.sh é manual (ver seção 5). Essa é a causa nº 1 de defasagem de versão do cliente.


4. Versionamento — Servidor

Fonte de verdade: dental-server/version.txt (lido em runtime, injetado no sidebar). package.json nunca é tocado no bump (preserva cache do Docker). Detalhes na 1.0.2.

# Versão servida (dentro do container é a fonte de verdade):
ssh deploy@10.99.0.1 "docker exec rx_scoreodonto_app cat /app/version.txt"
curl -s https://rx.scoreodonto.com/ | grep -o 'v[0-9]\.[0-9]\.[0-9]'

5. Cliente Windows — Build, Publicação e Auto-Update

Projeto: rx.scoreodonto.com-client (Electron + electron-updater).

5.1. Fonte de verdade

Tudo parte do package.json do cliente:

grep '"version"' /home/deploy/stack/rx.scoreodonto.com-client/package.json
# "version": "1.2.7"

O electron-builder lê esse número e gera 3 artefatos por versão: ScoreOdonto Dental Client Setup X.Y.Z.exe, ...exe.blockmap e latest.yml.

5.2. As DUAS pastas (e por que confundem)

Pasta Onde O que é
rx.scoreodonto.com-client/dist/ VPS4 Saída do build. Tem todos os .exe já gerados.
rx.scoreodonto.com/dental-server/updates/ VPS1 O que é servido em https://rx.scoreodonto.com/updates/. É o que as clínicas enxergam.

🔑 Buildar (gerar no dist/) ≠ publicar (copiar para updates/ na VPS1). O cliente só "existe" para as clínicas quando o latest.yml da VPS1 aponta para a nova versão.

5.3. Ciclo completo — deploy-client.sh

cd /home/deploy/stack/rx.scoreodonto.com-client
bash deploy-client.sh

O script faz, em ordem:

1. npm install
2. npx electron-builder --win --x64 --publish never   → gera dist/*.exe + dist/latest.yml (VPS4)
3. valida que dist/ tem .exe e latest.yml
4. rsync dist/*.exe dist/*.yml dist/*.blockmap → VPS1:/.../dental-server/updates/   ← PUBLICAÇÃO

Só termina o trabalho quando o passo 4 roda. Se você buildar manualmente (npm run dist) e parar aí, o dist/ na VPS4 fica novo, mas a VPS1 continua na versão antiga.

5.4. Fluxo de auto-update nas clínicas

App do cliente inicia
  ↓
electron-updater: GET https://rx.scoreodonto.com/updates/latest.yml
  ↓
versão do yml > versão instalada?  → baixa o .exe e instala ao reiniciar
                                    → senão, nada acontece

5.5. Verificação rápida (3 pontos têm que bater)

# 1. Fonte (código):
grep '"version"' /home/deploy/stack/rx.scoreodonto.com-client/package.json

# 2. Publicado na VPS1 (o que conta):
ssh deploy@10.99.0.1 "head -1 /home/deploy/stack/rx.scoreodonto.com/dental-server/updates/latest.yml"

# 3. O que o auto-updater realmente baixa (HTTP público):
curl -s https://rx.scoreodonto.com/updates/latest.yml | head -1

Se os três não baterem → rode deploy-client.sh até o fim.


6. Erros comuns e soluções

Erro A — Cliente em uma versão, servidor servindo outra (mais antiga)

Sintoma: package.json = 1.2.7, mas updates/latest.yml na VPS1 = 1.2.6. As clínicas não recebem o update e novas instalações baixam a versão velha.

Causa: a versão foi buildada no dist/ da VPS4 mas o rsync → VPS1 (passo 4 do deploy-client.sh) não rodou. Buildar não publica.

Diagnóstico:

# Build existe no dist/ (VPS4)?
ls -1 /home/deploy/stack/rx.scoreodonto.com-client/dist/*.exe | sort -V | tail -1
cat /home/deploy/stack/rx.scoreodonto.com-client/dist/latest.yml | head -1   # ex: 1.2.7

# Mas a VPS1 está atrás?
ssh deploy@10.99.0.1 "head -1 /home/deploy/.../dental-server/updates/latest.yml"  # ex: 1.2.6

Versões diferentes = build não publicado.

Solução (rápida, sem rebuild — artefato já existe e é válido):

cd /home/deploy/stack/rx.scoreodonto.com-client
rsync -avz dist/*.exe dist/*.yml dist/*.blockmap \
  deploy@10.99.0.1:/home/deploy/stack/rx.scoreodonto.com/dental-server/updates/

Solução (canônica): bash deploy-client.sh (rebuilda e publica).


Erro B — vite: not found no deploy do servidor

Causa: listener roda com NODE_ENV=productionnpm install pula devDependencies (vite). Solução: no deploy-prod.sh, NODE_ENV=development npm install --include=dev antes do vite build.

Erro C — Imagens do RX não aparecem (placeholder cinza, sem erro no DevTools)

Causa: endpoint de thumbnail retornava JSON {url} enquanto o <img src> apontava direto para ele. Solução: o endpoint serve bytes (image/jpeg); gera a thumb on-the-fly e faz backfill no Wasabi.

Erro D — Wasabi 403 após trocar credenciais

Causa: salvar credenciais no banco não recarregava o cliente S3 em memória. Solução: storage-config chama storage.loadConfigFromDb() após salvar.


7. Troubleshooting

Problema Diagnóstico Solução
Cliente desatualizado nas clínicas package.jsonupdates/latest.yml na VPS1? Rodar deploy-client.sh até o passo 4 (ou rsync do dist/)
Build do cliente falha Wine/electron-builder na VPS4 Ver log; npx electron-builder --win --x64 --publish never
Clínica não atualiza mesmo com yml novo versão instalada ≥ yml? Auto-update só sobe versão; conferir semver
Deploy do servidor vite: not found NODE_ENV=production no install --include=dev no deploy-client/deploy-prod
Imagens em branco thumb retornando JSON? Endpoint deve servir bytes image/jpeg
Wasabi 403 credenciais recarregadas? loadConfigFromDb() após salvar config
Deploy do servidor lento (3+ min) Modelo B? Modelo A (build na VPS4)

8. Changelog

Versão Data O que mudou
1.0.3 2026-05-31 Ciclo completo do Cliente Windows (build dist/ na VPS4 ≠ publicação updates/ na VPS1). Documenta a armadilha "buildado mas não publicado", verificação em 3 pontos, e o vite: not found.
1.0.2 2026-05-30 RX: switch para Modelo A (build VPS4), erros comuns, Wasabi. Deploy ~30-40s.
1.0.1 2026-05-30 Consolidação inicial: deploy + versionamento + segurança.
1.0.0 2026-05-30 Versão inicial.