跳到正文

callflow-server

callflow-serverapps/callflow-webpage 的后端 API,负责:

  1. 持久化 tts / recording 运行时配置,并代理触发 callflow-esl 热重载。
  2. 提供 FreeSWITCH PostgreSQL 表的只读分页查询与汇总视图。
  3. 管理 callflow.call_businessescallflow.call_business_number_mappings,并代理外呼、TTS / ASR 测试请求。

运行

bash
bun install
bun run start
bun run dev
bun run typecheck
bun run auth:generate

默认监听 0.0.0.0:9913

配置文件

本服务主要读取外置 config.json,仅少量部署相关字段支持环境变量覆盖,不直接读取 apps/callflow-esl/config.json。 凡是需要默认运行信息的接口,都会按需请求 callflow-esl GET /runtime-configs;若该接口不可用或响应不合法,请求直接失败,不再本地兜底。

  • bun run dev / bun run start:读取当前工作目录下的 config.json
  • 独立可执行文件:优先读取可执行文件同目录下的 config.json
  • 如果独立可执行文件目录下没有 config.json,则回退读取启动工作目录下的 config.json

部署前请确保启动目录或可执行文件目录下存在合法的 config.json

开发默认样例见 config.json

配置字段

json
{
  "server": {
    "host": "0.0.0.0",
    "port": 9913
  },
  "databases": {
    "freeswitch": {
      "url": "postgres://postgres:postgres@192.168.2.246:5432/freeswitch"
    },
    "callflow": {
      "url": "postgres://postgres:postgres@localhost:5432/freeswitch?options=-c search_path=callflow"
    }
  },
  "callflowEsl": {
    "baseUrl": "http://127.0.0.1:9912",
    "token": "esl-0x21"
  },
  "auth": {
    "enabled": true,
    "username": "admin",
    "passwordHash": "scrypt$CjCVHad_PLuE2lPnHJNvaQ$2AM7XWfy4p2ejRzFu7Qf7XkRpdIizXIefKECSnnbEU_cgfgV_PiZalpUm8-in7OzaElTpLyGlq3lyKLIrO4JIA",
    "tokenSecret": "N_jOol1eGo2zohOrPg4L7BwFZXYaTfmZ8BnxZUpW2Zo",
    "tokenTtlDays": 30
  }
}

字段说明:

  • server.host / server.port:HTTP 监听地址。
  • databases.freeswitch.url:FreeSWITCH 核心数据库连接串,只读查询使用。
  • databases.callflow.urlcallflow schema 连接串,运行时配置和业务 CRUD 使用。
  • callflowEsl.baseUrlcallflow-esl HTTP 基址,用于 /outbound-calls/freeswitch/runtime-status/runtime-configs/runtime-configs/reload 代理。
  • callflowEsl.token:代理到 callflow-esl 时附带的 token 请求头;未启用鉴权时可留空串。
  • auth.enabled:是否启用管理台登录鉴权。
  • auth.username:单管理员用户名。
  • auth.passwordHash:管理员密码哈希。支持 scrypt$<salt-base64url>$<hash-base64url>,也兼容 Bun.password 可校验的哈希格式。
  • auth.tokenSecret:Bearer token HMAC 签名密钥;生产环境必须替换。
  • auth.tokenTtlDays:Bearer token 有效期,单位天。
  • 当前仓库内默认联调账号为 admin,默认密码为 secret-123;对应哈希已写入 config.json

如需生成新的 auth.passwordHashauth.tokenSecret,可在 apps/callflow-server 下执行:

bash
bun run auth:generate

脚本会交互式要求输入两次密码,然后终端打印:

  • 新的 passwordHash
  • 新的 tokenSecret
  • 可直接粘贴到 auth 对象中的 JSON 片段

该脚本默认不会自动修改 config.json;请手动替换对应字段后重启服务。

当前优先级为:

  1. callflow.callflow_runtime_configs 数据库记录
  2. callflow-esl GET /runtime-configs 返回的对应节值

ASR 默认地址也不再由 callflow-server 本地配置维护,而是从 callflow-esl /runtime-configsdata.asr.wsUrl 实时读取。

/api/callflow/runtime-configs 返回的 source 现在只有两种:

  • database
  • config-file

鉴权与部署

  • 管理台默认方案是“单管理员 + Bearer token”。
  • 当前默认登录凭据为 admin / secret-123,仅用于本地联调或初始验证。
  • 开发时如果仍需匿名访问,可把 auth.enabled 设为 false;生产环境应启用。
  • 启用后,除 /api/health/health/api/auth/login/api/auth/me/api/auth/logout 外,其余 /api/... 全部要求登录。
  • 登录成功后,前端应把返回的 accessToken 保存到本地,并在后续请求中通过 Authorization: Bearer <token> 发送。
  • 服务端会统一返回宽松 CORS 头(Access-Control-Allow-Origin: *),因此浏览器可直接跨域访问;是否允许调用仍由现有 Bearer Token 鉴权决定。
  • tts/asr 测试接口只允许访问当前 runtime 配置、callflow-esl 提供的默认值,或私网 / 回环地址,避免管理台被滥用成 SSRF 跳板。
  • 对外部署前,务必改掉默认用户名/密码,并同步替换 auth.tokenSecret;推荐直接执行 bun run auth:generate 生成新值。
  • 对外发布时建议使用同域反向代理:
    • / -> callflow-webpage
    • /api/ -> callflow-server
    • /health -> callflow-server
    • callflow-server 自身可只监听内网地址,经反向代理统一暴露;若直接暴露公网,仍应配合鉴权和网络层限制

