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

@@ -27,6 +27,34 @@ topologia esperada é `Internet → OpenSIPS → rede SIP privada → FreeSWITCH
então o FreeSWITCH em si tende a ficar em rede privada mesmo, o que favorece
manter bridge/macvlan em vez de host).
## Achado real (PHASE 65): VM atrás de roteador, ramal externo sem áudio
Esta VM de laboratório está atrás de um roteador (NAT) — o IP da interface de
rede (`ens18`) é privado (`10.10.32.x`), o roteador é quem faz NAT pro IP
público real. Reportado pelo usuário: um softphone externo registrava com
sucesso, mas sem áudio.
Diagnóstico (contadores de pacotes do `iptables`, não suposição): 10 pacotes
chegaram em `5060/udp` (SIP), **zero** pacotes chegaram em qualquer porta da
faixa de RTP (`16384-16584/udp`). O REGISTER funciona porque a resposta
trafega de volta pelo mesmo "buraco" NAT que o próprio pacote do cliente abriu
— mas RTP usa portas completamente diferentes, como um fluxo NOVO. Sem uma
regra de **port forward no roteador** pra essa faixa (apontando pro IP
privado desta VM), esses pacotes nunca chegam até o Docker/FreeSWITCH.
Do lado desta VM estava tudo certo: `docker-compose.yml` publica a faixa de
RTP pra rede (não só loopback), `Ext-RTP-IP`/`Ext-SIP-IP` resolvem certo via
STUN (`sofia status profile internal` mostra o IP público real), e a
detecção de NAT do próprio FreeSWITCH (`apply-nat-acl value="nat.auto"`,
`nat.auto` é uma ACL auto-gerada pelo core do FreeSWITCH — RFC1918 exceto a
própria rede local do container, não precisa existir em `acl.conf.xml`)
funciona corretamente (testado direto via `fs_cli -x "acl <ip> nat.auto"`).
**Não tem fix de código pra isso** — é infraestrutura de rede fora do
controle desta aplicação. Checklist pra quem for expor telefonia real atrás
de um roteador: encaminhar UDP `5060` e toda a faixa RTP (`16384-16584`,
Dockerfile do FreeSWITCH) pro IP privado da VM, sem tradução de porta.
## Quando `apps/api` virar container
Hoje ela roda no host por conveniência de desenvolvimento. Quando virar o