- tauri.conf.json: configura nsis (installMode perMachine, allowToChangeInstallDirectory, installDirName, createDesktopShortcut) - main.tsx: Store.load agora usa appLocalDataDir (dados do app em AppData do usuário) - README: documenta instalação Windows, dados em AppData e build leve (--bundles nsis)
14 KiB
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).
- Seeds Better Auth automáticos: o container do web executa
pnpm auth:seedapósprisma migrate deploy, garantindo usuários padrão em toda inicialização (sem resetar senha existente por padrão).
Sessão de máquina (Desktop/Tauri)
- A rota
GET /machines/handshake?token=...&redirect=/portal|/dashboardé pública no middleware para permitir a criação da sessão "machine" a partir do agente desktop, mesmo sem login prévio. - Após o handshake, o servidor grava cookies de sessão (Better Auth) e um cookie
machine_ctxcom o vínculo (persona, assignedUser*, etc.). Em seguida, o App carrega/api/machines/sessionpara preencher o contexto no cliente (machineContext). - Com esse contexto, o Portal exibe corretamente o nome/e‑mail do colaborador/gestor no cabeçalho e permite abrir chamados em nome do usuário vinculado.
- Em sessões de máquina, o botão "Encerrar sessão" no menu do usuário é ocultado por padrão na UI interna.
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
# Seeds automáticos (Better Auth)
# Garante usuários padrão sem resetar senhas existentes
SEED_ENSURE_ONLY=true
# 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_EMAILprecisa 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çowebporta 3000.convex.esdrasrenan.com.br→ serviçoconvex_backendporta 3210.
Deploy da stack
Via Portainer (recomendado)
- Abra o Portainer → Stacks → Add/Update e cole o conteúdo de
stack.yml(ou vincule ao repositório para “Pull/Deploy”). - 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_webdocker 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/versionresponde para sanity‑check)
Zero‑downtime (sem queda durante deploy)
Para evitar interrupção perceptível no deploy, habilitamos rollout "start-first". Para este projeto, mantemos 1 réplica (web e Convex) por segurança, pois:
- O web usa SQLite (Prisma); múltiplas réplicas concorrendo gravação no mesmo arquivo podem causar erros de lock/readonly.
- O Convex backend self‑hosted não é clusterizado.
O stack.yml já inclui:
replicas: 1+update_config.order: start-first(Swarm sobe a nova task saudável antes de desligar a antiga).failure_action: rollback.healthcheckpor porta local, garantindo que o Swarm só troque quando a nova task estiver OK.
Se quiser ajustar recursos/estratégia:
deploy:
replicas: 2
update_config:
parallelism: 1
order: start-first
failure_action: rollback
restart_policy:
condition: any
healthcheck:
# web
test: ["CMD", "node", "-e", "fetch('http://localhost:3000').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 10s
timeout: 3s
retries: 5
start_period: 30s
Observação: o CI já força docker service update --force após stack deploy e passa RELEASE_SHA no ambiente para variar a spec em todo commit, assegurando rollout.
App Desktop (Tauri)
- Build local por SO:
- Linux:
pnpm -C apps/desktop tauri build - Windows/macOS: executar o mesmo comando no respectivo sistema (o Tauri gera .msi/.dmg/.app).
- Linux:
- Por padrão, o executável em modo release usa
https://tickets.esdrasrenan.com.brcomoAPP_URLeAPI_BASE_URL. - Para customizar, crie
apps/desktop/.envcomVITE_APP_URLeVITE_API_BASE_URL. - Saída dos pacotes:
apps/desktop/src-tauri/target/release/bundle/.
Alertas de postura (opcional)
- Variáveis de ambiente para geração automática de tickets em alertas de postura (CPU alta, serviço parado, SMART em falha):
MACHINE_ALERTS_CREATE_TICKETS=true|false(padrão: true)MACHINE_ALERTS_TICKET_REQUESTER_EMAIL=admin@sistema.dev(usuário solicitante dos tickets automáticos)
CI de Release do Desktop
- Workflow:
.github/workflows/desktop-release.yml(build Linux/Windows/macOS). - Preencha os Secrets no repositório (Settings > Secrets > Actions):
TAURI_PRIVATE_KEYTAURI_KEY_PASSWORD
- Disparo: tag
desktop-v*ou viaworkflow_dispatch.
Dashboard (opcional)
Você pode expor o painel do Convex para inspeção em produção.
DNS
- Criar
convex-admin.esdrasrenan.com.brapontando para a VPS.
Stack
- O serviço
convex_dashboardjá está definido emstack.ymlcom Traefik. Após atualizar a stack:- Acesse
https://convex-admin.esdrasrenan.com.br. - Use a Admin Key gerada por
./generate_admin_key.shpara autenticar.
- Acesse
Convex self‑hosted — configuração inicial
- 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|...
- 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.
Variáveis do Convex (importante)
As functions do Convex leem variáveis via convex env, não do .env do container.
No CI, defina os seguintes Secrets (Repo → Settings → Secrets and variables → Actions):
CONVEX_SELF_HOSTED_URL— ex.:https://convex.esdrasrenan.com.brCONVEX_SELF_HOSTED_ADMIN_KEY— gerada por./generate_admin_key.shMACHINE_PROVISIONING_SECRET— hex forte- (opcional)
MACHINE_TOKEN_TTL_MS— ex.:2592000000 - (opcional)
FLEET_SYNC_SECRET
O job convex_deploy sempre roda convex env set com os Secrets acima antes do convex deploy.
Se preferir setar manualmente:
MACHINE_PROVISIONING_SECRET— obrigatório para/api/machines/register- (opcional)
MACHINE_TOKEN_TTL_MS,FLEET_SYNC_SECRET
CLI manual (exemplo):
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' \
node:20-bullseye bash -lc "set -euo pipefail; corepack enable && corepack prepare pnpm@9 --activate && pnpm i --frozen-lockfile --prod=false; \
unset CONVEX_DEPLOYMENT; \
pnpm exec convex env set MACHINE_PROVISIONING_SECRET 'seu-hex' -y; \
pnpm exec convex env list"
Smoke test pós‑deploy (CI)
O pipeline executa um teste rápido após o deploy do Web:
- Registra uma máquina fake usando
MACHINE_PROVISIONING_SECRETdo/srv/apps/sistema/.env - Espera
HTTP 201e extraimachineToken - Envia
heartbeate esperaHTTP 200 - Se falhar, o job é marcado como erro (evita regressões silenciosas)
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:20compnpm exec convex deploy(ver seção Convex). - Reiniciar serviços sem alterar o stack:
docker service update --force sistema_web(ousistema_convex_backend).
CI/CD (GitHub Actions + runner self‑hosted)
- Registrar runner na VPS:
- Repo → Settings → Actions → Runners → New self‑hosted → Linux
- Labels:
self-hosted, linux, vps
- Ajustar job
deployem.github/workflows/ci-cd-web-desktop.ymlpara:cd /srv/apps/sistema && git pulldocker stack deploy --with-registry-auth -c stack.yml sistema
- Adicionar job
convex_deploy(opcional) no mesmo runner:- Executar container
node:20-bullseyecom envsCONVEX_SELF_HOSTED_URLeCONVEX_SELF_HOSTED_ADMIN_KEY(secrets do GitHub) - Rodar
pnpm exec convex deploy
- Executar container
Secrets necessários no GitHub (Repo → Settings → Secrets and variables → Actions)
CONVEX_SELF_HOSTED_URL=https://convex.esdrasrenan.com.brCONVEX_SELF_HOSTED_ADMIN_KEY= chave retornada por./generate_admin_key.sh- (Desktop)
VPS_HOST,VPS_USER,VPS_SSH_KEY,TAURI_PRIVATE_KEY,TAURI_KEY_PASSWORD— se usar o job de release desktop
Benefícios
- Push na
main→ pipeline atualiza app e (opcionalmente) publica mudanças no Convex.
Trocar domínio ou VPS (checklist)
- Criar DNS para novos domínios (app/convex) apontando para a VPS nova.
- Copiar o projeto para
/srv/apps/sistemana nova VPS. - Ajustar
.envcom novos domínios e SEGREDOS novos (gire novamente em produção). - Deploy da stack.
- Convex: gerar Admin Key no novo container e
convex deployapontando para a nova URL. - 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.
- Convex não está recebendo/concluindo handshake WS → ver logs
MAILER_SENDER_EMAILcom erro de parsing:- Adicionar aspas no
.env.
- Adicionar aspas no
pnpmreclama de workspace:- O
pnpm-workspace.yamlincluiapps/desktop. No deploy do web isso não impacta pois usamos filtros/paths do projeto. Se preferir isolar, ajuste para apenas..
- O
- Portainer erro de bind relativo:
- Usar caminho absoluto
/srv/apps/sistema:/appno stack (feito).
- Usar caminho absoluto
- Prisma CLI “not found”:
- Instalar devDependencies no build (
NPM_CONFIG_PRODUCTION=falseepnpm install --prod=false).
- Instalar devDependencies no build (
- Convex CLI pedindo interação:
- Não usar CLI em produção; usamos imagem oficial
convex-backendeconvex deployvia container transitório com Admin Key.
- Não usar CLI em produção; usamos imagem oficial
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
.envcom segredos reais. - Guarde a
Admin Keydo 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
Turbopack (Next.js)
- O projeto usa Turbopack em dev e build.
- Scripts (package.json):
dev:next dev --turbopackbuild:next build --turbopack
- O workflow de CI executa
pnpm build(que já chama Turbopack via script), e a stack utilizapnpm startsobre o artefato gerado.