# LisgloSIPS V2 实施状态 > 本文件用于跨 Codex 会话持续交接。每次新会话开始必须先读取本文件和 `SOFTSWITCH_PLATFORM_DESIGN_V2.md`;每次任务完成、失败或被阻塞后必须更新本文件。 ## 当前状态 - 当前任务:需求修改/二期变更:权限驱动导航和按钮 - 本次变更摘要:已完成登录/刷新响应透出 `user.permissions`,前端新增统一 `can(permission)` 权限封装;菜单按页面权限裁剪,核心真实 API 页面操作按钮按 manage/play 权限裁剪,无权限页面提供明确提示,并避免无权限启动时批量请求导致 403。 - 总体状态:S30 已完成;本地 KVM 开发环境 V2 闭环原冻结 release 为 `s28-v2-20260621220924`;B 已切换并冻结到 `s42-phase2-business-prefix-20260624140000` 作为二期业务前缀小样本联调基线,MySQL 已补齐号码库 migration `20260624095000_number_library` 与业务前缀 migration `20260624121000_business_prefix_gateway_rewrite`,Prisma status 为 up to date,config-publisher 当前 active 配置版本为 `1782286812696`,上一版本为 `1782286145681`,B preflight 直接执行通过;A 已加载业务前缀 Lua SHA `0b7ee595cdcad2f38a670dd8ff3553387820039e`,OpenSIPS 配置 SHA-256 为 `ae1544e9a39d2db114e6981babac042c2ab6d399d59ba597a52b85d597aa5aa5`,最终 `dlg_list` 已清空;T 已完成冻结验收实呼 `s28-1782288889943-ckv83lce@lisglosips-t`,B CDR 入库并计费成功;当前仍未导入真实 80 万手机号段;阿里云迁移前需按 S30 Runbook 重新演练 - 最后更新:2026-06-24 17:50 +08:00 - 当前阻塞:无阻塞。遗留问题:真实 80 万手机号段尚未导入;OpenSIPS dialog 在测试呼叫结束后可能残留,冻结前已通过重启清空,后续应单独分析 dialog 生命周期和 `dlg_end_dlg Operation failed` 根因;本次权限裁剪使用本地 mock API 完成只读账号浏览器冒烟,真实 B 服务器浏览器登录态逐页按钮、真实录音文件播放和 Nginx/X-Accel 链路仍需后续人工复测。 - 当前环境:A/B/T 为本地 KVM 开发服务器,通过 Tailscale 联调;开发完成后再迁移阿里云 - 私密访问资料:`.codex-private/SERVER_ACCESS.md`,只在实际连接时读取,禁止回显 ## 服务器索引 | 代号 | 地址 | 用户 | 用途 | | --- | --- | --- | --- | | A | `100.90.90.90` | `hector` | OpenSIPS、RTPEngine、录音内存盘、HEP、Exporter | | B | `100.90.90.91` | `hector` | API、Worker、Redis、MySQL、录音、HOMER、Prometheus/Grafana | | T | `100.93.185.30` | `hector` | 已安装 OpenSIPS,模拟客户 SIP 注册与呼叫 | ## 任务状态表 状态只能使用:`待开始`、`进行中`、`已完成`、`已阻塞`、`已跳过`。 | ID | 任务 | 状态 | 主要产物/验收 | | --- | --- | --- | --- | | S00 | SSH 安全接入与凭据迁移 | 已完成 | 三机 SSH Key、密码轮换、访问验证、访问 Runbook;后续 SSH 加固只调整管理端口并保留 Key 登录 | | S01 | 三机只读资产盘点 | 已完成 | `docs/inventory-A.md`、`inventory-B.md`、`inventory-T.md`、汇总报告 | | S02 | 网络与安全组验收 | 已完成 | `docs/infra-check.md`,含本地端口矩阵和未来阿里云安全组清单 | | S03 | Server B 基础系统初始化 | 已完成 | `docs/SERVER_B_BASELINE_RUNBOOK.md`、`infra/server-b/s03/`、远端备份 | | S04 | Server B MySQL 与 Redis | 已完成 | `docs/SERVER_B_DATA_SERVICES_RUNBOOK.md`、`infra/server-b/s04/`、备份恢复演练 | | S05 | Server B Node.js、Nginx 与 TLS 基线 | 已完成 | `docs/SERVER_B_WEB_RUNTIME_RUNBOOK.md`、`infra/server-b/s05/`、HTTPS 与重启验收 | | S06 | Server B HOMER 与基础监控 | 已完成 | HEP 接收、HOMER API、Prometheus、Grafana、exporters、A Node Exporter | | S07 | V2 后端 Monorepo 骨架 | 已完成 | NestJS/Fastify/Prisma、日志、配置、健康检查、测试框架;本地和 B 均可构建 | | S08 | 数据库 Schema 与迁移 | 已完成 | Prisma Schema、初始化迁移、内置角色/权限种子、B 临时空库迁移和备份恢复测试 | | S09 | 登录认证基础 | 已完成 | 登录、刷新、退出、Argon2id、Session/Token 安全 | | S10 | 用户、角色、权限与审计 | 已完成 | RBAC、内置角色保护、重置密码、审计拦截器 | | S11 | 客户管理 API | 已完成 | 客户 CRUD、启停、余额/授信读取、单元与集成测试 | | S12 | 充值与不可变余额流水 | 已完成 | 客户/供应商充值、幂等、事务、审计、并发测试 | | S13 | 客户网关 API | 已完成 | IP/SIP 注册认证配置、启停、密码安全存储 | | S14 | 客户网关策略与 Redis 配置发布 | 已完成 | 主被叫匹配、优先级、Outbox、配置版本和回滚 | | S15 | 供应商管理 API | 已完成 | 供应商 CRUD、余额/授信、启停 | | S16 | 落地网关 API | 已完成 | CPS/并发/时段/编码/号码转换/周期费率/启停 | | S17 | 落地线路组 API | 已完成 | 成员增删、优先级重排、并发汇总、完整性校验 | | S18 | Server A OpenSIPS 基线 | 已完成 | 15060、认证、防扫描、MI 本地绑定、Redis/HEP 模块 | | S19 | Server A RTPEngine 与录音 tmpfs | 已完成 | 内核转发、RTP 端口段、3 GiB tmpfs、录音 ready 规则 | | S20 | Server A Redis 热路径与 HEP/指标 | 已完成 | Lua 原子检查、配置读取、HEP 9060、Node Exporter | | S21 | Server T 客户模拟配置 | 已完成 | IP/SIP 注册两套测试账号、呼叫脚本、失败场景脚本 | | S22 | CDR Redis Stream | 已完成 | 标准事件、XADD/XREADGROUP、ACK、Pending、死信、幂等 | | S23 | 最小计费与余额扣减 | 已完成 | Decimal 计费、客户费用/成本、重复 CDR 不重复扣费 | | S24 | 录音搬运与播放 | 已完成 | A->B 私网搬运、校验、Range、权限、源文件安全删除 | | S25 | 质检后端 | 已完成 | 抽检规则、稳定抽样、录音详情、质检保存和审计 | | S26 | Dashboard 聚合 | 已完成 | 实时占位/聚合指标、趋势、失败码、异常网关、待质检 | | S27 | React Demo 接入真实 API | 已完成 | API Client、核心运营页真实 API、错误/加载/空状态 | | S28 | 三机端到端联调 | 已完成 | T 发起呼叫,A 转发录音,B 出 CDR/费用/信令/质检 | | S29 | 性能、故障与安全测试 | 已完成 | CPS/并发/录音、Redis/MySQL/Worker 故障、越权与重放 | | S30 | 备份、Runbook、灰度与上线 | 已完成 | 恢复演练、上线/回滚脚本、灰度记录、验收报告 | ## 每次新会话的固定开场指令 可直接向 Codex 发送: ```text 请先读取 SOFTSWITCH_PLATFORM_DESIGN_V2.md、IMPLEMENTATION_STATUS.md, 以及本任务关联的现有脚本/代码。只执行状态文件里的当前任务,不提前执行后续任务。 开始前复核上次交接记录;涉及服务器写操作、服务重启、防火墙、密码、数据库迁移或数据删除时先说明影响和回滚点。 完成后运行验收检查,并更新 IMPLEMENTATION_STATUS.md 的任务状态、产物、验证结果、遗留问题和下一任务。 ``` ## 单任务交接记录模板 每完成一个任务,在本节顶部新增记录: ```markdown ### YYYY-MM-DD HH:mm - Sxx 任务名称 - 状态:已完成 / 已阻塞 - 操作服务器:A / B / T / 本地 - 完成内容: - 修改文件: - 安装软件及固定版本: - 执行的关键命令:只记录无密码版本 - 验证结果: - 回滚方式: - 未解决问题: - 下一任务:Sxx ``` ## 交接记录 ### 2026-06-24 17:50 - 需求修改/二期变更:权限驱动导航和按钮 - 状态:已完成 - 操作服务器:本地 - 完成内容: - 后端登录/刷新响应新增 `user.permissions`,从用户启用角色的 `role_permissions` 汇总去重并排序后返回;保留原 `roles` 字段。 - 前端新增 `apps/web/src/permissions.js`,提供页面权限表、`permissionSet`、`can`、`canAll`、`canAny`。 - `App.jsx` 根据权限裁剪菜单;启动和手动刷新时只请求当前用户有权限的全局 API,避免无权限接口产生批量 403;无权限页面显示明确“无权限访问”提示。 - 核心页面按钮按后端真实权限 key 裁剪:当前通话挂断、客户/供应商管理、充值、客户网关、业务前缀、落地网关、落地线路组、号码库导入、话单录音播放、质检录音播放/评分/抽检规则、用户管理、角色管理。 - 修正角色权限页 dev fixture 的权限 key,使其与后端 `RequirePermissions` 使用的真实 key 保持一致。 - 修改文件:`apps/api/src/modules/auth/auth.types.ts`、`apps/api/src/modules/auth/auth.repository.ts`、`apps/api/src/modules/auth/auth.service.ts`、`apps/api/src/modules/auth/auth.service.spec.ts`、`apps/api/src/modules/auth/auth.e2e.spec.ts`、`apps/web/src/permissions.js`、`apps/web/src/App.jsx`、`apps/web/src/fixtures/devFixtures.js`、`apps/web/src/pages/*.jsx`、`IMPLEMENTATION_STATUS.md` - 安装软件及固定版本:未安装新软件。 - 执行的关键命令:`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/auth/auth.service.spec.ts apps/api/src/modules/auth/auth.e2e.spec.ts --hookTimeout=60000 --maxWorkers=1`、`corepack pnpm@10.33.0 exec vitest run --hookTimeout=60000 --maxWorkers=1`、`corepack pnpm@10.33.0 --filter @lisglosips/web dev -- --host 127.0.0.1` - 验证结果: - typecheck/lint/build 均通过。 - Auth 定向测试 2 files / 6 tests 通过,确认 login/refresh 均返回 permissions。 - 全量 Vitest 25 files / 88 tests 通过。 - 使用本地临时 mock API 与 in-app Browser 验证只读账号仅含 `dashboard.view/customers.view`:侧边栏只显示“概览 Dashboard”“客户管理”;“供应商管理”“质检中心”等菜单不可见;客户页可查看客户列表,但无“新增客户”“编辑”“充值”“删除”按钮;无 Vite overlay,无应用 console error/warn。 - 回滚方式:回滚上述后端 auth 文件、前端权限/页面文件和本状态文件即可;本次未修改 Prisma schema、未执行数据库迁移、未连服务器、未重启服务。 - 未解决问题:当前按钮级裁剪覆盖真实 API 核心页面;费率与计费、SIP 运维、监控告警、系统设置仍属于待设计/演示页面,后续接真实 API 时需继续补权限 key 和按钮裁剪。真实 B 登录态逐页按钮仍需后续人工复测。 - 下一任务:等待用户指定。 ### 2026-06-24 17:30 - 需求修改/二期变更:前端拆分与信息架构整理 - 状态:已完成 - 操作服务器:本地 - 完成内容: - 将 `App.jsx` 中的页面组件拆到 `apps/web/src/pages/`:`CdrPage.jsx`、`QualityPage.jsx`、`ActiveCallsPage.jsx`、`CustomersPage.jsx`、`CustomerGatewaysPage.jsx`、`VendorsPage.jsx`、`VendorGatewaysPage.jsx`、`VendorLineGroupsPage.jsx`、`BusinessPrefixesPage.jsx`、`NumberLibraryPage.jsx`、`RechargeRecordsPage.jsx`、`RoutesPage.jsx`、`BillingPage.jsx`、`SipOpsPage.jsx`、`MonitoringPage.jsx`、`SettingsPage.jsx`、`UsersPage.jsx`、`RolesPage.jsx`、`OperationLogsPage.jsx`。 - 将页面共享布局组件拆到 `apps/web/src/components/layout.jsx`,包含 `Icon`、`PageTitle`、`Panel`、`ApiNotice`、`Drawer`、`Modal`、`SimpleTable`、`KeyValue` 等。 - 将格式化和 API 归一化函数拆到 `apps/web/src/utils/formatters.js`,供 App 数据刷新和页面组件复用。 - 将残留静态演示/mock 数据集中到 `apps/web/src/fixtures/devFixtures.js`,避免继续散落在 `App.jsx`;未把这些旧 fixture 接入生产 API 流程。 - `App.jsx` 保留应用入口、登录、导航、全局 API 刷新与页面 props 分发,体积从约 237 KB 降到约 20 KB。 - 修改文件:`apps/web/src/App.jsx`、`apps/web/src/components/layout.jsx`、`apps/web/src/utils/formatters.js`、`apps/web/src/fixtures/devFixtures.js`、`apps/web/src/pages/*.jsx`、`IMPLEMENTATION_STATUS.md` - 安装软件及固定版本:未安装新软件。 - 执行的关键命令:`corepack pnpm@10.33.0 lint`、`corepack pnpm@10.33.0 typecheck`、`corepack pnpm@10.33.0 build`、`corepack pnpm@10.33.0 exec vitest run --hookTimeout=60000 --maxWorkers=1`、`corepack pnpm@10.33.0 --filter @lisglosips/web dev -- --host 127.0.0.1` - 验证结果: - lint/typecheck/build 均通过。 - 全量 Vitest 25 files / 88 tests 通过。 - 使用本地临时 mock API 与 in-app Browser 验证 `http://127.0.0.1:5173/`:登录后可切换“当前通话”“话单中心”“质检中心”“客户管理”,对应页面 `h1` 正确、root 正常挂载、无 Vite overlay、无应用 console error/warn。 - 拆分过程中发现并修复两个运行时拆分问题:`App.jsx` 主壳补回 `Badge` 导入;`emptySamplingRuleForm` 从 `CdrPage.jsx` 挪回 `QualityPage.jsx`。 - 回滚方式:回滚上述前端拆分文件和本状态文件即可;本次未修改 Prisma schema、未执行数据库迁移、未连服务器、未重启服务。 - 未解决问题:`fixtures/devFixtures.js` 仍承载费率、路由、监控、系统设置等未接真实 API 的旧演示数据;后续应按页面逐步接真实 API 或加 dev-only 开关彻底隔离。真实 B 服务器浏览器登录态逐页按钮仍需后续人工复测。 - 下一任务:等待用户指定。 ### 2026-06-24 17:10 - 需求修改/二期变更:质检中心接真实 API - 状态:已完成 - 操作服务器:本地 - 完成内容: - 录音列表从静态数据切换为 `api.recordings()`,接入 `GET /recordings`,支持待质检/已质检/全部筛选、条数筛选、加载中、错误提示与空状态。 - 录音详情接入 `GET /recordings/:id`,详情抽屉展示客户、被叫、业务、录音时长、抽样状态、命中规则与既有质检结果。 - 录音播放接入 `GET /recordings/:id/play`,以 blob URL 驱动页面内 `