feat: add structured versioned dialplan and asterisk admin

- packages/database: DialplanEntry + DialplanVersion (schema/config
  gerado, nunca dialplan cru vindo do usuario)
- apps/api/src/dialplan: DialplanService gera extensions a partir de
  entradas estruturadas (campos com allowlist estrita de caracteres),
  escreve em arquivo compartilhado via volume Docker 'dialplan-generated'
  entre api e asterisk, recarrega via AMI ('dialplan reload') e valida
  checando 'dialplan show <contexto>' por marcadores de erro. Falha na
  validacao dispara rollback automatico para a versao anterior; rollback
  manual tambem disponivel para qualquer versao no historico
- infrastructure/asterisk: extensions.conf agora inclui o arquivo gerado
  pela aplicacao; entrypoint garante que ele existe (vazio) no primeiro
  boot antes da primeira publicacao
- apps/api/src/asterisk-admin: status (AMI + heartbeat), module show, e
  diagnostico com ALLOWLIST ESTRITA de comandos exatos (nunca shell
  arbitraria) — agente.md secao 22

Testado ponta a ponta contra o Asterisk real: dialplan publicado fica
ativo imediatamente sem restart (confirmado via 'dialplan show'),
comando de diagnostico fora da allowlist rejeitado com 400.
This commit is contained in:
2026-08-27 13:14:50 -03:00
parent 8a41b5d2b2
commit cf3fc4b3ef
18 changed files with 789 additions and 10 deletions

View File

@@ -15,7 +15,8 @@ exten => 600,1,Answer()
same => n,Echo()
same => n,Hangup()
; Placeholder para o contexto de discagem outbound (Fase 6 — Campanhas).
[outbound]
exten => _X.,1,NoOp(B2BCall outbound placeholder - ${EXTEN})
same => n,Hangup()
; Dialplan gerenciado pela aplicação (Telefonia → Dialplan), gerado por
; DialplanService e compartilhado via volume Docker "dialplan-generated"
; (ver docs/ARCHITECTURE.md). Nunca editar este arquivo manualmente — toda
; alteração é versionada em dialplan_versions com backup/validação/rollback.
#include "/etc/asterisk-generated/b2bcall-dialplan.conf"

View File

@@ -28,6 +28,14 @@ for f in "$CONFIG_SRC"/*.conf; do
cp "$f" "$CONFIG_DST/$name"
done
chown -R asterisk:asterisk "$CONFIG_DST" /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk
# extensions.conf inclui este arquivo (dialplan gerado pela aplicação) —
# precisa existir mesmo vazio no primeiro boot, antes de a API publicar
# a primeira versão (ver DialplanService).
mkdir -p /etc/asterisk-generated
if [ ! -e /etc/asterisk-generated/b2bcall-dialplan.conf ]; then
echo "; vazio até a primeira publicação em Telefonia -> Dialplan" > /etc/asterisk-generated/b2bcall-dialplan.conf
fi
chown -R asterisk:asterisk "$CONFIG_DST" /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk /etc/asterisk-generated
exec "$@"