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
This commit is contained in:
2026-08-30 22:14:39 -03:00
parent a779a7e51f
commit 97ef8a6ba8
25 changed files with 1047 additions and 58 deletions

View File

@@ -1,8 +1,82 @@
# Copie pra `.env` (gitignored) e preencha. Ver docs/QA_SETUP.md pro passo a
# passo completo de como subir o ambiente do zero numa máquina nova.
# Token de acesso ao repositório de pacotes .deb do FreeSWITCH
# (freeswitch.signalwire.com) — só existe durante o build da imagem Docker
# (BuildKit secret, nunca vira camada da imagem nem chega no container em
# runtime). Peça este valor a quem já tem uma conta SignalWire; não é gerável
# localmente.
FREESWITCH_PAT=
DATABASE_URL=postgresql://user:password@localhost:5432/b2bcall?schema=public
POSTGRES_APP_USER=
# apps/api roda direto no host (fora do Docker) — fixado aqui pra nunca
# depender de quem inicia primeiro disputando a porta padrão 3000 com o
# apps/frontend.
API_PORT=3000
# --- Postgres (container b2bcall-postgres, gerar senhas com `openssl rand -base64 24`) ---
POSTGRES_USER=b2bcall
POSTGRES_PASSWORD=
POSTGRES_DB=b2bcall
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
# --- Redis (container b2bcall-redis) ---
REDIS_PASSWORD=
REDIS_HOST=redis
REDIS_PORT=6379
# --- Segredos da aplicação (gerar cada um com `openssl rand -hex 32`) ---
JWT_SECRET=
JWT_REFRESH_SECRET=
ENCRYPTION_KEY=
# Event Socket do FreeSWITCH — só apps/api (systemd, no host, fora do Docker)
# lê isto. "freeswitch" é um nome DNS que só existe na rede interna do
# Docker; os serviços que RODAM dentro do Docker (fs-events, fs-config,
# predictive-dialer) têm ESL_HOST=freeswitch fixo no próprio
# docker-compose.yml, nunca leem esta variável. Precisa ser 127.0.0.1 (a
# porta 8021 é publicada só em loopback, ver docker-compose.yml) — nunca
# "freeswitch" aqui.
ESL_HOST=127.0.0.1
ESL_PORT=8021
ESL_PASSWORD=
# Segurança de chamada real (agente.md secao 186) — as DUAS precisam estar
# explicitamente na posição de risco pra originar uma chamada PSTN de
# verdade. Deixe como está pra um ambiente de QA/laboratório.
DIALER_SIMULATION=true
ALLOW_REAL_OUTBOUND_CALLS=false
# --- Gravações (agente.md secao 90-93) ---
STORAGE_PROVIDER=LOCAL
LOCAL_STORAGE_ROOT=/opt/b2bcall/data/object-storage-local
# --- Prompts de áudio do IVR (PHASE 59) ---
IVR_PROMPTS_HOST_ROOT=/opt/b2bcall/data/ivr-prompts
# --- S3/MinIO (só usado se STORAGE_PROVIDER=s3; deixe em branco pro padrão LOCAL) ---
S3_ENDPOINT=
S3_REGION=
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_BUCKET=
S3_FORCE_PATH_STYLE=true
# --- Connection strings derivadas dos valores acima (preencher com os
# mesmos POSTGRES_PASSWORD/REDIS_PASSWORD já definidos) ---
DATABASE_URL=postgresql://b2bcall:@localhost:5432/b2bcall?schema=public
REDIS_URL=redis://:@localhost:6379
# Role restrito (não-superuser) que a aplicação usa em runtime pra RLS
# funcionar de verdade (agente.md secao 32) — a role em si é criada por uma
# migration do Prisma, mas a senha nunca fica num arquivo de migration
# commitado (ver scripts/db-setup-app-role.sh).
POSTGRES_APP_USER=b2bcall_app
POSTGRES_APP_PASSWORD=
APP_DATABASE_URL=postgresql://user:password@localhost:5432/b2bcall?schema=public
REDIS_URL=redis://:password@localhost:6379
APP_DATABASE_URL=postgresql://b2bcall_app:@localhost:5432/b2bcall?schema=public
# Credenciais que b2bcall-fs-config usa pra autenticar no Event Socket
# quando o PRÓPRIO FreeSWITCH chama de volta (mod_xml_curl) — role de app
# dedicado, nada a ver com FS_CONFIG_USER de um tenant.
FS_CONFIG_USER=
FS_CONFIG_PASSWORD=