Files
lisglosips/SOFTSWITCH_PLATFORM_DESIGN_V2.md
T

42 KiB
Raw Blame History

LisgloSIPS V2 项目设计与实施文档

中文名:聆界SIP管理平台
文档版本:V2.0
编制日期:2026-06-20
文档状态:实施基线草案
依据:服务器架构图、SOFTSWITCH_PLATFORM_DESIGN_V1.md、当前 React Web Demo、OPENSIPS_INSTALL_NOTES.md

1. 文档目的

V2 的目标是把当前纯前端原型转化为可部署、可联调、可上线的软交换运营平台。本文不仅描述产品功能,还给出服务器部署、软件安装、后端代码、OpenSIPS/RTPEngine 对接、数据库、Redis、录音迁移、测试和上线方案。

本文作为下一阶段执行基线,后续数据库 DDL、OpenAPI、OpenSIPS 脚本和部署脚本应从本文拆分并版本化管理。

2. V2 范围

2.1 本期实施页面

以下菜单已在 Web Demo 中完成交互设计,纳入 V2 后端和联调范围:

菜单 V2 实施内容
概览 Dashboard 通话、接通率、消费、成本、毛利、注册、节点、异常网关、质检指标
客户管理 客户新增、编辑、启停、余额、授信、充值、网关数量
客户网关管理 IP/SIP 注册认证、启停、多个策略、优先级、主被叫匹配、线路组绑定
充值记录 客户充值、供应商充值、余额前后值、操作人、备注
供应商管理 供应商账户、余额、授信、充值
落地网关管理 认证、并发、CPS、禁呼时段、编码、号码转换、计费周期、费率、启停
落地线路组 线路组、组内网关、优先级、并发汇总
话单中心 话单查询、挂断原因、费用、录音、信令入口、详情
质检中心 抽检规则、录音列表、连续播放、自动播放、问题标注、评分
用户管理 用户新增、编辑、启停、重置密码、角色绑定
角色与权限 角色、权限矩阵、角色用户数、内置角色保护
操作日志 条件查询、结果、详情、导出

2.2 延期页面

以下菜单在 Web Demo 中标记为“待设计”,本期不开发其业务页面:

  • 费率与计费
  • SIP 运维
  • 监控告警
  • 系统设置

说明:页面延期不代表底层能力完全取消。V2 仍需实现:

  • 最小计费引擎,用于生成话单客户费用、成本费用并更新余额。
  • Prometheus/Grafana 基础设施监控,但不接入自研“监控告警”页面。
  • OpenSIPS/RTPEngine 配置文件和环境变量管理,但不开放自研“系统设置”页面。
  • HOMER 信令查询入口,但不开发自研“SIP 运维”页面。

2.3 明确不做

  • 客户自助门户。
  • 多 OpenSIPS 节点和通话级高可用。
  • 完整账单、发票、对账和复杂费率管理页面。
  • 自研可视化 SIP Trace、监控告警和系统配置页面。
  • Kubernetes。双机阶段使用 systemd、Nginx 和 Docker Compose 的有限组合。

3. 总体架构

3.1 服务器规划

环境分为两个阶段:

  • 当前开发阶段:A、B、T 均为本地 KVM 虚拟机,通过 Tailscale 专网联调。
  • 开发完成后:将 A、B 部署到阿里云,按下表建立 VPC、公网入口和安全组;T 保留为外部 SIP 测试端。

下表为最终阿里云生产目标,不代表当前本地开发机已经位于阿里云:

服务器 规格 定位 公网暴露
Server A 阿里云计算型 4C8G 核心通信网关 SIP 15060/UDP、RTP UDP 端口段
Server B 阿里云通用型 4C16G 业务、缓存、数据库、录音、监控中心 443/TCP,可选 80/TCP 跳转 HTTPS

两台服务器必须位于同一 VPC、同一可用区或低时延可用区,使用私网 IP 通信。目标私网 RTT 小于 1 ms。

本地开发阶段的实测网络、端口矩阵和未来阿里云安全组清单见 docs/infra-check.md

3.2 逻辑拓扑

flowchart LR
    UA["客户 SIP / 上游线路"] -->|"SIP 15060/UDP"| OS["Server A: OpenSIPS"]
    UA <-->|"RTP UDP 端口段"| RTP["Server A: RTPEngine"]
    OS <-->|"call-time Redis 查询"| REDIS["Server B: Redis"]
    OS -->|"Redis Stream: CDR"| REDIS
    OS -->|"HEP/9060 私网"| HEP["Server B: Heplify-server + HOMER"]
    RTP --> TMP["Server A: /dev/shm/voip_rec"]
    WORKER["Server B: Recording Worker"] -->|"私网拉取 ready 文件"| TMP
    WORKER --> SSD["Server B: 录音数据盘"]
    API["Server B: LisgloSIPS API"] --> MYSQL["Server B: MySQL"]
    API --> REDIS
    CDRW["Server B: CDR/Billing Worker"] --> REDIS
    CDRW --> MYSQL
    WEB["React Web + Nginx"] --> API
    EXPORTER["Server A: Exporters"] --> PROM["Server B: Prometheus + Grafana"]

3.3 Server A 职责

  • OpenSIPS:SIP 鉴权、客户识别、策略匹配、路由、Dialog/CDR 事件。
  • RTPEngine:媒体锚定、NAT 穿透、双向录音、内核态转发。
  • /dev/shm/voip_rec3 GiB tmpfs 录音缓冲区。
  • HEP 发送端:向 Server B 发送信令镜像。
  • Node Exporter 和自定义 textfile 指标。
  • Fail2ban、nftables、OpenSIPS pike/ratelimit 防护。

“无状态”定义为不在 Server A 持久化业务主数据。OpenSIPS 运行时仍会维护事务和 Dialog 内存状态,服务重启会影响现有通话,V2 单节点接受此限制。

