- .kiro/specs/ → docs/specs/(41 个历史需求 spec 迁移,移除 .config.kiro) - CLAUDE.md 三层拆分:根文件精简 + apps/backend/CLAUDE.md + .claude/commands/ - 新增 /spec-close、/pre-change 两个工作流命令 - DDL 基线刷新(从测试库重新导出 11 个文件,dws 35→38 表,biz 18→21 表) - BD_Manual → BD_manual 命名统一(48 个文件) - 修复 3 处文档与数据库不一致(auth.users.status 默认值、scheduled_tasks 字段、RLS 视图数) - 新增 BD_manual_public_rbac_tables.md(public schema 8 张 RBAC/工作流表) - 合并 biz.trigger_jobs 文档(10→12 字段,归档独立文档) - docs/database/README.md 索引更新 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
需求文档:小程序数据获取与展示效率优化
简介
对小程序三个核心页面(Performance 绩效页、Task-List 任务列表页、Task-Detail 任务详情页)进行数据获取和展示效率优化。优化覆盖两个维度:页面加载速度(减少 SQL 查询次数和连接开销)和页面间跳转体验(减少重复请求)。通过后端批量查询、SQL 层过滤、前端内存缓存 + 版本校验等手段,提升整体用户体验。
术语表
- 小程序(Miniprogram):微信小程序客户端,面向门店助教使用
- Performance_页:绩效概览页面,展示助教当月绩效、收入、TOP 客户、服务记录等
- Task_List_页:任务列表页面,展示助教待办任务卡片列表及绩效进度条
- Task_Detail_页:任务详情页面,展示单个任务的客户信息、维客线索、服务记录、AI 分析等
- ETL_库:数据仓库(
test_etl_feiqiu),通过_fdw_context设置 RLS 参数后访问app.v_*视图 - 业务库:应用数据库(
test_zqyy_app),存储biz.coach_tasks、biz.notes、biz.ai_cache等业务表 - N_Plus_1_问题:循环中逐条执行 SQL 查询的反模式,导致查询次数随数据量线性增长
- Batch_Query:
fdw_queries.batch_query_for_task_list(),单连接内批量执行多条 ETL 查询的封装函数 - RS_指数:关系指数(
rs_display),来自v_dws_member_assistant_relation_index,衡量助教与客户的关系紧密度 - updated_at:数据版本时间戳,用于前端缓存校验后端数据是否已变更
- Cache_Store:前端内存缓存模块,存储跨页面共享的 ETL 数据(会员信息、余额、RS 指数等)
- salary_calc:
v_dws_assistant_salary_calc视图,按assistant_id + salary_month唯一,包含工资计算参数 - relation_index:
v_dws_member_assistant_relation_index视图,按assistant_id + member_id唯一
需求
需求 1:Performance 页 N+1 查询消除
用户故事: 作为助教,我希望绩效页加载更快,以便在繁忙时段快速查看当月绩效数据。
验收标准
- WHEN
get_coach_detail被调用, THE Coach_Service SHALL 通过单条批量 SQL 查询获取所有 TOP 客户的 RS 指数,替代当前按member_id逐条循环调用get_relation_index的模式 - THE FDW_Queries 模块 SHALL 提供
get_relation_index_batch(conn, site_id, assistant_id, member_ids)函数,接受member_ids列表参数,返回dict[int, float](member_id → rs_display 映射) - WHEN
member_ids列表为空, THEget_relation_index_batch函数 SHALL 返回空字典,不执行任何 SQL 查询 - WHEN 批量查询执行后, THE 返回结果 SHALL 与逐条查询
get_relation_index对相同member_ids的结果在 RS 指数值上完全一致 - THE
_build_top_customers函数 SHALL 调用get_relation_index_batch一次性获取所有客户的 RS 指数,替代当前的for mid in member_ids循环
需求 2:Task-List 页服务端过滤优化
用户故事: 作为助教,我希望任务列表加载更快且数据准确,以便高效管理待办任务。
验收标准
- WHEN
get_task_list_v2查询biz.coach_tasks时, THE Task_Manager SHALL 在 SQL WHERE 子句中直接排除不满足展示条件的任务,替代拉取全量 200 条后在内存中过滤的模式 - THE SQL 查询 SHALL 在 WHERE 子句中包含
relationship_building任务的 RS 范围过滤条件(排除 RS 指数不在[rs_min, rs_max]范围内的member_id) - WHEN RS 排除列表查询失败时, THE Task_Manager SHALL 降级为不排除任何任务(当前已有的容错行为保持不变)
- THE 分页
total计数 SHALL 与实际返回的过滤后结果集一致,跨页翻页时total值保持准确 - WHILE 前端请求
pageSize=200一次性加载时, THE 后端 SHALL 仅返回满足展示条件的任务,减少无效数据传输量
需求 3:前端内存缓存与版本校验
用户故事: 作为助教,我希望在页面间跳转时不重复等待相同数据加载,以获得流畅的操作体验。
验收标准
- THE Cache_Store SHALL 缓存以下跨页面共享的 ETL 数据:会员信息(
member_info)、会员余额(balance)、RS 指数(relation_index) - THE 后端接口 SHALL 在每条返回数据中包含
updated_at时间戳字段,表示该数据在后端的最后更新时间 - WHEN 前端请求数据时, THE Cache_Store SHALL 先检查本地缓存是否存在且
updated_at未过期;若缓存有效则直接使用,若缓存过期或不存在则发起网络请求 - WHEN 后端数据发生变更(
updated_at更新)时, THE Cache_Store SHALL 在下次请求时检测到版本变化并重新获取最新数据 - IF 缓存校验逻辑发生异常, THEN THE Cache_Store SHALL 降级为直接发起网络请求,确保功能可用性不受影响
- THE Cache_Store SHALL 在小程序
onHide(切后台)或用户主动下拉刷新时清空全部缓存,确保回到前台时获取最新数据
需求 4:跳转传参优化
用户故事: 作为助教,我希望从任务列表点击进入任务详情时,已加载的客户信息能直接展示,减少等待时间。
验收标准
- WHEN 用户从 Task_List_页 点击任务卡片跳转到 Task_Detail_页 时, THE Task_List_页 SHALL 将已加载的任务数据(
customer_name、heart_score、balance、task_type、task_type_label)通过全局 Cache_Store 传递给 Task_Detail_页 - WHEN Task_Detail_页 加载时, THE Task_Detail_页 SHALL 优先从 Cache_Store 读取已有数据立即渲染骨架内容,同时异步请求完整详情数据
- WHEN 完整详情数据返回后, THE Task_Detail_页 SHALL 用完整数据覆盖骨架内容,实现无缝过渡
- IF Cache_Store 中无对应任务的预加载数据, THEN THE Task_Detail_页 SHALL 回退为当前的全量加载模式(显示 loading → 请求 → 渲染)
- WHEN 用户从 Performance_页 点击客户卡片跳转到 Task_Detail_页 时, THE Performance_页 SHALL 同样将已有的客户数据(
customer_name、heart_score)通过 Cache_Store 传递
需求 5:Task-Detail 页 ETL 查询合并
用户故事: 作为助教,我希望任务详情页加载更快,以便快速查看客户信息并采取行动。
验收标准
- WHEN
get_task_detail查询 ETL 数据时, THE Task_Manager SHALL 将member_info、balance、relation_index三个独立 ETL 连接合并为单连接批量查询 - THE 合并后的查询 SHALL 复用
_fdw_context单次连接,在同一个事务中依次执行会员信息、余额、RS 指数查询 - WHEN 批量 ETL 查询失败时, THE Task_Manager SHALL 对每个子查询独立降级(返回默认值),不影响其他子查询的结果
- THE 合并后的查询结果 SHALL 与当前三个独立查询的结果在数据内容上完全一致
需求 6:后端 updated_at 版本字段支持
用户故事: 作为开发者,我希望后端接口返回数据版本时间戳,以便前端缓存能准确判断数据是否过期。
验收标准
- THE 后端 SHALL 在
get_task_list_v2返回的每个任务项中包含updated_at字段(来自biz.coach_tasks.updated_at) - THE 后端 SHALL 在
get_coach_detail返回的top_customers列表中,为每个客户附加data_updated_at字段(取 ETL 查询时的服务器时间戳) - THE 后端 SHALL 在
get_task_detail返回中包含updated_at字段 - IF
biz.coach_tasks表当前缺少updated_at列, THEN THE 数据库迁移 SHALL 添加该列,默认值为now(),并在任务状态变更时自动更新 - THE DDL 变更 SHALL 合并到主 DDL 迁移文件中,并通过审计流程记录
需求 7:Task-Detail 页折前/折后小时数条件显示
用户故事: 作为助教,我希望只在折前和折后小时数有差异时才看到折前小时数,以减少信息干扰。
验收标准
- WHEN 服务记录的折前小时数(
service_hours_raw)与折后小时数(service_hours)不相等时, THE Task_Detail_页 SHALL 在折后小时数旁显示"折前 XX.Xh"标注 - WHEN 折前小时数与折后小时数相等时, THE Task_Detail_页 SHALL 仅显示折后小时数,不显示折前标注
- IF 折前小时数(
duration_raw)为null或未返回, THEN THE Task_Detail_页 SHALL 视为与折后小时数相等,不显示折前标注 - THE 折前小时数 SHALL 格式化为一位小数(如"折前 2.5h"),与折后小时数的格式保持一致
需求 8:LEFT JOIN LATERAL 酒水聚合优化(低优先级)
用户故事: 作为开发者,我希望服务记录的酒水明细聚合查询在数据量增长时仍保持高效。
验收标准
- WHILE 单次查询涉及的服务记录超过 50 条时, THE FDW_Queries 模块 SHALL 使用 CTE 预聚合方式替代当前的
LEFT JOIN LATERAL子查询聚合酒水商品明细 - WHEN 使用 CTE 预聚合后, THE 查询结果 SHALL 与
LEFT JOIN LATERAL方式返回的drinks字段内容完全一致 - WHILE 单次查询涉及的服务记录不超过 50 条时, THE FDW_Queries 模块 SHALL 保持当前的
LEFT JOIN LATERAL方式(小数据量下性能已足够)
需求 9:数据基线快照与回归验证
用户故事: 作为开发者,我希望每次效率优化后能自动验证数据正确性,确保优化不引入数据偏差。
验收标准
- BEFORE 任何优化任务开始实施前, THE 验证脚本 SHALL 使用小燕(assistant_id:
2964673443302213、site_id:2790685415443269)的真实数据,对三个核心接口(get_coach_detail、get_task_list_v2、get_task_detail)各执行一次,将完整返回值序列化为 JSON 基线快照 - AFTER 每个优化任务完成后, THE 验证脚本 SHALL 使用相同参数再次调用接口,逐字段 diff 对比优化前后的返回值
- THE diff 对比 SHALL 覆盖以下关键校验点:到手金额(hours × net_rate)、RS 指数、会员余额、服务记录条数和排序、酒水商品明细、TOP 客户列表
- IF diff 发现任何数据值不一致(排除
updated_at、data_updated_at等时间戳字段), THEN THE 验证脚本 SHALL 报告失败并输出差异详情 - THE 验证脚本 SHALL 以 pytest 形式编写,放置在
tests/目录下,可通过pytest tests/test_perf_optimization_baseline.py -v执行 - THE 基线快照 JSON 文件 SHALL 存储在
tests/fixtures/perf_optimization/目录下,纳入版本控制
需求 10:AI 分析数据校对预留(后期)
用户故事: 作为开发者,我希望 AI 分析相关的数据字段在优化过程中保持接口兼容,以便后期校对和调整。
验收标准
- THE 优化过程 SHALL 不改变
aiAnalysis(app4_analysis)和talkingPoints(app5_talking_points)字段的数据来源、查询逻辑和返回结构 - THE
biz.ai_cache表的查询方式(按target_id + site_id + cache_type查询,ORDER BY created_at DESC)SHALL 在优化后保持不变 - IF 后续需要对 AI 分析数据进行校对或调整, THEN THE 接口返回结构 SHALL 保持向后兼容(新增字段可以,删除或改名已有字段不可以)
- THE 数据基线快照(需求 9)SHALL 包含
aiAnalysis和talkingPoints字段的完整内容,作为后期 AI 校对的参考基准