202 lines
8.2 KiB
Markdown
202 lines
8.2 KiB
Markdown
# Runbook de Operação — Produção (Traefik + Convex Self‑Hosted)
|
||
|
||
> Documento vivo. Guia completo para (1) preparar a VPS, (2) fazer deploy com Traefik/Swarm, (3) publicar o backend Convex self‑hosted, (4) popular seeds e (5) operar/atualizar com ou sem CI/CD. Tudo em PT‑BR.
|
||
|
||
## Visão geral
|
||
- Frontend (Next.js) público em `tickets.esdrasrenan.com.br`.
|
||
- Backend Convex self‑hosted em `convex.esdrasrenan.com.br` (imagem oficial Convex).
|
||
- Traefik no Docker Swarm (rede `traefik_public`) roteando por hostname (sem conflito de portas).
|
||
- Banco Prisma (SQLite) persistente via volume `sistema_db` (mapeado em `/app/data`).
|
||
- Estado do Convex persistente via volume `convex_data`.
|
||
- Seeds prontos (Better Auth e dados demo Convex).
|
||
|
||
## Requisitos
|
||
- VPS com Docker/Swarm e Traefik já em execução na rede externa `traefik_public`.
|
||
- Portainer opcional (para gerenciar a stack “sistema”).
|
||
- Domínios apontando para a VPS:
|
||
- `tickets.esdrasrenan.com.br` (frontend)
|
||
- `convex.esdrasrenan.com.br` (Convex backend)
|
||
|
||
## Layout do servidor
|
||
- Código do projeto: `/srv/apps/sistema` (bind no stack).
|
||
- Volumes Swarm:
|
||
- `sistema_db` → `/app/data` (SQLite / Prisma)
|
||
- `convex_data` → `/convex/data` (Convex backend)
|
||
|
||
## .env (produção)
|
||
Arquivo base: `.env` na raiz do projeto. Exemplo mínimo (substitua domínios/segredos):
|
||
|
||
```
|
||
NEXT_PUBLIC_APP_URL=https://tickets.esdrasrenan.com.br
|
||
BETTER_AUTH_URL=https://tickets.esdrasrenan.com.br
|
||
NEXT_PUBLIC_CONVEX_URL=https://convex.esdrasrenan.com.br
|
||
BETTER_AUTH_SECRET=<hex forte gerado por `openssl rand -hex 32`>
|
||
DATABASE_URL=file:./prisma/db.sqlite
|
||
|
||
# SMTP
|
||
SMTP_ADDRESS=<smtp.host>
|
||
SMTP_PORT=465
|
||
SMTP_DOMAIN=<seu-dominio>
|
||
SMTP_USERNAME=<usuario>
|
||
SMTP_PASSWORD=<senha>
|
||
SMTP_AUTHENTICATION=login
|
||
SMTP_ENABLE_STARTTLS_AUTO=false
|
||
SMTP_TLS=true
|
||
MAILER_SENDER_EMAIL="Nome <no-reply@seu-dominio.com>"
|
||
|
||
# Máquina/inventário
|
||
MACHINE_PROVISIONING_SECRET=<hex forte>
|
||
MACHINE_TOKEN_TTL_MS=2592000000
|
||
FLEET_SYNC_SECRET=<hex forte ou igual ao de provisionamento>
|
||
|
||
# Outros
|
||
CONVEX_SYNC_SECRET=dev-sync-secret
|
||
ALERTS_LOCAL_HOUR=8
|
||
SYNC_TENANT_ID=tenant-atlas
|
||
SEED_TENANT_ID=tenant-atlas
|
||
|
||
# Importante para self-hosted: comentar se existir
|
||
# CONVEX_DEPLOYMENT=...
|
||
```
|
||
|
||
Atenção
|
||
- `MAILER_SENDER_EMAIL` precisa de aspas se contiver espaços.
|
||
- Em self‑hosted, NÃO usar `CONVEX_DEPLOYMENT`.
|
||
|
||
## Stack (Docker Swarm + Traefik)
|
||
O arquivo do stack está versionado em `stack.yml`. Ele sobe:
|
||
- `web` (Next.js) — builda e roda na porta interna 3000 (roteada pelo Traefik por hostname).
|
||
- `convex_backend` — imagem oficial do Convex self‑hosted (porta interna 3210, roteada pelo Traefik).
|
||
|
||
Bind dos volumes (absolutos, compatível com Portainer/Swarm):
|
||
- `/srv/apps/sistema:/app` → código do projeto dentro do container web.
|
||
- volume `sistema_db` → `/app/data` (SQLite do Prisma).
|
||
- volume `convex_data` → `/convex/data` (estado do Convex backend).
|
||
|
||
Rótulos Traefik (labels) no stack mapeiam:
|
||
- `tickets.esdrasrenan.com.br` → serviço `web` porta 3000.
|
||
- `convex.esdrasrenan.com.br` → serviço `convex_backend` porta 3210.
|
||
|
||
## Deploy da stack
|
||
Via Portainer (recomendado)
|
||
1. Abra o Portainer → Stacks → Add/Update e cole o conteúdo de `stack.yml` (ou vincule ao repositório para “Pull/Deploy”).
|
||
2. Clique em “Deploy the stack” (ou “Update the stack”).
|
||
|
||
Via CLI
|
||
```
|
||
docker stack deploy --with-registry-auth -c /srv/apps/sistema/stack.yml sistema
|
||
```
|
||
|
||
Verificação
|
||
- Serviços: `docker stack services sistema`
|
||
- Logs:
|
||
- `docker service logs -f sistema_web`
|
||
- `docker service logs -f sistema_convex_backend`
|
||
|
||
Acesso
|
||
- App: `https://tickets.esdrasrenan.com.br`
|
||
- Convex: `https://convex.esdrasrenan.com.br` (o importante é o WebSocket do cliente conectar; o path `/version` responde para sanity‑check)
|
||
|
||
## Convex self‑hosted — configuração inicial
|
||
1. Gerar Admin Key (uma vez, dentro do container do Convex):
|
||
```
|
||
# Console/exec no container sistema_convex_backend
|
||
./generate_admin_key.sh
|
||
# Copiar/guardar a chave: convex-self-hosted|...
|
||
```
|
||
2. Publicar o código Convex (deploy das functions) — sem instalar nada na VPS:
|
||
```
|
||
docker run --rm -it \
|
||
-v /srv/apps/sistema:/app \
|
||
-w /app \
|
||
-e CONVEX_SELF_HOSTED_URL=https://convex.esdrasrenan.com.br \
|
||
-e CONVEX_SELF_HOSTED_ADMIN_KEY='COLE_A_CHAVE_AQUI' \
|
||
node:20-bullseye bash -lc "corepack enable && corepack prepare pnpm@9 --activate && pnpm install --frozen-lockfile --prod=false && pnpm exec convex deploy"
|
||
```
|
||
|
||
Observação
|
||
- Sempre que alterar código em `convex/`, repita o comando acima para publicar as mudanças.
|
||
|
||
## Seeds
|
||
- Dados de demonstração Convex: acesse uma vez `https://tickets.esdrasrenan.com.br/dev/seed`.
|
||
- Usuários (Better Auth):
|
||
```
|
||
CONTAINER=$(docker ps --format '{{.ID}} {{.Names}}' | grep sistema_web | awk '{print $1}' | head -n1)
|
||
docker exec -it "$CONTAINER" bash -lc 'cd /app && pnpm auth:seed'
|
||
```
|
||
- Apenas um admin (em produção):
|
||
```
|
||
CONTAINER=$(docker ps --format '{{.ID}} {{.Names}}' | grep sistema_web | awk '{print $1}' | head -n1)
|
||
docker exec -it "$CONTAINER" bash -lc 'cd /app && \
|
||
SEED_USER_EMAIL="seu-email@dominio.com" \
|
||
SEED_USER_PASSWORD="suaSenhaForte" \
|
||
SEED_USER_NAME="Seu Nome" \
|
||
SEED_USER_ROLE="admin" \
|
||
pnpm auth:seed'
|
||
```
|
||
- Filas padrão: `docker exec -it "$CONTAINER" bash -lc 'cd /app && pnpm queues:ensure'`
|
||
|
||
## Atualizações (sem CI)
|
||
- App (Next.js):
|
||
```
|
||
cd /srv/apps/sistema
|
||
git pull
|
||
docker stack deploy --with-registry-auth -c stack.yml sistema
|
||
```
|
||
- Convex (functions): repetir o container `node:20` com `pnpm exec convex deploy` (ver seção Convex).
|
||
- Reiniciar serviços sem alterar o stack: `docker service update --force sistema_web` (ou `sistema_convex_backend`).
|
||
|
||
## CI/CD (GitHub Actions + runner self‑hosted)
|
||
1. Registrar runner na VPS:
|
||
- Repo → Settings → Actions → Runners → New self‑hosted → Linux
|
||
- Labels: `self-hosted, linux, vps`
|
||
2. Ajustar job `deploy` em `.github/workflows/ci-cd-web-desktop.yml` para:
|
||
- `cd /srv/apps/sistema && git pull`
|
||
- `docker stack deploy --with-registry-auth -c stack.yml sistema`
|
||
3. Adicionar job `convex_deploy` (opcional) no mesmo runner:
|
||
- Executar container `node:20-bullseye` com envs `CONVEX_SELF_HOSTED_URL` e `CONVEX_SELF_HOSTED_ADMIN_KEY` (secrets do GitHub)
|
||
- Rodar `pnpm exec convex deploy`
|
||
|
||
Benefícios
|
||
- Push na `main` → pipeline atualiza app e (opcionalmente) publica mudanças no Convex.
|
||
|
||
## Trocar domínio ou VPS (checklist)
|
||
1. Criar DNS para novos domínios (app/convex) apontando para a VPS nova.
|
||
2. Copiar o projeto para `/srv/apps/sistema` na nova VPS.
|
||
3. Ajustar `.env` com novos domínios e SEGREDOS novos (gire novamente em produção).
|
||
4. Deploy da stack.
|
||
5. Convex: gerar Admin Key no novo container e `convex deploy` apontando para a nova URL.
|
||
6. Testar front + WS (sem erro 1006) e seeds conforme necessário.
|
||
|
||
## Problemas comuns e correções
|
||
- WebSocket 1006 no front:
|
||
- Convex não está recebendo/concluindo handshake WS → ver logs `sistema_convex_backend`.
|
||
- DNS/Traefik incorretos → confirmar labels/hostnames e DNS.
|
||
- `MAILER_SENDER_EMAIL` com erro de parsing:
|
||
- Adicionar aspas no `.env`.
|
||
- `pnpm` reclama de workspace:
|
||
- `pnpm-workspace.yaml` já aponta só para `.` (evita apps/desktop no deploy).
|
||
- Portainer erro de bind relativo:
|
||
- Usar caminho absoluto `/srv/apps/sistema:/app` no stack (feito).
|
||
- Prisma CLI “not found”:
|
||
- Instalar devDependencies no build (`NPM_CONFIG_PRODUCTION=false` e `pnpm install --prod=false`).
|
||
- Convex CLI pedindo interação:
|
||
- Não usar CLI em produção; usamos imagem oficial `convex-backend` e `convex deploy` via container transitório com Admin Key.
|
||
|
||
## Comandos úteis
|
||
- Serviços: `docker stack services sistema`
|
||
- Logs: `docker service logs -f sistema_web` / `docker service logs -f sistema_convex_backend`
|
||
- Reiniciar: `docker service update --force <service>`
|
||
- Status Traefik (se exposto): `docker service logs -f traefik`
|
||
|
||
## Segurança
|
||
- Nunca commit `.env` com segredos reais.
|
||
- Guarde a `Admin Key` do Convex em local seguro; use secrets no GitHub.
|
||
- Gire segredos ao migrar de VPS/domínio.
|
||
|
||
## Referências
|
||
- Stack do projeto: `stack.yml`
|
||
- CI/CD (web + desktop): `.github/workflows/ci-cd-web-desktop.yml`
|
||
- Guia CI/CD Desktop: `apps/desktop/docs/guia-ci-cd-web-desktop.md`
|
||
- Docs Convex self‑hosted: imagem oficial `ghcr.io/get-convex/convex-backend`
|
||
|