3.4 Server B 职责

  • Nginx、React 静态资源、HTTPS 和 API 反向代理。
  • LisgloSIPS API、CDR Worker、Recording Worker、Config Publisher。
  • Redis:呼叫热数据、配置版本、锁、Redis Streams。
  • MySQL:业务主数据、充值流水、话单、质检、权限、审计。
  • 录音数据盘:保存迁移后的录音文件。
  • Heplify-server、HOMER UI 及其独立存储。
  • Prometheus、Grafana 及必要 exporters。

4. 架构图必须修正的两点

4.1 RTP 端口不能只开放 SIP 端口

架构图写明 Server A 公网仅暴露 15060/UDP,这不足以完成 RTP 媒体通信。若 RTPEngine 负责公网媒体锚定,安全组和主机防火墙还必须开放 RTPEngine 配置的 UDP 端口范围,例如:

SIP: 15060/UDP
RTP: 30000-40000/UDP

端口范围应根据并发测算缩小,并尽量限制来源运营商或客户 IP 段。若上游 RTP 来源不可预知,需要保留公网 UDP 范围并强化速率限制和监控。

4.2 CDR 使用 Redis Stream

架构图中的 queue:cdr_payload 不应实现为无法确认消费的普通 Redis List。V2 使用 Redis Stream

stream:cdr_payload
consumer group: billing-workers

要求支持:

  • 消息 ID 和业务幂等键。
  • XREADGROUP 消费。
  • MySQL 提交成功后 XACK
  • Pending 消息重领。
  • 死信 Stream。
  • Redis 暂时不可用时 Server A 本地受限缓冲或告警降级。

5. 技术栈与下载清单

5.1 版本原则

  • 服务器统一 Ubuntu 24.04 LTS。
  • OpenSIPS 使用项目已验证的 3.6.x 分支。
  • 其他软件选择受支持稳定版,禁止部署时无条件升级“最新版”。
  • 所有版本写入 versions.env、部署脚本或容器镜像标签。
  • 先在预生产执行安装、通话和性能验证,再用于生产。

5.2 Server A 软件

软件 用途 安装来源
OpenSIPS 3.6.x SIP 核心 https://apt.opensips.org/
opensips-cli 管理与检查 OpenSIPS APT
OpenSIPS Redis/HTTP/JSON 模块 Redis 热路径、MI、事件 OpenSIPS APT
RTPEngine daemon + kernel module RTP 转发与录音 https://github.com/sipwise/rtpengine
Heplify client 或 OpenSIPS tracer/HEP 信令镜像 https://github.com/sipcapture/heplify
Node Exporter 主机指标 https://prometheus.io/docs/guides/node-exporter/
Fail2ban、nftables 主机防护 Ubuntu APT
chrony 时间同步 Ubuntu APT

建议 OpenSIPS 包:

opensips
opensips-cli
opensips-redis-module
opensips-http-modules
opensips-json-module
opensips-tls-module
opensips-auth-modules
opensips-mysql-dbschema

实际包名以 OpenSIPS 3.6 Ubuntu 24.04 仓库为准,安装脚本执行前用 apt-cache search opensips 校验。

5.3 Server B 软件

软件 用途 安装来源
Node.js LTS API 和 Worker https://nodejs.org/en/about/previous-releases
pnpm Node.js 包管理 Corepack
Nginx Web、HTTPS、反向代理 https://nginx.org/en/linux_packages.html
Redis 热数据与 Streams https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/
MySQL 业务持久化 https://dev.mysql.com/downloads/repo/apt/
Heplify-server + HOMER UI 信令接收和排障 https://github.com/sipcapture/heplify-server
Prometheus 指标存储 https://prometheus.io/docs/prometheus/latest/installation/
Grafana 监控大盘 https://grafana.com/docs/grafana/latest/setup-grafana/installation/debian/
mysqld_exporter、redis_exporter 数据库与缓存指标 Prometheus Community
Docker Engine/Compose 仅用于 HOMER 组合服务 https://docs.docker.com/engine/install/ubuntu/
ffmpeg 录音格式校验与转换 Ubuntu APT

HOMER 数据与业务 MySQL 必须逻辑隔离。优先使用 HOMER 官方 Compose 所要求的数据库,不把 HEP 海量信令写入业务库。

6. 网络、安全组和端口

6.1 Server A 入站

端口 来源 说明
15060/UDP 客户/供应商允许列表 SIP
30000-40000/UDP RTP 对端或允许网段 RTPEngine 媒体,最终按容量调整
<SSH_ADMIN_PORT>/TCP 堡垒机或管理 VPN SSH 管理端口,不对全网开放;保留密钥登录

6.2 Server B 入站

端口 来源 说明
443/TCP 管理端用户 LisgloSIPS HTTPS
80/TCP 可选 跳转 HTTPS,不承载登录
9060/UDP Server A 私网 IP HEP
<SSH_ADMIN_PORT>/TCP 堡垒机或管理 VPN SSH 管理端口;保留密钥登录

Redis 6379、MySQL 3306、Prometheus 9090、Grafana 3000、应用端口、HOMER 内部端口不得直接暴露公网。Redis 和 MySQL至少绑定私网 IP,并通过安全组仅允许明确来源;同机服务优先使用 127.0.0.1

6.3 安全要求

  • 全部服务器启用 chrony,CDR、HOMER 和审计日志时间必须一致。
  • Web 强制 HTTPS、HSTS、SameSite Cookie 和 CSRF 防护。
  • 管理员密码使用 Argon2id;不记录明文密码。
  • SIP 注册密码按 OpenSIPS Digest 需要保存 HA1 或受控密文,不直接返回前端。
  • MI HTTP 只绑定 Server A 127.0.0.1
  • 所有生产 Secret 放入权限为 0600 的环境文件或云 Secret 服务。
  • 操作日志不得记录密码、完整 Authorization、Cookie、录音签名 URL。

7. 基础环境部署

7.1 阿里云资源

  1. 创建 VPC 和私有子网。
  2. 创建 Server A 4C8G 计算型实例和 Server B 4C16G 通用型实例。
  3. Server B 挂载独立 ESSD 数据盘,业务数据库、录音和监控数据使用独立目录或分区。
  4. 配置安全组、EIP、DNS 和快照策略。
  5. 建议先创建同规格预生产环境,至少在上线前保留 3 天完整演练时间。

