diff --git a/deploy-prod-builder.sh b/deploy-prod-builder.sh deleted file mode 100755 index 120fc0e..0000000 --- a/deploy-prod-builder.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# ─── deploy-prod-builder.sh (ScoreOdonto) ──────────────────────────────────── -# Script sênior de automação de build e despacho (GitOps) de VPS 4 -> VPS 1. -# ───────────────────────────────────────────────────────────────────────────── -set -e - -LOCK_FILE="/tmp/deploy-prod-scoreodonto.lock" -if [ -f "$LOCK_FILE" ]; then - echo "🚨 Deploy já está em andamento! Aguarde..." - exit 1 -fi -touch "$LOCK_FILE" - -# Garante que o lock file será apagado no final do script mesmo se houver erro -trap 'rm -f "$LOCK_FILE"' EXIT - -LOG_FILE="/home/deploy/stack/webhook-listener/deploy.log" - -log() { - echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] [SCOREODONTO] $1" | tee -a "$LOG_FILE" -} - -log "🚀 Iniciando ciclo de build e deploy automático para ScoreOdonto..." - -# 1. Atualizar repositório Git -log "📦 Sincronizando repositório Git local na VPS 4..." -cd /home/deploy/stack/scoreodonto.com -git fetch origin main -git reset --hard origin/main - -# 1.1 Incrementar versão -log "🔢 Incrementando versão..." -node update-version.js - -# 2. Compilar o Backend -log "⚙️ Instalando dependências e preparando o Backend..." -cd /home/deploy/stack/scoreodonto.com/backend -npm install - -# 3. Compilar o Frontend -log "⚙️ Instalando dependências e compilando o Frontend (Vite)..." -cd /home/deploy/stack/scoreodonto.com/frontend -npm install -npm run build - -# 4. Reiniciar os serviços de Staging localmente na VPS 4 -log "🔄 Reiniciando contêineres de STAGING na VPS 4..." -docker compose -f /home/deploy/stack/scoreodonto.com/docker-compose-staging.yml up -d --build - -# 6. Salvar incremento de versão no Git -log "💾 Comitando o incremento de versão de volta para o repositório central..." -cd /home/deploy/stack/scoreodonto.com -git add frontend/constants.ts -git commit -m "chore(deploy): bump version" -git push origin main - -log "✅ Deploy de ScoreOdonto concluído com absoluto sucesso!" diff --git a/deploy-to-prod.sh b/deploy-to-prod.sh deleted file mode 100755 index 3e5eb33..0000000 --- a/deploy-to-prod.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# ─── deploy-to-prod.sh (ScoreOdonto) ────────────────────────────────────────── -# Script de Promoção Manual: Staging (VPS 4) ➔ Produção (VPS 1) -# ───────────────────────────────────────────────────────────────────────────── -set -e - -LOCK_FILE="/tmp/deploy-prod-scoreodonto-release.lock" -if [ -f "$LOCK_FILE" ]; then - echo "🚨 Promoção para produção já está em andamento! Aguarde..." - exit 1 -fi -touch "$LOCK_FILE" -trap 'rm -f "$LOCK_FILE"' EXIT - -LOG_FILE="/home/deploy/stack/webhook-listener/deploy.log" -log() { - echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] [SCOREODONTO-PROD] $1" | tee -a "$LOG_FILE" -} - -log "🚀 Iniciando PROMOÇÃO MANUAL de Staging (VPS 4) para PRODUÇÃO (VPS 1)..." - -# 1. Sincronizar Backend para a VPS 1 -log "🚚 Despachando Backend para a VPS 1 (Produção)..." -rsync -avz --delete \ - --exclude '.env' \ - --exclude 'node_modules/.cache' \ - /home/deploy/stack/scoreodonto.com/backend/ \ - deploy@10.99.0.1:/home/deploy/stack/scoreodonto.com/backend/ - -# 2. Sincronizar Frontend (build compilada em Staging) para a VPS 1 -log "🚚 Despachando Frontend (build) para a VPS 1 (Produção)..." -rsync -avz --delete \ - /home/deploy/stack/scoreodonto.com/frontend/dist/ \ - deploy@10.99.0.1:/home/deploy/stack/scoreodonto.com/frontend/dist/ - -# 3. Sincronizar Plugins para a VPS 1 -log "🚚 Despachando Plugins..." -rsync -avz --delete \ - /home/deploy/stack/scoreodonto.com/plugins/ \ - deploy@10.99.0.1:/home/deploy/stack/scoreodonto.com/plugins/ - -# 4. Sincronizar Docker Compose de Produção e Configurações de Nginx -log "🚚 Despachando Infraestrutura (Docker/Config) para a VPS 1..." -rsync -avz \ - /home/deploy/stack/scoreodonto.com/docker-compose.yml \ - /home/deploy/stack/scoreodonto.com/nginx \ - deploy@10.99.0.1:/home/deploy/stack/scoreodonto.com/ - -# 5. SSH na VPS 1 para Reiniciar Serviços de Produção -log "🔄 Reiniciando containers de PRODUÇÃO na VPS 1..." -ssh -o BatchMode=yes deploy@10.99.0.1 "cd /home/deploy/stack/scoreodonto.com && DOCKER_HOST=unix:///run/user/1000/docker.sock docker compose up -d" - -log "✅ PROMOÇÃO PARA PRODUÇÃO CONCLUÍDA COM SUCESSO!" diff --git a/docker-compose-staging.yml b/docker-compose-staging.yml deleted file mode 100644 index daa870a..0000000 --- a/docker-compose-staging.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: scoreodonto-staging - -services: - nginx: - image: nginx:alpine - container_name: scoreodonto-nginx-staging - restart: always - ports: - - "8082:80" - volumes: - - "./nginx/default-staging.conf:/etc/nginx/conf.d/default.conf:ro" - networks: - - staging-net - depends_on: - - scoreodonto-backend-staging - - scoreodonto-frontend-staging - - scoreodonto-backend-staging: - build: - context: "./backend" - dockerfile: Dockerfile - container_name: scoreodonto-backend-staging - restart: always - env_file: - - "./backend/.env" - environment: - - BAILEYS_ENGINE=infinite - - PORT=8018 - - NODE_ENV=staging - - DATABASE_URL=postgresql://scoreodonto_user:clube67_scoreodonto_pass_9903@10.99.0.3:5432/scoreodonto?schema=public - - DRAGONFLY_URL=redis://:clube67_dragonfly_pass_9903@10.99.0.3:6379/1 - - NATS_URL=nats://10.99.0.3:4222 - - TEMPORAL_ADDRESS=10.99.0.3:7233 - - BAILEYS_SESSIONS_PATH=/app/sessions - - APP_URL=https://staging.scoreodonto.com - - GOOGLE_REDIRECT_URI=https://staging.scoreodonto.com/api/oauth2callback - volumes: - - "/home/deploy/scoreodonto-sessions-staging:/app/sessions" - - "/home/deploy/scoreodonto-media-staging:/app/media" - - "./plugins:/app/plugins" - networks: - - staging-net - - scoreodonto-frontend-staging: - build: - context: "." - dockerfile: frontend/Dockerfile - container_name: scoreodonto-frontend-staging - restart: always - env_file: - - "./frontend/.env.production.local" - environment: - - PORT=3013 - - NODE_ENV=staging - - NEXT_PUBLIC_API_URL=https://staging.scoreodonto.com/api - networks: - - staging-net - -networks: - staging-net: - driver: bridge diff --git a/instrucoes_gerais/scoreodonto/CHECKLIST-DEPLOY-PRODUCAO.md b/instrucoes_gerais/scoreodonto/CHECKLIST-DEPLOY-PRODUCAO.md index e287ec5..457f0f8 100644 --- a/instrucoes_gerais/scoreodonto/CHECKLIST-DEPLOY-PRODUCAO.md +++ b/instrucoes_gerais/scoreodonto/CHECKLIST-DEPLOY-PRODUCAO.md @@ -1,61 +1,60 @@ # Checklist de Deploy para Produção — Pacote Financeiro + Salas (jun/2026) -> Consolida tudo entregue na rodada: **Financeiro V1 (Épicos 1–4)**, **V2 Comissão/Repasse**, **Glosas**, **GTO→Financeiro**, **modelo de contrato p/ convênio** e o **redesenho de Salas** (perfil Dono de Sala, sala como workspace, financeiro de locação, painel/relatório/agenda). -> Tudo foi desenvolvido e testado em **DEV (VPS4 / dev.scoreodonto.com)**. **Nada commitado/empurrado ainda.** +> Consolida a rodada: **Financeiro V1 (Épicos 1–4)**, **V2 Comissão/Repasse**, **Glosas**, **GTO→Financeiro**, **modelo de contrato p/ convênio** e o **redesenho de Salas** (perfil Dono de Sala, sala como workspace, financeiro de locação, painel/relatório/agenda). +> O **procedimento canônico de deploy** é o `DEPLOY-PRODUCAO.md` — este arquivo é só o checklist desta entrega. -## 0. Arquitetura / como o deploy funciona -- **DEV/builder:** VPS4. **PROD:** VPS1 (`10.99.0.1`). **Banco:** VPS3 (`10.99.0.3`, Postgres `scoreodonto`). -- **Atenção (verificar):** o `docker-compose.yml` aponta `DATABASE_URL=…@10.99.0.3:5432/scoreodonto`. Se PROD (VPS1) **usa o mesmo banco**, as migrações **já foram aplicadas** durante o desenvolvimento (rodam no boot do backend, que fala com o VPS3). Se PROD tiver `.env` próprio com outro banco, as migrações aplicam no **1º boot do backend de prod**. → **CONFIRMAR o `DATABASE_URL` efetivo na VPS1 antes de prosseguir.** -- **Scripts:** `deploy-prod-builder.sh` (GitOps: `git reset --hard origin/main` → build → despacha p/ VPS1) **ou** `deploy-to-prod.sh` (rsync de `backend/`, `frontend/dist/`, `plugins/`, `docker-compose.yml`, `nginx` → VPS1 → `docker compose up -d`). -- **Regra:** **NÃO** rodar `deploy-to-prod.sh` automaticamente — é execução manual do operador, com autorização. +## 0. Arquitetura (sem ambiente isolado) +- **VPS4** = **desenvolvimento + builder**. O ambiente de teste é **`dev.scoreodonto.com`** (servido pela VPS4 via Traefik da VPS1) e é onde se **buildam** as imagens que vão pra produção. +- **VPS1** = **produção** (`scoreodonto.com`) — só recebe a imagem pronta e sobe. +- **VPS3** = **dados** (Postgres `scoreodonto`, Dragonfly, Gitea). **Dev e prod apontam para o MESMO banco `scoreodonto`.** +- ⚠️ Consequência (confirmada): **dev e prod compartilham o banco** → as migrações desta entrega **já foram aplicadas** ao banco real durante o desenvolvimento (rodam no boot do backend de dev). Promover é, na prática, **levar o CÓDIGO** para a VPS1 — o schema já está migrado. **Não há ambiente nem banco isolado** entre dev e produção. -## 1. Pré-requisitos (antes de promover) -- [ ] **Backup do banco** VPS3 (`pg_dump scoreodonto`) — passo obrigatório. -- [ ] Código **commitado e pushado** para `origin/main` (Gitea `10.99.0.3`). O builder faz `git reset --hard origin/main`. *(push exige sua autorização; NUNCA `--force` na main.)* -- [ ] `node --check backend/server.js` OK. -- [ ] Build do frontend sem erros. +## 1. Fluxo de promoção (resumo do DEPLOY-PRODUCAO.md §2) +1. `git push origin main` (na VPS4) — já feito (commit `3e64514`). +2. Bump de versão (`update-version.js` → `frontend/constants.ts`). +3. **Build da imagem Docker na VPS4** (`npm install` + `vite build` dentro do Dockerfile) — peso fora da produção. +4. **Envia a imagem pronta para a VPS1** (registry privado pela WireGuard — recomendado — ou `docker save | ssh | docker load`). +5. **VPS1:** `docker compose up -d` (troca o container pela imagem nova). Backend leva ~10–30s no boot (reconecta Postgres/Dragonfly + roda migrações). +- *(Os scripts `deploy-prod-builder.sh` e `deploy-to-prod.sh` estão **DEPRECADOS** — ver seção "Fluxo ANTIGO" do `DEPLOY-PRODUCAO.md`. Não usar.)* + +## 2. Pré-requisitos +- [ ] **Backup do banco** VPS3 (`pg_dump scoreodonto` — custom format `-Fc`). Como dev/prod compartilham o banco, esse backup é a **única rede de segurança**. +- [ ] Código em `origin/main` (Gitea) — ✅ `3e64514`. +- [ ] `node --check backend/server.js` OK; build do frontend OK. - [ ] Validado em `dev.scoreodonto.com`. -## 2. Mudanças de banco (migrações idempotentes no boot — `runMigrations()`) -Todas são **aditivas** (`CREATE TABLE/INDEX IF NOT EXISTS`, `ADD COLUMN IF NOT EXISTS`) — **nenhuma destrutiva**. +## 3. Mudanças de banco (migrações idempotentes no boot — todas ADITIVAS) +> Já aplicadas no banco (dev=prod). Listadas para auditoria/rollback. Nenhuma destrutiva. - **Novas tabelas:** `procedimentos_realizados`, `procedimento_realizado_foto`, `comissao_regras`, `repasses`, `glosas`. - **ALTER `financeiro`:** `paciente_id, profissional_id, procedimento_id, agendamento_id, contrato_id, realizado_id, origem, sem_comissao, pago_em, deleted_at, fornecedor, centro_custo, recorrente, convenio_id, valor_glosa, data_competencia, competencia`. -- **ALTER `orcamentos`:** `financeiro_gerado`. -- **ALTER `contratos`:** `cobranca_automatica, valor_recorrente, periodicidade, dia_cobranca`. -- **ALTER `gto_builders`:** `financeiro_id`. **ALTER `sala_reservas`:** `financeiro_id`. -- **CHECK constraints (DROP+ADD no boot):** `usuarios_role_check` e `vinculos_role_check` ganham **`donosala`** (lista é superset → seguro; nenhum role existente é removido). -- **Índices:** troca `uq_comissao_regra` → `uq_comissao_regra2` (DROP+CREATE); novos `idx_financeiro_contrato_comp`, `idx_financeiro_convenio`, `idx_glosas_clinica/_financeiro/_item`, `idx_repasses_clinica`, `idx_gto_builders_financeiro`. -- **Seeds (boot):** `seedContratoModelos()` insere `cmod_odo_14` "Atendimento a Convênios / Repasse" (ON CONFLICT DO NOTHING). -- ⚠️ Se o banco for o mesmo do dev, **tudo isso já está aplicado** — o boot do backend de prod será no-op nas migrações. +- **ALTER `orcamentos`:** `financeiro_gerado`. **ALTER `contratos`:** `cobranca_automatica, valor_recorrente, periodicidade, dia_cobranca`. **ALTER `gto_builders`:** `financeiro_id`. **ALTER `sala_reservas`:** `financeiro_id`. +- **CHECK `usuarios_role_check` / `vinculos_role_check`** ganham `donosala` (DROP+ADD no boot — superset, seguro). +- **Índices:** troca `uq_comissao_regra` → `uq_comissao_regra2`; novos `idx_financeiro_contrato_comp`, `idx_financeiro_convenio`, `idx_glosas_*`, `idx_gto_builders_financeiro`. +- **Seed (boot):** `cmod_odo_14` "Atendimento a Convênios / Repasse" (ON CONFLICT DO NOTHING). -## 3. Backend — env / infra -- [ ] `DATABASE_URL` de prod correto (ver §0). -- [ ] `JWT_SECRET` definido e estável — usado no login **e** em `signMedia/verifyMedia` (URLs assinadas das **fotos de procedimento** e dos **comprovantes de repasse**). -- [ ] **Volume de mídia** (`MEDIA_PATH` → `MEDIA_ROOT`, default `/app/media`) montado e persistente: grava em `…/procedimentos//`, `…/repasses//`. -- [ ] **Cron** `processarVigenciasContratos` (boot + 6h): marca **Atrasado**, vigência de contratos, **renovação automática** e **cobrança recorrente** — conferir nos logs após subir. +## 4. Backend — env / infra (VPS1) +- [ ] `DATABASE_URL` → `…@10.99.0.3/scoreodonto`. `JWT_SECRET` estável (login + URLs assinadas de fotos/comprovantes). +- [ ] **Volume de mídia** persistente (`MEDIA_PATH`): grava em `…/procedimentos//` e `…/repasses//`. +- [ ] **Cron** `processarVigenciasContratos` (boot + 6h): Atrasado, vigência, **renovação automática**, **cobrança recorrente** — conferir nos logs. -## 4. Frontend — build -- [ ] `frontend/dist` recompilado e despachado. Views/arquivos novos/alterados: - - Novas views: `ComissoesView`, `GlosasView`, `ProcedimentosProntuario`, `SalaHomeView`. - - Alteradas: `FinanceiroView` (Receita/Despesa + baixa), `ReportsView` (relatório financeiro + convênio + glosa), `OrcamentoModal`, `ContratosView` (cobrança recorrente), `LancarGTO` (persiste + convênio), `SalasPlugin` (2 modos + receita locação + refresh workspaces), `OnboardingChat` (Dono de Sala), `Sidebar` (seletor de workspace agrupado + menus de sala), `App.tsx` (rotas/gates), `PluginsView` (locação "sempre incluído"), `pluginRegistry` (ALWAYS_ON), `services/backend.ts` (vários métodos novos). -- [ ] Conferir que **MINHAS SALAS / ALUGAR SALAS** aparecem (locação sempre ativa) e o **seletor de workspace** lista Clínicas × Salas. +## 5. Frontend +- [ ] Imagem rebuildada com as views novas (`ComissoesView`, `GlosasView`, `ProcedimentosProntuario`, `SalaHomeView`) e alterações (`FinanceiroView`, `ReportsView`, `OrcamentoModal`, `ContratosView`, `LancarGTO`, `SalasPlugin`, `OnboardingChat`, `Sidebar`, `App.tsx`, `PluginsView`, `pluginRegistry`, `services/backend.ts`). +- [ ] Conferir: locação **sempre ativa** (MINHAS/ALUGAR SALAS aparecem) e **seletor de workspace** lista Clínicas × Salas. -## 5. Smoke tests em PRODUÇÃO (pós-deploy) -- [ ] Login OK; workspaces carregam (clínicas + salas). -- [ ] **Financeiro:** criar lançamento Receita e Despesa (valida `normalizeFinanceiro` — sem ela NENHUM lançamento salvava pela UI). Relatório financeiro abre. -- [ ] **GTO:** Lançar GTO com convênio → finalizar → recebível aparece no financeiro. -- [ ] **Comissões:** definir % (padrão/procedimento/override) → relatório → fechar repasse → marcar pago (gera despesa) → anexar comprovante. -- [ ] **Glosas:** marcar glosa (item de GTO) → recorrer → recuperar. -- [ ] **Contratos:** gerar com "Atendimento a Convênios"; contrato vigente com cobrança recorrente → "Gerar cobrança do mês". -- [ ] **Orçamento:** assinar → parcelas no financeiro. -- [ ] **Salas:** cadastro **Dono de Sala**; criar sala; **seletor de workspace** troca p/ a sala; **Painel da Sala** (KPIs, agenda, recebíveis, relatório); confirmar reserva → recebível; dar baixa. -- [ ] **Isolamento:** em workspace = sala, telas clínicas somem; cross-tenant retorna 403. +## 6. Verificação pós-deploy (VPS1) +```bash +# versão no ar +curl -s https://scoreodonto.com | grep -o 'V[0-9]*\.[0-9]*\.[0-9]*' | head -1 +# logs do backend (Docker ROOTLESS na VPS1) — espere "[MIGRATION] all migrations OK" +ssh deploy@10.99.0.1 "DOCKER_HOST=unix:///run/user/1000/docker.sock docker logs scoreodontocom-scoreodonto-backend-1 --tail 40" +``` +Smoke tests: criar **lançamento financeiro** (valida `normalizeFinanceiro` — antes nenhum salvava pela UI); **GTO → recebível**; **comissão/repasse/comprovante**; **glosa**; **contrato de convênio**; **orçamento→parcelas**; **fluxo de salas** (Dono de Sala, reserva→recebível, painel); **isolamento cross-tenant 403**. -## 6. Rollback -- As migrações **só adicionam** → rollback de **código** é seguro (colunas/tabelas extras ficam inertes). Reverter para a imagem/artefato anterior na VPS1 e, se necessário, restaurar o dump do §1. +## 7. Rollback +- Migrações **só adicionam** → reverter o **código** (imagem anterior na VPS1) é seguro; colunas/tabelas extras ficam inertes. Restaurar o dump da §2 só se necessário (`pg_restore -d "" --clean `). -## 7. Riscos específicos desta entrega -- **`normalizeFinanceiro` (crítico):** corrige o bug em que `enforceUppercase` mandava `PAGO`/`PIX` e violava os CHECK capitalizados (`Pago`/`Pix`) — antes a tabela `financeiro` ficava sempre vazia. Garantir que entrou no build de prod. -- **Banco compartilhado dev/prod (se confirmado no §0):** dados de teste do desenvolvimento podem aparecer; os E2E desta rodada sempre limparam, mas conferir contagens de `financeiro`, `salas`, `repasses`, `glosas` antes de liberar. -- **Convênios:** o modelo de contrato e os textos jurídicos seguem padrão de mercado — recomendar revisão por advogado. -- **Locação sempre ativa:** todos os papéis (menos superadmin) passam a ver MINHAS/ALUGAR SALAS — confirmar que é o comportamento desejado em produção. +## 8. Riscos específicos desta entrega +- **`normalizeFinanceiro` (crítico):** corrige o bug em que `enforceUppercase` mandava `PAGO`/`PIX` violando o CHECK capitalizado — antes a tabela `financeiro` ficava vazia. Garantir que entrou na imagem. +- **Banco único dev/prod:** dado de teste de desenvolvimento pode aparecer; os E2E desta rodada sempre limparam, mas conferir contagens de `financeiro`, `salas`, `repasses`, `glosas`. +- **Contratos de convênio:** textos seguem padrão de mercado — recomendar revisão por advogado. +- **Locação sempre ativa:** todos os papéis (menos superadmin) passam a ver MINHAS/ALUGAR SALAS. diff --git a/nginx/default-staging.conf b/nginx/default-staging.conf deleted file mode 100644 index 4b3667d..0000000 --- a/nginx/default-staging.conf +++ /dev/null @@ -1,52 +0,0 @@ -server { - listen 80; - server_name _; - - # Limite de upload para mídias do WhatsApp - client_max_body_size 100M; - - # Resolver DNS interno do Docker para resolução dinâmica - resolver 127.0.0.11 valid=30s; - - # Proxy para o Backend (Express API) - location /api/ { - set $backend_upstream http://scoreodonto-backend-staging:8018; - rewrite ^/api/api/(.*)$ /api/$1 break; - proxy_pass $backend_upstream; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Proxy para o Socket.io (Realtime Events) - location /socket.io/ { - set $backend_upstream http://scoreodonto-backend-staging:8018; - proxy_pass $backend_upstream; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Proxy para o Frontend (Vite React SPA) - location / { - set $frontend_upstream http://scoreodonto-frontend-staging:3013; - proxy_pass $frontend_upstream; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -}