feat: add number library routing and cdr location support
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# LisgloSIPS V2 项目设计与实施文档
|
||||
|
||||
> 中文名:聆界SIP管理平台
|
||||
> 文档版本:V2.0
|
||||
> 文档版本:V2.2
|
||||
> 编制日期:2026-06-20
|
||||
> 文档状态:实施基线草案
|
||||
> 文档状态:S30 后二期需求变更持续补充
|
||||
> 依据:服务器架构图、`SOFTSWITCH_PLATFORM_DESIGN_V1.md`、当前 React Web Demo、`OPENSIPS_INSTALL_NOTES.md`
|
||||
|
||||
## 1. 文档目的
|
||||
@@ -21,12 +21,14 @@ V2 的目标是把当前纯前端原型转化为可部署、可联调、可上
|
||||
| 菜单 | V2 实施内容 |
|
||||
| --- | --- |
|
||||
| 概览 Dashboard | 通话、接通率、消费、成本、毛利、注册、节点、异常网关、质检指标 |
|
||||
| 客户管理 | 客户新增、编辑、启停、余额、授信、充值、网关数量 |
|
||||
| 客户网关管理 | IP/SIP 注册认证、启停、多个策略、优先级、主被叫匹配、线路组绑定 |
|
||||
| 充值记录 | 客户充值、供应商充值、余额前后值、操作人、备注 |
|
||||
| 供应商管理 | 供应商账户、余额、授信、充值 |
|
||||
| 落地网关管理 | 认证、并发、CPS、禁呼时段、编码、号码转换、计费周期、费率、启停 |
|
||||
| 落地线路组 | 线路组、组内网关、优先级、并发汇总 |
|
||||
| 客户管理 | 客户新增、编辑、启停、余额、授信、充值、网关数量、受控删除 |
|
||||
| 客户网关管理 | IP/SIP 注册认证、启停、删除、多个策略、优先级、主被叫匹配、线路组绑定 |
|
||||
| 充值记录 | 客户充值、供应商充值、余额前后值、操作人、备注;仅记录页面人工充值,不记录话单消费扣费 |
|
||||
| 供应商管理 | 供应商账户、余额、授信、充值、落地网关数量、受控删除 |
|
||||
| 落地网关管理 | 认证、并发、CPS、禁呼时段、编码、号码转换、计费周期、费率、启停、删除 |
|
||||
| 落地线路组 | 线路组、组内网关、优先级、并发汇总、使用客户网关数量、受控删除 |
|
||||
| 号码库 | 手机号码库、城市区号、运营商号码段规则;为话单归属地/运营商和落地网关屏蔽地区提供基础数据 |
|
||||
| 当前通话 | OpenSIPS Dialog 实时列表、呼叫方 IP、落地 IP、自动刷新、强制挂断 |
|
||||
| 话单中心 | 话单查询、挂断原因、费用、录音、信令入口、详情 |
|
||||
| 质检中心 | 抽检规则、录音列表、连续播放、自动播放、问题标注、评分 |
|
||||
| 用户管理 | 用户新增、编辑、启停、重置密码、角色绑定 |
|
||||
@@ -35,7 +37,7 @@ V2 的目标是把当前纯前端原型转化为可部署、可联调、可上
|
||||
|
||||
### 2.2 延期页面
|
||||
|
||||
以下菜单在 Web Demo 中标记为“待设计”,本期不开发其业务页面:
|
||||
以下菜单在 Web Demo 中曾标记为“待设计”,S30 后二期变更要求在导航中隐藏,不向运营用户展示入口:
|
||||
|
||||
- 费率与计费
|
||||
- SIP 运维
|
||||
@@ -299,7 +301,8 @@ INVITE
|
||||
-> Redis 查询客户、客户网关、状态、余额门槛
|
||||
-> Redis 查询客户网关策略(主叫条件 AND 被叫条件,按优先级)
|
||||
-> 获得落地线路组
|
||||
-> 按组内优先级、启用状态、并发/CPS 选择落地网关
|
||||
-> 识别被叫号码归属地级市和运营商
|
||||
-> 按组内优先级、启用状态、并发/CPS、屏蔽地区选择落地网关
|
||||
-> 执行主被叫前缀转换、时段和编码限制
|
||||
-> RTPEngine offer/answer
|
||||
-> 转发到供应商
|
||||
@@ -344,6 +347,10 @@ Redis Lua 脚本一次完成:
|
||||
"source_ip": "10.10.1.11",
|
||||
"caller": "02160010001",
|
||||
"callee": "13800138000",
|
||||
"callee_city_code": "310000",
|
||||
"callee_city_name": "上海",
|
||||
"callee_province_name": "上海",
|
||||
"callee_operator": "MOBILE",
|
||||
"vendor_id": "V1001",
|
||||
"vendor_gateway_id": "VGW-001",
|
||||
"line_group_id": "LG-001",
|
||||
@@ -412,11 +419,15 @@ customer_recharges
|
||||
vendors
|
||||
vendor_recharges
|
||||
vendor_gateways
|
||||
vendor_gateway_blocked_regions
|
||||
vendor_gateway_forbidden_periods
|
||||
vendor_gateway_codecs
|
||||
vendor_gateway_prefix_rules
|
||||
landing_line_groups
|
||||
landing_line_group_items
|
||||
geo_cities
|
||||
phone_number_segments
|
||||
carrier_prefix_rules
|
||||
raw_cdrs
|
||||
rated_cdrs
|
||||
recordings
|
||||
@@ -440,6 +451,7 @@ idempotency_keys
|
||||
- 网关策略唯一索引至少包含 `gateway_id + priority`。
|
||||
- 线路组成员唯一索引包含 `line_group_id + vendor_gateway_id`。
|
||||
- CDR 使用 `event_id` 唯一索引。
|
||||
- CDR 需要保存被叫号码解析出的地级市、省份和运营商快照,避免后续号码库更新影响历史话单解释。
|
||||
- 所有管理表包含 `created_at`、`updated_at`、`created_by`、`updated_by` 和乐观锁版本号。
|
||||
- 时间存 UTC;API 返回 ISO 8601。
|
||||
- 删除优先软删除;充值、CDR、审计日志不允许物理删除。
|
||||
@@ -1135,7 +1147,7 @@ V2 首期仅支持落地网关上的:
|
||||
|
||||
- 按菜单逐页替换 Mock;每次只接入一个领域。
|
||||
- 增加加载、空状态、错误、权限隐藏和并发更新提示。
|
||||
- 待设计菜单继续保留标识,不接临时 API。
|
||||
- 待设计菜单不接临时 API;S30 后二期变更要求导航中隐藏这些入口。
|
||||
|
||||
**S28 三机端到端联调**
|
||||
|
||||
@@ -1152,7 +1164,267 @@ V2 首期仅支持落地网关上的:
|
||||
- 完成恢复演练、上线/回滚脚本和灰度。
|
||||
- 上线前冻结版本和数据库迁移,输出最终验收报告。
|
||||
|
||||
### 25.5 Codex 新会话启动模板
|
||||
### 25.5 S30 后二期需求变更
|
||||
|
||||
S30 完成本地 KVM A/B/T 闭环后,用户基于实际试用继续提出二期变更。二期变更不重做 S00-S30 基线,按“在既有架构上最小增量、可验证、可回滚”的原则落地。当前本地冻结基线仍为 `s28-v2-20260621220924`,B 当前运行 release 为 `s33-active-calls-20260623094000`,多次二期前端/API/通信配置小改覆盖在该 release 上。阿里云迁移仍不得自动开始,迁移前必须按 S30 Runbook 重新演练。
|
||||
|
||||
#### 25.5.1 登录与验证码
|
||||
|
||||
- 登录页必须使用后端图形验证码,验证码刷新失败时应有明确错误提示,登录失败后必须刷新验证码。
|
||||
- 登录防爆破、Session/Refresh Token、Cookie 安全配置仍归属 S09/S10 安全基线。
|
||||
- 禁止在文档、日志或页面中输出明文密码;初始账号、服务器凭据只允许通过私密目录和受控流程读取。
|
||||
|
||||
#### 25.5.2 当前通话与强制挂断
|
||||
|
||||
新增“当前通话”能力,定位为实时运维视图,不作为 CDR 或计费真相源。
|
||||
|
||||
- Web 在“业务”菜单下提供“当前通话”页面,展示 OpenSIPS 当前 Dialog 列表。
|
||||
- B API 提供:
|
||||
- `GET /api/v2/active-calls`
|
||||
- `POST /api/v2/active-calls/:id/hangup`
|
||||
- 权限新增:
|
||||
- `active_calls.view`
|
||||
- `active_calls.manage`
|
||||
- 超级管理员具备查看和挂断权限;技术运维具备查看和挂断权限;运营管理员默认仅查看。
|
||||
- API 通过 B 上的受限 SSH key 调用 A 上的 forced-command `/usr/local/sbin/lisglosips-call-control`,只允许 `dlg_list` 和 `dlg_end_dlg`。OpenSIPS MI HTTP 仍只绑定 `127.0.0.1:8888`。
|
||||
- 当前通话列表字段至少包括:
|
||||
- Dialog ID / Call-ID
|
||||
- 主叫、被叫
|
||||
- 呼叫方 IP
|
||||
- 落地 IP
|
||||
- 状态、开始时间、持续时长
|
||||
- 强制挂断操作
|
||||
- 呼叫方 IP 和落地 IP 的解析优先级为 SIP Contact、SDP `c=IN IP4/IP6`、SIP URI、bind 地址兜底。生产上若落地网关不提供 Contact 或 SDP 连接地址,落地 IP 可能退回为 OpenSIPS 本地地址;后续可在路由侧写入 Dialog 变量提高精度。
|
||||
- 强制挂断必须弹出自研确认弹窗;操作必须进入 RBAC 和审计。
|
||||
- OpenSIPS `dlg_end_dlg` 可能返回 `500 Operation failed`,但 Dialog 进入 state `5` 并随后清空时,API 可按“已受理/处理中”处理。
|
||||
- 当前通话页面默认支持 5 秒自动刷新,并保留手动刷新。
|
||||
|
||||
#### 25.5.3 列表计数、删除和启停确认
|
||||
|
||||
二期增加删除能力时,优先使用软删除和引用保护,不允许破坏热路径配置一致性。
|
||||
|
||||
- 客户管理:
|
||||
- 列表显示客户网关数。
|
||||
- 删除客户前必须确认。
|
||||
- 若客户关联客户网关数大于 0,则拒绝删除。
|
||||
- 客户网关管理:
|
||||
- 支持删除,删除前必须确认。
|
||||
- 删除客户网关时,其关联路由策略应同步停止生效或软删除,并发布配置 Outbox。
|
||||
- 启用/禁用前必须确认。
|
||||
- 供应商管理:
|
||||
- 列表显示落地网关数。
|
||||
- 删除供应商前必须确认。
|
||||
- 若供应商关联落地网关数大于 0,则拒绝删除。
|
||||
- 落地网关管理:
|
||||
- 支持删除,删除前必须确认。
|
||||
- 启用/禁用前必须确认。
|
||||
- 若落地网关仍被未删除落地线路组引用,默认拒绝删除,避免线路组热配置引用已删除网关。若未来要支持自动从线路组移除,需单独设计成员优先级重排和配置发布语义。
|
||||
- 落地线路组:
|
||||
- 列表显示正在使用该线路组的去重客户网关数。
|
||||
- 删除线路组前必须确认。
|
||||
- 若有客户网关策略正在使用该线路组,则拒绝删除。
|
||||
- 所有删除按钮使用红色警示态;所有确认弹窗使用自研 UI,不再使用浏览器原生 `window.confirm`。
|
||||
|
||||
#### 25.5.4 充值记录与计费流水语义
|
||||
|
||||
充值记录页面只展示人工充值,不承载话单消费扣费记录。
|
||||
|
||||
- 页面人工充值写入 `customer_recharges` / `vendor_recharges` 或等价充值流水。
|
||||
- CDR Worker 的话单消费扣费只写 raw/rated CDR 和余额扣减结果,不再写客户充值记录。
|
||||
- 充值记录 API 需要过滤历史由 `worker-cdr`、`cdr:`、`CDR_CHARGE:` 等来源产生的消费类流水,避免在“充值记录”中混入话单扣费。
|
||||
- Web 充值成功后只局部更新对应余额和充值记录列表,不应触发整页 `refreshApi()`,避免供应商充值后长时间停留在“拉取 API”。
|
||||
- 话单消费、客户费用、供应商成本仍以 CDR/rated CDR 和余额变更为准。
|
||||
|
||||
#### 25.5.5 动态路由、CDR 和配置发布补齐
|
||||
|
||||
完整新建链路测试暴露出 S28 早期热路径仍有硬编码成功 CDR 和落地网关的问题。二期要求热路径使用配置发布结果动态选择路由。
|
||||
|
||||
- OpenSIPS Lua 热路径按客户网关策略匹配线路组,并选择线路组内首个启用落地网关。
|
||||
- OpenSIPS 成功 CDR 从 Dialog 变量写入动态 customer/gateway/policy/vendorGateway/lineGroup,不再写硬编码对象。
|
||||
- B 必须提供 `config-publisher.env` 并保持 `lisglosips@config-publisher` active。
|
||||
- CDR Worker 对 `config_version` 等大数版本字段必须避免 MySQL INT 越界。
|
||||
- 端到端验收流程应覆盖:
|
||||
1. 新建供应商
|
||||
2. 新建落地网关
|
||||
3. 新建落地线路组
|
||||
4. 新建客户
|
||||
5. 新建客户网关
|
||||
6. 配置客户网关策略指向新线路组
|
||||
7. 给客户充值
|
||||
8. 给供应商充值
|
||||
9. 打通电话
|
||||
10. 当前通话页面查看并强制挂断
|
||||
11. 核对 raw/rated CDR、客户余额、供应商成本和审计记录
|
||||
|
||||
#### 25.5.6 前端信息架构和交互细化
|
||||
|
||||
二期 UI 调整遵循当前控制台风格,不引入新的视觉体系。
|
||||
|
||||
- “待设计”菜单在导航中隐藏,包括费率与计费、SIP 运维、监控告警、系统设置。底层最小计费、HOMER、Prometheus/Grafana、配置文件能力仍按 S00-S30 保留。
|
||||
- 客户管理、客户网关管理、充值记录、供应商管理、落地网关管理等页面中,ID 和名称类列宽应适当收窄,长文本使用省略号,避免挤占金额、状态和操作列。
|
||||
- 话单详情抽屉应分区展示:
|
||||
- 顶部主叫到被叫概览
|
||||
- 通话摘要:时长、挂断原因、客户费用、成本费用
|
||||
- 链路信息:客户网关、呼叫 IP、落地网关、线路 IP
|
||||
- 时间轴:呼叫、接通、结束时间
|
||||
- 录音播放和信令查看入口
|
||||
- 当前通话、删除、启停、重置密码、策略删除、质检规则删除等确认场景统一使用自研确认弹窗。
|
||||
|
||||
#### 25.5.7 10 路虚拟呼叫测试工具
|
||||
|
||||
为观察当前通话页面的实时变化,二期新增 T 侧虚拟呼叫编排工具。
|
||||
|
||||
- 工具路径:`/opt/lisglosips-s40/lisglosips-s40-virtual-calls.py`,源码纳入 `infra/server-t/s40/`。
|
||||
- 默认测试参数:
|
||||
- 总计 10 路虚拟呼叫。
|
||||
- 每隔 15 秒发起 1 路。
|
||||
- 前 5 路先返回 `180 Ringing`,45 秒后返回 `200 OK`,通话保持 600 秒后 BYE。
|
||||
- 后 5 路先返回 `180 Ringing`,70 秒后返回 `480 Temporarily Unavailable`。
|
||||
- 使用当前本地测试策略的主叫 `s36-1001` 和被叫 `13800136036`,按 Call-ID 序号区分接通/不接通场景。
|
||||
- T 上旧 S28 UAS 占用 `100.93.185.30:50620`,完整测试时需要临时停旧 UAS,由 S40 UAS 接管;测试结束或提前停止后必须恢复旧 S28 UAS。
|
||||
- 首次测试暴露 A `fr_inv_timeout=30` 会在 45 秒接通前返回 `408 Request Timeout`。为了支持 45 秒接通和 70 秒未接场景,本地 KVM A 已将 `/etc/opensips/opensips.cfg` 中 `modparam("tm", "fr_inv_timeout", 30)` 临时调整为 `95` 并重启 OpenSIPS。该调整属于测试窗口配置,迁移生产前必须重新评估运营侧真实振铃超时策略。
|
||||
- 停止完整测试命令:
|
||||
|
||||
```bash
|
||||
sudo pkill -f /opt/lisglosips-s40/lisglosips-s40-virtual-calls.py
|
||||
```
|
||||
|
||||
- 若 T 旧 UAS 未恢复,可执行:
|
||||
|
||||
```bash
|
||||
sudo nohup runuser -u nobody -- /usr/bin/python3 /opt/lisglosips-s28/lisglosips-s28-sip.py uas --host 100.93.185.30 --port 50620 >/tmp/lisglosips-s28-uas.log 2>&1 &
|
||||
```
|
||||
|
||||
#### 25.5.8 二期变更的回归要求
|
||||
|
||||
每次二期变更完成后至少执行:
|
||||
|
||||
- 相关单元测试或 e2e 测试。
|
||||
- `corepack pnpm@10.33.0 typecheck`
|
||||
- `corepack pnpm@10.33.0 lint`
|
||||
- `corepack pnpm@10.33.0 build`
|
||||
- 若涉及 A/B/T 三机链路,则执行端到端验收并按 Call-ID 记录结果。
|
||||
- 若涉及 OpenSIPS 配置,必须先备份、执行 `opensips -C -f /etc/opensips/opensips.cfg`,再重启或 reload,并记录回滚点。
|
||||
- 若涉及 Web 发布,必须备份 B 当前 release 的 `apps/web/dist`,覆盖后执行 `nginx -t` 和 reload。
|
||||
- 每次完成后更新 `IMPLEMENTATION_STATUS.md`,写明修改内容、验证结果、回滚方式和遗留问题。
|
||||
|
||||
#### 25.5.9 号码库、归属地运营商识别与屏蔽地区路由
|
||||
|
||||
新增“号码库”菜单,定位为呼叫路由和话单归属地的基础数据管理,不属于普通费率页面。菜单包含四个 Tab:
|
||||
|
||||
- 地级市字典:维护稳定的地级市编码、省份、地级市名称、状态和生效期,供手机号码库、城市区号、落地网关屏蔽地区和话单快照统一引用。
|
||||
- 手机号码库:通过手机号前 7 位号段匹配地级市,预计约 80 万条号段。
|
||||
- 城市区号:保存全国固话区号,例如 `0551` 对应合肥、`021` 对应上海,维度到地级市。
|
||||
- 运营商号码段规则:通过手机号前 3-4 位匹配归属运营商,用于快速判断中国移动/中国联通/中国电信/广电/虚拟运营商等。
|
||||
|
||||
是否增加地级市字典:需要增加。原因是手机号码库和城市区号都要统一落到地级市维度,落地网关屏蔽地区也需要引用稳定地区编码;如果只在号段表中保存城市文本,会造成同名、改名、直辖市、省市归属和历史变更难以维护。建议新增 `geo_cities` 字典,字段至少包括:
|
||||
|
||||
- `code`:行政区划码或项目稳定编码,作为主键或唯一键。
|
||||
- `province_code`、`province_name`
|
||||
- `city_code`、`city_name`
|
||||
- `city_level`:地级市、直辖市、地区、自治州等。
|
||||
- `status`、`effective_from`、`effective_to`
|
||||
- 审计列和软删除列。
|
||||
|
||||
号码库数据模型建议:
|
||||
|
||||
- `phone_number_segments`
|
||||
- `segment7`:手机号前 7 位,唯一。
|
||||
- `city_code`:关联 `geo_cities`。
|
||||
- `province_name`、`city_name` 可冗余快照,便于导入校验和快速展示。
|
||||
- `carrier` 可选;若和运营商规则冲突,运营商以 `carrier_prefix_rules` 为准,并记录数据质量告警。
|
||||
- `source`、`batch_id`、`effective_from`、`effective_to`、`updated_at`。
|
||||
- `carrier_prefix_rules`
|
||||
- `prefix`:手机号前 3-4 位,唯一或按生效期唯一。
|
||||
- `carrier`:`MOBILE`、`UNICOM`、`TELECOM`、`BROADCAST`、`MVNO`、`UNKNOWN` 等枚举。
|
||||
- `priority`:前缀重叠时按最长前缀和优先级匹配。
|
||||
- `effective_from`、`effective_to`。
|
||||
- `phone_area_codes`
|
||||
- `area_code`:固话区号,例如 `021`、`0551`。
|
||||
- `city_code`:关联 `geo_cities`。
|
||||
- `province_name`、`city_name` 展示冗余。
|
||||
- `vendor_gateway_blocked_regions`
|
||||
- `vendor_gateway_id`
|
||||
- `city_code`,必要时支持省级屏蔽可通过 `region_scope=PROVINCE/CITY` 建模。
|
||||
- `created_at`、`created_by`。
|
||||
|
||||
匹配规则:
|
||||
|
||||
- 手机号归属地:优先取规范化后的被叫号码前 7 位匹配 `phone_number_segments.segment7`。
|
||||
- 手机号运营商:按被叫号码前 4 位、前 3 位依次匹配 `carrier_prefix_rules`,优先最长前缀。
|
||||
- 固话归属地:对被叫号码做号码规范化后匹配城市区号;区号需要支持 `0xx`、`0xxx`,并注意去掉外呼前缀、国家码 `+86/0086` 后再判断。
|
||||
- 无法识别时,城市和运营商写 `UNKNOWN`,呼叫不应仅因号码库缺失被拒绝,除非客户或全局策略明确要求。
|
||||
|
||||
每通话单必须保存号码识别快照:
|
||||
|
||||
- `callee_city_code`
|
||||
- `callee_city_name`
|
||||
- `callee_province_name`
|
||||
- `callee_operator`
|
||||
- 可选保存 `callee_number_type`:`MOBILE`、`LANDLINE`、`INTERNATIONAL`、`UNKNOWN`。
|
||||
|
||||
落地网关屏蔽地区路由要求:
|
||||
|
||||
- Config Publisher 发布线路组时,需要把线路组成员落地网关的屏蔽地区一起写入 Redis 热路径配置。
|
||||
- OpenSIPS/Lua 在选中客户网关策略和线路组后,先识别被叫地级市,再按线路组成员优先级选择落地网关。
|
||||
- 若某落地网关屏蔽该地级市或其所在省份,则跳过该网关,继续尝试同一线路组中的下一落地网关。
|
||||
- 若同一线路组所有可用落地网关都被屏蔽或不可用,返回明确失败原因,例如 `NO_VENDOR_ROUTE_REGION_BLOCKED`,并写入失败 CDR。
|
||||
- 成功 CDR 需要写入最终实际选中的 `vendor_gateway_id` 和号码识别快照;不能只记录第一次被跳过的网关。
|
||||
- 当前 V2 单节点 OpenSIPS 热路径必须保持可预测和低延迟,80 万手机号段不应在每通电话中扫描 MySQL。推荐路径是 B 侧导入 MySQL 后,由 Config Publisher 生成 Redis 查找结构:
|
||||
- `cfg:v:{version}:phone_segment:{segment7}` -> city/operator 快照。
|
||||
- `cfg:v:{version}:area_code:{areaCode}` -> city 快照。
|
||||
- `cfg:v:{version}:carrier_prefix:{prefix}` -> carrier。
|
||||
- `cfg:v:{version}:vendor_gateway:{id}:blocked_regions` -> city/province set 或紧凑 JSON。
|
||||
|
||||
实施拆分建议:
|
||||
|
||||
1. 数据建模与迁移:新增地级市字典、手机号码库、城市区号、运营商前缀规则、落地网关屏蔽地区和 raw CDR 号码识别字段。此步骤涉及数据库 schema migration,执行前必须备份 B MySQL,说明回滚点;80 万号段导入需要单独评估索引和迁移时间。
|
||||
2. 导入与管理 API:实现号码库导入、分页查询、按号段/区号/城市检索、批次校验、重复号段冲突报告;大批量导入应走文件/后台任务,不建议通过普通 JSON 表单一次提交。
|
||||
3. Web 菜单:新增“号码库”菜单和四个 Tab(地级市字典、手机号码库、城市区号、运营商号码段规则),先支持查询、导入结果查看和基础维护;超大号段列表必须服务端分页和筛选,不做前端全量加载。
|
||||
4. Config Publisher 与 Redis 热路径:把号码库快照、运营商规则、城市区号和落地网关屏蔽地区发布到版本化 Redis key;保留上一版本用于一键回滚。
|
||||
5. OpenSIPS/Lua 路由:在当前动态路由基础上增加号码规范化、地级市/运营商解析、屏蔽地区跳过下一落地网关、失败原因写入;改动前必须备份 A `/etc/opensips/opensips.cfg` 和 Lua,执行 `opensips -C -f` 后再重启。
|
||||
6. CDR Stream 与 Worker:升级 CDR event schema,解析并入库归属地/运营商字段;保持向后兼容旧 schema,避免旧 Stream 或 pending 消息死信。
|
||||
7. 话单中心展示:列表/详情增加地级市、运营商展示和筛选;历史无字段话单显示 `UNKNOWN` 或 `-`。
|
||||
8. 端到端验收:构造同一线路组两个落地网关,其中第一个屏蔽目标地级市,第二个允许;发起测试呼叫,验证当前通话/成功 CDR 使用第二个网关,并保存正确地级市和运营商;再验证全部网关屏蔽时失败 CDR 原因为 `NO_VENDOR_ROUTE_REGION_BLOCKED`。
|
||||
|
||||
风险与约束:
|
||||
|
||||
- 80 万手机号段属于大批量主数据,导入、索引、Redis 发布和回滚都需要独立 Runbook,不能夹在普通前端小改中发布。
|
||||
- 手机号段和行政区划会变更,必须保留数据来源、批次和生效期,避免“更新号码库”改变历史 CDR 解释。
|
||||
- Redis 热路径内 JSON 字符串解析能力有限,复杂匹配逻辑应提前在 Config Publisher 生成适合 Lua 快速读取的结构。
|
||||
- 地区屏蔽属于路由策略,必须与并发/CPS、禁呼时段、编码限制的优先级关系固定下来:推荐先过滤状态/禁呼/地区屏蔽,再做并发/CPS 占用。
|
||||
|
||||
本地实施状态:
|
||||
|
||||
- 2026-06-24 已完成第 1、2 步本地代码基线:Prisma Schema、迁移文件、号码库 API、RBAC/seed、审计和后端测试已完成;尚未发布到 B,尚未执行 MySQL migration,尚未导入真实 80 万号段。
|
||||
- 2026-06-24 已完成第 3 步 Web 本地代码基线:运营菜单新增“号码库”,页面包含地级市字典、手机号码库、城市区号、运营商号码段规则四个 Tab;每个 Tab 支持服务端分页查询入口、筛选、刷新和批量 JSON 导入弹窗。该导入弹窗只适合小批校验和后台接口联调,真实 80 万号段仍需按后续导入任务/Runbook 走文件或后台任务。
|
||||
- 2026-06-24 已完成第 4、5 步本地代码基线:Config Publisher 会把地级市、手机 7 位号段、固话区号、运营商前缀和落地网关屏蔽地区发布为版本化 Redis key;号码库导入会写入 `number_library_config` outbox 触发新快照。OpenSIPS S28 Lua 热路径会解析被叫号码,命中屏蔽城市/省份时跳过当前落地网关并尝试同一线路组下一网关,全部被屏蔽时返回 `NO_VENDOR_ROUTE_REGION_BLOCKED`;成功/失败 CDR Stream 已携带归属地和运营商字段。当前仅完成本地文件,尚未发布 B/A;发布 A 前必须重新加载 Lua、替换 `/etc/opensips/opensips.cfg` 前备份,并在 A 上执行 `opensips -C -f /etc/opensips/opensips.cfg` 后再重启。
|
||||
- 2026-06-24 已完成第 6、7 步本地代码基线:CDR Stream 解析兼容新增 `callee_city_code`、`callee_city_name`、`callee_province_name`、`callee_operator`、`callee_number_type`,旧 Stream 消息缺字段时仍可处理;CDR Worker 会把这些字段写入 `raw_cdrs` 号码识别快照列。新增 `GET /api/v2/cdrs` 与 `GET /api/v2/cdrs/:id`,复用 `cdr.view` 权限,支持主叫、被叫、客户网关、落地网关、地级市代码和运营商筛选。Web 话单中心已接入真实 CDR API,列表和详情展示地级市、运营商、号码类型、SIP 状态码和费用字段。
|
||||
|
||||
第 1、2 步已完成本地代码基线:
|
||||
|
||||
- Prisma Schema 和迁移新增:
|
||||
- `geo_cities`
|
||||
- `phone_number_segments`
|
||||
- `phone_area_codes`
|
||||
- `carrier_prefix_rules`
|
||||
- `vendor_gateway_blocked_regions`
|
||||
- `raw_cdrs` 被叫地级市、省份、运营商、号码类型快照字段
|
||||
- API 模块新增 `NumberLibraryModule`:
|
||||
- `GET /api/v2/number-library/cities`
|
||||
- `POST /api/v2/number-library/cities/import`
|
||||
- `GET /api/v2/number-library/phone-segments`
|
||||
- `POST /api/v2/number-library/phone-segments/import`
|
||||
- `GET /api/v2/number-library/area-codes`
|
||||
- `POST /api/v2/number-library/area-codes/import`
|
||||
- `GET /api/v2/number-library/carrier-prefix-rules`
|
||||
- `POST /api/v2/number-library/carrier-prefix-rules/import`
|
||||
- 权限新增:
|
||||
- `number_library.view`
|
||||
- `number_library.manage`
|
||||
- 当前导入接口采用单批 `items` upsert,单次限制 1000 条,适合脚本/后台任务分批调用。80 万号段的真实文件导入、进度表、失败明细和 Redis 发布仍属于后续步骤,不在本次第 1、2 步中直接执行。
|
||||
|
||||
### 25.6 Codex 新会话启动模板
|
||||
|
||||
```text
|
||||
请先读取 SOFTSWITCH_PLATFORM_DESIGN_V2.md 和 IMPLEMENTATION_STATUS.md,
|
||||
|
||||
Reference in New Issue
Block a user