7.2 两台服务器通用初始化

sudo apt update && sudo apt full-upgrade -y
sudo apt install -y curl wget ca-certificates gnupg jq git unzip chrony \
  nftables fail2ban vim htop iotop sysstat lsof net-tools tcpdump
sudo timedatectl set-timezone Asia/Shanghai
sudo systemctl enable --now chrony nftables fail2ban

生产环境推荐系统内部统一存 UTC,前端按 Asia/Shanghai 展示;若操作系统使用上海时区,数据库字段仍需明确 UTC 语义。

7.3 Server A tmpfs

sudo mkdir -p /dev/shm/voip_rec
sudo chown rtpengine:rtpengine /dev/shm/voip_rec
sudo chmod 0750 /dev/shm/voip_rec

/etc/fstab

tmpfs /dev/shm/voip_rec tmpfs rw,nosuid,nodev,noexec,size=3G,mode=0750 0 0

3 GiB 缓冲不是长期存储。按双向 G.711 原始音频约 16 KiB/s 粗略估算,只能容纳约 53 个“并发小时”,未计算容器和文件头开销。100 路持续录音时缓冲可能不到 35 分钟。Recording Worker 建议 5-15 秒扫描一次,使用量超过 70% 告警,超过 85% 时停止接受新的非强制录音或触发紧急迁移。

7.4 Server B 数据盘目录

/data/mysql
/data/redis
/data/recordings/YYYY/MM/DD
/data/prometheus
/data/grafana
/data/homer
/data/backups

数据盘挂载参数、文件系统和 IOPS 规格需根据压测结果确认。录音目录和 MySQL 不建议共享同一个容易打满的根分区。

8. OpenSIPS 与 RTPEngine 实施

8.1 OpenSIPS 呼叫路径

INVITE
  -> 基础合法性与防扫描检查
  -> IP 或 SIP Digest 认证
  -> Redis 查询客户、客户网关、状态、余额门槛
  -> Redis 查询客户网关策略(主叫条件 AND 被叫条件,按优先级)
  -> 获得落地线路组
  -> 按组内优先级、启用状态、并发/CPS 选择落地网关
  -> 执行主被叫前缀转换、时段和编码限制
  -> RTPEngine offer/answer
  -> 转发到供应商
  -> BYE/失败时生成标准化 CDR 事件

8.2 呼叫前原子检查

Redis Lua 脚本一次完成:

  • 客户是否启用。
  • 客户网关是否启用。
  • IP/账号是否匹配。
  • 余额加授信是否大于最小通话门槛。
  • 网关 CPS 和并发是否超限。
  • 黑名单是否命中。
  • 返回配置版本、线路组和路由策略。

金额禁止使用 Redis 浮点数,统一使用整数“微元”或其他固定精度最小单位。

8.3 RTPEngine

  • 使用内核转发模块并在启动时校验。
  • 控制接口只在本机或私网监听。
  • RTP 端口段与安全组保持一致。
  • 录音先写 .part,完成后原子重命名为 .ready
  • 文件名包含日期、Call-ID 哈希和方向,禁止直接拼接未清洗 SIP Header。

8.4 CDR 标准事件

{
  "event_id": "uuid",
  "idempotency_key": "call_id + ended_at 或 event_id",
  "call_id": "sip-call-id",
  "node_id": "a1",
  "opensips_instance": "opensips-a1",
  "ingress_a_ip": "100.90.90.90",
  "rtpengine_node": "a1",
  "customer_id": "C1001",
  "customer_gateway_id": "CGW-001",
  "source_ip": "10.10.1.11",
  "caller": "02160010001",
  "callee": "13800138000",
  "vendor_id": "V1001",
  "vendor_gateway_id": "VGW-001",
  "line_group_id": "LG-001",
  "started_at": "2026-06-20T02:14:22.123Z",
  "answered_at": "2026-06-20T02:14:27.010Z",
  "ended_at": "2026-06-20T02:17:30.445Z",
  "duration_sec": 183,
  "sip_code": 200,
  "hangup_reason": "NORMAL_CLEARING",
  "recording_key": "2026/06/20/xxx.ready",
  "config_version": 1042
}

event_idcall_id + ended_at 作为幂等依据。任何重试不得重复扣费或重复写充值/余额流水。

9. Redis 设计

9.1 Key 规范

cfg:active_version
cfg:customer:{customer_id}
cfg:customer_gateway:{gateway_id}
cfg:customer_gateway:{gateway_id}:policies
cfg:vendor_gateway:{gateway_id}
cfg:line_group:{group_id}:items
auth:ip:{ip}
auth:sip:{username}
balance:customer:{customer_id}
blacklist:caller
blacklist:callee
stream:cdr_payload
stream:cdr_deadletter
stream:recording_jobs
lock:cdr:{event_id}

9.2 配置发布

  1. API 在 MySQL 事务中写业务表和 outbox_events
  2. Config Publisher 读取 outbox,生成完整配置快照。
  3. 使用临时版本 Key 写入 Redis。
  4. 校验数量和哈希后原子切换 cfg:active_version
  5. 发布成功后更新 outbox 状态。
  6. 保留上一个版本,故障时一键回滚。

禁止 API 先改 Redis、后改 MySQL。MySQL 是唯一业务事实源,Redis 是呼叫热路径副本。

9.3 Redis 持久化

  • 启用 AOF appendfsync everysec
  • 配置 RDB 快照。
  • 限制 maxmemory,配置前评估淘汰策略;核心配置和队列不得被随机淘汰。
  • 监控 Stream 长度、Pending 数、消费延迟、内存和连接数。

10. MySQL 数据模型

10.1 业务核心表

