Resolve duas camadas de problema identificadas em teste end-to-end: 1. Embeddings falhavam com HTTP 404 (/codex/v1/embeddings não existe). Solução: Captain::Llm::EmbeddingService sempre usa OpenAI tradicional via Llm::Config.with_api_key(legacy_settings). ProviderConfig expõe legacy_openai_settings pra isso. 2. Servidor Codex ocasionalmente responde com response.failed + code=server_error (instabilidade transitória). Client agora retenta até 2x com backoff exponencial (0.5s, 1.5s) em erros retryable: HTTP 5xx, server_error no response.failed, ou stream inacabado. Outras correções nesta etapa: - Scenario#agent_model: em modo Codex, ignora CAPTAIN_OPEN_AI_MODEL_SCENARIO (que pode ter gpt-4o legado) e usa ProviderConfig.model. - ExtractionService/ContradictionCheckerService/TranslateQueryService: trocam constantes hardcoded gpt-4o-mini/gpt-4.1-nano por ProviderConfig.light_model (respeitando o provider ativo). - ProviderConfig.DEFAULT_CODEX_MODEL agora é gpt-5.2 (reconhecido pelo RubyLLM; gpt-5.4 não está no catalog do gem). Validado ponta-a-ponta: WhatsApp → Chatwoot → Jasmine → handoff Daniela → faq_lookup com embedding OK → resposta com preços corretos. Docs em docs/captain-codex-oauth.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.3 KiB
Chatwoot — Deploy de branch em staging paralela
Runbook pra subir qualquer branch do fork iachat como stack Swarm paralela
isolada da produção, testar, e só depois fazer merge pra main.
Automação: existe uma skill do Claude Code que executa esse runbook passo a passo. Invoque com "subir branch X em staging" no chat. Arquivos:
~/.claude/skills/chatwoot-staging-deploy/. Este doc é o backup versionado pra quando não for usar a skill.
Arquitetura atual
- Repo:
github.com/rodribm10/iachat(fork do Chatwoot) - VPS:
root@76.13.174.155(Leo), Docker Swarm + Traefik v2.11 + Let's Encrypt - Prod: stack
iachatemiachat.hoteis1001noites.com.br, imagemghcr.io/rodribm10/iachat:vN - Workflow CI:
.github/workflows/deploy_ghcr.yml→ publica:latest+:v<run_number>a cada push - Credenciais da VPS: em
docs/acessos_vps.md(gitignored — NÃO commitar)
Fluxo em 9 fases
1. Preparar commit local
# Trava credenciais fora do commit
git check-ignore docs/acessos_vps.md || (echo "PERIGO: credenciais não ignoradas"; exit 1)
git add -A
git diff --cached --name-only | grep -iE "acessos|vps" && { echo "FALHA: credenciais stageadas"; exit 1; }
Commit com mensagem estruturada (feat/fix + descrição).
Pre-commit hooks:
- ESLint exige i18n — adicionar keys em
app/javascript/dashboard/i18n/locale/{pt_BR,en}/captain.json - Rubocop metric violations:
# rubocop:disable Metrics/MethodLength,Metrics/AbcSizeantes daclass
Nunca usar --no-verify.
2. Push + aguardar CI
git push origin <branch>
gh run list --repo rodribm10/iachat --branch <branch> --limit 1
# aguarda status "completed success" (~10-15min multi-arch)
# Pega número da tag gerada
gh run view --repo rodribm10/iachat <run_id> --log \
| grep "imagetools create" -A 3 | grep -oE "v[0-9]+"
# → retorna "v67" (por exemplo)
Sempre usar a tag vN específica, NUNCA :latest (outras branches sobrescrevem).
3. Inspeção read-only da VPS
ssh root@76.13.174.155 '
docker stack ls
docker service inspect iachat_iachat_app --format "{{json .Spec}}" | python3 -m json.tool
docker service inspect iachat_iachat_app --format "{{range .Spec.TaskTemplate.ContainerSpec.Env}}{{println .}}{{end}}"
'
4. Gerar secrets únicos NA VPS
ssh root@76.13.174.155 "
mkdir -p /root/<stack-name>
cat > /root/<stack-name>/.secrets <<EOF
SECRET_KEY_BASE=\$(openssl rand -hex 64)
AR_PRIMARY=\$(openssl rand -hex 16)
AR_DETERMINISTIC=\$(openssl rand -hex 16)
AR_SALT=\$(openssl rand -hex 16)
POSTGRES_PASSWORD_NEW=\$(openssl rand -base64 24 | tr -d /=+)
EOF
chmod 600 /root/<stack-name>/.secrets
"
5. Criar stack.yml + app.env + postgres_password.txt
Templates em:
~/.claude/skills/chatwoot-staging-deploy/stack.yml.template~/.claude/skills/chatwoot-staging-deploy/app.env.template
Pontos críticos:
- Traefik
rule=Host('<dns>')compriority=100pra vencer catchall regex do prod - Network pública
network_swarm_public(external) - Volumes isolados (
postgres_data,redis,storage) - Postgres password via Docker Secret (arquivo
/root/<stack>/postgres_password.txt) POSTGRES_DATABASE=iachat_staging(nãoproduction)
6. Deploy
ssh root@76.13.174.155 "
docker pull ghcr.io/rodribm10/iachat:v<N>
docker stack deploy -c /root/<stack>/stack.yml --with-registry-auth <stack>
sleep 10
docker service ls --filter name=<stack>
"
Se <stack>_app reinicia em loop → é DB vazio. Próximo passo.
7. Schema + migrations (container one-off)
ssh root@76.13.174.155 "
docker run --rm --network <stack>_<stack>_internal \
--env-file /root/<stack>/app.env \
-e DISABLE_DATABASE_ENVIRONMENT_CHECK=1 \
ghcr.io/rodribm10/iachat:v<N> \
sh -c 'bundle exec rails db:schema:load db:migrate db:seed'
"
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 é necessário — Rails bloqueia destrutivas em prod, mas aqui DB é zero.
8. Restart do app
ssh root@76.13.174.155 "docker service update --force <stack>_app"
Aguarde ~20s. docker service ps <stack>_app deve mostrar Running sem crash.
9. Teste HTTPS
curl -sSI https://<dns>/
# Esperado: 302 redirect to /installation/onboarding
302 → abre no browser e cria admin via onboarding.
Troubleshooting
| Sintoma | Fix |
|---|---|
installation_configs does not exist |
Falta Fase 7 (schema:load) |
ActiveRecord::ProtectedEnvironmentError |
Adicionar DISABLE_DATABASE_ENVIRONMENT_CHECK=1 |
| Cert Let's Encrypt inválido | Labels Traefik erradas; conferir priority=100 e rule=Host() não regex |
| 302 pra página do prod | Catchall ganhou; aumentar priority ou verificar rule específica |
image not found no pull |
Tag errada; gh run list pra confirmar |
Segurança
docs/acessos_vps.md— gitignored. NUNCA commite.- Senha
Nicodemos1@@1foi compartilhada no histórico — trocar nas 4 VPSs (Leo, Rodrigo, Financeiro, Oracle). - Secrets por stack — gerar novos, nunca reutilizar entre envs.
- Tag
:latesté sobrescrita por qualquer push — sempre usarvN.
Estado atual de exemplo
Primeira execução desse runbook: 2026-04-21
- Branch:
feat/captain-semantic-memory - Stack:
iachat-v2 - DNS:
iachatv2.hoteis1001noites.com.br - Imagem:
ghcr.io/rodribm10/iachat:v67 - Status: ✅ deploy bem-sucedido, aguardando onboarding do admin