# 🚀 Deploy ScoreOdonto — Guia Completo (VPS 4 → VPS 1) Este documento detalha o processo de deploy contínuo do ScoreOdonto e o sistema de versionamento automático. --- ## 🔁 Visão Geral do Pipeline ``` Developer (VPS 4) └─► git push origin main └─► Gitea Webhook → POST http://10.99.0.4:9002/webhook?token=... └─► listener-scoreodonto.js (porta 9002, VPS 4) └─► deploy-prod-scoreodonto.sh ├─► git pull (VPS 4) ├─► rsync → VPS 1 (10.99.0.1) └─► ssh VPS 1 → docker compose up -d --build └─► update-version.js (auto-bump patch) └─► vite build → nginx:alpine ``` --- ## 📦 Versionamento do Sistema ### Arquivo de versão ``` frontend/constants.ts ``` ```ts export const APP_VERSION = 'V1.0.6'; ``` ### Como funciona o auto-incremento A cada `docker compose up -d --build`, o script `update-version.js` (na raiz do projeto) é chamado automaticamente pelo comando de build do frontend: ```json // frontend/package.json "scripts": { "build": "node ../update-version.js && vite build" } ``` O script incrementa o **patch** (terceiro número) da versão: - `V1.0.5` → `V1.0.6` → `V1.0.7` → ... > [!WARNING] > O incremento ocorre **dentro do container Docker durante o build**. Os arquivos no repositório Git não são modificados automaticamente. A nova versão aparece na interface em produção, mas o `constants.ts` no Git permanece com o valor anterior ao build. ### Tabela de tipos de versão | Tipo | Exemplo | Quando usar | Como fazer | |------|---------|-------------|------------| | **Patch** (automático) | `V1.0.5 → V1.0.6` | Cada deploy/build | Automático — `update-version.js` cuida | | **Minor** (manual) | `V1.0.x → V1.1.0` | Nova feature significativa ou sprint | Editar `constants.ts`, zerar patch, commitar | | **Major** (manual) | `V1.x.x → V2.0.0` | Rewrite, mudança arquitetural grande | Editar `constants.ts`, zerar minor e patch, commitar | ### Bumpar versão Minor ou Major manualmente ```bash # 1. Editar o arquivo diretamente nano /home/deploy/stack/scoreodonto.com/frontend/constants.ts # Alterar: export const APP_VERSION = 'V1.1.0'; # 2. Commitar cd /home/deploy/stack/scoreodonto.com git add frontend/constants.ts git commit -m "chore(version): bump para V1.1.0" git push origin main # → webhook dispara o deploy automaticamente ``` --- ## 🤖 Webhook — Configuração | Parâmetro | Valor | |-----------|-------| | URL | `http://10.99.0.4:9002/webhook?token=scoreodonto_deploy_token_9002` | | Método | `POST` | | Eventos | Push na branch `main` | | Listener | `/home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js` | | Deploy script | `/home/deploy/instrucoes/scoreodonto/deploy-prod-scoreodonto.sh` | ### Verificar se o listener está ativo ```bash ps aux | grep listener-scoreodonto # Deve aparecer: node /home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js ``` ### Reiniciar o listener (se parou) ```bash pkill -f listener-scoreodonto || true nohup node /home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js \ > /tmp/scoreodonto-webhook.log 2>&1 & echo $! > /tmp/scoreodonto-webhook.pid ``` --- ## 🛠️ Deploy Manual (sem webhook) Use quando o webhook não está disponível ou para forçar um rebuild imediato: ```bash # Na VPS 4 bash /home/deploy/instrucoes/scoreodonto/deploy-prod-scoreodonto.sh ``` O script executa: 1. `git pull origin main` — garante código atualizado na VPS 4 2. `rsync` — sincroniza arquivos para VPS 1 (`10.99.0.1`), excluindo `node_modules`, `.env` e `.git` 3. `docker compose up -d --build` — reconstrói e reinicia os containers na VPS 1 --- ## 🐳 Arquitetura Docker (Produção) ### Frontend ``` Dockerfile: frontend/Dockerfile Build context: . (raiz do projeto) ``` ```dockerfile # Stage 1: Build FROM node:20-alpine AS builder WORKDIR /app COPY update-version.js . # ← script de versionamento vem da raiz COPY frontend/package*.json frontend/ WORKDIR /app/frontend RUN npm install COPY frontend/ . RUN npm run build # → chama update-version.js + vite build # Stage 2: Serve FROM nginx:alpine COPY --from=builder /app/frontend/dist /usr/share/nginx/html EXPOSE 3013 ``` ### Backend ``` Dockerfile: backend/Dockerfile Porta: 8018 Runtime: Node.js 20 ``` ### Nginx (Proxy) ``` Porta externa: 8020 Traefik labels: scoreodonto.com / www.scoreodonto.com → HTTPS (Let's Encrypt) ``` --- ## 🔍 Verificação Pós-Deploy ```bash # 1. Checar containers na VPS 1 ssh deploy@10.99.0.1 "docker ps | grep scoreodonto" # 2. Checar versão em produção curl -s https://scoreodonto.com | grep -o 'V[0-9]*\.[0-9]*\.[0-9]*' | head -1 # 3. Ver logs do último build ssh deploy@10.99.0.1 "docker logs scoreodontocom-scoreodonto-frontend-1 --tail 30" # 4. Ver logs do backend ssh deploy@10.99.0.1 "docker logs scoreodontocom-scoreodonto-backend-1 --tail 30" ``` --- ## ⚠️ Troubleshooting | Problema | Diagnóstico | Solução | |----------|-------------|---------| | Webhook não dispara | `ps aux | grep listener` | Reiniciar o listener (ver acima) | | Versão não atualiza na UI | Versão incrementa no container, não no git | Normal — a versão no git é a base; o build incrementa | | `rsync` falha | `ssh deploy@10.99.0.1 echo ok` | Checar chave SSH e VPN WireGuard | | Docker build falha | `docker logs` na VPS 1 | Ver logs do container; checar `npm install` | | Frontend em branco | nginx config / dist vazia | Verificar se `vite build` completou sem erro | | nginx não sobe, porta 8020 ocupada | `sudo ss -tlnp \| grep 8020` | Ver seção abaixo — docker-proxy zumbi | --- ## 🔒 Alerta de Segurança — Docker Duplo (Rootless + Root) > [!CAUTION] > A VPS 1 usa **Docker Rootless**. O daemon root (`docker.service`) está **desabilitado intencionalmente**. Nunca o reative. ### Por que o daemon root é perigoso aqui O usuário `deploy` tem acesso `sudo`. Se o `docker.service` (root) estiver ativo e `deploy` estiver no grupo `docker`, qualquer `docker compose up` sem `DOCKER_HOST` cria containers como root — paralelos aos rootless, invisíveis ao `docker ps` normal, e inacessíveis ao Traefik (que monitora a rede rootless). ### Sintoma: porta 8020 ocupada após `docker rm -f` Quando um container nginx é `force-remove`d enquanto o daemon root está ativo, o processo `docker-proxy` root pode ficar preso na porta: ```bash # Diagnóstico sudo ss -tlnp | grep 8020 # Se aparecer docker-proxy com PID root → daemon root estava ativo # Solução de emergência sudo kill cd ~/stack/scoreodonto.com DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock docker compose rm -sf nginx DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock docker compose up -d nginx ``` ### Estado correto da VPS 1 ```bash # Verificar que o daemon root está morto sudo systemctl status docker # deve mostrar: inactive (dead) # Verificar que deploy não está no grupo docker groups deploy # não deve conter "docker" # Verificar que rootless está respondendo DOCKER_HOST=unix:///run/user/1000/docker.sock docker ps | grep scoreodonto ``` --- ## 📌 Comandos Git Rápidos (fluxo diário) ```bash cd /home/deploy/stack/scoreodonto.com # Ver estado git status # Commitar e enviar (dispara deploy automaticamente) git add -p # adicionar seletivamente git commit -m "feat: descrição" # mensagem em português git push origin main # → webhook → deploy automático ``` > [!TIP] > Quando trabalhando com Claude Code (worktrees), o merge para `main` acontece ao final da sessão. O push para `main` é quem efetivamente dispara o deploy — não o commit em si.