customers
customer_gateways
customer_gateway_policies
customer_recharges
vendors
vendor_recharges
vendor_gateways
vendor_gateway_forbidden_periods
vendor_gateway_codecs
vendor_gateway_prefix_rules
landing_line_groups
landing_line_group_items
raw_cdrs
rated_cdrs
recordings
quality_sampling_rules
quality_reviews
users
roles
permissions
user_roles
role_permissions
audit_logs
outbox_events
idempotency_keys

10.2 关键约束

  • ID 使用业务前缀 + 雪花 ID/UUID,禁止依赖前端生成。
  • 金额使用 DECIMAL(20,6),应用层不得使用 JavaScript 浮点直接计算金额。
  • 充值使用不可变流水,余额变化必须与流水在同一事务提交。
  • 网关策略唯一索引至少包含 gateway_id + priority
  • 线路组成员唯一索引包含 line_group_id + vendor_gateway_id
  • CDR 使用 event_id 唯一索引。
  • 所有管理表包含 created_atupdated_atcreated_byupdated_by 和乐观锁版本号。
  • 时间存 UTCAPI 返回 ISO 8601。
  • 删除优先软删除;充值、CDR、审计日志不允许物理删除。

10.3 余额事务

充值事务:

锁定客户/供应商账户行
  -> 读取充值前余额
  -> 插入充值流水
  -> 更新余额
  -> 插入审计日志/Outbox
  -> 提交

CDR 扣费事务:

检查 event_id 幂等
  -> 写 raw_cdr
  -> 计算最小计费结果
  -> 写 rated_cdr
  -> 锁定客户余额
  -> 扣费并写余额流水
  -> ACK Redis Stream

11. 后端工程设计

11.1 技术选型

  • TypeScript + Node.js LTS。
  • NestJS + Fastify Adapter。
  • Prisma 管理 MySQL Schema 和迁移。
  • ioredis 访问 Redis 和 Streams。
  • OpenAPI/Swagger 生成 API 契约。
  • Pino 输出结构化 JSON 日志。
  • Vitest/Jest 做单元测试,Supertest 做 API 集成测试。
  • systemd 管理 API 和 WorkerHOMER 可使用 Docker Compose。

11.2 推荐目录

lisglosips/
├── apps/
│   ├── web/
│   ├── api/
│   ├── worker-cdr/
│   ├── worker-recording/
│   └── worker-config-publisher/
├── packages/
│   ├── contracts/
│   ├── domain/
│   ├── database/
│   ├── redis/
│   ├── auth/
│   └── observability/
├── prisma/
│   ├── schema.prisma
│   └── migrations/
├── deploy/
│   ├── server-a/
│   ├── server-b/
│   ├── nginx/
│   ├── systemd/
│   └── homer/
├── opensips/
│   ├── opensips.cfg
│   ├── routes/
│   └── scripts/
├── docs/
│   ├── openapi.yaml
│   ├── redis-keys.md
│   └── runbooks/
└── tests/

11.3 后端模块

AuthModule
DashboardModule
CustomersModule
CustomerGatewaysModule
CustomerGatewayPoliciesModule
RechargesModule
VendorsModule
VendorGatewaysModule
LandingLineGroupsModule
CdrModule
RecordingsModule
QualityModule
UsersModule
RolesModule
AuditModule
ConfigPublisherModule
HealthModule

11.4 API 清单

POST   /api/v2/auth/login
POST   /api/v2/auth/refresh
POST   /api/v2/auth/logout
GET    /api/v2/dashboard/summary
GET    /api/v2/dashboard/trends

GET    /api/v2/customers
POST   /api/v2/customers
PATCH  /api/v2/customers/:id
POST   /api/v2/customers/:id/recharges

GET    /api/v2/customer-gateways
POST   /api/v2/customer-gateways
PATCH  /api/v2/customer-gateways/:id
POST   /api/v2/customer-gateways/:id/enable
POST   /api/v2/customer-gateways/:id/disable
GET    /api/v2/customer-gateways/:id/policies
POST   /api/v2/customer-gateways/:id/policies
PATCH  /api/v2/customer-gateway-policies/:id
DELETE /api/v2/customer-gateway-policies/:id
POST   /api/v2/customer-gateways/:id/policies/reorder

GET    /api/v2/vendors
POST   /api/v2/vendors
PATCH  /api/v2/vendors/:id
POST   /api/v2/vendors/:id/recharges
GET    /api/v2/recharges

GET    /api/v2/vendor-gateways
POST   /api/v2/vendor-gateways
PATCH  /api/v2/vendor-gateways/:id
POST   /api/v2/vendor-gateways/:id/enable
POST   /api/v2/vendor-gateways/:id/disable

GET    /api/v2/landing-line-groups
POST   /api/v2/landing-line-groups
PATCH  /api/v2/landing-line-groups/:id
POST   /api/v2/landing-line-groups/:id/items
DELETE /api/v2/landing-line-groups/:id/items/:gatewayId
POST   /api/v2/landing-line-groups/:id/items/reorder

GET    /api/v2/cdrs
GET    /api/v2/cdrs/:id
GET    /api/v2/cdrs/:id/recording
GET    /api/v2/cdrs/:id/signaling-link

GET    /api/v2/quality/rules
POST   /api/v2/quality/rules
PATCH  /api/v2/quality/rules/:id
DELETE /api/v2/quality/rules/:id
POST   /api/v2/quality/rules/:id/enable
POST   /api/v2/quality/rules/:id/disable
GET    /api/v2/recordings
GET    /api/v2/recordings/:id
PUT    /api/v2/recordings/:id/review

GET    /api/v2/users
POST   /api/v2/users
PATCH  /api/v2/users/:id
POST   /api/v2/users/:id/reset-password
GET    /api/v2/roles
POST   /api/v2/roles
PATCH  /api/v2/roles/:id
PUT    /api/v2/roles/:id/permissions
GET    /api/v2/audit-logs
GET    /api/v2/audit-logs/:id

