# B2BCall — Asterisk ## Versão e módulos Asterisk **22.10.1**, compilado do fonte (Debian trixie não empacota `asterisk`) — `infrastructure/docker/asterisk.Dockerfile`. Módulos habilitados: `chan_pjsip` (nunca `chan_sip`, removido/depreciado), `res_odbc`/`res_config_odbc` (Realtime), `app_queue`, `cdr_adaptive_odbc`, `cel_odbc`, AMI, ARI. ## Realtime (PJSIP via Postgres) Objetos PJSIP (`ps_endpoints`, `ps_auths`, `ps_aors`, `ps_contacts`, `ps_endpoint_id_ips`, `ps_registrations`) vivem no schema `asterisk` do mesmo Postgres da aplicação — nunca em arquivo estático. Escritos exclusivamente por `apps/api/src/telephony/pjsip-realtime.service.ts` quando um Tronco/Ramal é criado/editado pela API. - DSN ODBC: `infrastructure/asterisk/config/odbc.ini.tpl` → conexão nomeada `asterisk`, `ConnSettings = SET search_path TO asterisk, public;`. - `sorcery.conf`/`extconfig.conf` apontam os tipos PJSIP para essa conexão. - Depois de criar/editar um objeto, a API dispara reload seletivo via AMI (`pjsip reload`), nunca `core restart`. ## Dialplan e filas (gerados, versionados) - `infrastructure/asterisk/config/extensions.conf` inclui `/etc/asterisk-generated/b2bcall-dialplan.conf` — gerado por `DialplanService` a partir de `DialplanEntry`/`DialplanVersion` (Postgres). Toda alteração é uma nova `DialplanVersion` com validação (`dialplan reload` + checagem de erro) e rollback automático se falhar. - `infrastructure/asterisk/config/queues.conf` inclui `/etc/asterisk-generated/b2bcall-queues.conf` — gerado a partir de `Queue` (Postgres). **Membros nunca são estáticos** — adicionados/ removidos via AMI `QueueAdd`/`QueueRemove` no login/logout do agente (`AgentConsoleService`), para nunca ter duas fontes de verdade divergentes sobre quem está em qual fila. - Ambos os arquivos gerados vivem no volume Docker `dialplan-generated`, compartilhado entre `api` (escreve) e `asterisk` (lê + recarrega). - **Nunca editar esses dois arquivos gerados manualmente** — qualquer edição é sobrescrita na próxima publicação pela aplicação. ## AMI / ARI - AMI: client próprio em `packages/telephony` (TCP raw, sem biblioteca de terceiros — o protocolo de wire do Asterisk 22 para a action `Command` usa headers `Output:` repetidos, não o formato legado `Response: Follows`/`--END COMMAND--` documentado em versões antigas). - Usado para: Originate, Hangup, QueueAdd/Remove, QueuePause, QueueStatus, ExtensionState/DeviceState, PJSIP show endpoints/contacts, reloads seletivos. - ARI: reservado para controle fino de canais/bridges quando necessário — não usado extensivamente nesta fase (a maior parte das operações administrativas é feita via AMI). - **Nunca expostos além de `127.0.0.1`/rede interna** — bloqueados da LAN por nftables mesmo estando em `network_mode: host` (ver `docs/ARCHITECTURE.md` §3.1 e `infrastructure/nftables/`). ## Comandos úteis de diagnóstico ```bash docker exec b2bcall-asterisk asterisk -rx "core show uptime" docker exec b2bcall-asterisk asterisk -rx "pjsip show endpoints" docker exec b2bcall-asterisk asterisk -rx "pjsip show registrations" docker exec b2bcall-asterisk asterisk -rx "queue show" docker exec b2bcall-asterisk asterisk -rx "dialplan show b2bcall-healthcheck" docker exec b2bcall-asterisk asterisk -rx "module show like odbc" docker exec b2bcall-asterisk asterisk -rx "odbc show all" ``` Um subconjunto seguro e auditado desses comandos também é exposto via `GET /api/asterisk/diagnostic/allowed-commands` + `POST /api/asterisk/diagnostic` (allowlist explícita — nunca shell livre, seção 18) para uso pela interface web sem precisar SSH no servidor. ## Rede `network_mode: host` (necessário para a faixa de portas RTP — mapear porta a porta em bridge Docker é inviável). Implicações e mitigação em `docs/ARCHITECTURE.md` §3.1. ## Limitações conhecidas nesta fase - `res_pjsip_outbound_registration` pode logar erro no boot se nenhum registration estiver configurado ainda (nenhum tronco cadastrado) — não é um erro real, some ao cadastrar o primeiro tronco com `registration`. - `res_config_ldap` loga ERROR no boot (LDAP não configurado/não usado neste projeto) — módulo carregado por padrão pelo build, inofensivo. - `cdr_pgsql`/`cel_pgsql` (variante não-ODBC) não compilam nesta imagem por falta de `libpq-dev` — não é um problema porque `cdr_adaptive_odbc`/ `cel_odbc` (a variante realmente usada) funcionam normalmente. - Nenhuma correlação automática CDR↔`DialAttempt` para chamadas **reais** (não simuladas) além do timeout de segurança da reconciliação — ver `docs/PREDICTIVE_DIALER.md`.