Files
B2BCall-dialer/docs/QA_SETUP.md
Matheus 97ef8a6ba8 feat: edição de rotas de entrada, fix de 2 bugs reais no ESL, diagnóstico de NAT/áudio e softphone WebRTC (PHASE 65/66)
Três achados reportados pelo usuário numa mensagem só: (1) Rotas de Entrada
não tinha edição depois de criada — implementada no mesmo padrão de Filas;
(2) telas de Platform > Infraestrutura sempre davam "Timeout no ESL" nesta
VM — não era limitação permanente como o comentário antigo dizia, e sim
ESL_HOST=freeswitch (nome DNS que só existe dentro da rede do Docker) mais
um segundo bug independente (`show gateways as json` não é comando válido
nesta versão do FreeSWITCH); (3) ramal externo registrava mas sem áudio —
diagnosticado com contadores de pacote do iptables: a VM está atrás de um
roteador sem port-forward pra faixa de RTP, achado de infraestrutura de
rede, não bug de código.

Também integra o softphone WebRTC (handphone.js/OpenSIPS, já em produção):
código-fonte encontrado em git.falehandix.com.br/Handix/handphone-2.0,
patch mínimo pra aceitar o endereço do proxy em runtime (era build-time),
nova config global (Platform > Infraestrutura > Softphone WebRTC) e widget
na topbar do tenant que pega usuário/domínio/senha do ramal vinculado ao
agente logado.

Adiciona docs/QA_SETUP.md — runbook completo pra subir o ambiente do zero
numa máquina nova (Docker, migrations, seed, systemd), e completa o
.env.example que estava faltando a maioria das variáveis reais.

Testado ponta a ponta com Playwright: edição de rota (criar/editar/F5),
as 3 telas de Infraestrutura com dado real, e um tenant/ramal/agente de
teste criados na hora confirmando que o script do softphone recebe as
credenciais certas.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
2026-08-30 22:14:39 -03:00

10 KiB

Subindo o ambiente do zero numa máquina nova (QA)

Runbook pra clonar este repositório numa máquina nova e deixar tudo rodando — Postgres/Redis/FreeSWITCH em Docker, apps/api/apps/frontend como services systemd, banco migrado e semeado. Escrito pra outra sessão do Claude Code seguir sozinha, na ordem, verificando cada passo antes do próximo. Nada aqui precisa de intervenção manual além do que está marcado explicitamente como "precisa de um humano".

Este documento descreve como levantar um ambiente igual ao de desenvolvimento/laboratório (ACESSO_TESTE.md), não produção: sem HTTPS, sem domínio próprio, DIALER_SIMULATION=true (nenhuma chamada PSTN real sai). Rodar em produção de verdade é fora de escopo deste guia.