11.5 API 规范

  • 列表统一 pagepage_sizesort、筛选参数。
  • 返回 { data, meta, request_id }
  • 错误返回稳定业务码,不把数据库错误直接返回前端。
  • 新增、充值、重置密码、策略重排支持 Idempotency-Key
  • 写请求校验 If-Match 或版本字段,防止覆盖其他管理员修改。
  • 导出采用异步任务和短期下载地址,避免长请求占用 5 Mbps 公网带宽。

12. 录音迁移和质检

12.1 文件生命周期

RTPEngine 写入 .part
  -> 录音完成原子改名 .ready
  -> Recording Worker 私网扫描
  -> 拉取到 Server B 临时目录
  -> 校验大小、SHA-256、音频时长
  -> 原子移动到 /data/recordings/YYYY/MM/DD
  -> 写 recordings 表
  -> 删除 Server A 源文件

任何一步失败都不得先删除 Server A 文件。Worker 使用文件锁或 Redis 锁防止重复搬运,并对 .part、过期 .ready、孤儿文件分别处理。

12.2 播放

  • API 先校验 recording.play 权限。
  • Nginx X-Accel-Redirect 发送文件,Node.js 不直接读取整段音频到内存。
  • 支持 HTTP Range,便于拖动播放。
  • 操作日志记录播放人、录音 ID、时间和 IP。
  • Server B 公网只有 5 Mbps 时需限制并发播放;后续可迁移至阿里云 OSS,使用短期签名 URL。

12.3 抽检规则

V2 字段与 Web Demo 保持一致:

  • 规则名称。
  • 客户。
  • 抽检比例。
  • 指定线路。
  • 生效时间。
  • 状态。

Worker 在录音入库后根据客户、线路和稳定哈希进行抽样,避免重启导致随机结果变化。

13. 权限与审计

13.1 权限模型

权限粒度采用 resource.action

customers.view
customers.manage
vendors.view
vendors.manage
gateways.view
gateways.manage
routes.view
routes.manage
recharge.manage
cdr.view
cdr.export
recording.play
quality.manage
users.manage
roles.manage
logs.view

超级管理员、运营管理员、财务、质检和技术运维为内置角色。内置角色名称和关键权限禁止普通管理员修改。

13.2 审计要求

审计日志至少记录:

  • request_id、操作人、用户账号、角色。
  • 时间、IP、User-Agent。
  • 模块、动作、对象类型、对象 ID。
  • 修改前/后摘要,敏感字段脱敏。
  • 成功/失败和业务错误码。

审计日志由服务端生成,前端传入的“操作人”不可信。

14. Dashboard 数据策略

  • 实时在线通话和注册:Redis 热数据或 OpenSIPS 指标。
  • 今日通话、费用、成本、毛利:MySQL 聚合表。
  • 24 小时趋势:按 5 分钟或 1 小时预聚合,禁止首页扫描全量 CDR。
  • 失败响应码:CDR 聚合。
  • 异常网关:健康状态缓存。
  • 质检待处理:recordings/quality_reviews 聚合。

创建定时聚合任务 worker-metrics 或复用 CDR Worker 增量写统计表。

15. 最小计费实现

虽然“费率与计费”页面延期,V2 仍需最小计费能力支持话单费用和余额。

V2 首期仅支持落地网关上的:

  • 计费周期,单位秒,最大 60。
  • 周期费率。
  • 分钟费率展示值:周期费率 * 60 / 计费周期

计算使用 Decimal

计费周期数 = ceil(通话秒数 / 计费周期)
费用 = 计费周期数 * 周期费率

客户侧费率在完整页面设计前可由受控配置表或迁移脚本维护,不对普通运营角色开放。所有费率变更必须留审计记录和生效时间。

16. 监控、日志和备份

16.1 基础监控

即使自研“监控告警”页面延期,也必须部署:

  • Server A/B CPU、内存、磁盘、网络、负载。
  • OpenSIPS 进程、SIP 请求量、响应码、活动 Dialog。
  • RTPEngine 会话、丢包、端口使用率。
  • tmpfs 使用率和最老录音文件年龄。
  • Redis 内存、连接、Stream 长度、Pending。
  • MySQL 连接、慢查询、锁等待、磁盘。
  • API P95/P99、5xx、Worker 延迟。

16.2 日志

  • 应用日志输出 JSON,包含 request_idcall_idevent_id
  • journald 保留短期日志;可选 Loki/Promtail 后续集中化。
  • 禁止在普通日志输出 SIP 密码、Web Token 和录音内容。

16.3 备份

  • MySQL:每日全量备份 + binlog,定期恢复演练。
  • RedisAOF + RDBRedis 不是业务主数据唯一副本。
  • 录音:数据盘快照,后续转 OSS 生命周期管理。
  • OpenSIPS、Nginx、systemd、Prometheus 配置进入 Git。
  • 备份密钥与业务数据分开保存。

17. 开发与部署阶段

阶段 0:确认技术决策(2-3 天)

  • 确认 SIP 公网端口、RTP 端口段和运营商 IP 范围。
  • 确认预估并发、CPS、日通话量、日录音小时数。
  • 确认客户余额实时控制规则和最低余额门槛。
  • 确认录音保存周期和是否接 OSS。
  • 确认 MySQL 还是 MariaDB。本文默认 MySQL;若沿用现有 MariaDB,需先验证 Prisma 和 SQL 兼容性。

阶段 1:服务器和网络(3-4 天)

  • 创建 VPC、Server A/B、EIP、数据盘和安全组。
  • 安装基础工具、时间同步、防火墙。
  • 验证私网 RTT、带宽、磁盘吞吐和 DNS。
  • 输出 infra-check.md 和端口验收结果。

阶段 2Server A 通信栈(5-7 天)

  • 安装 OpenSIPS 3.6.x、RTPEngine 和内核模块。
  • 配置 SIP 15060、RTP 端口范围和 MI 本地端口。
  • 配置 Redis 连接、HEP、录音 tmpfs、指标和安全限制。
  • 完成 IP 认证、SIP 注册认证和基础呼叫。
  • 完成单通、双通、挂断、失败响应和录音测试。

