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
3.4 KiB
Arquitetura de Rede
Estado atual (fase FreeSWITCH inicial)
freeswitch roda na rede padrão do Docker Compose (bridge, b2bcall_default),
igual a postgres e redis. Nenhuma porta é publicada no host — nem 8021
(ESL), nem SIP (5060/5080), nem RTP. Isso é intencional: ainda não existe
nenhum tronco SIP real nem ramal externo, então não há motivo pra expor nada.
apps/api roda hoje direto no host (fora do Docker), então usa
APP_DATABASE_URL/REDIS_URL apontando pra localhost nas portas publicadas
pelo Postgres/Redis. Ela não consegue (nem precisa, ainda) alcançar o
FreeSWITCH.
Decisão pendente: network_mode do FreeSWITCH (agente.md secao 19)
Quando existir um tronco SIP real (fase Trunks), será preciso decidir entre:
network_mode: host: mais simples pra SIP/RTP (sem NAT entre o container e a rede), mas perde isolamento de rede do Docker.- macvlan/ipvlan: dá ao FreeSWITCH um IP próprio na rede física, sem expor outros serviços do host: mais trabalho de configurar, melhor isolamento.
Não decidido ainda — só vira relevante quando houver um carrier/SBC real pra
conectar (secao 17: "FreeSWITCH não deverá depender de IP SIP público" — a
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
serviço Docker b2bcall-api (agente.md secao 14), as connection strings
precisam trocar de localhost pros hostnames internos do compose
(postgres, redis, freeswitch) — ver nota em docs/AUTHENTICATION.md sobre
essa pegadinha.