5 Commits

Author SHA1 Message Date
6c23513f42 fix(frontend): cursor de seta nos cantos do FAB do widget (border-radius exclui hit-test)
Pedido do usuário: "vira a mão quando está sobre a letra e não sobre o
retângulo inteiro". O FAB flutuante é rounded-full 56x56 — Chrome exclui
os cantos cortados desse quadrado do hit-test de elementos com
border-radius, então o mouse nos cantos caía pro <div> de posicionamento
por trás (sem cursor:pointer) em vez do botão. Clique dentro do círculo
real sempre funcionou; só o cursor ficava inconsistente. Confirmado com
hover real via Playwright piercing o shadow DOM. Fix: cursor-pointer no
wrapper.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
2026-08-31 16:40:22 -03:00
dd095077dd fix(frontend): widget usava config antigo do localStorage em vez do ramal real do agente
Dois bugs reais reportados pelo usuário testando um ramal de verdade
(teste@teste.com.br / ramal 1501):

1. widgetStorage.mergeConfig fazia `{...externalConfig, ...stored}` —
   um sip_config salvo de sessão/ramal anterior no mesmo navegador
   sempre vencia sobre as credenciais que o backend acabou de injetar
   via data-sip-* pro agente logado agora, então o widget tentava
   registrar com o ramal errado (ou senha vazia) pra sempre, sem erro
   visível. Invertido: externalConfig (sempre fresco, vindo do agente
   logado) vence; stored só preenche o que faltar.

2. crypto.subtle é undefined em contexto inseguro (HTTP puro, mesma
   classe de bug do botão de copiar da PHASE 71) — salvar a senha na
   aba Configurações do widget quebrava com "Cannot read properties of
   undefined (reading 'importKey')". Agora cai pra um fallback base64
   reversível quando SubtleCrypto não está disponível.

Testado com Playwright: config "errado" salvo no localStorage não sobrevive
mais a um reload — o próximo connect() usa o ramal real do agente.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
2026-08-31 16:14:16 -03:00
e75872faec fix(frontend): widget do softphone preso em cinza — dupla chamada de connect() sem cooldown
Dois efeitos de auto-connect do Widget.jsx (mount + reconnect-on-drop)
podiam disparar connect() em sequência rápida sem respeitar o cooldown
de 5s (só o efeito de reconexão gravava o timestamp), abrindo um
segundo SimpleUser/registro concorrente que sip.js rejeita com
RequestPendingError — e o catch sobrescrevia connectionStatus pra
"disconnected" incondicionalmente, travando o widget em cinza.
Trava por promise em useSip.js::connect() + cooldown também no
auto-connect de mount resolvem: testado com Playwright dentro do app
real, connect() dispara uma única vez e o status nunca mais volta
pra cinza.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
2026-08-31 13:46:52 -03:00
b33d35db50 fix(softphone): widget nunca calculava o AOR quando config vinha via data-sip-* — ficava preso em "desconectado" pra sempre
Usuário configurou o proxy WebRTC de QA de verdade (Platform > Sistema >
Softphone WebRTC) e tentou registrar o ramal 1501 (tenant teste01) — o
widget só ficava cinza, sem nenhum erro visível.

Descartado infraestrutura/credenciais primeiro (testes diretos: DNS, TCP,
TLS, handshake WebSocket manual, e um REGISTER SIP cru com autenticação
digest através do proxy — chegou no FreeSWITCH de verdade e voltou 200 OK).
O bug estava no código-fonte do próprio widget: `widgetStorage.mergeConfig`
só calculava o campo `aor` (sip:user@domain) no branch de config salva
manualmente no localStorage — no branch usado quando a config vem via
data-sip-*/window.HandphoneConfig (sempre, neste app), `aor` nunca era
calculado, e `connect()` quebrava em `cfg.aor.startsWith(...)` com `aor`
undefined — erro só no console, nunca visível pro usuário.

Corrigido na mesma cópia local do handphone-2.0 (nunca enviado pro repo
externo do usuário), rebuildado e revendorizado. Testado ponta a ponta com
Playwright + navegador real fora do app (data-sip-* do ramal 1501 de
verdade, sem depender do login do tenant): REGISTER 200 OK, botão do
widget vira verde.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
2026-08-31 13:03:38 -03:00
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