阶段 3Server B 基础服务(4-5 天)

  • 安装 Nginx、Node.js、Redis、MySQL。
  • 部署 HOMER、Prometheus、Grafana 和 exporters。
  • 初始化数据盘、备份目录和 TLS。
  • 创建应用系统用户、systemd 服务账户和最小权限目录。

阶段 4:后端骨架(5 天)

  • 初始化 monorepo、NestJS、Prisma、OpenAPI、日志和健康检查。
  • 完成认证、JWT 刷新、RBAC、审计拦截器。
  • 建立数据库迁移、种子数据和 CI。
  • 完成 Redis 客户端、Stream 基础库和 outbox publisher。

阶段 5:运营业务 API(10-12 天)

  • 客户、客户网关、策略、充值。
  • 供应商、落地网关、落地线路组。
  • 用户、角色、权限、操作日志。
  • 接入当前 React Demo,移除 Mock 数据。

阶段 6:通话、CDR 和录音闭环(8-10 天)

  • Redis 配置发布和回滚。
  • OpenSIPS 呼叫时查询和路由。
  • CDR Stream、幂等消费、最小计费、余额扣减。
  • Recording Worker、文件校验、Range 播放。
  • HOMER Call-ID 跳转。

阶段 7Dashboard 和质检(5-7 天)

  • Dashboard 聚合指标。
  • 抽检规则、录音列表、连续播放、质检结果。
  • 权限校验和播放审计。

阶段 8:测试和上线(7-10 天)

  • 功能、集成、故障、性能、安全测试。
  • 全量上线演练和回滚演练。
  • 小流量客户灰度。
  • 观察 24-72 小时后扩大流量。

预计总周期 8-10 周,建议至少配置:后端 1 人、SIP/媒体 1 人、前端 1 人、运维 0.5 人、测试 0.5 人。单人实施需要相应延长周期并优先保证呼叫、CDR、余额和录音闭环。

18. 后端代码完成标准

  • 所有本期页面均使用真实 API,不再依赖硬编码 Mock。
  • OpenAPI 可生成前端类型或 API Client。
  • 数据库迁移可在空库一键执行,也能回滚最近一次变更。
  • 关键服务有 /health/live/health/ready
  • CDR 重复投递不会重复扣费。
  • 充值重复请求不会重复加余额。
  • 配置发布失败不会留下半套 Redis 配置。
  • 录音搬运失败不会删除源文件。
  • RBAC 在服务端生效,隐藏按钮不能替代权限校验。
  • 敏感操作全部进入审计日志。
  • 单元测试覆盖金额、优先级、主被叫条件、幂等和权限。

19. 测试与验收

19.1 功能验收

  • IP 和 SIP 注册两种客户网关认证成功/失败路径。
  • 主叫等于、主叫前缀、被叫等于、被叫前缀及组合条件。
  • 多策略优先级和多落地网关优先级。
  • 网关启停、禁呼时段、编码、号码前缀转换。
  • 充值、余额前后值、授信和审计。
  • CDR 字段、挂断原因、客户费用、成本费用。
  • 抽检规则、录音播放、上下条、自动播放、保存质检结果。
  • 用户、角色、权限和重置密码。

19.2 性能验收

压测目标必须在阶段 0 根据业务量确认。最低应覆盖:

  • 目标 CPS 的 1.5 倍持续 30 分钟。
  • 目标并发的 1.2 倍持续 2 小时。
  • Redis 呼叫时查询 P99。
  • CDR Worker 堆积恢复速度。
  • 100% 录音下 tmpfs 增长和迁移速度。
  • 多用户同时查询 CDR 和播放录音时 Server B 带宽。

19.3 故障验收

  • Redis 短暂不可用。
  • MySQL 重启和事务回滚。
  • CDR Worker 异常退出后重领 Pending。
  • Recording Worker 重复执行。
  • Server B 数据盘接近满。
  • Server A tmpfs 达 70%/85%。
  • RTPEngine 重启。
  • 配置版本回滚。

19.4 安全验收

  • SIP 扫描、暴力注册、非法来源 IP、超 CPS。
  • 越权访问其他模块 API。
  • 重放充值请求。
  • SQL 注入、XSS、CSRF、弱密码和 Session 失效。
  • 录音 URL 过期、Range 越权和路径穿越。

20. 上线和回滚

20.1 上线顺序

  1. 备份 MySQL、Redis、OpenSIPS 和 Nginx 配置。
  2. 部署 Server B 数据库迁移和后端,但暂不切流。
  3. 发布 Redis 配置快照并校验。
  4. 部署 Server A OpenSIPS/RTPEngine 配置。
  5. 使用测试账号完成真实呼叫、CDR、扣费和录音。
  6. 灰度一个低风险客户或一条线路。
  7. 观察指标、CDR 差异、余额和录音完整性。
  8. 逐步扩大流量。

20.2 回滚

  • Web/API:切回上一个发布目录或镜像。
  • 数据库:使用向前兼容迁移;上线窗口不执行不可逆删列。
  • Redis 配置:切回上一个 cfg:active_version
  • OpenSIPS:恢复上一版配置并执行语法检查后重载。
  • RTPEngine:恢复上一版 systemd 参数。
  • CDR:停止 Consumer,不删除 Stream;修复后重放。
  • 录音:停止删除 Server A 源文件,保留 B 端临时文件等待人工处理。

21. 主要风险

风险 影响 控制措施
Server A 单点 重启影响通话 V2 接受;配置快速恢复;后续增加双节点
仅开放 15060 无 RTP 或单通 必须开放并验证 RTP UDP 端口段
3 GiB tmpfs 打满 录音丢失、进程异常 高频搬运、阈值告警、降级策略
Server B 5 Mbps 多录音播放卡顿 Range、限并发、后续 OSS/CDN
Redis 成为呼叫热路径单点 新呼叫失败 AOF/RDB、监控、后续主从/Sentinel
CDR 重复消费 重复扣费 Stream ACK、唯一索引、幂等事务
配置半发布 路由不一致 MySQL Outbox + Redis 版本原子切换
HOMER 数据膨胀 数据盘占满 独立存储、保留周期、容量告警
金额浮点误差 对账差异 Decimal/整数最小单位,禁止 JS Number 计费

