feat: add number library routing and cdr location support
This commit is contained in:
+243
-4
@@ -4,10 +4,10 @@
|
||||
|
||||
## 当前状态
|
||||
|
||||
- 当前任务:无,S00-S30 本地 V2 闭环已完成
|
||||
- 总体状态:S30 已完成;本地 KVM 开发环境 V2 闭环冻结在 `s28-v2-20260621220924`,阿里云迁移前需按 S30 Runbook 重新演练
|
||||
- 最后更新:2026-06-22 10:35 +08:00
|
||||
- 当前阻塞:无。遗留风险为 Redis 恢复后 OpenSIPS 热路径可能需要重启 `opensips` 才恢复,已纳入 S30 Runbook,根因级修复需后续单独处理。
|
||||
- 当前任务:需求修改/二期变更:号码库第 6、7 步本地实现并提交 Git
|
||||
- 总体状态:S30 已完成;本地 KVM 开发环境 V2 闭环原冻结 release 为 `s28-v2-20260621220924`,当前 B release 仍为 `s33-active-calls-20260623094000`,已在该 release 上覆盖发布 s41 用户/角色删除小改;A `/etc/opensips/opensips.cfg` 已将 `fr_inv_timeout` 从 30 临时调为 95 并重启;T 已新增 `/opt/lisglosips-s40/lisglosips-s40-virtual-calls.py` 并启动 10 路虚拟呼叫场景;号码库第 1-7 步已完成本地代码基线,尚未发布到 B/A、尚未执行 MySQL migration、尚未导入真实 80 万号段;阿里云迁移前需按 S30 Runbook 重新演练
|
||||
- 最后更新:2026-06-24 11:41 +08:00
|
||||
- 当前阻塞:无。遗留风险为 Redis 恢复后 OpenSIPS 热路径可能需要重启 `opensips` 才恢复,已纳入 S30 Runbook;本次发现并补齐 B `config-publisher.env`,当前 `lisglosips@config-publisher` 已 active。
|
||||
- 当前环境:A/B/T 为本地 KVM 开发服务器,通过 Tailscale 联调;开发完成后再迁移阿里云
|
||||
- 私密访问资料:`.codex-private/SERVER_ACCESS.md`,只在实际连接时读取,禁止回显
|
||||
|
||||
@@ -89,6 +89,245 @@
|
||||
|
||||
## 交接记录
|
||||
|
||||
### 2026-06-24 11:41 - 需求修改/二期变更:号码库第 6、7 步本地实现
|
||||
|
||||
- 状态:已完成本地代码;准备提交 Git;未发布到 B/A,未执行数据库迁移,未重启服务
|
||||
- 操作服务器:本地
|
||||
- 完成内容:CDR Stream 契约新增可选号码识别快照字段,并保持旧 Stream/pending 消息兼容;CDR Worker 入库 `raw_cdrs` 时写入 `calleeCityCode`、`calleeCityName`、`calleeProvinceName`、`calleeOperator`、`calleeNumberType`。新增 `CdrsModule`,提供 `GET /api/v2/cdrs` 与 `GET /api/v2/cdrs/:id`,复用 `cdr.view` 权限,支持主叫、被叫、客户网关、落地网关、地级市代码、运营商分页筛选,并返回客户/网关/线路组名称与 rated CDR 费用。Web 话单中心改为读取真实 CDR API,列表和详情展示地级市、运营商、号码类型、SIP 状态码、客户费用、成本和毛利。
|
||||
- 修改文件:`packages/redis/src/cdr-stream.ts`、`packages/redis/src/cdr-stream.spec.ts`、`apps/worker-cdr/src/rating.ts`、`apps/worker-cdr/src/rating.spec.ts`、`apps/api/src/modules/app.module.ts`、`apps/api/src/modules/cdrs/cdrs.module.ts`、`apps/api/src/modules/cdrs/cdrs.controller.ts`、`apps/api/src/modules/cdrs/cdrs.service.ts`、`apps/api/src/modules/cdrs/cdrs.repository.ts`、`apps/api/src/modules/cdrs/cdrs.service.spec.ts`、`apps/web/src/api.js`、`apps/web/src/App.jsx`、`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 pnpm `10.33.0`、Prisma `6.19.0`。
|
||||
- 执行的关键命令:`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 vitest run packages/redis/src/cdr-stream.spec.ts apps/worker-cdr/src/rating.spec.ts apps/api/src/modules/cdrs/cdrs.service.spec.ts`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 test`、`corepack pnpm@10.33.0 build`
|
||||
- 验证结果:typecheck 通过;目标测试 3 个文件、13 条测试通过;lint 通过;workspace build 通过;第一次将全量 test 与 build 并行执行时 3 个依赖本地服务的 e2e `beforeAll` 因资源争用超时,随后单独重跑 `corepack pnpm@10.33.0 test` 通过,25 个测试文件、85 条测试全部通过。
|
||||
- 回滚方式:恢复上述文件即可;本次未连接服务器、未发布 B/A、未写 Redis、未执行 MySQL migration、未重启 OpenSIPS,因此无远端回滚项。后续若发布,B 发布前需备份 MySQL 和当前 release;A 发布仍需先备份 OpenSIPS 配置/Lua 并执行 `opensips -C -f`。
|
||||
- 未解决问题:真实 80 万号段文件导入、Redis 发布容量评估、落地网关屏蔽地区 API/Web 管理入口、A/B/T 地区屏蔽端到端验收仍未实施;当前 CDR API 已能显示新字段,但历史话单在迁移前/旧消息场景下会显示 `UNKNOWN` 或 `-`。
|
||||
- 下一任务:提交 Git 后,建议优先补落地网关屏蔽地区管理入口和大批量号码库导入 Runbook,再安排 B/A 发布与 A/B/T 验收。
|
||||
|
||||
### 2026-06-24 11:31 - 需求修改/二期变更:号码库第 4、5 步本地实现
|
||||
|
||||
- 状态:已完成本地代码;未发布到 B/A,未执行数据库迁移,未重启服务
|
||||
- 操作服务器:本地
|
||||
- 完成内容:Config Publisher 快照新增地级市、手机 7 位号段、固话区号、运营商前缀和落地网关屏蔽地区;Redis 写入版本化 `geo_city`、`phone_segment`、`area_code`、`carrier_prefix` key,以及 `vendor_gateway:{id}:blocked_city_codes`/`blocked_province_codes` set。号码库导入新增 `number_library_config` outbox,导入后可触发发布器生成新快照。S28 OpenSIPS Lua 热路径新增被叫号码规范化、手机 7 位号段解析、固话区号解析、运营商前缀解析、落地网关城市/省份屏蔽跳过逻辑;全部可用网关都被地区屏蔽时返回 `NO_VENDOR_ROUTE_REGION_BLOCKED`。S28 `opensips.cfg` 更新 Lua SHA1、读取追加返回字段,并在成功/失败 CDR Stream 中携带 `callee_city_code`、`callee_city_name`、`callee_province_name`、`callee_operator`、`callee_number_type`。
|
||||
- 修改文件:`apps/worker-config-publisher/src/publisher.ts`、`apps/worker-config-publisher/src/publisher.spec.ts`、`apps/api/src/modules/number-library/number-library.repository.ts`、`infra/server-a/s28/lisglosips_hotpath.lua`、`infra/server-a/s28/opensips.cfg`、`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 pnpm `10.33.0`、Prisma `6.19.0`。
|
||||
- 执行的关键命令:`corepack pnpm@10.33.0 vitest run apps/worker-config-publisher/src/publisher.spec.ts apps/api/src/modules/number-library/number-library.e2e.spec.ts`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 test`、`corepack pnpm@10.33.0 build`、`Get-FileHash -Algorithm SHA1 infra/server-a/s28/lisglosips_hotpath.lua`
|
||||
- 验证结果:目标测试 2 个文件、4 条测试通过;typecheck 通过;lint 通过;全量 Vitest 24 个测试文件、82 条测试通过;workspace build 通过;本机无 `lua`、无 `opensips` 命令,因此未在本地执行 Lua 解释器语法检查和 `opensips -C`。
|
||||
- 回滚方式:恢复上述本地文件即可;本次未连接服务器、未发布 B/A、未写 Redis、未执行 MySQL migration、未重启 OpenSIPS,因此无远端回滚项。后续若发布:B 需先备份 MySQL/Redis 和当前 release,回滚 Redis 可切回 `cfg:previous_version`;A 需先备份 `/etc/opensips/opensips.cfg` 与 `/etc/opensips/lisglosips_hotpath.lua`,回滚时恢复备份、执行 `opensips -C -f /etc/opensips/opensips.cfg` 通过后重启 OpenSIPS。
|
||||
- 未解决问题:第 6 步 CDR Worker 尚未把 `callee_city_code`、`callee_city_name`、`callee_province_name`、`callee_operator`、`callee_number_type` 入库到 `raw_cdrs` 新字段;落地网关屏蔽地区仍缺少 Web/API 管理入口;真实 80 万号段文件导入、Redis 发布容量评估、A/B/T 端到端地区屏蔽验收仍未执行。
|
||||
- 下一任务:建议第 6 步改造 CDR Stream/Worker 入库号码识别字段,并补落地网关屏蔽地区的 API/Web 管理入口后,再安排 B/A 发布和 A/B/T 验收。
|
||||
|
||||
### 2026-06-24 11:15 - 需求修改/二期变更:号码库第 3 步 Web 本地实现
|
||||
|
||||
- 状态:已完成本地代码;未发布到 B,未执行数据库迁移
|
||||
- 操作服务器:本地
|
||||
- 完成内容:新增 Web “号码库”运营菜单,页面包含地级市字典、手机号码库、城市区号、运营商号码段规则四个 Tab。每个 Tab 接入 `/number-library/*` API,支持服务端查询入口、筛选、刷新、总数显示和批量 JSON 导入弹窗;导入成功后刷新当前 Tab。同步更新 V2 设计文档,将号码库菜单从三个 Tab 调整为四个 Tab,并补充第 3 步本地实施状态。
|
||||
- 修改文件:`apps/web/src/api.js`、`apps/web/src/App.jsx`、`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 pnpm `10.33.0`。
|
||||
- 执行的关键命令:`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`、`corepack pnpm@10.33.0 test`
|
||||
- 验证结果:typecheck 通过;lint 通过;workspace build 通过;第一次将 test 与 build 并行执行时 5 个依赖本地服务的 e2e `beforeAll` 因资源争用超时,随后单独重跑 `corepack pnpm@10.33.0 test` 通过,23 个测试文件、81 条测试全部通过。
|
||||
- 回滚方式:恢复 `apps/web/src/api.js`、`apps/web/src/App.jsx`、`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md` 本次改动即可;本次未连接服务器、未发布 B、未执行 MySQL migration、未写入 Redis、未重启服务,因此无远端回滚项。
|
||||
- 未解决问题:号码库前端当前使用批量 JSON 导入,只适合小批验证和接口联调;真实 80 万号段仍需文件导入/后台任务/进度与失败明细。号码解析服务、Config Publisher Redis 快照、OpenSIPS/Lua 屏蔽地区跳转、CDR Worker 新字段入库、话单中心展示与 A/B/T 端到端验收仍未实施。
|
||||
- 下一任务:建议第 4 步实现 Config Publisher/Redis 热路径快照前,先补大批量导入任务 Runbook 和文件导入接口,避免把 80 万号段通过普通 JSON 表单导入。
|
||||
|
||||
### 2026-06-24 11:07 - 需求修改/二期变更:号码库第 1、2 步本地实现
|
||||
|
||||
- 状态:已完成本地代码;未发布到 B,未执行数据库迁移
|
||||
- 操作服务器:本地
|
||||
- 完成内容:完成号码库第 1、2 步本地基线。Prisma Schema 和迁移新增 `geo_cities`、`phone_number_segments`、`phone_area_codes`、`carrier_prefix_rules`、`vendor_gateway_blocked_regions`,并在 `raw_cdrs` 预留被叫地级市、省份、运营商和号码类型快照字段。新增 `NumberLibraryModule`,提供城市、手机 7 位号段、固话区号、运营商前缀规则的分页查询与批量 upsert 导入 API,单批限制 1000 条,接入 RBAC 和审计。新增权限 `number_library.view`、`number_library.manage` 并写入 seed;更新 schema contract 和号码库 e2e 测试。
|
||||
- 修改文件:`prisma/schema.prisma`、`prisma/migrations/20260624095000_number_library/migration.sql`、`apps/api/src/modules/app.module.ts`、`apps/api/src/modules/number-library/number-library.module.ts`、`apps/api/src/modules/number-library/number-library.controller.ts`、`apps/api/src/modules/number-library/number-library.service.ts`、`apps/api/src/modules/number-library/number-library.repository.ts`、`apps/api/src/modules/number-library/number-library.e2e.spec.ts`、`packages/auth/src/index.ts`、`packages/database/src/schema-contract.spec.ts`、`prisma/seed.ts`、`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Prisma `6.19.0`、pnpm `10.33.0`。
|
||||
- 执行的关键命令:`corepack pnpm@10.33.0 prisma format`、`corepack pnpm@10.33.0 prisma:validate`、`corepack pnpm@10.33.0 prisma:generate`、`corepack pnpm@10.33.0 vitest run apps/api/src/modules/number-library/number-library.e2e.spec.ts packages/database/src/schema-contract.spec.ts`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 test`、`corepack pnpm@10.33.0 build`
|
||||
- 验证结果:Prisma format/validate/generate 通过;号码库 e2e 与 schema contract 共 8 条测试通过;typecheck 通过;lint 通过;全量 Vitest 23 个测试文件、81 条测试通过;workspace build 通过。
|
||||
- 回滚方式:恢复上述本地文件改动即可;因为未连接服务器、未发布 B、未执行 MySQL migration、未导入真实数据,所以无远端回滚项。若后续发布到 B,执行迁移前必须先备份 B MySQL;回滚需恢复迁移前备份或执行经验证的反向迁移,并清理新增权限/seed 变更。
|
||||
- 未解决问题:真实 80 万号段文件导入、导入任务进度/失败明细、号码解析服务、Config Publisher Redis 发布、OpenSIPS/Lua 屏蔽地区跳转、CDR Worker 入库新字段、话单中心展示与筛选、A/B/T 端到端验收仍未实施。
|
||||
- 下一任务:建议第 3 步 Web “号码库”菜单和三个 Tab;或先实现第 4 步 Config Publisher/Redis 快照结构前的导入任务 Runbook。
|
||||
|
||||
### 2026-06-24 09:48 - 需求修改/二期变更:号码库与屏蔽地区路由需求评估
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:本地
|
||||
- 完成内容:评估新增“号码库”菜单及手机号码库、城市区号、运营商号码段规则三个 Tab 的影响范围;明确需要新增地级市字典 `geo_cities`,用于手机 7 位号段、固话区号、落地网关屏蔽地区和 CDR 快照统一引用;明确每通话单需要保存被叫地级市、省份、运营商和号码类型快照;明确落地网关屏蔽地区应在 OpenSIPS/Lua 热路径中跳过当前网关并尝试同一线路组下一落地网关。已将需求、数据模型建议、Redis 热路径结构、CDR 字段、路由规则、风险和 8 步实施拆分写入 `SOFTSWITCH_PLATFORM_DESIGN_V2.md`,文档版本升级为 V2.2。
|
||||
- 修改文件:`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件。
|
||||
- 执行的关键命令:`rg` 检查现有 Schema、CDR Stream、OpenSIPS Lua 和 Web 中的地区/运营商/屏蔽地区相关实现;文档更新后用 `rg` 校验 V2.2、号码库、`geo_cities`、`phone_number_segments`、`carrier_prefix_rules`、`vendor_gateway_blocked_regions`、`NO_VENDOR_ROUTE_REGION_BLOCKED` 等关键条目。
|
||||
- 验证结果:本次为需求评估和 Markdown 文档更新,未运行 typecheck/lint/test/build;未连接服务器,未做数据库迁移、服务重启或数据导入。
|
||||
- 回滚方式:恢复 `SOFTSWITCH_PLATFORM_DESIGN_V2.md` 和 `IMPLEMENTATION_STATUS.md` 本次文档改动即可;不涉及 B release、MySQL、Redis、OpenSIPS、RTPEngine、Worker 或 Web 发布回滚。
|
||||
- 未解决问题:真实实施前仍需确认号码库数据来源、更新频率、导入格式、行政区划编码口径、运营商枚举口径、省级屏蔽是否需要、以及 80 万号段导入对 MySQL/Redis 内存和发布耗时的影响。
|
||||
- 下一任务:如确认实施,建议从“数据建模与迁移 + 导入 Runbook”单独开工,不要与 OpenSIPS 热路径改造混在同一次发布。
|
||||
|
||||
### 2026-06-24 09:31 - 需求修改/二期变更:用户与角色删除
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:本地、B
|
||||
- 完成内容:用户管理新增红色“删除”按钮和自研确认弹窗,确认后调用 `DELETE /api/v2/users/:id`;角色与权限新增红色“删除”按钮和自研确认弹窗,内置角色前端禁用删除,后端同时保护内置角色并在角色仍有关联用户时拒绝删除。后端用户删除为软删除:禁用账号、写入 `deletedAt`、清理用户角色关联以释放角色用户数;角色删除为软删除:禁用角色并写入 `deletedAt`。两个删除接口均接入 RBAC `users.manage`/`roles.manage` 和审计日志。未改 Prisma Schema,未执行数据库迁移。
|
||||
- 修改文件:`apps/api/src/modules/users/users.controller.ts`、`apps/api/src/modules/users/users.service.ts`、`apps/api/src/modules/users/users.repository.ts`、`apps/api/src/modules/roles/roles.controller.ts`、`apps/api/src/modules/roles/roles.service.ts`、`apps/api/src/modules/roles/roles.repository.ts`、`apps/api/src/modules/security/security-rbac-audit.e2e.spec.ts`、`apps/api/src/modules/users-roles-delete.e2e.spec.ts`、`apps/web/src/App.jsx`、`apps/web/src/api.js`、`IMPLEMENTATION_STATUS.md`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中已覆盖 API/Web dist。
|
||||
- 安装软件及固定版本:未安装新软件。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 vitest run apps/api/src/modules/users-roles-delete.e2e.spec.ts`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 test`、`corepack pnpm@10.33.0 build`;B `tar --no-same-owner -xzf` 覆盖当前 release API/Web dist、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`curl http://127.0.0.1:3000/api/v2/health/ready`。
|
||||
- 验证结果:新增用户/角色删除 E2E 3 条通过;typecheck 通过;lint 通过;全量 Vitest 22 个测试文件、77 条测试通过;workspace build 通过。B `lisglosips@api` 与 `nginx` active,API ready 返回 `config/database/redis` 均 ok;服务日志确认已映射 `DELETE /api/v2/users/:id` 与 `DELETE /api/v2/roles/:id`;Web 首页 `https://100.90.90.91/` 返回 200 并引用新构建资源。
|
||||
- 回滚方式:B 已备份覆盖前 dist 到 `/var/backups/lisglosips-s41-user-role-delete/20260624T092950/api-dist` 与 `/var/backups/lisglosips-s41-user-role-delete/20260624T092950/web-dist`;如需回滚,将两目录恢复到 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/api/dist` 与 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/web/dist`,重启 `lisglosips@api` 并执行 `nginx -t && systemctl reload nginx`。本次无数据库 schema migration;若已通过新功能误删用户/角色,删除为软删除,需要在维护窗口受控恢复对应 `deleted_at/status`,用户还需按审计和业务确认恢复 `user_roles` 关联。
|
||||
- 未解决问题:用户管理、角色与权限的新增/编辑/启停仍沿用旧的前端本地态实现,未纳入本次需求重构;未做 A/B/T SIP 端到端,因为本次只涉及 B API/Web 管理面,不影响 Redis 热路径、OpenSIPS、RTPEngine、Worker 或三机呼叫链路。
|
||||
- 下一任务:等待下一个二期需求。
|
||||
|
||||
### 2026-06-23 22:07 - 需求修改/二期变更:S30 后需求写入 V2 设计文档
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:本地
|
||||
- 完成内容:将 S30 以后用户新增需求整理进 `SOFTSWITCH_PLATFORM_DESIGN_V2.md`,文档版本从 V2.0 调整为 V2.1,新增“25.5 S30 后二期需求变更”章节;同步更新 V2 范围表,纳入当前通话、受控删除、网关/线路组计数、人工充值记录语义、待设计菜单隐藏等内容;补充登录验证码、当前通话和强制挂断、删除/启停确认、充值与计费流水语义、动态路由和 CDR 补齐、前端交互、10 路虚拟呼叫测试工具、二期回归要求;修正 S27 描述中“待设计菜单继续保留标识”的旧表述。
|
||||
- 修改文件:`SOFTSWITCH_PLATFORM_DESIGN_V2.md`、`IMPLEMENTATION_STATUS.md`
|
||||
- 安装软件及固定版本:未安装新软件。
|
||||
- 执行关键命令:`rg` 检查 V2 文档关键章节和条目;`git diff -- SOFTSWITCH_PLATFORM_DESIGN_V2.md --stat` 复核文档差异。
|
||||
- 验证结果:文档已包含 V2.1 状态、当前通话实施范围、待设计菜单隐藏说明、“25.5 S30 后二期需求变更”及 25.5.1-25.5.8 子章节;本次为纯 Markdown 文档更新,未运行 typecheck/lint/build。
|
||||
- 回滚方式:恢复 `SOFTSWITCH_PLATFORM_DESIGN_V2.md` 和 `IMPLEMENTATION_STATUS.md` 本次文档改动即可;不涉及服务器、数据库、Redis、OpenSIPS、RTPEngine 或 Worker 回滚。
|
||||
- 未解决问题:S40 10 路虚拟呼叫完整场景此前仍在 T 后台运行,本文档更新未等待其全程结束;若需确认最终结果,应继续查看 `/tmp/lisglosips-s40-virtual-calls-20260623T215430.log`。
|
||||
|
||||
### 2026-06-23 21:51 - 需求修改/二期变更:10 路虚拟呼叫测试工具与当前通话自动刷新
|
||||
|
||||
- 状态:已完成工具部署,完整 10 路场景已启动并运行中
|
||||
- 操作服务器:A、B、T、本地
|
||||
- 完成内容:当前通话页面新增默认开启的 5 秒自动刷新开关,保留手动刷新;T 新增 `/opt/lisglosips-s40/lisglosips-s40-virtual-calls.py`,可按 15 秒间隔发起 10 路虚拟呼叫,前 5 路先回 `180 Ringing`、45 秒后 `200 OK`、保持 600 秒后 BYE,后 5 路先回 `180 Ringing`、70 秒后 `480 Temporarily Unavailable`。脚本默认使用当前已打通策略的主叫 `s36-1001`、被叫 `13800136036`,并按 Call-ID 序号区分接通/不接通场景。首次完整场景暴露 A `fr_inv_timeout=30` 会在 45 秒接通前返回 408,已将 A OpenSIPS `fr_inv_timeout` 临时调为 95 并重启后重新启动场景。
|
||||
- 修改文件:`apps/web/src/App.jsx`、`infra/server-t/s40/lisglosips-s40-virtual-calls.py`、`infra/server-a/s28/opensips.cfg`、`IMPLEMENTATION_STATUS.md`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中已覆盖 `apps/web/dist`;T 已部署 `/opt/lisglosips-s40`;A 已就地修改 `/etc/opensips/opensips.cfg`。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Node.js `v22.22.2`、pnpm `10.33.0`、Vite `5.4.21`、T 既有 Python 3.12。
|
||||
- 执行关键命令:本地 `corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`;B `tar -xzf` 覆盖 web dist、`nginx -t`、`systemctl reload nginx`、`curl -sk https://127.0.0.1/`;T `python3 -m py_compile /opt/lisglosips-s40/lisglosips-s40-virtual-calls.py`、短烟测 `--total 1 --answer-ring 2 --hold 3`、后台启动完整场景;A `opensips -C -f /etc/opensips/opensips.cfg`、`systemctl restart opensips`。
|
||||
- 验证结果:本地 typecheck/lint/build 均通过;B nginx 配置测试通过且 active,首页 HTML 返回新资源 `/assets/index-DwIXfg91.js` 和 `/assets/index-TA3aiKvG.css`;T 脚本 Python 编译通过。短烟测先发现 `50620` 被旧 S28 UAS 占用且新号码无策略,已调整为临时停旧 UAS、固定主叫/被叫并按 Call-ID 分流;最终 1 路短烟测通过:收到 `100 Giving it a try`、`180 Ringing`、延迟后 `200 OK`、3 秒后 BYE 且 UAS 返回 `200 OK`。首次完整场景因 A `fr_inv_timeout=30` 导致 45 秒接通前被 A 返回 408,已停止并恢复旧 UAS;A 超时调为 95 后重新启动完整场景,PID `32120`,日志 `/tmp/lisglosips-s40-virtual-calls-20260623T215430.log`,已验证第 1、2 路均在 45 秒后收到 `200 OK` 并进入 `connected hold=600.0s`。
|
||||
- 回滚方式:B 前端回滚可从 `/var/backups/lisglosips-s40-active-calls-autorefresh/20260623T214444/web-dist` 恢复当前 release 的 `apps/web/dist`,再执行 `nginx -t && systemctl reload nginx`。A 超时回滚可从 `/var/backups/lisglosips-s40-fr-inv-timeout/20260623T215330/opensips.cfg` 恢复 `/etc/opensips/opensips.cfg`,再执行 `opensips -C -f /etc/opensips/opensips.cfg && systemctl restart opensips`。T 脚本回滚可删除 `/opt/lisglosips-s40`,或从 `/var/backups/lisglosips-s40-virtual-calls/20260623T214907/lisglosips-s40` 恢复上一版。若需提前停止完整场景:在 T 执行 `sudo pkill -f /opt/lisglosips-s40/lisglosips-s40-virtual-calls.py`,然后确认 `100.93.185.30:50620` 有旧 S28 UAS;若未恢复,执行 `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 &`。
|
||||
- 未解决问题:完整 10 路场景仍在运行中,尚未等待约 12 分钟全程结束;测试会产生真实本地开发环境呼叫事件和少量计费/失败 CDR,使用的是现有 S36 测试客户网关/路由。当前通话页面观察地址为 `https://100.90.90.91/`。
|
||||
|
||||
### 2026-06-23 18:38 - 需求修改/二期变更:话单详情弹窗布局重排
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:话单中心“查看详情”抽屉内部从单列 KeyValue 堆叠调整为主被叫概览、通话摘要、链路信息、时间轴和录音/信令操作分区;新增专用 `cdr-detail` 系列样式,移动端自动切为单列;补充本地 `Icon` 的 `arrow` 图标用于主叫到被叫方向展示。
|
||||
- 修改文件:`apps/web/src/App.jsx`、`apps/web/src/styles.css`、`IMPLEMENTATION_STATUS.md`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中已覆盖 `apps/web/dist`。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Node.js `v22.22.2`、pnpm `10.33.0`、Vite `5.4.21`。
|
||||
- 执行关键命令:`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`、B `tar -xzf` 覆盖 web dist、`nginx -t`、`systemctl reload nginx`、`curl -sk https://127.0.0.1/`。
|
||||
- 验证结果:本地 typecheck/lint/build 均通过;B nginx 配置测试通过且 active;首页 HTML 返回新资源 `/assets/index-CYrIkAAk.js` 和 `/assets/index-TA3aiKvG.css`。
|
||||
- 回滚方式:从 B `/var/backups/lisglosips-s39-cdr-detail-layout/20260623T183751/web-dist` 恢复当前 release 的 `apps/web/dist`,再执行 `nginx -t && systemctl reload nginx`;本地恢复 `apps/web/src/App.jsx`、`apps/web/src/styles.css` 的本次改动。
|
||||
- 未解决问题:未做浏览器截图交互验证;本次为纯前端抽屉布局调整,不涉及 API、数据库、Redis 热路径、OpenSIPS、RTPEngine 或 Worker。
|
||||
|
||||
### 2026-06-23 18:29 - 需求修改/二期变更:列表列宽优化与隐藏待设计菜单
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:增强 `SimpleTable` 支持可选列宽和单元格 class;客户管理、客户网关管理、充值记录、供应商管理、落地网关管理页面的 ID/名称类列已适当收窄,并对长文本使用省略号避免撑宽列表;左侧菜单渲染时过滤 `pending` 项,隐藏“费率与计费”“SIP 运维”“监控告警”“系统设置”等待设计菜单。
|
||||
- 修改文件:`apps/web/src/App.jsx`、`apps/web/src/styles.css`、`IMPLEMENTATION_STATUS.md`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中已覆盖 `apps/web/dist`。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Node.js `v22.22.2`、pnpm `10.33.0`、Vite `5.4.21`。
|
||||
- 执行关键命令:`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`、B `tar -xzf` 覆盖 web dist、`nginx -t`、`systemctl reload nginx`、`curl -sk https://127.0.0.1/`。
|
||||
- 验证结果:本地 typecheck/lint/build 均通过;B nginx 配置测试通过且 active;首页 HTML 返回新资源 `/assets/index-N60ySjGq.js` 和 `/assets/index-uhdBdVZH.css`。
|
||||
- 回滚方式:从 B `/var/backups/lisglosips-s38-web-ui-layout/20260623T182343/web-dist` 恢复当前 release 的 `apps/web/dist`,再执行 `nginx -t && systemctl reload nginx`;本地恢复 `apps/web/src/App.jsx`、`apps/web/src/styles.css` 的本次改动。
|
||||
- 未解决问题:未做浏览器截图交互验证;本次为纯前端布局/菜单渲染调整,不涉及 API、数据库、Redis 热路径、OpenSIPS、RTPEngine 或 Worker。
|
||||
|
||||
### 2026-06-23 17:47 - 需求修改/二期变更:自研确认弹窗与删除按钮警示色
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:新增通用 `ConfirmDialog`,按现有 Modal/UI 风格替换原生 `window.confirm` 和旧确认弹窗;当前通话强制挂断、客户/供应商/客户网关/落地网关/落地线路组删除、客户网关/落地网关启停、策略删除、抽检规则删除、重置密码确认均使用自研弹窗;所有删除按钮改为 `danger` 红色警示态,包括表格删除、编辑抽屉中的删除行按钮以及线路组移除网关按钮。
|
||||
- 修改文件:`apps/web/src/App.jsx`、`apps/web/src/styles.css`、`IMPLEMENTATION_STATUS.md`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中已覆盖 `apps/web/dist`。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Node.js `v22.22.2`、pnpm `10.33.0`、Vite `5.4.21`。
|
||||
- 执行关键命令:`rg 'window\.confirm' apps/web/src/App.jsx`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`、B `tar -xzf` 覆盖 web dist、`nginx -t`、`systemctl reload nginx`、`curl -sk https://127.0.0.1/`。
|
||||
- 验证结果:本地 typecheck/lint/build 均通过;`rg 'window\.confirm' apps/web/src/App.jsx` 无匹配;B nginx 配置测试通过且 active;首页 HTML 返回新资源 `/assets/index-CWnw3J5O.js` 和 `/assets/index-BuNsq8w9.css`。
|
||||
- 回滚方式:从 B `/var/backups/lisglosips-s37-confirm-dialog-ui/20260623T094434/web-dist` 恢复当前 release 的 `apps/web/dist`,再执行 `nginx -t && systemctl reload nginx`;本地恢复 `apps/web/src/App.jsx`、`apps/web/src/styles.css` 的本次改动。
|
||||
- 未解决问题:未做浏览器交互截图验证;功能行为已通过构建和页面资源烟测。
|
||||
|
||||
### 2026-06-23 16:20 - 需求修改/二期变更:充值记录过滤、充值性能与新建链路通话测试
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:A、B、T、本地
|
||||
- 完成内容:客户话单消费不再写入 `customer_recharges`,CDR worker 仅写 raw/rated CDR 并扣客户余额;充值记录 API 过滤历史 `worker-cdr`/`cdr:`/`CDR_CHARGE:` 客户消费流水;Web 客户/供应商充值成功后改为局部更新余额与充值列表,不再触发全量 `refreshApi()`,避免供应商充值后长时间停留在“拉取API”。完整流程测试时发现 A 热路径仍硬编码成功 CDR 和落地网关,已新增 S28 Lua 动态选择线路组首个启用落地网关,并让 OpenSIPS 成功 CDR 从 dialog 变量写入动态 customer/gateway/policy/vendorGateway/lineGroup;补齐 B `/etc/lisglosips/config-publisher.env` 并启动 `lisglosips@config-publisher`;修复 CDR worker 对超大 `config_version` 写 MySQL INT 越界的问题。
|
||||
- 修改文件:`apps/worker-cdr/src/rating.ts`、`apps/worker-cdr/src/rating.spec.ts`、`apps/api/src/modules/recharges/recharges.repository.ts`、`apps/web/src/App.jsx`、`infra/server-a/s28/opensips.cfg`、`infra/server-a/s28/lisglosips_hotpath.lua`、`IMPLEMENTATION_STATUS.md`;B 当前 release 的 `apps/api/dist`、`apps/web/dist`、`apps/worker-cdr/dist` 已覆盖部署;A `/etc/opensips/opensips.cfg` 与 `/usr/local/lib/lisglosips/lisglosips_hotpath.lua` 已更新;B 新增 `/etc/lisglosips/config-publisher.env`。
|
||||
- 验证结果:本地 `corepack pnpm@10.33.0 typecheck` 通过;`corepack pnpm@10.33.0 exec vitest run apps/worker-cdr/src/rating.spec.ts apps/api/src/modules/recharges/recharges.e2e.spec.ts --maxWorkers=1` 通过;全量 `corepack pnpm@10.33.0 exec vitest run --maxWorkers=1` 21 个测试文件 74 条测试通过;最终 `lint` 与全 workspace `build` 通过。B API `/api/v2/health/ready` 正常;客户充值记录按测试客户查询仅 1 条人工充值,未出现 CDR 消费充值;供应商充值接口实测约 818ms,客户充值约 1063ms。A `opensips -C` 通过并 active;Redis active config 版本 `1782201896870` 下 `auth:ip:100.93.185.30` 命中新建 `cgw_zz_s36_20260623160046`。完整流程测试创建供应商、落地网关、落地线路组、客户、客户网关、策略、客户充值、供应商充值后,由 T 发起 `s36-1001 -> 13800136036`,当前通话 API 显示 `callerIp=100.93.185.30`、`landingIp=100.93.185.30`,强制挂断返回 `HANGUP_IN_PROGRESS`,随后当前通话列表清空;最终 CDR `raw_66b73108dc1e485ab17c6ac52a9464c1` 为 `RATED`,rated CDR `customer_fee=0.012000`、`vendor_cost=0.012000`,测试客户余额从 `10.000000` 扣为 `9.988000`。
|
||||
- 回滚方式:B 应用回滚可从 `/var/backups/lisglosips-s36-recharge-flow/20260623T074955` 恢复 `api-dist`、`web-dist`、`worker-cdr-dist` 并重启 `lisglosips@api`、`lisglosips@cdr-worker`;worker 后续补丁可从 `/var/backups/lisglosips-s36-worker-cdr-config-version/20260623T081403` 恢复。A OpenSIPS 热路径回滚点包括 `/var/backups/lisglosips-s36-hotpath/20260623T080010` 和 `/var/backups/lisglosips-s36-dialog-cdr/20260623T080956`,恢复 `/etc/opensips/opensips.cfg` 后执行 `opensips -C -f /etc/opensips/opensips.cfg` 并重启 `opensips`;B config-publisher env 回滚点为 `/var/backups/lisglosips-s36-config-publisher-env/20260623T080456`。测试业务数据使用前缀 `S36 Flow 20260623160046`,如需清理,应按 API 软删除客户网关/策略、线路组、落地网关、客户和供应商,不直接删除充值/话单审计记录。
|
||||
- 遗留问题:测试实体当前保留启用,T 源 IP 会命中新建测试客户网关;若后续要恢复 S28 原始测试路由,应软删除或停用该测试客户网关并等待 config-publisher 发布。两次早期测试呼叫因 A 成功 CDR 动态变量和 worker `config_version` 越界进入 `stream:cdr_deadletter`,未进入 raw/rated CDR,已作为本次排障证据保留。T 在测试中曾出现一次 SSH banner 超时和一次 ping 丢包,重试后恢复。
|
||||
|
||||
### 2026-06-23 15:36 - 需求修改/二期变更:列表计数、删除功能和启停确认
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:供应商列表显示落地网关数;客户管理、供应商管理前端增加删除按钮和确认弹窗,后端沿用已有软删除并分别在客户网关数/落地网关数大于 0 时拒绝删除。客户网关、落地网关后端新增 `DELETE` 软删除接口并纳入审计;客户网关删除会同步软删该网关下的路由策略并发布配置 outbox;落地网关删除在仍被未删除落地线路组引用时拒绝,避免热配置断链。落地线路组 API 新增 `customerGatewayCount`,按正在使用该线路组的去重客户网关数统计;删除落地线路组时若该数大于 0 则拒绝。Web 客户网关、落地网关启用/禁用前增加确认弹窗;客户网关、落地网关、落地线路组页面增加删除按钮和确认弹窗,并接入真实 API 列表/操作。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`apps/api/src/modules/customer-gateways/customer-gateways.controller.ts`、`apps/api/src/modules/customer-gateways/customer-gateways.service.ts`、`apps/api/src/modules/customer-gateways/customer-gateways.repository.ts`、`apps/api/src/modules/customer-gateways/customer-gateways.e2e.spec.ts`、`apps/api/src/modules/vendor-gateways/vendor-gateways.controller.ts`、`apps/api/src/modules/vendor-gateways/vendor-gateways.service.ts`、`apps/api/src/modules/vendor-gateways/vendor-gateways.repository.ts`、`apps/api/src/modules/vendor-gateways/vendor-gateways.e2e.spec.ts`、`apps/api/src/modules/landing-line-groups/landing-line-groups.repository.ts`、`apps/api/src/modules/landing-line-groups/landing-line-groups.e2e.spec.ts`、`apps/web/src/api.js`、`apps/web/src/App.jsx`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中覆盖 API/Web dist。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 B 既有 Node.js `v22.22.2`、pnpm `10.33.0`、NestJS、Vite、Prisma、Nginx。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`、`corepack pnpm@10.33.0 exec vitest run apps/api/src/modules/customer-gateways/customer-gateways.e2e.spec.ts apps/api/src/modules/vendor-gateways/vendor-gateways.e2e.spec.ts apps/api/src/modules/landing-line-groups/landing-line-groups.e2e.spec.ts apps/api/src/modules/customers/customers.e2e.spec.ts --maxWorkers=1`、`corepack pnpm@10.33.0 exec vitest run apps/api/src/modules/vendors/vendors.e2e.spec.ts --maxWorkers=1`;B `tar -xzf` 覆盖当前 release API/Web dist、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`curl http://127.0.0.1:3000/api/v2/health/ready`
|
||||
- 验证结果:typecheck、lint、build 均通过。相关 e2e 验证通过:客户、供应商、客户网关、落地网关、落地线路组;一次组合运行中 `vendors.e2e` 因 Nest 多模块启动超过 10 秒 hookTimeout 被跳过/失败,随后单独运行 `vendors.e2e` 3 条测试全部通过。最终全量 Vitest 单 worker 模式 21 个测试文件、74 条测试通过。B `lisglosips@api` 与 `nginx` active,API ready 返回 `config/database/redis` 均 ok。B 只读烟测通过:`/vendors` 返回 `gatewayCount`,`/landing-line-groups` 返回 `customerGatewayCount`;当前本地数据示例 `ven_s28_t.gatewayCount=1`、`llg_s28_t.customerGatewayCount=1`。
|
||||
- 回滚方式:B 已备份覆盖前 dist 到 `/var/backups/lisglosips-s35-delete-count-confirm/20260623T153500/api-dist` 与 `/var/backups/lisglosips-s35-delete-count-confirm/20260623T153500/web-dist`;如需回滚,将两目录恢复到 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/api/dist` 与 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/web/dist`,重启 `lisglosips@api` 并 `nginx -t && systemctl reload nginx`。本次无数据库 schema migration;如已通过新功能执行业务删除,删除为软删除,需要按具体对象在维护窗口受控恢复 `deleted_at/status` 与相关 outbox。
|
||||
- 未解决问题:落地网关删除目前在被落地线路组引用时会拒绝,比本次需求更保守,目的是避免线路组热配置引用已删除网关;如果后续希望“删除落地网关时自动从线路组移除”,需单独设计优先级重排和配置发布语义。
|
||||
- 下一任务:继续等待下一项二期需求;阿里云迁移仍不要直接开始。
|
||||
|
||||
### 2026-06-23 15:12 - 需求修改/二期变更:当前通话增加呼叫方 IP 与落地 IP
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:B、T、本地
|
||||
- 完成内容:在当前通话 API 归一化结果中新增 `callerIp` 与 `landingIp` 字段;解析优先级为 SIP Contact、SDP `c=IN IP4/IP6`、SIP URI、bind addr 兜底。Web “当前通话 / 实时呼叫列表”新增“呼叫方 IP”和“落地 IP”两列。该变更不涉及数据库 schema、Redis 热路径、OpenSIPS 配置、RTPEngine 或 Worker。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`apps/api/src/modules/active-calls/active-calls.service.ts`、`apps/api/src/modules/active-calls/active-calls.service.spec.ts`、`apps/web/src/App.jsx`;B 当前 release `/opt/lisglosips/releases/s33-active-calls-20260623094000` 中覆盖 API/Web dist。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 B 既有 Node.js `v22.22.2`、pnpm `10.33.0`、NestJS、Vite、Nginx。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 exec vitest run apps/api/src/modules/active-calls/active-calls.service.spec.ts --maxWorkers=1`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 build`;B `tar -xzf` 覆盖当前 release API/Web dist、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`curl http://127.0.0.1:3000/api/v2/health/ready`;T `/opt/lisglosips-s28/lisglosips-s28-sip.py invite --timeout 20 --hold 60`
|
||||
- 验证结果:当前通话单测 5 条通过;typecheck、lint、build 均通过。B `lisglosips@api` 与 `nginx` active,API ready 返回 `config/database/redis` 均 ok。A/B/T 端到端验证:T 发起保持呼叫后,B API 查询到当前通话并返回 `callerIp=100.93.185.30`、`landingIp=100.93.185.30`;当前本地 T 同时模拟主叫与落地 UAS,因此两者相同符合测试拓扑。API 挂断返回 `HANGUP_IN_PROGRESS`,等待 OpenSIPS 删除延迟后当前通话列表清空。
|
||||
- 回滚方式:B 已备份覆盖前 dist 到 `/var/backups/lisglosips-s34-active-call-ips/20260623T150800/api-dist` 与 `/var/backups/lisglosips-s34-active-call-ips/20260623T150800/web-dist`;如需回滚,将两目录恢复到 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/api/dist` 与 `/opt/lisglosips/releases/s33-active-calls-20260623094000/apps/web/dist`,重启 `lisglosips@api` 并 `nginx -t && systemctl reload nginx`。无数据库、A/OpenSIPS、Redis、RTPEngine 回滚项。
|
||||
- 未解决问题:真实生产落地网关若不返回 SIP Contact 或 SDP 连接地址,`landingIp` 会退回到可解析的 URI/bind 地址,可能显示为 OpenSIPS 本地地址;后续可在路由侧显式写入 dialog 变量以获得更精确的落地网关 IP。
|
||||
- 下一任务:继续等待下一项二期需求;阿里云迁移仍不要直接开始。
|
||||
|
||||
### 2026-06-23 10:15 - 需求修改/二期变更:新增“当前通话”菜单与强制挂断
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:A、B、T、本地
|
||||
- 完成内容:新增 Web “业务 / 当前通话”菜单,可刷新查看 OpenSIPS 当前 Dialog 列表,展示主叫、被叫、Call-ID、状态、时长、联系方式,并提供确认后的“挂断”按钮。B API 新增 `GET /api/v2/active-calls` 与 `POST /api/v2/active-calls/:id/hangup`,使用新增权限 `active_calls.view`、`active_calls.manage` 和审计拦截器;超级管理员具备全部权限,技术运维具备查看/挂断,运营管理员仅查看。A 启用 OpenSIPS `dialog.so` 并在 INVITE 路径执行 `create_dialog()`;新增受限 SSH forced-command `/usr/local/sbin/lisglosips-call-control`,仅允许 `dlg_list` 与 `dlg_end_dlg`,MI HTTP 仍绑定本机 `127.0.0.1:8888`。B 新增专用 `lisglosips` 服务用户出站 SSH key 与 `/etc/lisglosips/call-control/ssh_config`,API 通过该受限通道访问 A;修复 `AUTH_COOKIE_SECURE` 和 `ACTIVE_CALLS_SSH_HOST` 空值导致的 B API 启动/调用兼容问题。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`apps/api/src/modules/active-calls/active-calls.controller.ts`、`apps/api/src/modules/active-calls/active-calls.module.ts`、`apps/api/src/modules/active-calls/active-calls.service.ts`、`apps/api/src/modules/active-calls/active-calls.service.spec.ts`、`apps/api/src/modules/active-calls/opensips-mi.client.ts`、`apps/api/src/modules/app.module.ts`、`apps/api/src/shared/config.ts`、`apps/web/src/App.jsx`、`apps/web/src/api.js`、`packages/auth/src/index.ts`、`prisma/seed.ts`、`infra/server-a/s28/opensips.cfg`、`infra/server-a/s32/lisglosips-call-control`;A `/etc/opensips/opensips.cfg`、A `/usr/local/sbin/lisglosips-call-control`、B `/etc/lisglosips/api.env`、B `/etc/lisglosips/call-control/*`、B release `/opt/lisglosips/releases/s33-active-calls-20260623094000`
|
||||
- 安装软件及固定版本:未安装新软件;使用 A 既有 OpenSIPS `3.4.11` dialog 模块、B 既有 Node.js `v22.22.2`、pnpm `10.33.0`、NestJS、Vite、Prisma、MySQL、Redis、Nginx。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 exec vitest run --maxWorkers=1`、`corepack pnpm@10.33.0 build`;A `opensips -C -f`、`systemctl restart opensips`、`systemctl is-active opensips rtpengine`;B `systemctl start lisglosips-backup.service`、`corepack pnpm@10.33.0 db:seed`、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`curl http://127.0.0.1:3000/api/v2/health/ready`;T `/opt/lisglosips-s28/lisglosips-s28-sip.py invite --timeout 20 --hold 60`
|
||||
- 验证结果:本地 lint 通过;typecheck 通过;全量 Vitest 单 worker 模式 21 个测试文件、73 条测试通过;workspace build 通过。A OpenSIPS 配置语法检查通过并已重启,`opensips`、`rtpengine` active;B `lisglosips@api`、`nginx`、`mysql`、`redis-server` active,API ready 返回 `config/database/redis` 均 ok。未登录访问 `/api/v2/active-calls` 返回 401;登录态访问空闲列表返回 `source=opensips-mi,total=0`。A/B/T 端到端验收:T 发起保持呼叫后,B API 查询到 1 条当前通话;调用 B API 挂断返回 `HANGUP_IN_PROGRESS`,OpenSIPS Dialog 状态进入 `5`,等待删除延迟后 B API 当前通话列表清空。
|
||||
- 回滚方式:B 应用回滚可将 `/opt/lisglosips/current` 切回上一 release `/opt/lisglosips/releases/s32-captcha-admin-20260622124659`,重启 `lisglosips@api` 并 reload Nginx;如需还原 B 环境变量,使用 `/var/backups/lisglosips-s33-active-calls-b/20260623T014402Z/api.env`。A 回滚可从 `/var/backups/lisglosips-s33-active-calls/20260623T014315Z` 恢复 `/etc/opensips/opensips.cfg` 后重启 `opensips`,并移除 `/usr/local/sbin/lisglosips-call-control`、`lisglo-callctl` 用户/authorized_keys 以及 B `/etc/lisglosips/call-control` 专用 key。数据库无 schema migration;新增权限/角色授权来自 seed,可保留,若需清理需维护窗口执行受控 SQL。B 发布前 MySQL/Redis 备份为 `/data/backups/mysql/20260623T014114Z` 与 `/data/backups/redis/20260623T014114Z`。
|
||||
- 未解决问题:OpenSIPS HTTP MI 的 `dlg_end_dlg` 在实际终止 Dialog 时会返回 `500 Operation failed`,但 Dialog 会进入 state `5` 并随后清空;API 已按“500 后复查消失或 state 5 则视为已受理”处理。当前通话列表依赖 OpenSIPS dialog 模块,只覆盖本地 KVM A 单节点;未来多 OpenSIPS 节点需按节点聚合。强制挂断会影响被选中的实时呼叫,操作已纳入 RBAC 与审计,生产迁移前需再次演练。
|
||||
- 下一任务:继续等待下一项二期需求;阿里云迁移仍不要直接开始。
|
||||
|
||||
### 2026-06-22 14:20 - 需求修改/二期变更:修复登录验证码刷新后不显示
|
||||
|
||||
- 状态:已完成,等待用户浏览器复验
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:定位验证码接口返回的是 `data:image/svg+xml;base64,...` SVG 图片,而 B Nginx 安全头 `Content-Security-Policy` 未显式允许 `img-src data:`,浏览器会拦截验证码图片渲染,表现为“验证码刷新不出来”。已将仓库和 B 当前 Nginx 安全头更新为 `default-src 'self'; img-src 'self' data:; base-uri 'self'; frame-ancestors 'none'; form-action 'self'; object-src 'none'`,保留原有同源、禁止嵌入和禁止 object 的安全基线。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`infra/server-b/s05/nginx/lisglosips-security-headers.conf`;B `/etc/nginx/snippets/lisglosips-security-headers.conf`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 B 既有 Nginx `1.24.0-2ubuntu7.12` 和当前 release `/opt/lisglosips/releases/s32-captcha-admin-20260622124659`
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 prisma:validate`、`corepack pnpm@10.33.0 exec vitest run --maxWorkers=1`、`corepack pnpm@10.33.0 build`;B `cp -a` 备份 Nginx 安全头、`nginx -t`、`systemctl reload nginx`、`curl -k -sI https://127.0.0.1/`、`curl http://127.0.0.1:3000/api/v2/auth/captcha`
|
||||
- 验证结果:本地 lint、typecheck、Prisma validate 均通过;全量 Vitest 单 worker 模式 20 个测试文件、69 条测试通过;workspace build 通过。B 当前 release 确认为 `/opt/lisglosips/releases/s32-captcha-admin-20260622124659`;`nginx -t` 通过并已 reload;HTTPS 首页响应头已返回 `Content-Security-Policy: default-src 'self'; img-src 'self' data:; base-uri 'self'; frame-ancestors 'none'; form-action 'self'; object-src 'none'`;`GET http://127.0.0.1:3000/api/v2/auth/captcha` 返回新的 `captchaId`、`data:image/svg+xml;base64,...` 图片和过期时间;B `nginx`、`lisglosips@api`、`lisglosips@cdr-worker`、`lisglosips@recording-worker` 均 active。本次未做 A/B/T SIP 呼叫链路,因为变更只涉及 B Web 安全头,不影响 Redis 热路径、OpenSIPS、RTPEngine、CDR 或录音链路。
|
||||
- 回滚方式:B 已备份原安全头到 `/var/backups/lisglosips-s32-captcha-csp/20260622T061944Z/lisglosips-security-headers.conf`;如需回滚,恢复该文件到 `/etc/nginx/snippets/lisglosips-security-headers.conf`,执行 `nginx -t` 通过后 `systemctl reload nginx`。仓库侧回滚 `infra/server-b/s05/nginx/lisglosips-security-headers.conf` 的本次一行 CSP 修改即可。无数据库、Redis、服务 release、OpenSIPS 或 RTPEngine 回滚项。
|
||||
- 未解决问题:尚未由用户在真实浏览器中点击验证码刷新并确认图片可见;验证码仍为 API 单进程内存存储,后续多 API 实例/生产高可用建议迁移到 Redis 或共享缓存。
|
||||
- 下一任务:用户浏览器复验 B 登录页验证码刷新;继续等待下一项二期需求。
|
||||
|
||||
### 2026-06-22 12:54 - 需求修改/二期变更发布到 B:登录图形验证码与 admin 初始账号
|
||||
|
||||
- 状态:已完成,等待用户验收
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:在登录接口新增一次性图形验证码,`GET /api/v2/auth/captcha` 生成 5 位 SVG 验证码并只返回 `captchaId`、图片 data URL 和过期时间;`POST /api/v2/auth/login` 必须携带 `captchaId` 和 `captchaCode`,验证码错误返回 `401 AUTH_CAPTCHA_INVALID`,缺少登录字段继续返回统一认证失败以降低账号枚举风险。Web 登录页新增验证码图片、输入框和刷新按钮,登录失败后自动刷新验证码。B 数据库已新增/更新用户名 `admin`,启用状态,授予超级管理员角色,并按用户提供的初始口令写入 Argon2id 哈希;未在文档或命令输出中记录明文口令。发布为 B 新 release `/opt/lisglosips/releases/s32-captcha-admin-20260622124659`,`/opt/lisglosips/current` 已切换到该 release。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`apps/api/src/modules/auth/auth.controller.ts`、`apps/api/src/modules/auth/auth.module.ts`、`apps/api/src/modules/auth/captcha.service.ts`、`apps/api/src/modules/auth/auth.e2e.spec.ts`、`apps/web/src/App.jsx`、`apps/web/src/api.js`、`apps/web/src/styles.css`;B 新 release 中覆盖 API/Web dist 与对应源码。延续上一轮登录防爆破相关文件:`apps/api/src/modules/auth/auth.service.ts`、`apps/api/src/modules/auth/auth.service.spec.ts`、`apps/api/src/shared/config.ts`。
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 B 既有 Node.js `v22.22.2`、pnpm `10.33.0`、NestJS、Vite、Prisma、Nginx、Grafana `13.0.2`、Prometheus `2.45.3`。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 prisma:validate`、`corepack pnpm@10.33.0 exec vitest run --maxWorkers=1`、`corepack pnpm@10.33.0 build`、`tar -czf` 打包、`scp` 上传;B `systemctl start lisglosips-backup.service`、`cp -a` 创建新 release、`tar --no-same-owner -xzf` 覆盖产物、`ln -sfn` 切换 current、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`/tmp/lisglosips-release-preflight.sh`;B 通过临时脚本按用户提供口令 upsert `admin` 用户并撤销旧会话。
|
||||
- 验证结果:本地 lint、typecheck、Prisma validate、build 均通过;全量 Vitest 单 worker 模式 20 个测试文件、69 条测试通过,新增认证 e2e 覆盖 captcha 接口不泄露答案、无验证码登录被拒绝、携带正确验证码后可登录。B 发布前备份目录为 MySQL `/data/backups/mysql/20260622T044834Z`、Redis `/data/backups/redis/20260622T044834Z`,两者 `SHA256SUMS` 校验通过。B preflight 通过:MySQL、Redis、Nginx、API、CDR Worker、Recording Worker、Heplify、Prometheus、Grafana 均 active,API ready 返回 ok,Nginx 配置测试成功。`GET http://127.0.0.1:3000/api/v2/auth/captcha` 返回 captcha JSON 与 SVG data URL 且不含答案;使用错误验证码调用登录返回 `401 AUTH_CAPTCHA_INVALID`;`https://127.0.0.1/` 返回新前端构建资产 `index-B6ms7F5U.js` 与 `index-C60rDiFV.css`。
|
||||
- 回滚方式:如需回滚应用,按 `docs/S30_RELEASE_BACKUP_RUNBOOK.md` 将 B `/opt/lisglosips/current` 切回上一稳定 release `/opt/lisglosips/releases/s31-auth-login-20260622115851` 或原冻结 release `/opt/lisglosips/releases/s28-v2-20260621220924`,重启 `lisglosips@api` 并 reload Nginx。数据库只新增/更新 `admin` 用户密码哈希和会话撤销记录;如需回滚账号变更,可在维护窗口按 B 发布前 MySQL 备份 `/data/backups/mysql/20260622T044834Z` 恢复,或单独执行受控账号禁用/密码重置脚本,执行前需再次说明影响和回滚点。
|
||||
- 未解决问题:尚未由用户在浏览器中完成真实登录验收;验证码当前为单 API 进程内存存储,适配当前 B 单实例开发环境,后续多 API 实例/生产高可用应迁移到 Redis 或共享缓存。登录防爆破仍为进程内存级节流,生产多实例同样建议升级为 Redis/网关级共享限流。本次未做 A/B/T SIP 呼叫链路,因为变更只涉及 Web/API 登录鉴权和 B 用户数据,不影响 Redis 热路径、OpenSIPS、RTPEngine、CDR 或录音链路。
|
||||
- 下一任务:用户验收 B 登录页;继续等待下一项二期需求。
|
||||
|
||||
### 2026-06-22 12:04 - 需求修改/二期变更发布到 B:登录页与登录防爆破
|
||||
|
||||
- 状态:已完成,等待用户验收
|
||||
- 操作服务器:B、本地
|
||||
- 完成内容:将本地登录页与登录防爆破变更发布为 B 新 release `/opt/lisglosips/releases/s31-auth-login-20260622115851`,`/opt/lisglosips/current` 已切换到该 release。发布方式为复制上一 release `/opt/lisglosips/releases/s28-v2-20260621220924` 后覆盖本次 API/Web 构建产物和相关源码;未执行数据库迁移,未改 Redis 配置,未触碰 A/T、OpenSIPS 或 RTPEngine。发布前触发 B MySQL/Redis 备份并校验哈希。
|
||||
- 修改文件:本地 `IMPLEMENTATION_STATUS.md`;B 新 release 中的 `apps/api/dist/`、`apps/api/src/modules/auth/auth.service.ts`、`apps/api/src/modules/auth/auth.service.spec.ts`、`apps/api/src/shared/config.ts`、`apps/web/dist/`、`apps/web/src/App.jsx`、`apps/web/src/api.js`、`apps/web/src/styles.css`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 B 既有 Node.js `v22.22.2`、pnpm `10.33.0`、NestJS、Vite、Prisma、Nginx、Grafana `13.0.2`、Prometheus `2.45.3`
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 build`、`tar -czf` 打包发布覆盖包、`scp` 上传;B `systemctl start lisglosips-backup.service`、`cp -a` 创建新 release、`tar --no-same-owner -xzf` 覆盖产物、`ln -sfn` 切换 current、`systemctl restart lisglosips@api`、`nginx -t`、`systemctl reload nginx`、`/tmp/lisglosips-release-preflight.sh`
|
||||
- 验证结果:发布前备份目录为 MySQL `/data/backups/mysql/20260622T040339Z`、Redis `/data/backups/redis/20260622T040339Z`,两者 `SHA256SUMS` 校验通过。B preflight 通过:MySQL、Redis、Nginx、API、CDR Worker、Recording Worker、Heplify、Prometheus、Grafana 均 active,API ready 返回 ok,Nginx 配置测试成功。`GET http://127.0.0.1:3000/api/v2/health/ready` 返回 ok;未登录访问 `/api/v2/dashboard/summary` 返回 `401 AUTH_REQUIRED`;`https://127.0.0.1/` 返回新前端构建资产 `index-7KkZS1Fz.js` 与 `index-ChBVfysf.css`。Grafana health `http://127.0.0.1:3001/api/health` 返回 database ok/version `13.0.2`,Prometheus `/-/ready` 返回 ready。
|
||||
- 回滚方式:B 应用可执行 `sudo /tmp/lisglosips-release-preflight.sh` 复核状态;如需回滚,按 `docs/S30_RELEASE_BACKUP_RUNBOOK.md` 将 `/opt/lisglosips/current` 切回 `/opt/lisglosips/releases/s28-v2-20260621220924`,重启 `lisglosips@api` 并 reload Nginx;数据库和 Redis 未变更,备份目录仅作为发布前恢复点保留。
|
||||
- 未解决问题:尚未由用户在浏览器中完成真实登录验收;本次未做 A/B/T SIP 呼叫链路,因为变更只涉及 Web/API 登录鉴权,不影响 Redis 热路径、OpenSIPS、RTPEngine、CDR 或录音链路。后续多 API 实例/生产环境仍建议把登录节流升级为 Redis 或网关级共享限流。
|
||||
- 下一任务:用户验收登录页面;继续等待下一项二期需求。
|
||||
|
||||
### 2026-06-22 11:53 - 需求修改/二期变更:登录页与登录防爆破
|
||||
|
||||
- 状态:已完成
|
||||
- 操作服务器:本地
|
||||
- 完成内容:完善 Web 登录闭环,打开应用时先尝试 `/api/v2/auth/refresh` 恢复会话,未认证时只显示登录页面;输入用户名和密码调用 `/api/v2/auth/login`,登录成功后保存 access token 并加载业务数据;顶部显示当前登录用户并支持退出,退出时调用 `/api/v2/auth/logout`、清理本地 token 和页面数据。后端在既有 Argon2id、用户失败次数和账号锁定基础上,新增内存级登录节流,按用户名与来源 IP 统计失败次数;即使用户名不存在,连续失败也会触发 `429 AUTH_LOGIN_THROTTLED`,避免撞库/爆破时泄露账号存在性。新增运行时配置 `AUTH_LOGIN_THROTTLE_MAX_FAILURES` 和 `AUTH_LOGIN_THROTTLE_WINDOW_SECONDS`。
|
||||
- 修改文件:`IMPLEMENTATION_STATUS.md`、`apps/web/src/App.jsx`、`apps/web/src/api.js`、`apps/web/src/styles.css`、`apps/api/src/shared/config.ts`、`apps/api/src/modules/auth/auth.service.ts`、`apps/api/src/modules/auth/auth.service.spec.ts`
|
||||
- 安装软件及固定版本:未安装新软件;继续使用 Node.js/pnpm、NestJS、Vite、Vitest、Prisma 既有版本。
|
||||
- 执行的关键命令:本地 `corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 exec vitest run apps/api/src/modules/auth/auth.service.spec.ts apps/api/src/modules/auth/auth.e2e.spec.ts`、`corepack pnpm@10.33.0 exec vitest run --maxWorkers=1`、`corepack pnpm@10.33.0 prisma:validate`、`corepack pnpm@10.33.0 build`
|
||||
- 验证结果:lint 通过;typecheck 通过;认证单测/e2e 6 条通过;全量 Vitest 使用 `--maxWorkers=1` 后 20 个测试文件、69 条测试全部通过;Prisma schema validate 通过;workspace build 通过。首次全量并行测试曾出现多个 Nest e2e `beforeAll` 超时,改为单 worker 后全部通过,判断为本地并行资源/初始化竞争导致的假失败。
|
||||
- 回滚方式:恢复上述 7 个文件到本次修改前版本即可;无数据库 schema 变更、无服务器写操作、无 Redis/OpenSIPS/RTPEngine 配置变更。若已发布到 B,可按 `docs/S30_RELEASE_BACKUP_RUNBOOK.md` 使用上一 release 切回并重启 API/Web 相关服务。
|
||||
- 未解决问题:本次只完成本地代码修改,尚未发布到 B 当前冻结 release,也未做浏览器视觉截图或 A/B/T 端到端验收;登录节流为单进程内存级,足以覆盖当前单 API 进程开发环境,后续多 API 实例或生产环境建议迁移到 Redis/网关级限流以跨进程共享计数。
|
||||
- 下一任务:等待下一个二期需求;如需上线本变更,应按 S30 发布流程创建新 B release 并做 preflight/登录冒烟。
|
||||
|
||||
### 2026-06-22 10:35 - S30 备份、Runbook、灰度与上线完成
|
||||
|
||||
- 状态:已完成
|
||||
|
||||
Reference in New Issue
Block a user