Table of Contents
- 🚀 Deploy V.1.0.1 — Guia Completo (Deploy + Versionamento)
- 📋 Índice
- 1. Arquitetura Multi-VPS
- 2. Pipeline de Deploy Automático (GitOps)
- 3. O Listener do Webhook
- 4. Dois Modelos de Deploy
- 🅰️ Builder-to-Host — build na VPS4, VPS1 só reinicia
- 🅱️ Build no Host — rsync do fonte, VPS1 builda a imagem Docker
- Promoção manual Staging → Produção
- 5. Configurar um Novo Projeto
- 6. Versionamento — Servidor rx.scoreodonto.com
- Onde a versão existe (3 arquivos, hoje dessincronizados)
- Consultar versão em produção
- Como bumpar (processo atual — manual)
- 7. Versionamento — Cliente Windows rx.scoreodonto.com-client
- Fonte única de verdade: package.json
- Como o auto-update funciona nas clínicas
- Estado atual (detectado em 28/05/2026)
- Como bumpar (processo correto)
- Histórico de versões (dist/ VPS4)
- 8. Convenção de Numeração (Semver)
- Servidor (rx.scoreodonto.com) — versão atual: v2.1.2
- Cliente Windows (rx.scoreodonto.com-client) — versão atual: 1.2.7
- 9. Relação entre Versão do Servidor e do Cliente
- 10. Segurança
- 11. Troubleshooting
- 12. Changelog desta Wiki
🚀 Deploy V.1.0.1 — Guia Completo (Deploy + Versionamento)
Versão 1.0.1 — consolida tudo num único documento: pipeline de deploy automático, versionamento do servidor e do cliente Windows, convenções e regras de ouro. Um agente ou desenvolvedor deve conseguir executar qualquer tarefa lendo apenas esta página.
📋 Índice
- Arquitetura Multi-VPS
- Pipeline de Deploy Automático (GitOps)
- O Listener do Webhook
- Dois Modelos de Deploy
- Configurar um Novo Projeto
- Versionamento — Servidor rx.scoreodonto.com
- Versionamento — Cliente Windows
- Convenção de Numeração (Semver)
- Relação entre Versão do Servidor e do Cliente
- Segurança
- Troubleshooting
- Changelog desta Wiki
1. Arquitetura Multi-VPS
| Servidor | IP (VPN WireGuard) | Função |
|---|---|---|
| VPS 1 — App | 10.99.0.1 |
Produção — roda os containers Docker (rootless) |
| VPS 3 — Data/Git | 10.99.0.3 |
Gitea + PostgreSQL |
| VPS 4 — Builder | 10.99.0.4 |
Desenvolvimento, build e disparo do deploy |
Dev (VPS4) ──git push──► Gitea (VPS3) ──webhook──► Listener (VPS4:porta)
│
deploy-*.sh (VPS4)
│
┌─────────────────────┴──────────────────────┐
▼ ▼
Modelo A: build na VPS4 Modelo B: rsync do fonte
rsync artefatos → VPS1 build na VPS1
docker compose up -d docker compose up --build
Princípios:
- A fonte de verdade é sempre o Gitea — o deploy faz
git reset --hard origin/mainantes de qualquer coisa. - Produção (VPS1) nunca recebe edição manual — o
rsync --deletesobrescreve tudo no próximo deploy. - Docker rootless na VPS1 — sempre usar
DOCKER_HOST=unix:///run/user/1000/docker.sock. - Toda comunicação VPS↔VPS é pela VPN (
10.99.0.x) via chave SSH do usuáriodeploy.
2. Pipeline de Deploy Automático (GitOps)
git push origin main
└─► Gitea dispara POST http://10.99.0.4:<porta>/webhook?token=<TOKEN>
└─► listener valida token + trava de concorrência
└─► responde 202 imediatamente (não trava o Gitea)
└─► executa deploy-*.sh em background
└─► git reset --hard
└─► build / version bump
└─► rsync → VPS1
└─► ssh VPS1: docker restart/rebuild
└─► git push do bump ("chore(deploy): bump version")
└─► listener IGNORA este commit (anti-loop)
└─► reporta status ao Gitea: pending → success / failure (✔ ✘ no commit)
Um listener por projeto, cada um em uma porta:
| Projeto | Porta | Script | Service systemd |
|---|---|---|---|
| clube67 / newwhats | 9000 | clube67/deploy-prod-builder.sh |
webhook-listener.service ✅ ativo |
| scoreodonto.com | 9002 | deploy-prod-scoreodonto.sh |
webhook-scoreodonto.service ✅ ativo |
| rx.scoreodonto.com | — | rx.scoreodonto.com/deploy-prod.sh |
nenhum — deploy manual |
| rx.scoreodonto.com-client | — | rx.scoreodonto.com-client/deploy-client.sh |
nenhum — deploy manual |
3. O Listener do Webhook
Código de referência: webhook-listener/listener.js neste repositório.
Lógica:
- Valida token (
x-gitea-tokenheader ou?token=query string). - Trava
isBuilding— retorna429se já há build rodando (sem deploys concorrentes). - Anti-loop de CI — ignora commits cuja mensagem case com
^chore\(deploy\): bump version. - Responde 202 imediatamente; roda o script em background.
- Reporta status via API do Gitea:
pending→success/failure.
Variáveis de ambiente (configurar em <projeto>.env, nunca commitar):
PORT=<porta única por projeto>
WEBHOOK_TOKEN=<token forte>
DEPLOY_SCRIPT=/home/deploy/stack/<projeto>/deploy-prod-builder.sh
LOG_FILE=/home/deploy/stack/webhook-listener/deploy.log
GITEA_API_URL=http://10.99.0.3:3000/api/v1
GITEA_TOKEN=<token da API do Gitea com escopo repo:status>
Instalar como serviço:
sudo cp webhook-listener/webhook-listener.service /etc/systemd/system/webhook-<projeto>.service
sudo systemctl daemon-reload && sudo systemctl enable --now webhook-<projeto>
4. Dois Modelos de Deploy
🅰️ Builder-to-Host — build na VPS4, VPS1 só reinicia
Usado pelo clube67 / newwhats. Indicado para frontends pesados (Next.js / Vite).
Script: scripts/deploy-prod-builder.sh
git reset --hard ► npm install + build ► rsync dist/ + node_modules/ → VPS1 ► docker compose up -d
- VPS1 nunca roda
npm installounpm build. - Ao final:
git commit "chore(deploy): bump version" && git push(anti-loop).
🅱️ Build no Host — rsync do fonte, VPS1 builda a imagem Docker
Usado pelo scoreodonto.com e rx.scoreodonto.com. Indicado para apps leves (Node servindo estáticos).
Script: scripts/deploy-prod-onhost.sh
git reset --hard ► rsync do código-fonte → VPS1 ► ssh VPS1: docker compose build app + up -d --no-deps app
- Swap do container com quase zero downtime (
--no-deps). - VPS1 builda a imagem com
Dockerfilelocal (no caso do rx:node:22-alpine).
Promoção manual Staging → Produção
Script: scripts/deploy-to-prod.sh — usado quando há staging na VPS4 e se quer promover a build validada para produção sem rebuild.
5. Configurar um Novo Projeto
# 1. Criar o .env do listener (nunca commitar)
cp webhook-listener/config.example.env /home/deploy/stack/webhook-listener/<projeto>.env
# editar: PORT, WEBHOOK_TOKEN, DEPLOY_SCRIPT, GITEA_TOKEN
# 2. Instalar o service systemd
sudo cp webhook-listener/webhook-listener.service /etc/systemd/system/webhook-<projeto>.service
# editar: Description, SyslogIdentifier, EnvironmentFile
sudo systemctl daemon-reload && sudo systemctl enable --now webhook-<projeto>
# 3. Criar webhook no Gitea
# Repo → Settings → Webhooks → Add Webhook → Gitea
# URL: http://10.99.0.4:<PORT>/webhook?token=<WEBHOOK_TOKEN>
# Método: POST | Evento: Push | Branch: main
# 4. Criar GITEA_TOKEN de status
# Gitea → Settings → Applications → Generate Token (escopo: repo:status / write:repository)
# 5. Testar
git commit --allow-empty -m "test: dispara webhook" && git push origin main
tail -f /home/deploy/stack/webhook-listener/deploy.log
Pré-requisitos:
- Chave SSH do
deploy(VPS4) com acesso sem senha à VPS1:ssh deploy@10.99.0.1 echo ok - Chave SSH do
deploycom permissão de push no Gitea. - Porta do listener liberada apenas na VPN (
10.99.0.0/24).
6. Versionamento — Servidor rx.scoreodonto.com
Onde a versão existe (3 arquivos, hoje dessincronizados)
| Arquivo | Valor atual | Quem usa |
|---|---|---|
dental-server/version.txt |
2.1.0 |
Lido pelo servidor em runtime |
dental-server/package.json → "version" |
2.0.5 |
Metadado Node (não exibido ao usuário) |
dental-server/public/index.html linha 33 |
v2.1.2 |
Exibido na sidebar do painel web |
A versão que o usuário vê é o index.html — hardcoded diretamente no HTML:
<h2>RF Dental <span>v2.1.2</span></h2>
Não existe script que sincronize os três automaticamente. Qualquer um pode ficar para trás.
Consultar versão em produção
# O que o usuário vê no painel:
ssh deploy@10.99.0.1 "grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+' /home/deploy/stack/rx.scoreodonto.com/dental-server/public/index.html | head -1"
# O que o servidor lê em runtime:
ssh deploy@10.99.0.1 "cat /home/deploy/stack/rx.scoreodonto.com/dental-server/version.txt"
Como bumpar (processo atual — manual)
# 1. Editar os 3 arquivos para o mesmo número
nano /home/deploy/stack/rx.scoreodonto.com/dental-server/version.txt
nano /home/deploy/stack/rx.scoreodonto.com/dental-server/package.json
nano /home/deploy/stack/rx.scoreodonto.com/dental-server/public/index.html # linha 33
# 2. Commitar e deploy
cd /home/deploy/stack/rx.scoreodonto.com
git add -p && git commit -m "chore(version): bump para vX.Y.Z"
git push origin main
./deploy-prod.sh
# 3. Verificar no painel web
7. Versionamento — Cliente Windows rx.scoreodonto.com-client
Fonte única de verdade: package.json
{
"version": "1.2.7"
}
O electron-builder lê esse valor e:
- Nomeia o instalador:
ScoreOdonto Dental Client Setup 1.2.7.exe - Gera o
latest.ymlque vai paradental-server/updates/:
version: 1.2.6 ← versão atual nas clínicas
files:
- url: ScoreOdonto Dental Client Setup 1.2.6.exe
sha512: zEYuIRBU...
size: 102459655
Como o auto-update funciona nas clínicas
Clínica (Windows) ao iniciar o app:
└─► GET https://rx.scoreodonto.com/updates/latest.yml
│
├─ version no yml > version instalada? SIM → baixa .exe em background → instala ao reiniciar
└─ NÃO → nada acontece, app continua normalmente
⚠️ Regra de ouro: a versão que as clínicas têm é determinada exclusivamente pelo
latest.ymlem produção. O.exena VPS4 não vale nada enquanto olatest.ymlnão for atualizado.
Estado atual (detectado em 28/05/2026)
| Local | Versão |
|---|---|
package.json (VPS4) |
1.2.7 |
.exe em dist/ (VPS4) |
1.2.7 — buildado |
latest.yml em updates/ (VPS1) |
1.2.6 — as clínicas não recebem o 1.2.7 |
Como bumpar (processo correto)
# 1. Subir a versão no package.json
nano /home/deploy/stack/rx.scoreodonto.com-client/package.json
# "version": "1.2.7" → "1.2.8"
# 2. Commitar
cd /home/deploy/stack/rx.scoreodonto.com-client
git add package.json && git commit -m "chore(version): bump client para 1.2.8"
git push origin main
# 3. Build + deploy (gera .exe e envia latest.yml para VPS1)
./deploy-client.sh
# 4. Confirmar que o latest.yml foi atualizado
curl -s https://rx.scoreodonto.com/updates/latest.yml
# → version: 1.2.8
Histórico de versões (dist/ VPS4)
| Versão | Build | Status |
|---|---|---|
| 1.2.0 | 28/05/2026 02:59 | publicado |
| 1.2.1 | 28/05/2026 03:09 | publicado |
| 1.2.2 | 28/05/2026 03:18 | publicado |
| 1.2.3 | 28/05/2026 03:32 | publicado |
| 1.2.4 | 28/05/2026 03:56 | publicado |
| 1.2.5 | 28/05/2026 05:34 | publicado |
| 1.2.6 | 28/05/2026 05:45 | ✅ em produção (VPS1 / clínicas) |
| 1.2.7 | 28/05/2026 20:38 | ⚠️ buildado — não publicado |
8. Convenção de Numeração (Semver)
Ambos os projetos seguem MAJOR.MINOR.PATCH. As regras são independentes — servidor e cliente têm ciclos de versão separados.
Servidor (rx.scoreodonto.com) — versão atual: v2.1.2
| Parte | Quando subir | Exemplos |
|---|---|---|
PATCH v2.1.X |
Qualquer bugfix, ajuste visual, melhoria pequena, correção de CSS/JS | v2.1.2 → v2.1.3 |
MINOR v2.X.0 |
Nova funcionalidade no painel, nova rota de API, novo modal/fluxo | v2.1.x → v2.2.0 |
MAJOR vX.0.0 |
Rewrite de arquitetura, mudança de banco, quebra de compatibilidade | v2.x.x → v3.0.0 |
Cliente Windows (rx.scoreodonto.com-client) — versão atual: 1.2.7
| Parte | Quando subir | Exemplos |
|---|---|---|
PATCH 1.2.X |
Bugfix no monitoramento, ajuste de config, correção de conexão | 1.2.7 → 1.2.8 |
MINOR 1.X.0 |
Nova funcionalidade no cliente (nova tela, novo comportamento, novo evento socket) | 1.2.x → 1.3.0 |
MAJOR X.0.0 |
Mudança de protocolo (Socket.IO incompatível), rewrite completo | 1.x.x → 2.0.0 |
Regra prática: na dúvida, sobe o PATCH. MINOR e MAJOR são decisões conscientes.
9. Relação entre Versão do Servidor e do Cliente
Servidor e cliente são projetos independentes com versões independentes. Não há numeração sincronizada entre v2.1.2 (servidor) e 1.2.7 (cliente).
O que importa é a compatibilidade de protocolo:
| Ponto de integração | Onde está definido | Risco de quebra |
|---|---|---|
| URL do servidor Socket.IO | index.js do cliente → https://rx.scoreodonto.com |
Baixo — só muda se o domínio mudar |
Evento send-image (socket) |
client-monitor.js + server.js |
Alto — se mudar o payload, servidor e cliente devem ser atualizados juntos |
Autenticação via machine_token JWT |
routes/client-auth.js + index.js |
Alto — mudança de algoritmo exige deploy sincronizado |
| URL de auto-update | package.json → publish.url = https://rx.scoreodonto.com/updates/ |
Médio — se o path mudar no servidor, clientes antigos param de atualizar |
Quando fazer deploy sincronizado (servidor + cliente no mesmo ciclo): qualquer mudança no contrato do Socket.IO (eventos, payload) ou na autenticação JWT exige que servidor e cliente sejam publicados juntos, ou na ordem: servidor primeiro, cliente depois.
10. Segurança
- Sem segredos no Git — tokens, senhas, JWT em
.env+EnvironmentFile=no systemd..gitignorebloqueia*.env. - Docker rootless na VPS1 —
DOCKER_HOST=unix:///run/user/1000/docker.sockem todos os comandos remotos. Daemon root desabilitado de propósito; se reativado junto comdeployno grupodocker, cria containers root paralelos invisíveis ao Traefik. - SSH — chave do
deploysem passphrase para automação,BatchMode=yesnos scripts, acesso só pela VPN. - Commite antes de buildar — o deploy faz
git reset --harde descarta mudanças locais não commitadas. - Nunca editar na VPS1 — o
rsync --deletesobrescreve tudo no próximo deploy. - Tokens distintos por projeto (WEBHOOK_TOKEN e GITEA_TOKEN). Rotacionar periodicamente.
11. Troubleshooting
| Problema | Diagnóstico | Solução |
|---|---|---|
| Webhook não dispara | systemctl status webhook-<projeto> |
Reiniciar o listener |
429 no webhook |
Build concorrente em andamento | Aguardar o build terminar |
rsync / ssh falha |
ssh deploy@10.99.0.1 echo ok |
Checar chave SSH e VPN WireGuard |
| Build falha na VPS1 | docker logs <container> |
Ver erro de npm/Dockerfile |
| Deploy em loop | Commit de bump re-dispara | Confirmar regex anti-loop no listener |
| Versão não atualiza no painel | index.html não foi editado |
Editar os 3 arquivos do servidor sincronizados |
| Clínicas não recebem update | curl https://rx.scoreodonto.com/updates/latest.yml |
Verificar se latest.yml tem a versão nova; se não, re-rodar deploy-client.sh |
| Port 8020 ocupada na VPS1 | sudo ss -tlnp | grep 8020 |
docker-proxy root zumbi — ver seção de Docker rootless |
docker.service root ativo na VPS1 |
sudo systemctl status docker |
sudo systemctl disable --now docker |
12. Changelog desta Wiki
| Versão | Data | O que mudou |
|---|---|---|
| 1.0.1 | 2026-05-30 | Consolidação total: deploy + versionamento servidor + versionamento cliente + convenções semver + relação entre versões. Tudo numa página só. |
| 1.0.0 | 2026-05-30 | Versão inicial: listener de webhook, modelos A/B de deploy, configuração no Gitea, segurança. |