# vos-rs-api-server **Repository Path**: vos-rs/vos-rs-api-server ## Basic Information - **Project Name**: vos-rs-api-server - **Description**: 电信级 VoIP 软交换 REST API 服务:资源管理、计费、集群、Copilot、系统管理 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2026-07-31 - **Last Updated**: 2026-09-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # api-server 桌面客户端:[`vos-rs-softphone-desktop`](https://gitee.com/vos-rs/vos-rs-softphone-desktop)。客户端通过本服务完成网页 SSO、桌面 JWT 交换、软电话配置获取和权限校验;拿到短时 SIP 凭据后由客户端协议适配器完成 REGISTER,成功后才进入拨号页。 > 电信级 VoIP 软交换 REST API 服务:资源管理、计费、集群、Copilot、系统管理。 ![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg) ![Rust Version](https://img.shields.io/badge/rust-1.94%2B-orange.svg) ![Framework](https://img.shields.io/badge/axum-0.8-blueviolet.svg) ![Database](https://img.shields.io/badge/PostgreSQL-required-336791.svg) ![Redis](https://img.shields.io/badge/Redis-required-d62828.svg) ## 特性概览 - 🚀 **基于 Axum 的高性能 REST API**:基于 `tokio` + `axum 0.8` 异步框架,支持高并发请求处理;统一中间件链(JWT 鉴权 → 审计日志 → 响应契约)保障安全与可观测性。 - 🌐 **资源管理全覆盖**:网关(Trunk)/号码/路由规则/租户/注册 一体化 CRUD,支持批量导入与模板下载。 - 💳 **计费账户体系**:接入账户(Access Account)与落地账户(Egress Account)双账户模型,支持充值、冻结、额度流水查询。 - 🔐 **反欺诈与安全**:可配置反欺诈规则引擎(频次、目的地、金额阈值),支持深度伪造通话检测日志查询与审计日志检索。 - 📊 **实时集群管理**:SIP 集群节点状态查询与控制(启动/停止/重载),媒体集群(Media Cluster)配置,活跃通话监控与强制拆线。 - 🤖 **Copilot AI 运维(企业版)**:基于 LLM 的智能运维助手,支持自然语言查询资源、分析通话、执行安全审批动作;从模型中心选择已启用的多厂商 `LLM_TEXT` 模型。 - 🎙️ **录音回放**:基于 `call-core::storage` 的统一录音存储后端(本地 / 对象存储),支持 HTTP Range 请求分段回放,本地录音自动归档到对象存储。 - 🔑 **认证与权限**:JWT 登录认证 + RBAC 角色权限模型 + 菜单可见性控制 + 用户/角色 CRUD 与角色分配。 - 📡 **通知中心**:系统通知扫描、未读计数、单条/全部已读标记;后台扫描循环自动生成告警通知。 - 📢 **公告管理**:系统公告发布与查阅,支持按用户维度推送与已读标记。 - ⚙️ **系统管理**:系统配置热更新(无需重启)、Prometheus 指标导出、OpenAPI 规范自描述、健康检查与就绪探针。 - 📡 **VCI 事件 WebSocket**:统一事件与命令确认通道,支持 Dashboard 长连接实时消费。 ## 快速开始 ### 前置依赖 `api-server` 是一个二进制服务,**必须**依赖以下运行时基础设施: - **PostgreSQL**(必需):存储 CDR、资源、账户、配置等所有持久化数据,由 `call-core::cdr_store` 提供 `PostgresCdrStore`。 - **Redis**(必需):JWT 黑名单、活跃通话缓存、限流等热数据存储。 - **NATS**(可选):实时事件总线,未配置时自动降级为 `None`。 - **sip-edge**(可选):VoIP 软交换信令边缘节点,提供集群管理与通话控制 HTTP 接口;单节点模式下回退到 `manage_bind` 地址。 ### 编译 ```bash cargo build --release ``` 生成的二进制位于 `target/release/api-server`。 > **企业版特性**:默认编译为社区版基线(`default = []`)。`enterprise` feature 聚合 `enterprise-ivr` / `enterprise-acd` / `enterprise-copilot` / `enterprise-ai-voice`,也可以按需启用独立能力: > > ```bash > cargo build --release --features enterprise # 全量企业版(IVR / ACD / Copilot / AI Voice) > cargo build --release --features enterprise-acd # 仅 ACD > cargo build --release --features enterprise-ai-voice # 仅 AI 模型/语音管理 > ``` > > 只要任一企业能力 feature 启用,`GET /api/v1/site-info` 的 `edition` 就返回 `enterprise`; > `enterprise-ai-voice` 不会开放 Copilot Agent,会话和 Agent runtime 仍只属于 `enterprise-copilot`。 ### 配置文件 `api-server` 通过环境变量 `VOS_RS_CONFIG_FILE` 指定 YAML 配置文件路径(默认 `config.yaml`): ```yaml # config.yaml api_server: network: host: "0.0.0.0" port: 8080 allowed_origins: "https://console.example.com,http://tauri.localhost,tauri://localhost" security: jwt_secret: "your-strong-jwt-secret" internal_secret: "your-internal-secret" connections: database: host: "127.0.0.1" port: 5432 username: "vos" password: "vos-pass" database: "vos_rs" max_connections: 20 redis: host: "127.0.0.1" port: 6379 password: "" database: 0 nats: url: "nats://127.0.0.1:4222" sip_edge: auth: realm: "vos-rs" network: manage_bind: "127.0.0.1:8082" cluster: enabled: false node_key_prefix: "vos_rs:cluster:sip_nodes" management_url: "http://127.0.0.1:8082" ``` ### 启动 ```bash VOS_RS_CONFIG_FILE=config.yaml ./target/release/api-server ``` 或通过环境变量覆盖关键配置: | 环境变量 | 说明 | 默认值 | | --- | --- | --- | | `VOS_RS_CONFIG_FILE` | 配置文件路径 | `config.yaml` | | `VOS_RS_API_HOST` | 监听地址(覆盖配置文件) | `127.0.0.1` | | `VOS_RS_API_JWT_SECRET` | JWT 签名密钥(覆盖配置文件) | 内置弱密钥(仅开发) | | `VOS_RS_SOFTPHONE_SIP_SERVER` | 桌面软电话信令地址;`sip(s)` 走 Rust SIP,`ws(s)` 走 WebRTC/SIP.js;无 scheme 自动按 SIP | `sip://127.0.0.1:5060`(仅开发) | | `VOS_RS_INTERNAL_SECRET` | 内部服务调用密钥 | `internal-dev-secret` | | `VOS_RS_ENV` | 设为 `production` 强制启用生产模式密钥校验 | — | | `VOS_RS_BOOTSTRAP_ADMIN_PASSWORD` | 首次启动引导管理员密码 | 内置默认 | | `VOS_COPILOT_PROJECT_ROOTS` | **(enterprise-copilot)** vos-rs* 各仓绝对路径列表;macOS/Linux 用 `:`,Windows 用 `;` 分隔。空或未配置时 `/copilot` 仍然可用,但文档 RAG/阶段查询会给出"未配置"友好提示 | 空(空索引) | | `VOS_COPILOT_BUILD_STATE` | **(enterprise-copilot)** 部署流水线写入的 `build-state.json` 绝对路径;`vos_build_status` 读不到时自动回退到 env 变量/Cargo profile | `./build-state.json` | > **生产警告**:当绑定地址非 loopback 或 `VOS_RS_ENV=production` 时,服务会强制校验 `jwt_secret` 与 `internal_secret` 不为弱默认值,启动失败并报错。 ## API 概览 `api-server` 对外仅提供当前版本化管理接口(`/api/v1/*`)。SIP、媒体、录音、CDR 和呼叫控制的 `X-VOS-Token` 服务间端点属于内部协议,不是租户 API。 登录后的桌面端必须调用受保护的 `GET /api/v1/auth/softphone-config` 获取独立软电话凭据, 然后按 `server` 的 scheme 完成真实 REGISTER。数据库只保存 SIP Digest HA1,明文密码只在 本次 HTTPS 响应中返回,不复用控制台 Argon2 密码,也不会放入回调 URL 或日志。 ### 公开端点(无需鉴权) | 方法 | 路径 | 说明 | | --- | --- | --- | | `GET` | `/health` | 存活探针(Liveness);同时返回 API、SIP、媒体、录音、呼叫控制、数据库、消息队列和按 feature 启用的 IVR/ACD/AI 服务状态 | | `GET` | `/ready` | 就绪探针(Readiness) | | `GET` | `/metrics` | Prometheus 指标 | | `GET` | `/api/v1/openapi.json` | OpenAPI 规范 JSON | | `GET` | `/api/v1/scalar` | Scalar 全量 API 文档页面 | | `GET` | `/api/v1/capabilities` | 平台能力清单(enterprise / ivr / acd / copilot / anti_fraud / ai_voice / ai,由编译期 Cargo feature 派生,供前端动态渲染菜单) | | `POST` | `/api/v1/auth/sessions` | 版本化登录 | | `POST` | `/api/v1/auth/sso/start` | 创建桌面端 SSO 状态 | | `GET` | `/api/v1/auth/sso/status` | 查询桌面端 SSO 是否已完成网页确认 | | `POST` | `/api/v1/auth/sso/exchange` | 兑换桌面端 SSO 会话 | ### 受保护端点(需 Bearer JWT) 以下端点均要求 `Authorization: Bearer ` 头。 桌面端 SSO 授权和软电话注册接口: | 方法 | 路径 | 说明 | | --- | --- | --- | | `POST` | `/api/v1/auth/sso/authorize` | Web 控制台用户确认桌面端授权 | | `GET` | `/api/v1/auth/softphone-config` | 获取 SIP 配置并由桌面端完成 REGISTER | 完整的 SSO 时序、请求/响应样例、错误处理和部署要求见 [`docs/SSO.md`](docs/SSO.md)。 客户端项目地址与桌面端运行、协议分流和本地记录说明见 [`vos-rs-softphone-desktop`](https://gitee.com/vos-rs/vos-rs-softphone-desktop) 项目 README。 > `GET /api/v1/openapi.json` 是完整的 OpenAPI 3.1 机器可读接口契约,而非仅用于打开 Scalar 的占位文件。服务在导出前会用 `utoipa::openapi::OpenApi` 校验 feature-gated 文档结构,再保留原始 3.1 扩展字段返回;每个操作都包含用途、认证、路径/查询参数、请求体和响应模型,Scalar 直接渲染同一份契约。接口是否出现始终以当前运行制品实际启用的 Cargo feature 为准。 `GET /health` 的企业能力检查也按同一 feature 契约执行:`enterprise-copilot` 会同时校验 Copilot 会话、共享 AI 模型、下载任务、音色、Prompt 和 Agent 表;`enterprise-ai-voice` 还会继续检查 至少一套可用的 ASR/TTS 模型。这样模型下载表或共享 AI 表迁移不完整时,健康页面会显示降级, 而不是等到模型中心或 Agent 首次调用才暴露数据库缺表。 无需启动数据库和 Redis 也可以导出当前编译 feature 对应的同一份契约: ```bash VOS_RS_PRINT_OPENAPI=1 cargo run --features enterprise --bin api-server > openapi.json VOS_RS_OPENAPI_FILE=/absolute/path/to/openapi.json npm run test:api-contract ``` > > OpenAPI 契约只收录当前 `/api/v1/*` 接口;已移除的旧版 `/api/*` 入口不会继续提供服务或出现在 Scalar 中。 #### 概览与仪表盘 - `GET /api/v1/overview/summary` / `trends` / `node-traffic` / `monitoring-extras` / `events` #### 资源管理(Subscriber / Interconnect / Routing) - 注册:`GET /api/v1/registrations` - 号码:`GET|POST /api/v1/numbers`、`PUT|DELETE /api/v1/numbers/:number`、批量导入 `/import` - 网关(Trunk):`GET|POST /api/v1/trunks`、`GET|PUT|DELETE /api/v1/trunks/:id` - 路由规则:`GET|POST /api/v1/routing/rules`、`PUT|DELETE /api/v1/routing/rules/:id`、路由仿真 `/routing/simulations` #### IVR 与 ACD 管理(企业版,按 capabilities 条件注册) - IVR 菜单:`GET|POST /api/v1/ivr/menus`、`GET|PUT|DELETE /api/v1/ivr/menus/:id` - IVR 提示音:`GET /api/v1/ivr/prompts`、`POST /api/v1/ivr/prompts/upload`、`GET|DELETE /api/v1/ivr/prompts/:filename` - ACD 队列:`GET|POST /api/v1/acd/queues`、`GET|PUT|DELETE /api/v1/acd/queues/:id`、队列-坐席关联 `/api/v1/acd/queues/:id/agents`(`GET|POST`)、`DELETE /api/v1/acd/queues/:id/agents/:agent_id` - ACD 坐席:`GET|POST /api/v1/acd/agents`、`GET|PUT|DELETE /api/v1/acd/agents/:id` #### AI 模型与语音管理(企业版,按 `capabilities.ai` 条件注册) - 模型:`GET|POST /api/v1/ai/models`、`GET|PUT|DELETE /api/v1/ai/models/:id`、`POST /api/v1/ai/models/:id/test` - 离线模型目录:`GET|POST /api/v1/ai/models/catalog`、`PUT|DELETE /api/v1/ai/models/catalog/:id`;下载任务:`POST /api/v1/ai/models/downloads`、`GET /api/v1/ai/models/downloads/events`(SSE)、`GET|DELETE /api/v1/ai/models/downloads/:id` - 音色:`GET|POST /api/v1/ai/voices`、`GET|PUT|DELETE /api/v1/ai/voices/:id`、`POST /api/v1/ai/voices/:id/preview` - Prompt:`GET|POST /api/v1/ai/prompts`、`GET|PUT|DELETE /api/v1/ai/prompts/:id`、`POST /api/v1/ai/prompts/:id/dry-run` - Agent:`GET|POST /api/v1/ai/agents`、`GET|PUT|DELETE /api/v1/ai/agents/:id`、`POST /api/v1/ai/agents/:id/test`(仅 `capabilities.copilot=true`;AI Voice-only 只提供模型/音色/Prompt 管理) #### 落地策略(Termination) - IP 规则、落地端点、出站策略:`/api/v1/trunks/:id/ip-rules`、`/egress-endpoints`、`/outbound-policy` - 号码归属与分配:`/api/v1/numbers/:number/owner`、`/allocations`、`/did-destination` - 主叫池(Caller Pool):`GET|POST /api/v1/caller-pools`、`GET|PUT|DELETE /api/v1/caller-pools/:id`、成员管理 `/members` - 落地分组(Egress Group):`GET|POST /api/v1/egress-groups`、`GET|PUT|DELETE /api/v1/egress-groups/:id`、成员管理 `/members` - 出站策略:`GET /api/v1/outbound-policies`、`GET|PUT|DELETE /api/v1/outbound-policies/:source_type/:source_id` - DID 目的地:`GET|POST /api/v1/did-destinations`、`PUT|DELETE /api/v1/did-destinations/:number` #### 通话与报表 - 通话列表 / 详情 / 媒体 / DTMF / SIP 流程:`GET /api/v1/calls`、`/calls/:call_id`、`/media`、`/dtmf`、`/sipflow` - 活跃通话:`GET /api/v1/calls/active` - 通话与媒体动作:统一通过 `POST /api/v1/vci/commands` 提交 VCI 命令信封;支持 `originate`(可先振铃 `agent_extension` 再桥接外部号码)、挂断、播放/停止播放、静音、监听、录音、DTMF、转接、排队、实时 AI 和媒体重协商等动作。异步命令可通过 `GET /api/v1/vci/commands/{command_id}` 查询最终回执;旧版 `/actions/*` 路径不属于当前 API 契约。 - 录音回放:`GET /api/v1/calls/:call_id/recording`(支持 HTTP Range) - 报表:`GET /api/v1/reports/summary`、`/api/v1/reports/export`(CSV 导出) #### 计费 - 接入账户:`GET|POST /api/v1/billing/access-accounts`、`PUT|DELETE /:id`、`POST /:id/credit` - 落地账户:`GET|POST /api/v1/billing/egress-accounts`、`PUT|DELETE /:id`、`POST /:id/credit` - 流水:`GET /api/v1/billing/credits`、`GET /api/v1/billing/transactions` #### 安全 - 反欺诈策略:`GET|POST /api/v1/security/anti-fraud/policies`、`PUT|DELETE /:id` - 反欺诈设置:`GET /api/v1/security/anti-fraud/settings`、`PUT /api/v1/security/anti-fraud/settings/:key` - 审计日志:`GET /api/v1/security/audit-logs` #### Copilot AI 运维(企业版) - 对话:`POST /api/v1/copilot/chat`(无 feature 时路由不注册) - 会话管理:`GET|POST /api/v1/copilot/sessions`、`GET|PUT|DELETE /sessions/:id`、`POST /sessions/:id/chat`、`/chat/stream`(SSE 流式) - 安全审批:`GET /sessions/:id/actions`、`POST /actions/:action_id/approve`、`/reject` - Copilot 文本模型:`GET /api/v1/copilot/text-models`(返回模型中心中已启用的 `LLM_TEXT` 模型) - **ProjectInsight / 项目文档 RAG(v0.1.0 新增,无需新增 HTTP 接口)**: - 通过 4 只 LLM 工具暴露能力:`vos_project_rag_search`、`vos_project_overview`、`vos_feature_status_query`、`vos_build_status` - 启动一次性构建索引,后续 `/chat` / `/chat/stream` 请求中 LLM 按需调用;不增加独立 REST 端点,不引入外部 crate。 - 启用方法:设置 `VOS_COPILOT_PROJECT_ROOTS`(必选,11 仓绝对路径)和 `VOS_COPILOT_BUILD_STATE`(可选)后重启;详细配置见 vos-rs-enterprise `docs/copilot-project-rag.md`。 #### 基础设施 - 系统配置:`GET|POST /api/v1/infrastructure/settings` - 媒体集群:`GET|PUT /api/v1/infrastructure/media-cluster` - SIP 集群:`GET /api/v1/infrastructure/sip-cluster`、`POST /sip-cluster/nodes/:node_id/:action` - 媒体指标:`GET /api/v1/infrastructure/media/metrics` - CDR 管线指标:`GET /api/v1/infrastructure/cdr/metrics`(队列、spool 重放与不可恢复丢弃) #### 访问控制(RBAC) - 用户:`POST /api/v1/access-control/users`、`PUT|DELETE /users/:username` - 角色:`POST /api/v1/access-control/roles`、`PUT|DELETE /roles/:role_key` - 角色分配:`PUT /api/v1/access-control/roles/user-assignments` - 权限替换:`PUT /api/v1/access-control/roles/:role_key/permissions` - 菜单:`PUT /api/v1/access-control/menus/:item_key` #### 租户 - `GET|POST /api/v1/tenants`、`GET|PUT|DELETE /api/v1/tenants/:id`、`POST /api/v1/tenants/:id/enabled` #### 通知与公告 - 通知:`GET /api/v1/notifications`、`/unread-count`、`POST /read-all`、`/scan`、`/:id/read` - 公告:`GET|POST /api/v1/announcements`、`/:id/publish`、`GET|PUT|DELETE /:id`、`GET /my-announcements`、`POST /my-announcements/:id/read` #### 实时通道 - `GET /api/v1/vci/events/ws`:VCI 统一事件 WebSocket,Dashboard 实时事件与命令确认流 ## 模块结构 ``` src/ ├── main.rs # 应用入口、AppState、路由总装、启动流程 ├── config.rs # YAML 配置加载(ApiServerConfig) ├── access_control.rs # RBAC 初始化与访问控制概览 ├── announcements.rs # 公告发布与查阅 ├── dashboard.rs # 仪表盘统计、趋势、事件流、活跃通话缓存 ├── details.rs # 资源详情聚合查询 ├── error.rs # ApiError 统一错误类型 ├── helpers.rs # 通用工具:分页、日期解析、密钥校验、日志过滤 ├── import.rs # 号码/路由批量导入与模板下载 ├── middleware.rs # jwt_auth / audit_log 中间件 ├── notifications.rs # 通知中心与后台扫描循环 ├── rwi_ws.rs # VCI 统一事件 WebSocket 通道 ├── v1/ # 版本化管理 API │ ├── mod.rs # v1 路由组装、Capabilities 能力发现与 Copilot 入口分发 │ ├── response.rs # 统一响应契约中间件 │ └── routes.rs # 按业务域分组的 v1 路由定义 ├── billing/ # 计费:账户、流水、反欺诈、CDR、报表 │ ├── accounts/ # 接入账户与落地账户 CRUD/充值 │ ├── anti_fraud.rs # 反欺诈规则与配置、深度伪造日志 │ ├── cdr.rs # CDR 查询与 DTMF 事件 │ ├── operations.rs # 账户流水查询 │ └── report.rs # 报表汇总与 CSV 导出 ├── cluster/ # 集群管理 │ ├── calls/ # 活跃通话、强制拆线、SIP 流程、媒体指标 │ ├── media_cluster.rs # 媒体集群配置 │ └── sip_cluster.rs # SIP 集群状态与节点控制 ├── copilot/ # ai-copilot 企业 crate 的状态、身份与 HTTP 路由适配层 ├── integration/ # 无 feature 时的 Copilot stub ├── recording/ # 录音回放与本地归档同步 ├── resources/ # 资源管理:网关、号码、注册、路由、租户、IVR、ACD、集成凭据 ├── system/ # 系统管理 │ ├── metrics/ # Prometheus 指标、RTCP、快照 │ ├── audit.rs # 审计日志查询 │ ├── auth.rs # JWT 登录与会话 │ ├── config_reload.rs # 配置热更新 │ ├── hot_cache.rs # 热缓存 │ ├── permissions.rs # 权限模型 │ ├── system.rs # 系统配置、健康检查、OpenAPI │ └── utils.rs # 系统工具 └── termination/ # 落地策略:DID、分组、池、号码、策略、Trunk ``` ## 配置说明 ### 数据库配置(`connections.database`) | 字段 | 类型 | 说明 | | --- | --- | --- | | `host` | string | PostgreSQL 主机 | | `port` | u16 | 端口 | | `username` / `password` | string | 账号密码(密码为空时省略) | | `database` | string | 数据库名 | | `max_connections` | u32 | 连接池上限,默认 `10` | ### Redis 配置(`connections.redis`) 必需。提供 `host` / `port` / `password` / `database`,未配置完整时回退到 `redis://127.0.0.1:6379`。 ### NATS 配置(`connections.nats`) 可选。`url` 为空时降级为 `None`,实时事件功能不可用但服务正常启动。 ### 录音存储 录音后端由 `call-core::storage` 提供,运行时从数据库 `storage_backend` / `recording_dir` 系统配置读取: - `local`:本地文件系统,录音保存在 `recording_dir`。 - 对象存储(如 S3 兼容):录音先写本地,后台每 15 秒同步归档到对象存储并清理本地。 回放端点支持 HTTP `Range` 请求,可分段拉取大录音文件。 ### SIP 集群配置(`sip_edge.cluster`) - `enabled: false`(单节点):`sip_manage_base` 回退到 `sip_edge.network.manage_bind`,避免误配 `management_url` 死端口导致 `/calls/active` 等转发接口 502。 - `enabled: true`(集群):优先使用 `management_url`,未配置时回退到 `manage_bind`。 - `node_key_prefix`:Redis 中 SIP 节点状态键前缀,默认 `vos_rs:cluster:sip_nodes`。 ## 许可证 Apache-2.0。详见 [LICENSE](LICENSE)。