0. Pré-requisitos da máquina

  • Linux com systemd (as units em infrastructure/systemd/ assumem isso)
  • Docker + Docker Compose plugin (docker compose version funcionando)
  • Node.js >= 22 (node -v) e pnpm (corepack enable costuma bastar — o packageManager no package.json da raiz fixa a versão exata)
  • Pelo menos ~2GB de RAM livres pro Postgres+Redis+FreeSWITCH juntos, mais o que o Next.js dev server e o tsc do apps/api consumirem
  • Este repositório precisa ficar em /opt/b2bcall — as units systemd em infrastructure/systemd/*.service têm esse caminho fixo (WorkingDirectory=, EnvironmentFile=). Cloná-lo em outro lugar exige editar essas duas linhas nas duas units antes de instalar.

Verifique antes de prosseguir:

docker compose version
node -v          # >= 22
corepack enable && corepack prepare pnpm@$(node -e "console.log(require('/opt/b2bcall/package.json').packageManager.split('@')[1])") --activate
pnpm -v

1. Clonar e instalar dependências

cd /opt
git clone <url-do-repositorio> b2bcall   # ou `git pull` se já existe
cd /opt/b2bcall
pnpm install

2. Criar o .env

.env nunca é commitado (segredos reais). Copie o template e preencha:

cp .env.example .env

Abra .env.example pra ver o comentário de cada variável — ele já explica o que cada uma faz e como gerar as que são segredos aleatórios (openssl rand -hex 32 / openssl rand -base64 24). Resumo do que precisa de valor manual:

Variável Como preencher
FREESWITCH_PAT Precisa de um humano — token de acesso ao repositório de pacotes do FreeSWITCH (freeswitch.signalwire.com), não é gerável localmente. Peça ao dono do projeto.
POSTGRES_PASSWORD, REDIS_PASSWORD, POSTGRES_APP_PASSWORD openssl rand -base64 24 (gerar um valor diferente pra cada)
JWT_SECRET, JWT_REFRESH_SECRET, ENCRYPTION_KEY openssl rand -hex 32 (gerar um valor diferente pra cada — ENCRYPTION_KEY cifra segredos reversíveis como senha SIP de ramal, nunca reaproveitar entre ambientes)
ESL_PASSWORD openssl rand -base64 24
FS_CONFIG_PASSWORD openssl rand -base64 24
DATABASE_URL postgresql://b2bcall:<POSTGRES_PASSWORD>@localhost:5432/b2bcall?schema=public
REDIS_URL redis://:<REDIS_PASSWORD>@localhost:6379
APP_DATABASE_URL postgresql://b2bcall_app:<POSTGRES_APP_PASSWORD>@localhost:5432/b2bcall?schema=public
FS_CONFIG_USER Qualquer string curta sem espaço (ex.: fsconfig)

Todas as outras variáveis do .env.example já têm um valor padrão sensato pra este tipo de ambiente (deixe como está).

Crie também apps/frontend/.env.local (não existe ainda num clone novo, também gitignored):

echo "B2BCALL_API_URL=http://localhost:3000" > apps/frontend/.env.local

3. Subir os containers Docker

cd /opt/b2bcall
docker compose up -d --build

O docker composeFREESWITCH_PAT automaticamente do .env na raiz pro build da imagem do FreeSWITCH (BuildKit secret — não fica em nenhuma camada da imagem final). O build do FreeSWITCH baixa pacotes .deb externos, pode levar alguns minutos na primeira vez.

Verifique que todos os 7 containers subiram saudáveis:

docker compose ps

Espera-se b2bcall-postgres, b2bcall-redis, b2bcall-freeswitch, b2bcall-fs-config, b2bcall-fs-events, b2bcall-predictive-dialer, b2bcall-ai-worker todos Up (os 3 primeiros com healthcheck healthy). Se algum não subir, docker compose logs <serviço> quase sempre mostra a causa na hora (comum: .env com uma variável faltando/typo).

4. Migrar e semear o banco

cd /opt/b2bcall/packages/database
set -a && source /opt/b2bcall/.env && set +a
npx prisma migrate deploy
npx prisma generate

Isso cria todas as tabelas, incluindo a role restrita b2bcall_app (não tem senha ainda — a migration não pode embutir um segredo). Defina a senha dela agora:

cd /opt/b2bcall
bash scripts/db-setup-app-role.sh

Depois, rode o seed (idempotente — cria o catálogo de permissions/roles do sistema e o usuário Platform Super Admin):

pnpm --filter @b2bcall/auth run seed

A senha temporária do Platform Super Admin (admin@b2bcall.local) é gravada em /opt/b2bcall/FIRST_LOGIN.txt (permissão 600, gitignored) — leia esse arquivo pra saber a senha do primeiro login, ele não aparece no terminal.

5. Instalar os services systemd

cd /opt/b2bcall
sudo cp infrastructure/systemd/b2bcall-api.service /etc/systemd/system/
sudo cp infrastructure/systemd/b2bcall-frontend.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now b2bcall-api.service
sudo systemctl enable --now b2bcall-frontend.service

Verifique:

systemctl status b2bcall-api.service b2bcall-frontend.service
journalctl -u b2bcall-api.service -n 50    # esperado: "Nest application successfully started" (ou similar)

apps/api recompila (tsc) toda vez que a unit sobe — leva uns 15-20s. Detalhes/troubleshooting em infrastructure/systemd/README.md.

6. Verificação de ponta a ponta

curl -s http://localhost:3000/health/ready    # apps/api + Postgres + Redis, tudo respondendo
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3001/login  # apps/frontend respondendo (espera 200)

Depois, pelo navegador (ou um túnel SSH se a máquina não for acessível direto: ssh -L 3001:localhost:3001 <usuario>@<ip-da-maquina>):

  1. Acesse http://<ip-da-maquina>:3001/login
  2. Entre com admin@b2bcall.local e a senha de FIRST_LOGIN.txt
  3. A tela "Trocar senha" aparece automaticamente (senha temporária, mustChangePassword=true) — troque por uma senha sua
  4. Depois de trocar, você cai em /platform (Platform Super Admin)
  5. Crie um tenant de teste em Clientes > Tenants pra ter algo pra testar (a senha do admin desse tenant também é mostrada uma única vez na tela — anote ou copie na hora)

7. Se for testar telefonia real (SIP/RTP de fora da rede Docker)

Só necessário se for registrar um softphone/telefone físico de verdade contra este ambiente — não é preciso pra testar só a aplicação web.

docker-compose.yml já publica 5060/udp, 5060/tcp e a faixa de RTP 16384-16584/udp pra rede (não só loopback). Se esta máquina estiver atrás de um roteador/NAT (IP da interface de rede é privado, tipo 10.x.x.x/192.168.x.x), é preciso configurar port forward no roteador pra essas mesmas portas apontando pro IP privado desta máquina — sem isso, o registro SIP até funciona (a resposta volta pelo mesmo "buraco" que o cliente abriu), mas o áudio não passa (RTP é um fluxo novo, em portas diferentes, e chega bloqueado). Isto foi um achado real diagnosticado numa sessão anterior — detalhes completos e como confirmar com contadores de pacote do iptables em docs/NETWORK_ARCHITECTURE.md ("Achado real (PHASE 65)").

8. Softphone WebRTC (widget embutido, PHASE 66)

O app do tenant tem um softphone WebRTC embutido (apps/frontend/public/ handphone.js) que conecta via WebRTC num proxy OpenSIPS externo (já em produção, fora deste repositório) — o FreeSWITCH desta instalação nunca fala WebRTC diretamente, cada ramal continua um registro SIP puro.

Pra funcionar, um Platform Super Admin precisa configurar o endereço WSS desse proxy em Platform > Infraestrutura > Softphone WebRTC (PUT /platform/webrtc-proxy, guardado na tabela platform_settings — não tem nada a configurar via .env ou variável de ambiente pra isso). Sem essa configuração, o widget simplesmente não conecta (fica sem aparecer/logar um aviso no console do navegador) — não é um erro de deploy, só falta esse passo manual pós-subida.

Referência rápida — o que roda onde

Componente Como sobe Restart depois de mudar código
Postgres, Redis, FreeSWITCH, fs-config, fs-events, predictive-dialer, ai-worker Docker (restart: unless-stopped) docker compose build <serviço> && docker compose up -d <serviço>
apps/api systemd (b2bcall-api.service), pnpm dev (modo dev, não build de produção — decisão deliberada, ver infrastructure/systemd/README.md) systemctl restart b2bcall-api.service
apps/frontend systemd (b2bcall-frontend.service), pnpm dev Hot-reload sozinho (Next.js dev server); systemctl restart só depois de mudar dependências

Problemas comuns

  • EADDRINUSE na porta 3000/3001: confira que API_PORT=3000 está no .env e que a unit do frontend tem Environment=PORT=3001 — sem os dois fixos, os dois processos competem pela mesma porta.
  • Timeout conectando no ESL do FreeSWITCH (telas de Platform > Infraestrutura): confira ESL_HOST=127.0.0.1 no .env (nunca freeswitch — esse nome só resolve dentro da rede Docker) e que a porta 8021 está publicada em loopback (docker compose ps deve mostrar 127.0.0.1:8021->8021/tcp no FreeSWITCH).
  • RLS bloqueando tudo silenciosamente (contagens sempre zero, listas sempre vazias mesmo com dado no banco): confirme que scripts/db-setup-app-role.sh rodou depois da migration — sem a senha do role b2bcall_app setada, APP_DATABASE_URL não autentica e apps/api provavelmente nem sobe.
  • Container do FreeSWITCH não builda: quase sempre FREESWITCH_PAT errado/expirado no .envdocker compose logs freeswitch mostra o erro de autenticação do apt contra o repositório do SignalWire.