22. 下一步执行清单

立即执行

  • 确认预计 CPS、并发、日话单、录音小时数。
  • 确认 Server A RTP 端口段和安全组来源范围。
  • 确认 Server B 数据盘容量、IOPS 和录音保留期。
  • 确认 MySQL/MariaDB 最终选择。
  • 申请域名和 TLS 证书。
  • 创建预生产 VPC 和两台服务器。

服务器部署完成条件

  • Server A OpenSIPS、RTPEngine、Redis 私网连接、HEP、tmpfs、exporter 正常。
  • Server B Nginx、Node.js、Redis、MySQL、HOMER、Prometheus、Grafana 正常。
  • 安全组端口和主机防火墙验收。
  • 备份、日志轮转、时间同步和系统用户验收。
  • 完成端到端测试呼叫并在 HOMER 查询到信令。
  • 完成录音从 A 内存盘到 B 数据盘的搬运测试。

后端开发启动条件

  • 创建 V2 monorepo 和 CI。
  • 提交 Prisma Schema V1 和初始化迁移。
  • 提交 OpenAPI V2 基线。
  • 提交 Redis Key 和 Stream 契约。
  • 完成 Auth/RBAC/Audit 骨架。
  • 先实现客户、网关、线路组和配置发布,再实现 CDR/录音。

23. V2 交付物

1. 阿里云双机部署记录和安全组清单
2. Server A/Server B 幂等安装脚本
3. OpenSIPS 和 RTPEngine 配置仓库
4. MySQL DDL/Prisma migrations
5. Redis Key/Stream 契约
6. OpenAPI 文档
7. LisgloSIPS API 和 Workers 源码
8. React Web 与真实 API 集成版本
9. Prometheus/Grafana/HOMER 部署配置
10. 自动化测试、压测报告和安全检查报告
11. 上线、回滚、备份恢复和故障处置 Runbook

24. 最终实施原则

  • 先打通“配置发布 -> 呼叫 -> CDR -> 计费 -> 余额 -> 录音 -> 质检”闭环,再扩展页面。
  • MySQL 是业务事实源,Redis 是呼叫热路径和队列,不反向替代主库。
  • 金额、CDR、充值和录音全部按可重试、可审计、幂等设计。
  • Server A 保持精简,Server B 承担业务复杂度。
  • 待设计菜单不阻塞底层必需能力,但不得在 V2 临时扩张为未确认的产品页面。
  • 所有部署和配置必须脚本化、版本化、可回滚。

25. Codex 全流程分步实施规范

25.1 目的

本项目计划主要由 Codex 持续实施。为避免单次任务过大、上下文丢失、误操作和新会话重复工作,整个 V2 被拆分为 31 个原子任务 S00-S30。每个会话默认只完成一个任务,除非用户明确授权合并。

详细实时状态记录在 IMPLEMENTATION_STATUS.md,服务器密码只保存在被 .gitignore 排除的 .codex-private/SERVER_ACCESS.md

25.2 服务器固定代号

代号 IP SSH 用户 职责
Server A 100.90.90.90 hector 核心通信网关
Server B 100.90.90.91 hector 业务、缓存与监控中心
Server T 100.93.185.30 hector 已安装 OpenSIPS,模拟 SIP 客户

主文档不保存明文密码。新会话只有在用户授权当前任务连接服务器后,才读取私密访问文件,并禁止在回复或日志中回显密码。

25.3 单会话执行纪律

  1. 先读取 SOFTSWITCH_PLATFORM_DESIGN_V2.mdIMPLEMENTATION_STATUS.md
  2. 只执行状态文件中的“当前任务”。
  3. 服务器任务先做只读检查,再做写操作。
  4. 修改配置前备份,记录绝对路径、时间戳和回滚命令。
  5. 服务重启、防火墙、SSH、数据库迁移、数据删除前说明影响。
  6. 不能因安装困难随意更换技术栈或扩大公网端口。
  7. 安装软件必须记录来源、版本和校验结果。
  8. 完成后执行该任务的验收,不以“命令无报错”代替功能验证。
  9. 更新状态文件后再结束会话。
  10. 出现阻塞时停止在安全状态,不绕过安全控制继续后续任务。

25.4 原子任务顺序

S00-S02:安全接入和资产盘点

S00 SSH 安全接入与凭据迁移

  • 用户明确授权后连接 A/B/T。
  • 在本机生成项目专用 Ed25519 Key,不覆盖现有 Key。
  • 安装公钥并验证三个独立新会话。
  • 备份 sshd_config,确认不会锁死后只调整 SSH 管理端口,不禁止 SSH 密钥登录。
  • 轮换当前密码,私密文件同步更新或改为只记录 Key。
  • 验收:新端口 Key 登录成功;sudo 可用;现有会话保留到新会话验证完成。

S01 三机只读资产盘点

  • 只读取 OS、内核、CPU、内存、磁盘、网卡、路由、时间、端口、服务、包版本。
  • 盘点 T 上现有 OpenSIPS 配置和测试能力,不修改。
  • 输出 docs/inventory-A.mdinventory-B.mdinventory-T.md
  • 验收:报告包含差异、风险和安装前备份清单。

S02 网络与安全组验收

  • 验证 A/B/T 双向可达性和实际私网 RTT。
  • 确认 A 的 SIP 15060/UDP、RTP 端口段;B 的 443/TCP、私网 HEP 9060/UDP。
  • 不通过 SSH 直接修改云安全组;生成阿里云控制台操作清单供用户确认。
  • 验收:形成端口矩阵和最小暴露方案。

S03-S06Server B 基础设施

S03 Server B 基础系统初始化

  • 更新系统、安装基础包、chrony、nftables、fail2ban。
  • 检查并初始化数据盘目录,不格式化未知数据盘。
  • 创建应用、录音和监控系统用户与目录权限。
  • 验收:重启后时间、挂载、权限和防火墙正常。

