Files
Neo-ZQYY/docs/specs/miniapp-data-perf-optimization/tasks.md
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

15 KiB
Raw Blame History

实施计划:小程序数据获取与展示效率优化

概述

按"数据正确性优先于性能"原则,先拍基线快照、再做 DDL 变更、然后后端优化、前端优化,最后收尾验证。后端使用 PythonFastAPI + pytest/hypothesis前端使用 TypeScript微信小程序 + fast-check数据库使用 PostgreSQL DDL。

任务

  • 1. 数据基线快照(优化前)

    • 1.1 创建基线快照测试脚本 tests/test_perf_optimization_baseline.py

      • 使用小燕真实数据(assistant_id: 2964673443302213site_id: 2790685415443269
      • get_coach_detailget_task_list_v2get_task_detail 各执行一次
      • 将完整返回值序列化为 JSON 存储到 tests/fixtures/perf_optimization/
      • 实现逐字段 diff 对比函数,排除 updated_atdata_updated_at 等时间戳字段
      • diff 覆盖到手金额、RS 指数、会员余额、服务记录条数/排序、酒水明细、TOP 客户列表、aiAnalysistalkingPoints
      • Requirements: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 10.4
    • 1.2 执行基线快照采集

      • 运行 pytest tests/test_perf_optimization_baseline.py -v 生成基线 JSON 文件
      • 确认三个快照文件已生成并纳入版本控制
      • Requirements: 9.1, 9.6
  • 2. 数据库 DDL 变更

    • 2.1 创建迁移脚本 db/zqyy_app/migrations/YYYY-MM-DD__coach_tasks_updated_at.sql

      • ALTER TABLE biz.coach_tasks ADD COLUMN updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
      • 创建触发器函数 biz.coach_tasks_set_updated_at() 和触发器 trg_coach_tasks_updated_at
      • 触发器在 BEFORE UPDATE 时自动设置 NEW.updated_at = now()
      • Requirements: 6.4, 6.5
    • 2.2 编写属性测试updated_at 自动更新

      • Property 9: 任务更新后 updated_at 自动变化
      • 使用 hypothesis 生成随机任务状态变更
      • 验证 UPDATE 后 updated_at 严格大于更新前的值
      • 验证: 需求 6.4
  • 3. 检查点 — DDL 变更验证

    • 执行迁移脚本到测试库,验证新字段和触发器已正确创建
    • 确保 Property 9 测试通过ask the user if questions arise.
  • 4. 后端优化Performance 页 N+1 查询消除

    • 4.1 新增 fdw_queries.get_relation_index_batch() 函数

      • 接受 conn, site_id, assistant_id, member_ids 参数
      • 返回 dict[int, float]member_id → rs_display 映射)
      • member_ids 为空时直接返回空字典,不执行 SQL
      • 使用 WHERE assistant_id = %s AND member_id = ANY(%s) 查询
      • 复用已有 _fdw_context 连接管理
      • Requirements: 1.2, 1.3
    • 4.2 编写属性测试:批量 RS 查询与逐条查询等价性

      • Property 1: 批量 RS 查询与逐条查询等价性
      • 使用 hypothesis st.lists(st.integers(min_value=1)) 生成 member_ids
      • 验证 get_relation_index_batch 返回与逐条 get_relation_index 结果完全一致
      • 验证: 需求 1.4
    • 4.3 修改 coach_service._build_top_customers() 使用批量查询

      • for mid in member_ids 循环替换为单次 get_relation_index_batch 调用
      • 返回数据结构不变
      • Requirements: 1.1, 1.5
    • 4.4 修改 coach_service.get_coach_detail() 添加 data_updated_at 字段

      • top_customers 列表中每个客户新增 data_updated_at(取查询时 now()
      • Requirements: 6.2
    • 4.5 编写单元测试:member_ids 为空返回空字典

      • 验证边界条件:空列表不执行 SQL直接返回 {}
      • Requirements: 1.3
  • 5. 后端优化Task-List 页服务端过滤

    • 5.1 验证并完善 task_manager.get_task_list_v2() SQL 层过滤

      • 确认 SQL WHERE 子句已包含 relationship_building 任务的 RS 范围过滤
      • 验证 total 计数与实际过滤后结果集一致
      • 返回每个任务项新增 updated_at 字段
      • Requirements: 2.1, 2.2, 2.4, 2.5, 6.1
    • 5.2 编写属性测试RS 范围过滤

      • Property 2: relationship_building 任务 RS 范围过滤
      • 生成随机 RS 值和 rs_min/rs_max 范围
      • 验证返回的 relationship_building 任务 RS 指数在 (rs_min, rs_max) 范围内
      • 验证: 需求 2.2
    • 5.3 编写属性测试:分页 total 一致性

      • Property 3: 分页 total 与实际结果集一致性
      • 生成随机 page/page_size 参数
      • 验证 total 等于遍历所有页累计的 items 总数
      • 验证: 需求 2.4
    • 5.4 编写单元测试RS 排除列表查询失败降级

      • 验证查询失败时降级为不排除任何任务
      • Requirements: 2.3
  • 6. 后端优化Task-Detail 页 ETL 查询合并

    • 6.1 新增 fdw_queries.batch_query_for_task_detail() 函数

      • 接受 conn, site_id, assistant_id, member_id 参数
      • 单连接批量查询 member_infobalancers_score
      • 每个子查询用 try/except 包裹,失败返回默认值
      • 复用 _fdw_context 单连接模式
      • Requirements: 5.1, 5.2, 5.3
    • 6.2 编写属性测试Task-Detail 批量查询等价性

      • Property 8: Task-Detail 批量查询与独立查询等价性
      • 生成随机 member_id
      • 验证 batch_query_for_task_detail 返回与三个独立查询结果一致
      • 验证: 需求 5.4
    • 6.3 修改 task_manager.get_task_detail() 使用批量查询

      • 将 3 个独立 ETL 查询替换为 batch_query_for_task_detail 单次调用
      • 返回数据结构不变,新增 updated_at 字段
      • Requirements: 5.1, 6.3
    • 6.4 编写属性测试:接口返回包含版本时间戳

      • Property 4: 接口返回包含版本时间戳
      • 验证 get_task_list_v2get_task_detailget_coach_detail 返回数据包含有效 ISO 8601 时间戳
      • 验证: 需求 3.2, 6.1, 6.2, 6.3
    • 6.5 编写单元测试:子查询独立降级

      • 验证某子查询失败时返回默认值,不影响其他子查询
      • Requirements: 5.3
  • 7. 后端优化:酒水聚合 CTE 预聚合(低优先级)

    • 7.1 修改 fdw_queries.get_service_records_for_task() 添加 CTE 分支

      • 服务记录 > 50 条时使用 CTE 预聚合替代 LEFT JOIN LATERAL
      • ≤ 50 条时保持现有方式
      • Requirements: 8.1, 8.3
    • 7.2 编写属性测试CTE 预聚合与 LEFT JOIN LATERAL 等价性

      • Property 12: CTE 预聚合与 LEFT JOIN LATERAL 等价性
      • 生成随机服务记录集合(> 50 条)
      • 验证两种方式返回的 drinks 字段内容完全一致
      • 验证: 需求 8.2
  • 8. 后端回归验证

    • 8.1 运行基线快照 diff 对比
      • 使用相同参数再次调用三个核心接口
      • 逐字段 diff 对比优化前后返回值
      • 确认 aiAnalysistalkingPoints 字段未被改变
      • Requirements: 9.2, 9.3, 9.4, 10.1, 10.2, 10.3, 10.4
  • 9. 检查点 — 后端优化完成验证

    • 运行 Monorepo 属性测试:cd C:\Project\NeoZQYY && pytest tests/ -v
    • 运行后端单元测试:cd apps/backend && pytest tests/ -v
    • 确保所有属性测试Property 1-4, 8-9, 12和单元测试全部通过
    • 确保基线快照 diff 无数据偏差
    • ask the user if questions arise.
  • 10. 前端优化CacheStore 缓存模块

    • 10.1 创建 utils/cache-store.ts 缓存模块

      • 实现 CacheEntry<T> 接口(dataupdatedAtcachedAt
      • 实现 CacheStore 类:get()set()clear()setTaskPreload()getTaskPreload()
      • 缓存 key 格式:{dataType}:{id}
      • 所有读写操作用 try/catch 包裹,异常时静默降级
      • Requirements: 3.1, 3.3, 3.4, 3.5, 3.6
    • 10.2 编写属性测试:缓存版本校验行为

      • Property 5: 缓存版本校验行为
      • 使用 fast-check fc.string() 生成 updatedAt 时间戳
      • 验证缓存命中/过期判定逻辑
      • 验证: 需求 3.3, 3.4
    • 10.3 编写属性测试:缓存 clear 后为空

      • Property 6: 缓存 clear 后为空
      • 使用 fast-check fc.dictionary() 生成随机缓存条目
      • 验证 clear() 后所有 get() 返回 null
      • 验证: 需求 3.6
    • 10.4 编写属性测试:预加载数据 round-trip

      • Property 7: 预加载数据 round-trip
      • 使用 fast-check fc.record() 生成 TaskPreloadData
      • 验证 setTaskPreloadgetTaskPreload 数据完全一致
      • 验证: 需求 4.1
    • 10.5 编写单元测试CacheStore 异常降级

      • 验证缓存读写异常时静默降级为网络请求
      • Requirements: 3.5
  • 11. 前端优化:跳转传参与骨架渲染

    • 11.1 修改 Task-List 页跳转传参

      • 点击任务卡片时调用 cacheStore.setTaskPreload() 写入预加载数据
      • 传递字段:customer_nameheart_scorebalancetask_typetask_type_label
      • Requirements: 4.1
    • 11.2 修改 Task-Detail 页骨架渲染

      • onLoad 时先从 cacheStore.getTaskPreload() 读取预加载数据
      • 有缓存:立即渲染骨架内容,同时异步请求完整详情数据
      • 完整数据返回后覆盖骨架内容,实现无缝过渡
      • 无缓存:回退为当前全量加载模式
      • Requirements: 4.2, 4.3, 4.4
    • 11.3 修改 Performance 页跳转传参

      • 点击客户卡片跳转 Task-Detail 时,将 customer_nameheart_score 写入 cacheStore
      • Requirements: 4.5
    • 11.4 集成 onHide 和下拉刷新清空缓存

      • 在 App 级 onHide 回调中调用 cacheStore.clear()
      • 在支持下拉刷新的页面 onPullDownRefresh 中调用 cacheStore.clear()
      • Requirements: 3.6
  • 12. 前端优化:折前/折后小时数条件显示

    • 12.1 实现折前/折后条件显示逻辑

      • duration_raw 不为 null 且 duration_raw ≠ duration 时显示"折前 XX.Xh"标注
      • duration_raw 为 null 或等于 duration 时仅显示折后小时数
      • 格式化为一位小数(如"折前 2.5h"
      • Requirements: 7.1, 7.2, 7.3, 7.4
    • 12.2 编写属性测试:折前/折后条件显示逻辑

      • Property 10: 折前/折后条件显示逻辑
      • 使用 fast-check fc.float() 生成 duration 和 duration_raw
      • 验证显示/隐藏"折前"标注的条件判断
      • 验证: 需求 7.1, 7.2, 7.3
    • 12.3 编写属性测试:折前小时数格式化

      • Property 11: 折前小时数格式化
      • 使用 fast-check fc.float({min: 0, max: 1000})
      • 验证输出恰好一位小数且 parseFloat(formatted) ≈ round(hours, 1)
      • 验证: 需求 7.4
  • 13. 检查点 — 前端优化完成验证

    • 运行前端测试:cd apps/miniprogram && npm test
    • 确保所有属性测试Property 5-7, 10-11和单元测试全部通过
    • ask the user if questions arise.
  • 14. 前后端联调与集成验证

    • 14.1 启动后端服务,验证各端点完整请求-响应链路
      • 使用真实 FDW 连接验证 SQL 查询正确性
      • 验证 JSON 响应结构与 Schema 定义一致camelCase 序列化)
      • 验证 updated_at / data_updated_at 字段在响应中正确返回
      • Requirements: 6.1, 6.2, 6.3
    • 14.2 前端联调验证
      • 确认前端页面能正确调用优化后的 API 并渲染数据
      • 验证缓存命中/过期场景下前端行为正确
      • 验证空数据/降级场景下前端不崩溃
      • Requirements: 3.3, 3.4, 3.5, 4.2, 4.3, 4.4
  • 15. 数据库变更审计与 DDL 合并

    • 15.1 审计本次实现中对数据库的所有改动
      • 检查新增字段(updated_at)、新增触发器(trg_coach_tasks_updated_at
      • 确认无遗漏的 DDL 变更
      • Requirements: 6.4, 6.5
    • 15.2 执行迁移脚本到测试库
      • 验证新字段和触发器已正确创建(使用 BD 手册中的验证 SQL
      • Requirements: 6.4
    • 15.3 合并到主 DDL 基线文件
      • 业务库 → docs/database/ddl/zqyy_app__biz.sql
      • Requirements: 6.5
    • 15.4 编写回滚脚本(逆序 DROP TRIGGER / DROP FUNCTION / DROP COLUMN
      • Requirements: 6.5
  • 16. BD 手册更新

    • 16.1 更新 BD 手册 docs/database/BD_Manual_coach_tasks.md
      • 新增 updated_at 字段明细、触发器说明
      • 包含:字段明细、约束与索引、验证 SQL≥3 条)、兼容性影响、回滚策略
      • 记录变更原因和影响范围
      • Requirements: 6.4, 6.5
  • 17. 文档同步更新

    • 17.1 更新后端 API 参考文档
      • apps/backend/docs/API-REFERENCE.md 更新接口返回结构变更(updated_atdata_updated_at 字段)
      • 更新 apps/backend/README.md 相关模块摘要
      • Requirements: 6.1, 6.2, 6.3
    • 17.2 更新小程序接口契约文档
      • docs/miniprogram-dev/API-contract.md 更新接口返回结构
      • Requirements: 3.2, 6.1, 6.2, 6.3
    • 17.3 更新文档地图
      • docs/DOCUMENTATION-MAP.md 新增本次变更相关条目
      • Requirements: 6.5
  • 18. 最终检查点 — 全量验证

    • 运行 Monorepo 属性测试:cd C:\Project\NeoZQYY && pytest tests/ -v
    • 运行后端单元测试:cd apps/backend && pytest tests/ -v
    • 运行前端测试:cd apps/miniprogram && npm test
    • 确保所有属性测试Property 1-12和单元测试全部通过
    • 确保基线快照 diff 无数据偏差
    • 确保 DDL 迁移已合并到主基线
    • 确保 BD 手册已同步更新
    • 确保 API 文档、后端 README、文档地图均已更新
    • 确保前端页面连接真实后端运行正常
    • ask the user if questions arise.

备注

  • 标记 * 的子任务为可选(属性测试/单元测试),可跳过以加速 MVP
  • 每个任务引用了具体的需求编号以确保可追溯性
  • 属性测试验证通用正确性属性Property 1-12单元测试验证具体边界条件
  • 检查点任务确保增量验证,避免问题累积
  • 需求 10AI 分析数据校对预留)通过基线快照覆盖(任务 1.1 和 8.1),无需独立实施任务

硬性规定:属性测试执行规范

  1. 分组执行:每次只运行单个属性测试函数(-k "test_property_N"),禁止一次性跑全部
  2. 后台 CLI:使用 controlPwshProcess 启动测试,getProcessOutput 轮询结果(间隔 ≥ 15 秒)
  3. 确认完成再继续:必须在输出中看到明确的 passed/failed/error 后才可进入下一步,禁止"启动测试后立即继续编码"
  4. 超时保护executePwshtimeout 设为预估时间 3 倍(最少 120 秒hypothesis max_examples=100
  5. 详见.kiro/steering/testing-env.md 属性测试执行规范章节

硬性规定:前后端联调期间的效率优化框架

当用户在联调过程中提及"效率优化"或"本页已完成,进行效率优化"时,所有调试和改动必须在本 spec 的框架下进行:

  1. 数据正确性优先:任何优化改动前先确认基线快照存在(任务 1改动后跑 diff 验证(任务 8
  2. AI 数据不动aiAnalysistalkingPoints 的查询逻辑和返回结构保持不变(需求 10后期单独校对
  3. 联调中的样式/交互调整:属于联调范畴,不受效率优化 spec 约束,但改动不得破坏优化后的数据链路
  4. 联调中发现的数据问题:如果是优化引入的偏差,回退到基线快照对比定位;如果是原有问题,单独记录不混入本 spec