diff --git a/Deploy-V.1.0.1.md b/Deploy-V.1.0.1.md new file mode 100644 index 0000000..cb68649 --- /dev/null +++ b/Deploy-V.1.0.1.md @@ -0,0 +1,368 @@ +# 🚀 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 + +1. [Arquitetura Multi-VPS](#1-arquitetura-multi-vps) +2. [Pipeline de Deploy Automático (GitOps)](#2-pipeline-de-deploy-automático-gitops) +3. [O Listener do Webhook](#3-o-listener-do-webhook) +4. [Dois Modelos de Deploy](#4-dois-modelos-de-deploy) +5. [Configurar um Novo Projeto](#5-configurar-um-novo-projeto) +6. [Versionamento — Servidor rx.scoreodonto.com](#6-versionamento--servidor-rxscoredontcom) +7. [Versionamento — Cliente Windows](#7-versionamento--cliente-windows) +8. [Convenção de Numeração (Semver)](#8-convenção-de-numeração-semver) +9. [Relação entre Versão do Servidor e do Cliente](#9-relação-entre-versão-do-servidor-e-do-cliente) +10. [Segurança](#10-segurança) +11. [Troubleshooting](#11-troubleshooting) +12. [Changelog desta Wiki](#12-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/main` antes de qualquer coisa. +- **Produção (VPS1) nunca recebe edição manual** — o `rsync --delete` sobrescreve 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ário `deploy`. + +--- + +## 2. Pipeline de Deploy Automático (GitOps) + +``` +git push origin main + └─► Gitea dispara POST http://10.99.0.4:/webhook?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:** +1. Valida token (`x-gitea-token` header ou `?token=` query string). +2. **Trava `isBuilding`** — retorna `429` se já há build rodando (sem deploys concorrentes). +3. **Anti-loop de CI** — ignora commits cuja mensagem case com `^chore\(deploy\): bump version`. +4. Responde **202** imediatamente; roda o script em background. +5. Reporta status via API do Gitea: `pending` → `success` / `failure`. + +**Variáveis de ambiente** (configurar em `.env`, nunca commitar): +``` +PORT= +WEBHOOK_TOKEN= +DEPLOY_SCRIPT=/home/deploy/stack//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= +``` + +**Instalar como serviço:** +```bash +sudo cp webhook-listener/webhook-listener.service /etc/systemd/system/webhook-.service +sudo systemctl daemon-reload && sudo systemctl enable --now webhook- +``` + +--- + +## 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 install` ou `npm 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 `Dockerfile` local (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 + +```bash +# 1. Criar o .env do listener (nunca commitar) +cp webhook-listener/config.example.env /home/deploy/stack/webhook-listener/.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-.service +# editar: Description, SyslogIdentifier, EnvironmentFile +sudo systemctl daemon-reload && sudo systemctl enable --now webhook- + +# 3. Criar webhook no Gitea +# Repo → Settings → Webhooks → Add Webhook → Gitea +# URL: http://10.99.0.4:/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 `deploy` com 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: +```html +

RF Dental v2.1.2

+``` +Não existe script que sincronize os três automaticamente. Qualquer um pode ficar para trás. + +### Consultar versão em produção + +```bash +# 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) + +```bash +# 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` + +```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.yml` que vai para `dental-server/updates/`: + +```yaml +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.yml` +> em produção. O `.exe` na VPS4 não vale nada enquanto o `latest.yml` nã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) + +```bash +# 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. `.gitignore` bloqueia `*.env`. +- **Docker rootless na VPS1** — `DOCKER_HOST=unix:///run/user/1000/docker.sock` em todos os comandos remotos. Daemon root desabilitado de propósito; se reativado junto com `deploy` no grupo `docker`, cria containers root paralelos invisíveis ao Traefik. +- **SSH** — chave do `deploy` sem passphrase para automação, `BatchMode=yes` nos scripts, acesso só pela VPN. +- **Commite antes de buildar** — o deploy faz `git reset --hard` e descarta mudanças locais não commitadas. +- **Nunca editar na VPS1** — o `rsync --delete` sobrescreve 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-` | 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 ` | 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. | diff --git a/Home.md b/Home.md index ef2c1fd..46b93d7 100644 --- a/Home.md +++ b/Home.md @@ -1,17 +1,18 @@ # 🏠 Deploy-Automático — Wiki -Documentação da automação de deploy GitOps (Gitea + Multi-VPS) usada no ecossistema. +Documentação da automação de deploy GitOps (Gitea + Multi-VPS) e versionamento dos projetos. -## Versões -- [Deploy V.1.0.0](Deploy-V.1.0.0) — versão inicial: listener de webhook, modelos A/B de deploy, - configuração no Gitea e segurança. +## Versão atual -## Documentação complementar -- [Versionamento](Versionamento) — como o servidor e o cliente Windows controlam versões, - onde cada número é definido, problemas atuais de dessincronização e como garantir que - as clínicas recebem o update correto. +- **[Deploy V.1.0.1](Deploy-V.1.0.1)** ← versão mais recente — contém tudo: deploy automático, + versionamento do servidor, versionamento do cliente Windows, convenções semver, segurança e troubleshooting. + +## Arquivo de versões anteriores + +- [Deploy V.1.0.0](Deploy-V.1.0.0) — versão inicial (apenas deploy, sem versionamento). ## Repositório de exemplos + Scripts e instruções de referência (sanitizados) estão no repositório [`ruicesar/Deploy-Automatico`](http://10.99.0.3:3000/ruicesar/Deploy-Automatico): `webhook-listener/`, `scripts/` e `docs/`.