feat(ivr): editor visual do menu (canvas de nós, sem Node-RED)

Pedido do usuário: "ajusta o IVR para fazer o fluxo de maneira visual
usando nodeRED". Perguntei antes de construir: integrar Node-RED de
verdade significa rodar uma plataforma externa completa (motor de
execução próprio, nós "function" = execução de código arbitrário — o
mesmo tipo de risco corrigido no dialplan nesta sessão — e sem
multi-tenancy nativa), um projeto de vários dias com decisões de
arquitetura antes de começar a construir. O usuário escolheu a
alternativa: um editor visual próprio, sem dependência externa.

`@xyflow/react` (sucessor mantido do reactflow) — canvas de nós/setas
dentro da própria tela "Telefonia > IVR": 1 nó "Entrada" fixo conectado
a 1 nó por opção (dígito + select de ramal + descrição, editável direto
no nó, arrastável pro canvas). "Adicionar opção"/"Salvar alterações"
chamam o mesmo PATCH /ivr-menus/:id que já existia — nenhuma mudança de
backend necessária, só uma forma nova de editar o mesmo dado (o modelo
IvrMenu/IvrMenuOption continua sendo a fonte da verdade).

Testado ponta a ponta pela tela de verdade, não só leitura de código:
criado um menu real, enviado um prompt de VOZ real (WAV sintetizado com
espeak-ng dizendo uma saudação de verdade, não um tom sintético como nos
testes anteriores desta fase) e completada uma chamada real — a saudação
de ~6s tocou até o fim, o dígito foi capturado, o ramal certo atendeu
com áudio de verdade. Depois, uma segunda opção foi adicionada via PATCH
(a mesma chamada que o botão "Salvar" do editor visual faz) — confirmado
no banco que a versão 2 do dialplan compilou as duas opções
corretamente, superando a versão 1.

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 18:21:26 -03:00
parent 486c39803a
commit 0148b926a0
7 changed files with 499 additions and 19 deletions

View File

@@ -179,9 +179,34 @@ o DID, `play_and_get_digits` abriu e tocou o arquivo até o fim duas
vezes (`mod_sndfile` resample automático, sem erro no log), colheu o
dígito real e bridged corretamente com o ramal de destino.
## Editor visual (PHASE 60)
`apps/frontend/.../telefonia/ivr/ivr-flow-editor.tsx` — canvas de nós e
setas (`@xyflow/react`) em cima do MESMO modelo de sempre (entrada +
opções por dígito), sem nenhuma dependência de execução externa. Um nó
"Entrada" fixo conectado a um nó por opção (dígito + select de ramal +
descrição, editável direto no nó); "Adicionar opção"/"Salvar alterações"
chamam o mesmo `PATCH /ivr-menus/:id` que já existia. Avaliado (e
descartado por enquanto, ver AskUserQuestion desta sessão) integrar
Node-RED de verdade: seria uma plataforma externa completa (motor de
execução próprio, nós "function" = RCE, sem multi-tenancy nativa) —
esforço de vários dias e superfície de risco nova, não um ajuste na tela
atual. Um editor visual próprio, sobre o backend já existente, entrega o
mesmo valor imediato (ver estrutura do menu como grafo, editar visualmente)
sem essas duas desvantagens.
Testado ponta a ponta pela tela de verdade: menu criado, prompt de voz
real enviado (WAV sintetizado com `espeak-ng`, não um tom sintético),
uma segunda opção adicionada via `PATCH` (mesma chamada que o botão
"Salvar" do editor visual faz) — confirmado no banco que a versão 2 do
dialplan compilou as duas opções corretamente, superando a versão 1.
## O que falta
- Sem TTS (texto→voz) — só upload de arquivo WAV já gravado.
- Editor visual não persiste posição manual dos nós entre recargas
(layout recalculado a cada carga da página — arrastar só ajuda
durante a mesma sessão de edição).
- Menu de IVR não suporta sub-menus (uma opção levando a OUTRO IVR) nem
destino "fila" — só ramal, dentro do contexto `default`.
- Tela de frontend "Rotas de Entrada" cobre só CRUD simples (DID →