S04 MySQL 与 Redis

  • 固定版本安装并限制监听地址。
  • 创建业务库/用户,启用 MySQL binlog、Redis AOF/RDB。
  • 配置备份脚本和健康检查。
  • 验收:重启恢复、权限隔离、备份和恢复样例通过。

S05 Node.js、Nginx 与 TLS 基线

  • 安装固定 Node.js LTS 和 pnpm。
  • 建立 /opt/lisglosips/releasescurrent 和 systemd 模板。
  • 配置 Nginx 静态站点、API 代理、Range、限流和 HTTPS 预案。
  • 验收:占位健康页通过 Nginx 访问,应用端口不暴露公网。

S06 HOMER 与基础监控

  • 部署 Heplify-server/HOMER、Prometheus、Grafana、exporters。
  • HOMER 数据和业务 MySQL 分离。
  • 验收:B 私网 9060 接收测试 HEP;A/B 主机指标可见。

S07-S10:后端基础

S07 后端 Monorepo 骨架

  • 创建 NestJS/Fastify、Prisma、结构化日志、配置校验、健康检查和测试框架。
  • 建立 CI 命令:lint、typecheck、test、build。
  • 验收:本地和 B 均可构建;健康检查可用。

S08 数据库 Schema 与迁移

  • 实现本文第 10 章表结构、索引、Decimal、审计列和 Outbox。
  • 提供空库迁移、种子和回滚/恢复说明。
  • 验收:空库一键初始化;重复执行安全;Schema 测试通过。

S09 登录认证基础

  • 登录、刷新、退出、Argon2id、失败锁定、Token/Cookie 安全。
  • 验收:成功、失败、过期、刷新、注销和暴力尝试路径通过。

S10 用户、角色、权限与审计

  • 实现用户、角色、权限矩阵、内置角色保护和重置密码。
  • 服务端 RBAC 和审计拦截器必须先于业务 API 完成。
  • 验收:越权被拒绝;敏感字段脱敏;审计详情可查询。

S11-S17:运营业务 API

S11 客户管理:客户 CRUD、启停、余额/授信读取。
S12 充值流水:客户/供应商充值、事务、幂等、并发。
S13 客户网关:IP/SIP 注册认证、启停、密码安全。
S14 网关策略与配置发布:主被叫条件、优先级、Outbox、Redis 版本。
S15 供应商管理:供应商 CRUD、余额、授信。
S16 落地网关:认证、CPS、并发、禁呼、编码、号码转换、周期费率。
S17 落地线路组:成员增删、优先级、并发汇总、引用校验。

每个任务必须同时完成:数据库迁移、领域校验、API、权限、审计、单元测试、集成测试和 OpenAPI,不允许先堆积未测试接口后统一补测。

S18-S21:通信栈和测试客户

S18 Server A OpenSIPS 基线

  • 先备份现状,再安装/固定 OpenSIPS 3.6.x。
  • 配置 15060、认证、防扫描、MI 本地绑定和模块基线。
  • 每次改动先执行语法检查,验证失败立即回滚。

S19 RTPEngine 与录音 tmpfs

  • 配置内核转发、RTP 端口段、3 GiB tmpfs 和 .part -> .ready 生命周期。
  • 验收:双向音频、NAT、录音、重启和 tmpfs 阈值。

S20 Redis 热路径、HEP 与指标

  • 实现 Lua 原子检查、版本化配置读取、CDR XADD、HEP 发送和指标采集。
  • 验收:Redis 超时、配置缺失、HEP 中断均有明确降级和日志。

S21 Server T 客户模拟

  • 在不破坏 T 现有 OpenSIPS 的前提下配置测试域、IP 认证和 SIP 注册账号。
  • 编写成功呼叫、忙、拒绝、超时、错误密码、超 CPS 测试脚本。
  • 验收:所有脚本可重复执行并输出 Call-ID。

S22-S26:异步闭环

S22 CDR Redis Stream:事件契约、Consumer Group、ACK、Pending、死信、幂等。
S23 最小计费:Decimal 周期计费、客户费用、成本、余额扣减。
S24 录音搬运与播放:私网拉取、哈希、原子移动、Range、权限和源文件删除保护。
S25 质检后端:规则、稳定抽样、连续录音查询、质检保存和审计。
S26 Dashboard 聚合:实时指标和预聚合趋势,避免扫描全量 CDR。

S27-S30:联调和上线

S27 React 接入真实 API

  • 按菜单逐页替换 Mock;每次只接入一个领域。
  • 增加加载、空状态、错误、权限隐藏和并发更新提示。
  • 待设计菜单继续保留标识,不接临时 API。

S28 三机端到端联调

  • T 发起 SIP -> A 鉴权/路由/媒体/录音 -> B CDR/费用/信令/质检。
  • 按 Call-ID 核对 OpenSIPS、Redis Stream、MySQL、HOMER 和录音文件。

S29 性能、故障与安全测试

  • 执行 CPS、并发、录音、Redis/MySQL/Worker 故障和 Web/SIP 安全测试。
  • 所有失败必须形成缺陷、修复和复测记录。

S30 备份、Runbook、灰度与上线

  • 完成恢复演练、上线/回滚脚本和灰度。
  • 上线前冻结版本和数据库迁移,输出最终验收报告。

25.5 Codex 新会话启动模板

请先读取 SOFTSWITCH_PLATFORM_DESIGN_V2.md 和 IMPLEMENTATION_STATUS.md
只执行当前任务 Sxx,不提前执行下一任务。
如任务需要服务器访问,读取 .codex-private/SERVER_ACCESS.md,但不要在回复、日志或文档中回显密码。
所有服务器写操作先备份并给出回滚点;涉及重启、SSH、防火墙、数据库迁移或删除时先说明影响。
完成后执行验收并更新 IMPLEMENTATION_STATUS.md,包括状态、产物、验证、回滚、遗留问题和下一任务。