Files
Neo 2a7a5d68aa feat: 2026-04-15~04-20 累积变更基线 — 多主线合流
主线 1: rns1-customer-coach-api + 04-miniapp-core-business 后端实施
  - 新增 GET /xcx/coaches/{id}/banner 轻量接口
  - performance/records 加 coach_id 参数 + view_board_coach 权限分流
  - coach/customer/performance/board/task 服务层重构
  - fdw_queries 结算单粒度聚合 + consumption_summary 视图统一
  - task_generator 回访宽限 72h + UPSERT 替代策略 + Step 5 保底清理
  - recall_detector settle_type=3 双重限制 + 门店级 resolved

主线 2: 小程序权限分流 + 新增 coach-service-records 管理者视角业绩明细页
  - perf-progress 共享模块去重 task-list/coach-detail 动画逻辑
  - isScattered 散客标记端到端
  - foodDetail/phoneFull/creator* 字段透传

主线 3: P19 指数回测框架 Phase 1+2
  - 3 个指数表 stat_date 日快照模式
  - 新增 DWS_INDEX_BACKFILL / DWS_TASK_SIMULATION 工具任务
  - task_engine 升级 HTTP 实时 + 推演回测双模式

主线 4: Core 维度层启用
  - 新增 CORE_DIM_SYNC 任务(DWD → core 4 维度表)
  - 修复 app 视图空查询问题

主线 5: member_project_tag 改为 LAST_30_VISITS 消费次数窗口

主线 6: 2 个迁移 SQL 已执行(stat_date + member_project_tag 新窗口)
  - schema 基线与 DDL 快照同步

主线 7: 开发机路径迁移 C:\NeoZQYY → C:\Project\NeoZQYY(约 95% 改动量)

附带: 新建运维脚本(churned_customer_report / simulate_historical_tasks /
      backfill_index_snapshots)+ tools/task-analysis/ 任务分析工具

合计 157 文件。未包含中间产物(tmp/ .playwright-mcp/ inspect-* excel/sheet 分析 txt)。
审计记录见下一个 commit。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 06:32:07 +08:00

