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
This commit is contained in:
2026-08-31 13:03:38 -03:00
parent 5c23b105b3
commit b33d35db50
2 changed files with 50 additions and 1 deletions

49
TODO.md
View File

@@ -2524,6 +2524,55 @@ rota de entrada")
1503→1502), áudio bidirecional e chamada sobrevivendo bem além
dos 32s que travavam toda tentativa antes do achado 3.
## PHASE 69 — Sessão web expirando cedo demais pra call center (pedido do
usuário: "no minimo 12 hs")
- [x] Access token JWT (`packages/auth/src/tokens.ts`) e o teto absoluto do
cookie de sessão (duplicado em `login`/`post-login`/`select-tenant`
route handlers + `middleware.ts`) subiram de 15min/8h pra 12h. O
refresh silencioso do middleware (decodifica o `exp` do JWT, renova
via `/auth/refresh` uns 60s antes de vencer) continua existindo e
deslizando a sessão a cada requisição — 12h passa a ser só o teto de
segurança pra quando esse refresh falhar (aba parada, logout em
outro lugar), não o intervalo real de renovação.
- [x] Verificado com login real: token decodificado mostra expiat = 12h
exatas.
## PHASE 70 — Softphone WebRTC não registrava, ficava cinza pra sempre
(usuário configurou o proxy QA de verdade e testou o ramal 1501 do tenant
teste01 — "so fica cinza")
- [x] Confirmado primeiro que a config em si estava certa
(`GET /platform/webrtc-proxy` devolvia a URL nova) e que a
infraestrutura de rede/proxy funcionava — DNS resolve, TCP conecta,
certificado TLS válido, e um handshake WebSocket manual (`ws`, com
header `Origin`) completa normal. Um REGISTER SIP cru (autenticação
digest manual) através do proxy chegou até o FreeSWITCH de verdade
(`User-Agent: FreeSWITCH-mod_sofia` na resposta) e voltou 200 OK —
credenciais do ramal 1501 corretas, proxy e FreeSWITCH 100% ok.
- [x] **Achado real, bug no próprio código-fonte do widget** (não
descoberto antes porque a verificação da PHASE 66 só conferia se o
`<script data-sip-*>` recebia os atributos certos, nunca deixava o
widget tentar registrar de verdade contra um proxy ao vivo):
`widgetStorage.mergeConfig` (`src/widget/widgetStorage.js`) só
calculava o campo `aor` (`sip:user@domain`) no branch de config
SALVA MANUALMENTE (localStorage) — no branch usado quando a config
vem de `data-sip-*`/`window.HandphoneConfig` (nosso caso, sempre),
`aor` nunca era calculado. `connect()` (`useSip.js`) quebra em
`cfg.aor.startsWith(...)` com `aor` undefined — erro só visível no
console do navegador (`[Widget] Connect failed: TypeError...`),
nunca pro usuário, que só via o botão preso em cinza (desconectado)
pra sempre, sem nenhuma tentativa de conexão visível.
- [x] Fix: `mergeConfig` agora calcula `aor` a partir de
`externalConfig.username`/`externalConfig.domain` também no branch
sem config salva. Patch na mesma cópia local do
`git.falehandix.com.br/Handix/handphone-2.0` já usada na PHASE 66
(nunca enviado pro repo externo do usuário) — rebuildado e
revendorizado em `apps/frontend/public/handphone.js`.
- [x] Testado ponta a ponta com Playwright + navegador real, fora do app
(uma página HTML isolada com os `data-sip-*` do ramal 1501 de
verdade, sem depender do login do tenant): REGISTER completa com
200 OK observado no tráfego WebSocket real, botão do widget muda de
cinza pra verde (conectado).
---
## Riscos conhecidos

File diff suppressed because one or more lines are too long