Files
Neo-ZQYY/docs/prd/2026-04-07__board-audit-fix-plan.md
2026-04-10 06:24:13 +08:00

12 KiB
Raw Blame History

看板全面排查修复计划

排查日期2026-04-07 范围客户看板BOARD-28 维度 + 助教看板BOARD-14 维度 状态:待实施(新对话执行)


一、已完成的修复

# 问题 修复内容 文件
SPI 消费口径用 pay_amount 而非 items_sum 3 处 settlement_head 查询改为 items_sumDWD 规则 #1 apps/etl/connectors/feiqiu/tasks/dws/index/spending_power_index_task.py
潜力标签阈值 60 但数据范围 0-10 阈值 60→6返回 [{text, theme}] 对象数组 apps/backend/app/services/fdw_queries.py _derive_potential_tags

二、待实施修复(共 10 项)

P1 — 功能性 Bug

Fix-1客户看板项目筛选崩溃C-1

  • 问题_project_filter_clause() 硬编码 vd.member_id,但 6/8 维度主表别名不是 vd,选择项目筛选时后端 SQL 500
  • 影响维度recall / balance / recharge / spend60 / freq60 / loyal
  • 不受影响recent别名 vd、potential自写子查询
  • 修复方案:统一改为独立子查询模式 member_id IN (SELECT member_id FROM app.v_dws_member_project_tag WHERE category_code = %s AND is_tagged = true),不依赖外层别名(参考 potential 维度已有写法)
  • 文件apps/backend/app/services/fdw_queries.py_project_filter_clause() 函数及 6 个维度查询函数

Fix-2助教看板 task 维度 callback 映射错误A-3

  • 问题callback 统计映射到 relationship_building,但业务上"回访"应对应 follow_up_visit
  • 修复board_service.py _query_coach_tasks() 中 callback 的 task_type 从 relationship_building 改为 follow_up_visit
  • 文件apps/backend/app/services/board_service.py

P2 — 数据口径错误

Fix-3recall 维度 visits_30d 实为 14dC-2

  • 问题dws_member_winback_indexvisits_30d 字段,后端用 visits_14d 近似,前端显示"30天到店"
  • 修复
    1. DDLdws.dws_member_winback_index 加列 visits_30d INTEGER DEFAULT 0
    2. ETLWBI 计算任务增加 30 天到店次数统计
    3. RLS 视图:dws.v_dws_member_winback_indexapp.v_dws_member_winback_index 加新列
    4. 后端:查询改用新字段
    5. DDL 文档同步更新
  • 文件
    • db/etl_feiqiu/schemas/dws.sqlDDL
    • apps/etl/connectors/feiqiu/tasks/dws/index/winback_index_task.pyETL
    • db/etl_feiqiu/schemas/app.sqlRLS 视图)
    • apps/backend/app/services/fdw_queries.py(查询)
    • docs/database/ddl/etl_feiqiu__dws.sql / etl_feiqiu__app.sqlDDL 文档)

Fix-4balance 维度月均消耗和可用月数偏差 2 倍C-3 + C-4

  • 问题
    • monthlyConsume:直接用 consume_amount_60d60天总额标签"月均消耗"应为 consume_amount_60d / 2
    • availableMonthsbalance / consume_amount_60d,应为 balance / (consume_amount_60d / 2)2 * balance / consume_amount_60d
  • 示例:余额 49780 / 60天消费 14521 → 当前显示 3.4 个月,实际应 6.9 个月
  • 文件apps/backend/app/services/fdw_queries.pyget_customer_board_balance()

Fix-5freq60 柱状图数据源不一致C-7

  • 问题:汇总数据来自 v_dws_member_consumption_summary(消费维度),但 8 周柱状图来自 v_dwd_assistant_service_log(助教服务维度),口径不一致
  • 修复:柱状图改为从消费汇总或结算维度获取周数据,与汇总口径一致
  • 文件apps/backend/app/services/fdw_queries.py — freq60 相关查询