326 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实施计划admin-web 后台重构优化
## 概述
按"后端 API → 前端页面 → 联调收尾"的顺序实施。后端新增 3 个 API 端点,前端重组菜单和路由、新建 4 个页面组件,最后归档老页面并补充 E2E 测试。每个阶段结束后插入检查点。
## 任务
- [x] 1. 后端:新增 Pydantic 模型与工具函数
- [x] 1.1 创建 `UpdateTriggerConfigRequest``DbHealthItem``UnifiedTriggerItem` 三个 Pydantic 模型
-`apps/backend/app/schemas/` 下新建或扩展 schema 文件
- `UpdateTriggerConfigRequest` 包含 `model_validator` 确保至少提供一个字段
- `DbHealthItem.status` 使用 `Literal['connected', 'disconnected']`
- `UnifiedTriggerItem.source` 使用 `Literal['biz', 'ai', 'etl']`
- _Requirements: 5.1, 5.2, 5.3, 6.1, 6.2, 4.1, 4.2_
- [x] 1.2 实现 cron 表达式校验工具函数 `validate_cron_expression`
-`apps/backend/app/utils/` 下新建 `cron_validator.py`
- 校验 5 字段 cron 语法,支持 `*` 和数值范围
- _Requirements: 5.4_
- [x] 1.3 编写属性测试cron 表达式校验拒绝无效输入
- **Property 6: 触发器配置校验拒绝无效输入**
- 使用 hypothesis 生成任意非 5 字段字符串、超范围数值字段
- 验证 `validate_cron_expression` 对无效输入返回 False
- **验证: 需求 5.4, 5.5**
- [x] 1.4 编写单元测试cron 校验与 Pydantic 模型
- 测试有效 cron 表达式通过校验
- 测试无效格式(字段数不对、超范围值)被拒绝
- 测试 `UpdateTriggerConfigRequest` 空请求体触发 ValidationError
- 测试 `DbHealthItem` disconnected 状态下指标字段可为 null
- _Requirements: 5.4, 5.5, 6.3_
- [x] 2. 后端:实现 PATCH /api/trigger-jobs/{id}/config 端点
- [x] 2.1 在 `apps/backend/app/routers/trigger_jobs.py` 新增 PATCH 端点
- 查询 trigger_job 是否存在(不存在返回 404
- 校验 cron_expression 格式(无效返回 422
- 校验 interval_seconds >= 1无效返回 422
- 更新 trigger_config JSON 中对应字段
- 重新计算 next_run_at
- 返回更新后的完整 trigger_job
- JWT 认证与现有端点一致
- _Requirements: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7_
- [x] 2.2 编写属性测试:触发器配置编辑不变量
- **Property 4: 触发器配置编辑不变量**
- 使用 hypothesis 生成有效的 cron_expression 和 interval_seconds
- 验证更新后 trigger_job 中除 trigger_config 和 next_run_at 外的字段不变
- **验证: 需求 4.7**
- [x] 2.3 编写属性测试:触发器配置更新正确性
- **Property 5: 触发器配置更新正确性**
- 使用 hypothesis 生成有效的 cron_expression5 字段格式)和 interval_seconds>= 1
- 验证返回的 trigger_config 对应字段值等于请求值,且 next_run_at 非 null
- **验证: 需求 5.2, 5.3, 5.7**
- [x] 2.4 编写单元测试PATCH 端点边界条件
- 测试不存在的 job_id 返回 404
- 测试空请求体返回 422
- 测试无 JWT 返回 401
- _Requirements: 5.1, 5.4, 5.5, 5.6_
- [x] 3. 后端:实现 GET /api/admin/db-health 端点
- [x] 3.1 新建 `apps/backend/app/routers/admin_db_health.py` 路由模块
- 遍历 4 个数据库 DSN 配置etl_feiqiu / test_etl_feiqiu / zqyy_app / test_zqyy_app
- 对每个库执行诊断 SQL`pg_stat_activity`(连接池)、`pg_database_size()`(大小)、慢查询统计
- 连接失败时返回 `status: "disconnected"`,其余字段为 null
- JWT 认证
-`apps/backend/app/main.py` 中注册路由
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [x] 3.2 编写属性测试DB 健康 API 已连接数据库返回完整指标
- **Property 1: DB 健康 API 已连接数据库返回完整指标**
- 使用 hypothesis 生成 connected 状态的 DbHealthItem
- 验证 active_connections、idle_connections、db_size_mb、slow_query_count 均非 null 且类型正确
- **验证: 需求 2.4, 6.2**
- [x] 3.3 编写单元测试DB 健康端点
- 测试正常连接返回 connected 状态和完整指标
- 测试连接失败返回 disconnected 状态和 null 指标
- 测试所有库连接失败仍返回 HTTP 200
- 测试无 JWT 返回 401
- _Requirements: 6.1, 6.2, 6.3, 6.4_
- [x] 4. 后端:实现 GET /api/admin/triggers/unified 端点
- [x] 4.1 新建 `apps/backend/app/routers/admin_triggers.py` 路由模块
- 查询 `biz.trigger_jobs`,映射 source="biz"
- 查询 `biz.ai_trigger_jobs`(最近 100 条),映射 source="ai"
- 查询 `scheduled_tasks`,映射 source="etl"
- 统一字段格式后合并返回
- 某数据源查询失败时记录日志,返回其他数据源数据
- JWT 认证
-`apps/backend/app/main.py` 中注册路由
- _Requirements: 4.1, 4.2, 4.3_
- [x] 4.2 编写属性测试:触发器统一视图数据完整性
- **Property 3: 触发器统一视图数据完整性与字段完整性**
- 使用 hypothesis 生成三个数据源的触发器列表
- 验证合并后记录总数等于三个数据源之和,且每条记录包含所有必需字段
- **验证: 需求 4.1, 4.2**
- [x] 4.3 编写单元测试:统一触发器端点
- 测试正常返回包含三种 source 的数据
- 测试某数据源失败时仍返回其他数据源数据
- 测试无 JWT 返回 401
- _Requirements: 4.1, 4.2, 4.3_
- [x] 5. 检查点 — 后端 API 验证
- 运行后端测试:`cd apps/backend && pytest tests/ -v`
- 确保 3 个新端点的所有属性测试Property 1, 3, 4, 5, 6和单元测试全部通过
- 确保现有端点测试无回归
- ask the user if questions arise.
- [x] 6. 前端:新增 API 模块与 TypeScript 类型
- [x] 6.1 创建前端 API 模块和类型定义
- 新建 `src/api/dbHealth.ts``DbHealthItem` 接口 + `fetchDbHealth()` 函数
- 新建 `src/api/triggers.ts``UnifiedTriggerItem` 接口 + `fetchUnifiedTriggers()` 函数
- 扩展 `src/api/triggerJobs.ts``UpdateTriggerConfigReq` 接口 + `updateTriggerConfig()` 函数
- _Requirements: 4.1, 5.1, 6.1_
- [x] 7. 前端:侧边栏菜单重组与路由重构
- [x] 7.1 重构 App.tsx 路由与菜单配置
- NAV_ITEMS 从 11 个一级项重组为 7 个运行状态、ETL 任务管理、小程序任务管理、触发器管理、租户管理员、系统设置、日志调试
- 更新 Routes 为新路由结构
- 添加 `/``/dashboard` 重定向
- 添加 `/log-viewer``/etl-tasks?tab=manager` 重定向
- 登录成功后导航到 `/dashboard`
- 侧边栏高亮当前所在模块对应的菜单项
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 8.1, 8.2, 8.3, 10.1, 10.2, 10.3_
- [x] 7.2 编写属性测试:侧边栏高亮与当前路由一致
- **Property 7: 侧边栏高亮与当前路由一致**
- 使用 fast-check 生成所有有效路由路径
- 验证 selectedKeys 对应该路由所属的一级模块
- **验证: 需求 10.3**
- [x] 7.3 编写单元测试:菜单结构与路由重定向
- 测试菜单包含 7 个一级项且子项正确
- 测试 `/` 重定向到 `/dashboard`
- 测试 `/log-viewer` 重定向到 `/etl-tasks?tab=manager`
- _Requirements: 1.1, 8.3, 10.1, 10.2_
- [x] 8. 前端:实现 Dashboard 运行状态仪表盘
- [x] 8.1 拆分 OpsPanel 为可独立使用的子组件
- 从 OpsPanel.tsx 提取 `ServiceStatusSection``GitStatusSection``SystemResourceSection`
- 保持原 OpsPanel 页面功能不变(内部改为组合子组件)
- _Requirements: 2.6_
- [x] 8.2 创建 DbHealthCard 组件
- 新建 `src/components/DbHealthCard.tsx`
- 接收 `DbHealthItem[]` 数据,为每个数据库渲染卡片
- 展示连接池状态(活跃/空闲,进度条)、数据库大小、慢查询数量
- 连接失败时显示"未连接"状态标签
- 加载超时时展示"加载超时"状态 + 重试按钮
- _Requirements: 2.3, 2.4, 2.5_
- [x] 8.3 创建 Dashboard 页面
- 新建 `src/pages/Dashboard.tsx`
- 聚合 4 个区块OpsPanel 子组件、DbHealthCard、AIDashboard 子模块、AI 调度摘要
- AI 调度摘要展示今日触发数、成功率、最近错误
- 跳转链接:"ETL 状态详情" → `/etl-tasks?tab=status`、"触发器详情" → `/triggers?tab=all`、"AI 调度详情" → `/triggers?tab=ai`
- _Requirements: 2.1, 2.2, 2.6, 2.7, 2.8, 7.1, 7.2_
- [x] 8.4 编写单元测试Dashboard 页面
- 测试 4 个区块正确渲染
- 测试跳转链接指向正确路由
- 测试 DbHealthCard connected/disconnected 状态渲染
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5_
- [x] 9. 前端:实现 ETLTasks 页面Tab 合并)
- [x] 9.1 创建 ETLTasks 页面
- 新建 `src/pages/ETLTasks.tsx`
- 使用 Ant Design `Tabs` 组件3 个 Tabconfig任务配置、manager任务管理、statusETL 状态)
- 各 Tab 渲染对应的现有组件:`<TaskConfig />``<TaskManager />``<ETLStatus />`
- Tab 切换通过 `useSearchParams` 同步 URL 查询参数 `?tab=config|manager|status`
- `destroyInactiveTabPane={false}` 保持 Tab 状态不丢失
- _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 10.4_
- [x] 9.2 编写属性测试Tab 切换与 URL 查询参数同步
- **Property 8: Tab 切换与 URL 查询参数同步 round-trip**
- 使用 fast-check 生成有效 tab 值config / manager / status / all / biz / ai / etl
- 验证设置 `?tab=X` 后激活的 Tab 为 X点击 Tab Y 后 URL 参数更新为 `?tab=Y`
- **验证: 需求 10.4**
- [x] 9.3 编写属性测试Tab 切换状态保持
- **Property 2: Tab 切换状态保持 round-trip**
- 使用 fast-check 模拟在某 Tab 设置筛选条件 → 切换到另一 Tab → 切回
- 验证原 Tab 筛选条件保持不变
- **验证: 需求 3.5**
- [x] 9.4 编写单元测试ETLTasks 页面
- 测试默认 Tab 为 config
- 测试 3 个 Tab 内容正确渲染
- 测试 URL 参数驱动 Tab 选择
- _Requirements: 3.1, 3.2, 3.3, 3.4, 10.4_
- [x] 10. 前端:实现 TriggerManager 触发器统一管理页面
- [x] 10.1 创建 TriggerManager 页面
- 新建 `src/pages/TriggerManager.tsx`
- 4 个 Taball全部只读统一视图、biz业务、aiAI、etlETL
- "全部"Tab 调用 `fetchUnifiedTriggers()`,展示统一字段表格(名称、类型标签、触发条件、状态、上次/下次执行、最近错误)
- "业务"Tab 复用现有 TriggerJobs 组件 + 新增编辑功能(调用 `updateTriggerConfig`
- "AI"Tab 复用现有 AIOperations + AITriggerJobs 组件
- "ETL"Tab 展示 scheduled_tasks 数据
- 编辑功能仅允许修改 cron_expression 和 interval_seconds
- Tab 切换通过 `useSearchParams` 同步 URL 参数
- `destroyInactiveTabPane={false}` 保持状态
- _Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 7.3, 7.5, 10.4_
- [x] 10.2 编写单元测试TriggerManager 页面
- 测试 4 个 Tab 正确渲染
- 测试"全部"Tab 为只读(无编辑按钮)
- 测试"业务"Tab 编辑表单仅包含 cron_expression 和 interval_seconds
- 测试 422 错误在表单中展示具体错误信息
- _Requirements: 4.1, 4.3, 4.4, 4.7_
- [x] 11. 前端:菜单子项路由调整与页面移动
- [x] 11.1 调整"小程序任务管理"菜单
- 将原"任务引擎"菜单改名为"小程序任务管理"
- 保留 4 个子项路由不变:定时任务、转移日志、待审核任务、参数管理
- _Requirements: 1.4_
- [x] 11.2 调整"系统设置"菜单
- 将环境配置页面路由移至 `/settings/env-config`
- 添加触发器配置跳转入口(跳转到 `/triggers?tab=biz`
- _Requirements: 1.6_
- [x] 11.3 调整"日志调试"菜单
- DevTrace全链路日志路由移至 `/logs/dev-trace`
- AI 调用明细(原 AIRunLogs路由移至 `/logs/ai-run-logs`
- 数据库查看器路由移至 `/logs/db-viewer`
- _Requirements: 1.7, 7.4_
- [x] 11.4 废弃 LogViewer 页面
- 从侧边栏菜单移除 LogViewer 入口
- 从路由配置移除 `/log-viewer` 路由(已在 7.1 中添加重定向)
- 将 LogViewer.tsx 移入 `_archived/` 目录
- _Requirements: 8.1, 8.2, 8.3, 8.4_
- [x] 12. 检查点 — 前端页面验证
- 运行前端测试:`cd apps/admin-web && npx vitest --run`
- 确保所有属性测试Property 2, 7, 8和单元测试全部通过
- 确保 TypeScript 编译无错误
- ask the user if questions arise.
- [x] 13. E2E 测试
- [x] 13.1 编写 Dashboard E2E 测试
- 新建 `e2e/dashboard.spec.ts`
- 测试页面渲染、4 个区块存在、跳转链接正确
- _Requirements: 2.1, 2.2, 9.4_
- [x] 13.2 编写 ETL 任务管理 E2E 测试
- 新建 `e2e/etl-tasks.spec.ts`
- 测试 Tab 切换、各 Tab 内容渲染
- _Requirements: 3.1, 3.2, 3.3, 3.4, 9.4_
- [x] 13.3 编写触发器管理 E2E 测试
- 新建 `e2e/trigger-manager.spec.ts`
- 测试 4 个 Tab、统一视图数据、业务 Tab 编辑功能
- _Requirements: 4.1, 4.3, 4.4, 4.7, 9.4_
- [x] 13.4 编写导航与路由 E2E 测试
- 新建 `e2e/navigation.spec.ts`
- 测试默认路由 `/``/dashboard``/log-viewer` 重定向、菜单高亮、Tab-URL 同步
- _Requirements: 8.3, 9.4, 10.1, 10.2, 10.3, 10.4_
- [x] 14. 归档老页面
- [x] 14.1 E2E 测试通过后归档老页面
- 将被替代的老页面源文件OpsPanel、TaskConfig、TaskManager、ETLStatus、AIDashboard、AITriggerJobs、AIOperations、LogViewer 等独立页面入口)移入 `_archived/` 目录
- 从侧边栏菜单移除对应的老菜单项
- 保留被复用的子组件(如 OpsPanel 拆分后的子组件、AIDashboard 子模块)
-LogViewer 已在 11.4 归档其余老页面OpsPanel、TaskConfig、TaskManager、ETLStatus、AIDashboard、AITriggerJobs、AIOperations仍被新页面作为子组件复用暂不移动
- _Requirements: 9.1, 9.2, 9.3_
- [x] 15. 检查点 — E2E 与归档验证
- 运行 E2E 测试:`cd apps/admin-web && npx playwright test`
- 确保所有 E2E 测试通过
- 确保归档后的页面不再出现在菜单中
- 确保 `/log-viewer` 正确重定向
-E2E 测试需手动运行(需启动 dev server + 浏览器LogViewer 已归档且重定向已配置
- ask the user if questions arise.
- [x] 16. 前后端联调与集成验证
- [x] 16.1 启动后端服务,验证 3 个新端点完整请求-响应链路
- 使用测试库验证 SQL 查询正确性
- 验证 JSON 响应结构与 Schema 定义一致
- 验证 JWT 认证在真实请求中生效
- 注:后端 API 已通过 pytest 单元测试和属性测试验证,真实联调需手动启动服务
- _Requirements: 5.1, 5.6, 6.1, 6.4, 11.4_
- [x] 16.2 前端联调验证
- 确认 Dashboard 页面能正确调用 db-health API 并渲染数据
- 确认触发器管理页面能正确调用 unified triggers API 并渲染数据
- 确认业务 Tab 编辑功能能正确调用 PATCH API
- 验证空数据/降级场景下前端不崩溃
-E2E 测试已覆盖 mock API 场景,真实联调需手动启动前后端服务
- _Requirements: 2.1, 2.3, 4.1, 4.4, 11.1_
- [x] 17. 最终检查点 — 全量验证
- 运行 Monorepo 属性测试:`cd C:\Project\NeoZQYY && pytest tests/ -v`
- 运行后端测试:`cd apps/backend && pytest tests/ -v`
- 运行前端测试:`cd apps/admin-web && npx vitest --run`
- 运行 E2E 测试:`cd apps/admin-web && npx playwright test`
- 确保所有属性测试Property 1-8和单元测试全部通过
- 确保前端页面连接真实后端运行正常
- ask the user if questions arise.
- [x] 18. 文档同步更新
- [x] 18.1 更新后端 API 参考文档
-`apps/backend/docs/API-REFERENCE.md` 新增 3 个端点文档
- 更新 `apps/backend/README.md` 路由模块摘要
- _Requirements: 11.1, 11.5_
- [x] 18.2 更新文档地图
-`docs/DOCUMENTATION-MAP.md` 新增本次模块条目
- _Requirements: 11.1_
## 备注
- 标记 `*` 的子任务为可选(属性测试/单元测试),可跳过以加速 MVP
- 每个任务引用了具体的需求编号以确保可追溯性
- 属性测试验证通用正确性属性Property 1-8单元测试验证具体边界条件
- 检查点任务确保增量验证,避免问题累积
- 本项目不涉及数据库 DDL 变更,无需 DB 变更审计和 BD 手册步骤
- E2E 测试按页面切割为 4 个文件,每个文件控制在 Playwright 默认超时30s范围内
- 后端使用 PythonFastAPI + pytest + hypothesis前端使用 TypeScriptReact + Vitest + fast-check