管理台前端主用健康检查入口是 /api/health;顶层 /health 保留给现有运维探针、反向代理兼容和人工排查。

当前推荐使用 bun run auth:generate 统一生成 scrypt$<salt-base64url>$<hash-base64url> 格式的 auth.passwordHash 和新的 auth.tokenSecret;脚本只负责打印结果,不会自动改写配置文件。

部署示例

开发模式:

bash
cd apps/callflow-server
bun run start

独立目录部署时建议把二进制和 config.json 放在同一目录,例如:

text
deploy/
  callflow-server.exe
  config.json

然后直接运行可执行文件。

HTTP API

方法路径用途
GET/api/health管理台主用健康检查;返回服务状态与两个数据库的连通性
GET/health/api/health 完全一致的兼容 / 运维别名
POST/api/auth/login管理员登录并返回 Bearer token
GET/api/auth/me返回当前登录状态与是否启用鉴权;带 token 时校验其有效性
POST/api/auth/logout幂等成功;前端自行删除本地 token
GET/api/freeswitch/overview通话 / 注册数量,以及近期 channels / registrations
GET/api/freeswitch/runtime-status代理 callflow-esl FreeSWITCH 运行时状态
GET/api/freeswitch/tables列出可浏览的 FreeSWITCH 表(元数据)
GET/api/freeswitch/tables/{name}分页、可搜索地读取 FreeSWITCH 表数据
GET/api/freeswitch/basic-callstables/basic_calls 的快捷入口
GET/api/freeswitch/detailed-callstables/detailed_calls 的快捷入口
GET/api/callflow/businesses分页读取 callflow 业务
PUT/api/callflow/businesses/{id}更新业务级 JSON 配置,固定请求体 { "businessConfig": { ... } }
DELETE/api/callflow/businesses/{id}软删除业务
GET/api/callflow/number-mappings分页读取号码 → 业务映射
POST/api/callflow/number-mappings创建号码映射
PUT/api/callflow/number-mappings/{id}更新号码映射
DELETE/api/callflow/number-mappings/{id}软删除号码映射
POST/api/callflow/outbound-calls附加配置的 ESL token,代理调用 callflow-esl POST /outbound-calls
GET/api/callflow/runtime-configs当前 tts + recording 运行时配置
PUT/api/callflow/runtime-configs/tts更新 tts 运行时配置
PUT/api/callflow/runtime-configs/recording更新 recording 运行时配置
POST/api/callflow/runtime-configs/reload转发重载请求到 {callflowEsl.baseUrl}/runtime-configs/reload
POST/api/tts/audition通过 sherpa-tts-server 或兼容 TTS 网关合成试听音频
POST/api/tts/health探测 sherpa-tts-server 或兼容 TTS 网关 /health
POST/api/asr/health探测 sherpa-asr-online-server 或兼容 ASR 网关 /health
POST/api/asr/recognize接收 16kHz mono PCM16 WAV,转发到 ASR WebSocket 并返回 partial / final 结果

所有普通 JSON 响应都使用 { code, data, msg } 结构,三个字段始终存在。成功码固定为 字符串 "0000";失败码使用与错误语义对应的字符串,并保留 HTTP status。SSE、下载、 音频流与 OPTIONS 预检不套用该信封。

外呼管理接口接收与 callflow-esl POST /outbound-calls 相同的字段: destinationNumberbusinessCodevariablescallerIdNumbercallerIdNamedialStringTemplate。当上游 HTTP 请求成功且响应符合 { ok: boolean } 协议时,管理接口会解析上游结果并重新封装。上游 ok=true 时结果位于 data(其中业务字段 data.ok 保留);上游 ok=false 时管理接口返回失败码与 msg, 不会把旧信封直接透传。调用链为:

text
callflow-webpage -> callflow-server -> callflow-esl -> FreeSWITCH inbound ESL

页面与调用方不能覆盖 callflowEsl.baseUrl 或 token;这两项始终取自服务端配置。

数据来源

  • callflow 数据库:call_businessescall_business_number_mappingscallflow_runtime_configs
  • FreeSWITCH 数据库:channelscallsregistrationssip_registrationssip_dialogsbasic_callsdetailed_calls
  • sherpa-tts-server / 兼容 TTS 网关:TTS 试听与健康检查
  • sherpa-asr-online-server / 兼容 ASR 网关:ASR 健康检查与识别测试
  • callflow-esl:外呼 originate、运行时配置默认值读取、运行时配置重载与 FreeSWITCH 运行时状态代理

call_businesses.businessConfig 与号码映射的 mappingConfig 都是直接的业务配置 JSON 对象;保存 {} 表示清空该层覆盖。callflow-esl 对新通话按“配置文件 < 业务配置 < 号码映射配置”深合并。显式 business_code 路由只使用前两层,不读取号码映射。 数据库升级时须先增加字段,再启动新服务:

sql
ALTER TABLE callflow.call_businesses
  ADD COLUMN IF NOT EXISTS "businessConfig" jsonb NOT NULL DEFAULT '{}'::jsonb;

日志

服务同时输出彩色控制台日志和每日滚动文件 logs/application-YYYY-MM-DD.logconfig.jsonlogging.dirlevelmaxSizemaxFiles 分别控制目录、最低级别、单文件大小和保留周期, 默认值为 logsinfo20m14d。可用 CALLFLOW_SERVER_LOG_DIRCALLFLOW_SERVER_LOG_LEVELCALLFLOW_SERVER_LOG_MAX_SIZECALLFLOW_SERVER_LOG_MAX_FILES 覆盖。HTTP 日志跳过健康检查,只记录 method、path、status、durationMs 等摘要,不记录密码、 Bearer token、数据库连接串或请求体。

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。