Fix-6助教看板 sv 维度不响应时间筛选A-4

  • 问题:函数接收 start_date/end_date 但 SQL 未使用,"消耗"始终是固定 60 天
  • 修复sv_consume 的查询加入 start_date/end_date 过滤,使其随时间筛选联动
  • 文件apps/backend/app/services/fdw_queries.pyget_coach_sv_data()

P3 — 标签/文案修正

Fix-7loyal 维度标签"近60天"→"近90天"

  • 问题ETL 关系指数实际使用 90 天窗口(lookback_days: 90),非 60 天
  • 修复:下拉选项文本 最专一 近60天最专一 近90天
  • 文件apps/miniprogram/miniprogram/pages/board-customer/board-customer.tsDIMENSION_OPTIONS

Fix-8potential 维度"月均到店"→"近30天到店"

  • 问题:实际是 30 天到店天数(同一天多次只算一天),非"月均到店次数"
  • 位置board-customer 页面 → 最大消费潜力 tab → 4 列网格第 2 格
  • 文件apps/miniprogram/miniprogram/pages/board-customer/board-customer.wxml

Fix-9recharge 维度"充值"→"累计充值"

  • 问题:实际是 SUM(pay_amount) 历史累计充值总额,标签仅"充值"易误解为单次
  • 位置board-customer 页面 → 最近充值 tab → 4 列网格第 2 格
  • 文件apps/miniprogram/miniprogram/pages/board-customer/board-customer.wxml

Fix-10freq60 维度标签确认

  • 此维度标签"最频繁 近60天"与实际口径一致(visit_count_60d),无需修改

三、DWD 合规检查结果(通过)

检查项 客户看板 助教看板
consume_money 禁止直接使用 全部走 DWS items_sum
settle_type IN (1,3) 不直查结算表
DQ-6 会员姓名通过 dim_member
DQ-7 会员卡通过 dim_member_card_account
助教费用拆分 pd/cx N/A

四、已知但不修的项

原因
A-2sv 维度客户重复计算 业务定义确认:每个助教看"我的客户总余额",允许跨助教重叠,作为催促消耗的参考值
A-5后端 dim_type 冗余 功能无影响,两端映射一致

五、recall_detector 修复 + 任务统计需求(同期实施)

需求确认日期2026-04-07

背景

biz.coach_tasks 当前 255 条记录completed = 0。排查确认

  • 系统完成逻辑设计正确(recall_detector.py 匹配服务记录→标记 completed
  • 但两个技术问题导致完成检测不可靠
  • 缺少"助教主动标记完成"能力
  • 任务完成统计需要三个维度

当前架构(调研结果)

服务 文件 职责 调度方式
recall_detector app/services/recall_detector.py 检测客户到店→标记召回任务完成→生成回访任务 event: etl_data_updated(当前无人触发)
task_generator app/services/task_generator.py 根据 WBI/NCI/RS 指数生成召回/关系维护任务 cron: 0 4 * * *(每日凌晨 4 点)

生成规则(四级漏斗):

  • max(WBI, NCI) > 7high_priority_recall
  • max(WBI, NCI) > 5priority_recall
  • 1 < RS < 6relationship_building
  • 不满足 → 不生成;session_count > 0 无任务时保底补充 relationship_building

回溯逻辑(已有):recall_detector 检测到新服务记录时,如匹配到活跃的 follow_up_visit,关闭旧任务(superseded_by_new_visit)并创建新回访。

Fix-11recall_detector 增量时序 Bug + 编排顺序

问题recall_detectorcreate_time > last_run_at 全局增量指针。任务创建与客户到店时序不一致时漏匹配。

示例时间线

  1. 4/5 08:00 — recall_detector 运行,last_run_at = 08:00
  2. 4/5 14:00 — 客户张三到店,服务记录 create_time = 14:00
  3. 4/6 02:00 — task_generator 为张三创建召回任务
  4. 4/6 08:00 — recall_detector 再次运行,但 last_run_at 已更新,张三 4/5 的记录在上轮已扫描过(当时无任务)→ 永远不会重新匹配

修复方案

  1. 废弃 last_run_at 增量指针,改为:对所有活跃任务,检查 dwd_settlement_head 中是否有 pay_time > task.created_at 的结算记录(settle_type IN (1,3)),匹配 (site_id, assistant_id, member_id)
  2. 合并运行顺序ETL 完成后,统一编排器按顺序执行:
    ETL 完成 → HTTP callback → 后端编排器:
      Step 1: recall_detector.run()    # 先检查完成(含回溯)
      Step 2: task_generator.run()     # 再生成新任务
    
  3. 保留 task_generator 的每日 cron0 4 * * *)作为兜底
  4. 两个服务保持独立文件,仅在调度层串联

