diff --git a/Deploy-V.1.0.2.md b/Deploy-V.1.0.2.md new file mode 100644 index 0000000..f53cf57 --- /dev/null +++ b/Deploy-V.1.0.2.md @@ -0,0 +1,281 @@ +# 🚀 Deploy V.1.0.2 — GitOps + Modelo A otimizado para Wasabi + +> Versão **1.0.2** — RX agora usa **Modelo A (build na VPS4, imagem pronta para VPS1)** com Wasabi como storage. +> Tempo de deploy: **~30-40 segundos** (era 3-7min com Modelo B). +> Evita os erros comuns documentados aqui. + +--- + +## 📋 Índice + +1. [Arquitetura Multi-VPS](#1-arquitetura-multi-vps) +2. [Pipeline GitOps](#2-pipeline-gitops-modelo-a) +3. [Por que RX usa Modelo A (não B)](#3-por-que-rx-usa-modelo-a) +4. [O Listener do Webhook](#4-o-listener-do-webhook) +5. [Versionamento do Servidor](#5-versionamento--servidor) +6. [Versionamento do Cliente Windows](#6-versionamento--cliente-windows) +7. [Erros comuns e soluções](#7-erros-comuns-e-soluções) +8. [Troubleshooting](#8-troubleshooting) +9. [Changelog](#9-changelog) + +--- + +## 1. Arquitetura Multi-VPS + +| Servidor | IP (VPN) | Função | +|---|---|---| +| **VPS 1 — App** | `10.99.0.1` | Produção (Docker rootless) | +| **VPS 3 — Data/Git** | `10.99.0.3` | Gitea + PostgreSQL | +| **VPS 4 — Builder** | `10.99.0.4` | Build + deploy | +| **Wasabi** | S3-compatível | Storage de imagens (não no disco) | + +--- + +## 2. Pipeline GitOps (Modelo A) + +``` +git push origin main + ↓ +Gitea dispara webhook → VPS4:9003/webhook + ↓ +listener-rx.js: valida token, dispara deploy-prod.sh + ↓ +VPS4: docker compose build app (cria imagem) + ↓ +VPS4: docker save → app.tar.gz (exporta imagem compilada) + ↓ +VPS4: rsync app.tar.gz + docker-compose.yml → VPS1 + ↓ +VPS1: docker load < app.tar.gz (carrega imagem) + ↓ +VPS1: docker compose up -d --no-deps app (reinicia container) + ↓ +VPS4: git push chore(deploy): bump version (anti-loop) + ↓ +✅ Deploy concluído (~30-40 segundos) +``` + +**Por que é rápido:** +- ✅ VPS4 faz o build pesado (docker compose build) +- ✅ VPS1 só recebe a imagem pronta (docker load) +- ✅ Nenhuma compilação na produção +- ✅ Usa cache do Docker na VPS4 (npm install reutilizado) + +--- + +## 3. Por que RX usa Modelo A (não B) + +**Modelo B** (build na VPS1, descontinuado para RX): +``` +VPS4: rsync código-fonte → VPS1 +VPS1: docker compose build app ← LENTO (3-7 min) +``` + +**Problema:** `COPY . .` no Dockerfile invalida cache a cada mudança de código. +Docker tem que recompile tudo mesmo que `package.json` não tenha mudado. + +**RX com Wasabi:** +- Imagens estão no Wasabi (não no container) +- Container é **stateless** (sem volumes de dados) +- Modelo A é perfeito: build rápido na VPS4, imagem pronta na VPS1 + +**Clube67 (modelo A histórico):** +``` +VPS4: npm install + npm build (front) ✓ rápido +VPS4: rsync dist/ → VPS1 ✓ rápido +VPS1: docker compose up (sem build) ✓ instantâneo +``` + +--- + +## 4. O Listener do Webhook + +**Arquivo:** `/home/deploy/stack/webhook-listener/listener-rx.js` (porta 9003) + +**Responsabilidades:** +- Valida token (`x-gitea-token` ou `?token=...`) +- **Trava de concorrência:** `isBuilding` flag (não permite deploys paralelos) +- **Anti-loop:** ignora commits `chore(deploy): bump version` (senão loop infinito) +- Dispara `deploy-prod.sh` em background +- Reporta status ao Gitea (pending → success/failure) + +**Configuração:** +```bash +# /etc/systemd/system/webhook-rx.service +PORT=9003 +WEBHOOK_TOKEN=rx_deploy_token_9003_c7f2a1b4e8d5 +DEPLOY_SCRIPT=/home/deploy/stack/rx.scoreodonto.com/deploy-prod.sh +GITEA_TOKEN= +``` + +--- + +## 5. Versionamento — Servidor + +### Fonte de verdade: `dental-server/version.txt` + +```bash +# Arquivo: +cat /home/deploy/stack/rx.scoreodonto.com/dental-server/version.txt +# Output: 2.1.4 + +# Ou via HTTP (injetado pelo server no sidebar): +curl -s http://rx.scoreodonto.com/ | grep -o 'v[0-9]\.[0-9]\.[0-9]' +# Output: v2.1.4 +``` + +### Como o versionamento funciona + +| Arquivo | Quando muda | +|---|---| +| `version.txt` | A cada deploy (auto-bump PATCH) | +| `package.json` | **NUNCA** (preserva Docker cache) | +| `index.html` | A cada deploy (versão injetada) | +| Server em runtime | Lê `version.txt` (não package.json) | + +**Importante:** `update-version.js` **NÃO toca** `package.json`: +```javascript +// ❌ NÃO faz isso (invalida cache Docker): +fs.writeFileSync(packageFile, JSON.stringify(pkg, null, 2)); + +// ✅ Só toca esses: +fs.writeFileSync(versionFile, next); // version.txt +fs.writeFileSync(indexFile, html); // index.html (versão injetada) +``` + +--- + +## 6. Versionamento — Cliente Windows + +### Fonte de verdade: `package.json` → `latest.yml` + +```bash +# Arquivo: +cat /home/deploy/stack/rx.scoreodonto.com-client/package.json | grep version +# Output: "version": "1.2.7" + +# Gerado no build: +cat /home/deploy/stack/rx.scoreodonto.com/dental-server/updates/latest.yml +# Output: +# version: 1.2.7 +# files: +# - url: ScoreOdonto Dental Client Setup 1.2.7.exe +``` + +**Fluxo de atualização nas clínicas:** +``` +Clínica inicia app + ↓ +electron-updater: GET /updates/latest.yml + ↓ +version no yml > versão instalada? + ↓ SIM + Baixa .exe + instala ao reiniciar + ↓ NÃO + Nada acontece +``` + +**⚠️ CRÍTICO:** Se `latest.yml` não for atualizado, **clínicas não recebem update**. + +--- + +## 7. Erros comuns e soluções + +### ❌ Erro 1: `previewStyle is not defined` +**Causa:** Variável não definida no `patientCardHTML()` +**Solução:** Sempre ter `` ou placeholder, nunca deixar vazio +```javascript +// ❌ ERRADO: +const preview = thumb ? `` : ''; +
// previewStyle não existe + +// ✅ CORRETO: +const preview = thumb + ? `` + : `
`; +
+ ${preview} +
+``` + +### ❌ Erro 2: Deploy leva 3-7 minutos +**Causa:** Modelo B com `docker compose build` na VPS1 +**Solução:** Usar Modelo A — build na VPS4, imagem para VPS1 +```bash +# ❌ LENTO (Modelo B): +ssh VPS1 "docker compose build app && docker compose up" + +# ✅ RÁPIDO (Modelo A): +docker compose build app # VPS4 (local, cache reutilizado) +docker save | gzip > app.tar.gz +rsync app.tar.gz → VPS1 +ssh VPS1 "docker load < app.tar.gz && docker compose up" +``` + +### ❌ Erro 3: Docker cache sempre invalida +**Causa:** `COPY . .` no Dockerfile invalida cache quando código muda +**Solução:** Não tocar `package.json` no version bump +```dockerfile +# ❌ PROBLEMA: +FROM node:22-alpine +RUN npm install # camada 1 +COPY . . # camada 2 (invalida sempre que código muda) + +# ✅ SOLUÇÃO: +FROM node:22-alpine +COPY package*.json ./ # copia ANTES de install +RUN npm install # camada 2 (reutiliza cache se package.json não muda) +COPY . . # camada 3 (invalida, mas npm install já rodou) +``` + +### ❌ Erro 4: Imagens dos cards ficam em branco +**Causa:** Sem `thumb_filename` no banco, sem placeholder no frontend +**Solução:** SEMPRE gerar thumbnail + mostrar placeholder +```javascript +// Servidor gera thumb ao receber imagem: +const thumbBuffer = await imageProcessor.getThumbnail(imageBuffer, 500, 500); +thumbFilename = `thumb_${filename}`; +await storage.saveImage(thumbFilename, thumbBuffer, ...); +// Salva no banco com thumb_filename + +// Frontend SEMPRE mostra algo: +const preview = thumb + ? `` // mostra thumb rápido + : `
`; // fallback cinza enquanto carrega +``` + +### ❌ Erro 5: Loop infinito de CI +**Causa:** Listener não ignora commits de bump de versão +**Solução:** Regex anti-loop no listener +```javascript +const VERSION_BUMP_RE = /^chore\(deploy\):\s*bump version/i; + +if (messages.every(m => VERSION_BUMP_RE.test(m))) { + // Ignora commit de bump → sem loop + return res.json({ status: 'skipped' }); +} +``` + +--- + +## 8. Troubleshooting + +| Problema | Diagnóstico | Solução | +|---|---|---| +| Deploy leva 3+ min | Está usando Modelo B? | Mudar para Modelo A (build na VPS4) | +| Docker cache invalida | `COPY . .` perde cache? | Não tocar `package.json` no bump | +| Webhook não dispara | `systemctl status webhook-rx` | Reiniciar listener ou verificar token | +| `429` no webhook | Build em progresso? | Aguardar concluir | +| Imagens em branco nos cards | Sem `thumb_filename` no banco? | Rodar `/api/images/backfill-thumbs` | +| Clínicas não recebem update | `latest.yml` desatualizado? | Verificar se deploy-client.sh roda completo | +| `docker load` falha | Imagem corrompida? | Refazer build: `docker compose build app` | + +--- + +## 9. Changelog + +| Versão | Data | O que mudou | +|---|---|---| +| **1.0.2** | 2026-05-30 | RX: switch para Modelo A (build VPS4), documentar erros comuns, Wasabi storage. Deploy agora ~30-40s. | +| 1.0.1 | 2026-05-30 | Consolidação inicial: deploy + versionamento + segurança. | +| 1.0.0 | 2026-05-30 | Versão inicial. |