Files
Neo-ZQYY/.kiro/specs/etl-aggregation-fix/requirements.md

6.6 KiB
Raw Permalink Blame History

需求文档

简介

v8 联调修复了 11 个 BUG其中 4 个的当前修复方式是"临时止血",需要更完整的方案。本 Spec 覆盖以下四个需求:

  • 需求 A:助教月度聚合按档位分段统计,替代 MAX() 聚合
  • 需求 B:多门店会员查询 register_site_id 已知限制标记 + 预留扩展方案
  • 需求 C会员生日字段全链路补齐C1: ETL 链路 / C2: 手动补录)
  • 需求 DDwdLoadTask.load() 返回值格式规范化

术语表

  • DwdLoadTaskDWD 层装载任务,负责将 ODS 原始数据清洗装载至 DWD 明细层
  • DWS 任务:数据汇总层任务,从 DWD 层聚合生成业务报表数据
  • SCD2:缓慢变化维度类型 2通过版本化记录维度属性的历史变化
  • BaseTaskETL 任务基类,提供 Extract/Transform/Load 模板方法和计数累加逻辑
  • FlowRunnerETL 流程编排器,按层级顺序执行任务并汇总计数
  • dim_memberDWD 层会员维度表,使用 SCD2 管理历史版本
  • dws_assistant_monthly_summaryDWS 层助教月度汇总表
  • dws_assistant_salary_calcDWS 层助教工资计算表
  • register_site_id:会员注册门店 ID当前 dim_member 中唯一的门店标识
  • assistant_level_code:助教档位代码,助教月内可能因升级/降级而变化
  • dim_member_birthday_manual:手动补录生日表(位于 zqyy_app 业务库),存储助教提交的会员生日信息,通过 FDW 只读映射供 ETL DWS 任务读取
  • _safe_int()flow_runner.py 中的类型安全辅助函数,将 int/list/None 统一转为 int
  • _accumulate_counts()BaseTask 中的计数累加方法,合并多段执行的统计结果

需求

需求 1DwdLoadTask 返回值格式规范化(需求 D

用户故事: 作为 ETL 开发者,我希望 DwdLoadTask.load() 的返回值格式与其他任务保持一致,以便 FlowRunner 能安全地汇总所有任务的计数。

验收标准

  1. WHEN DwdLoadTask.load() 执行完成, THE DwdLoadTask SHALL 返回包含 errors 键(值为 int 类型,等于错误列表长度)和 error_details 键(值为 list[dict] 类型,包含错误详情)的字典
  2. WHEN BaseTask._accumulate_counts() 遇到值为 list 类型的计数项, THE BaseTask SHALL 将该值转换为 len(list) 后再累加(防御层)
  3. WHEN FlowRunner 汇总所有任务计数, THE FlowRunner SHALL 保留 _safe_int() 作为最终防御层,确保 sum() 不会因类型不一致而崩溃

需求 2助教月度聚合按档位分段统计需求 A

用户故事: 作为运营管理者,我希望助教月度汇总按档位分段统计业绩,以便准确反映助教在不同档位期间的表现和工资计算。

验收标准

  1. WHEN 助教在同一月内存在多个 assistant_level_code, THE AssistantMonthlyTask SHALL 按 (assistant_id, stat_month, assistant_level_code) 分组生成多行记录,分别统计各档位的业绩指标
  2. THE dws_assistant_monthly_summary 表 SHALL 使用 (site_id, assistant_id, stat_month, assistant_level_code) 作为唯一约束
  3. WHEN AssistantMonthlyTask 需要取 nickname 值, THE AssistantMonthlyTask SHALL 按时间倒序取最后一条记录的 nickname而非使用 MAX() 聚合
  4. WHEN AssistantSalaryTask 计算工资, THE AssistantSalaryTask SHALL 按档位分段计算抽成,适配新的多行月度汇总结构
  5. WHEN AssistantFinanceTask 提取日度收入需要 nickname, THE AssistantFinanceTask SHALL 按时间倒序取最后一条记录的 nickname而非使用 MAX() 聚合
  6. WHEN AssistantCustomerTask 提取服务对需要 nickname, THE AssistantCustomerTask SHALL 按时间倒序取最后一条记录的 nickname而非使用 MAX() 聚合

需求 3多门店会员查询支持需求 B

用户故事: 作为运营管理者,我希望 DWS 任务能正确查询跨店消费的会员信息,以便 B 店能看到在 A 店注册但在 B 店消费的会员维度数据。

验收标准

  1. WHEN DWS 任务需要查询会员信息, THE DWS 任务 SHALL 通过事实表中的 member_id 反查 dim_member,而非使用 WHERE register_site_id = %s 预筛选
  2. WHEN 会员在 A 店注册并在 B 店消费, THE B 店的 DWS 任务 SHALL 能查询到该会员的昵称、手机号等维度信息
  3. WHEN DWS 任务执行会员信息提取, THE DWS 任务 SHALL 使用 WHERE member_id IN (SELECT DISTINCT member_id FROM dwd.事实表 WHERE site_id = %s) 模式获取会员维度数据

需求 4会员生日字段 ETL 链路补齐(需求 C1

用户故事: 作为运营管理者,我希望会员生日信息能从上游 API 完整传递到 DWS 层,以便用于会员分析和销售线索。

验收标准

  1. THE dim_member 表 SHALL 包含 birthday DATE
  2. WHEN DwdLoadTask 执行 ODS → DWD 装载, THE DwdLoadTask SHALL 在列映射中包含 birthday 字段,将 ODS 中的生日数据装载到 dim_member.birthday
  3. WHEN SCD2 更新 dim_member 记录, THE DwdLoadTask SHALL 将 birthday 作为变化检测字段之一,正常处理生日值的变化
  4. WHEN MemberVisitTask 等 DWS 任务提取会员信息, THE DWS 任务 SHALL 从 dim_member.birthday 读取生日字段并写入 DWS 目标表

需求 5助教手动补录会员生日需求 C2

用户故事: 作为助教,我希望能手动提交客户的生日信息,以便在上游 API 未提供生日数据时补充这一重要销售线索。

验收标准

  1. THE zqyy_app 业务库(开发/测试环境使用 test_zqyy_appSHALL 包含 member_birthday_manual 表,结构包含 member_idbirthday_valuerecorded_by_assistant_idrecorded_by_namerecorded_atsource 字段,唯一约束为 (member_id, recorded_by_assistant_id)
  2. WHEN 同一助教对同一会员重复提交生日, THE 系统 SHALL 更新该助教的已有记录UPSERT保留所有其他助教的提交记录
  3. WHEN DWS 任务需要读取手动补录生日, THE DWS 任务 SHALL 通过 FDW 只读映射从 zqyy_app.member_birthday_manual 读取数据
  4. WHEN dim_member.birthdayAPI 来源)和 member_birthday_manual手动来源同时存在, THE DWS 任务 SHALL 优先使用手动补录值
  5. WHEN 助教通过后端 API 提交生日, THE 后端 SHALL 提供 POST 接口接收 member_idbirthday_valueassistant_idassistant_name 参数,执行 UPSERT 写入 zqyy_app.member_birthday_manual
  6. WHEN SCD2 更新 dim_member.birthday, THE DwdLoadTask SHALL 正常更新 API 来源的生日值,不影响业务库中手动补录表的数据