文件apps/backend/app/services/recall_detector.py、调度编排器

Fix-12ETL 完成后自动触发HTTP callback

问题etl_data_updated 事件无调用方recall_detector 仅靠手动触发。

业务影响ETL 每小时同步完新的飞球数据后,系统不会自动检查召回完成情况。客户回店后,助教看不到任务完成,必须有人手动在管理后台触发。

修复方案ETL api_full pipeline 完成后,通过 HTTP callback 通知后端。

实现:

  1. 后端新增 APIPOST /api/internal/etl-completed(内部接口,仅限本机调用)
  2. 该接口触发统一编排:recall_detector.run()task_generator.run()
  3. ETL orchestrator 在 pipeline 完成后调用此接口
  4. 安全:校验来源 IP 或 shared secret

文件

  • apps/backend/app/routers/internal.py(新增)
  • apps/etl/connectors/feiqiu/orchestration/ — pipeline 完成回调
  • apps/backend/app/services/trigger_scheduler.py — 编排逻辑

Fix-13任务完成统计三维度

需求确认:任务完成分三个统计维度:

统计维度 触发条件 是否需已有任务 判定数据源
召回完成(广义) 关联客户来店 + 有结算单 不需要,只要是 dws_member_assistant_relation_index 中的关联客户 dwd_settlement_headsettle_type IN (1,3)
优先/高优先召回完成 已有 priority_recall / high_priority_recall 任务 + 客户到店 需要 同上 + coach_tasks.status = 'completed'
回访完成 完成 follow_up_visit 任务(含回溯完成) 需要 coach_tasks + 回溯检测

关键定义:

  • "关联客户"dws_member_assistant_relation_index 中有关系记录的客户
  • "来店"判定dwd_settlement_head 中有结算单(settle_type IN (1,3)
  • 时间窗口:不限间隔,只要来了就算一次
  • 统计时间范围:全量(任务系统上线至今)

完成类型标记(两种都要记录):

完成类型 触发方式 当前状态
自动完成 客户到店,系统匹配结算记录 逻辑存在但有 BugFix-11 + Fix-12
手动完成 助教在小程序中主动标记 当前不存在,需新建

手动完成需要:

  • 小程序端:任务卡片增加"标记完成"按钮
  • 后端 APIPOST /api/xcx/tasks/{task_id}/completebody: {type: "manual", note?: string}
  • 数据库:coach_tasks 增加 completion_type 字段(auto / manual
  • coach_task_history 增加 action='manual_completed'

Fix-14助教看板 task 维度展示

展示位置:微信小程序 board-coach 页面 task_desc 排序维度

统计口径(按助教/按月):

  • 召回完成数:coach_task_historyaction='completed' 的任务数(优先+高优先)
  • 回访完成数:follow_up_visit 类型的完成数(含自动+手动+回溯)
  • 广义召回(关联客户来店):从 dwd_settlement_head + 关系表统计

数据来源biz.coach_tasks + biz.coach_task_history + ETL 关系/结算表 时间范围:全量 后续:更详细的趋势报表作为独立需求

实施依赖关系

Fix-11时序Bug+编排顺序)──┐
                              ├→ Fix-14看板展示
Fix-12ETL 自动触发)────────┤
                              │
Fix-13手动完成+三维度统计)─┘

建议实施顺序Fix-11 → Fix-12 → Fix-13 → Fix-14