12 KiB
看板全面排查修复计划
排查日期:2026-04-07 范围:客户看板(BOARD-2)8 维度 + 助教看板(BOARD-1)4 维度 状态:待实施(新对话执行)
一、已完成的修复
| # | 问题 | 修复内容 | 文件 |
|---|---|---|---|
| ✅ | SPI 消费口径用 pay_amount 而非 items_sum |
3 处 settlement_head 查询改为 items_sum(DWD 规则 #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-3:recall 维度 visits_30d 实为 14d(C-2)
- 问题:
dws_member_winback_index无visits_30d字段,后端用visits_14d近似,前端显示"30天到店" - 修复:
- DDL:
dws.dws_member_winback_index加列visits_30d INTEGER DEFAULT 0 - ETL:WBI 计算任务增加 30 天到店次数统计
- RLS 视图:
dws.v_dws_member_winback_index和app.v_dws_member_winback_index加新列 - 后端:查询改用新字段
- DDL 文档同步更新
- DDL:
- 文件:
db/etl_feiqiu/schemas/dws.sql(DDL)apps/etl/connectors/feiqiu/tasks/dws/index/winback_index_task.py(ETL)db/etl_feiqiu/schemas/app.sql(RLS 视图)apps/backend/app/services/fdw_queries.py(查询)docs/database/ddl/etl_feiqiu__dws.sql/etl_feiqiu__app.sql(DDL 文档)
Fix-4:balance 维度月均消耗和可用月数偏差 2 倍(C-3 + C-4)
- 问题:
monthlyConsume:直接用consume_amount_60d(60天总额),标签"月均消耗"应为consume_amount_60d / 2availableMonths:balance / 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.py—get_customer_board_balance()
Fix-5:freq60 柱状图数据源不一致(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.py—get_coach_sv_data()
P3 — 标签/文案修正
Fix-7:loyal 维度标签"近60天"→"近90天"
- 问题:ETL 关系指数实际使用 90 天窗口(
lookback_days: 90),非 60 天 - 修复:下拉选项文本
最专一 近60天→最专一 近90天 - 文件:
apps/miniprogram/miniprogram/pages/board-customer/board-customer.ts—DIMENSION_OPTIONS
Fix-8:potential 维度"月均到店"→"近30天到店"
- 问题:实际是 30 天到店天数(同一天多次只算一天),非"月均到店次数"
- 位置:board-customer 页面 → 最大消费潜力 tab → 4 列网格第 2 格
- 文件:
apps/miniprogram/miniprogram/pages/board-customer/board-customer.wxml
Fix-9:recharge 维度"充值"→"累计充值"
- 问题:实际是
SUM(pay_amount)历史累计充值总额,标签仅"充值"易误解为单次 - 位置:board-customer 页面 → 最近充值 tab → 4 列网格第 2 格
- 文件:
apps/miniprogram/miniprogram/pages/board-customer/board-customer.wxml
Fix-10:freq60 维度标签确认
- 此维度标签"最频繁 近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-2:sv 维度客户重复计算 | 业务定义确认:每个助教看"我的客户总余额",允许跨助教重叠,作为催促消耗的参考值 |
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) > 7→high_priority_recallmax(WBI, NCI) > 5→priority_recall1 < RS < 6→relationship_building- 不满足 → 不生成;
session_count > 0无任务时保底补充relationship_building
回溯逻辑(已有):recall_detector 检测到新服务记录时,如匹配到活跃的 follow_up_visit,关闭旧任务(superseded_by_new_visit)并创建新回访。
Fix-11:recall_detector 增量时序 Bug + 编排顺序
问题:recall_detector 用 create_time > last_run_at 全局增量指针。任务创建与客户到店时序不一致时漏匹配。
示例时间线:
- 4/5 08:00 —
recall_detector运行,last_run_at = 08:00 - 4/5 14:00 — 客户张三到店,服务记录
create_time = 14:00 - 4/6 02:00 —
task_generator为张三创建召回任务 - 4/6 08:00 —
recall_detector再次运行,但last_run_at已更新,张三 4/5 的记录在上轮已扫描过(当时无任务)→ 永远不会重新匹配
修复方案:
- 废弃
last_run_at增量指针,改为:对所有活跃任务,检查dwd_settlement_head中是否有pay_time > task.created_at的结算记录(settle_type IN (1,3)),匹配(site_id, assistant_id, member_id) - 合并运行顺序:ETL 完成后,统一编排器按顺序执行:
ETL 完成 → HTTP callback → 后端编排器: Step 1: recall_detector.run() # 先检查完成(含回溯) Step 2: task_generator.run() # 再生成新任务 - 保留
task_generator的每日 cron(0 4 * * *)作为兜底 - 两个服务保持独立文件,仅在调度层串联
文件:apps/backend/app/services/recall_detector.py、调度编排器
Fix-12:ETL 完成后自动触发(HTTP callback)
问题:etl_data_updated 事件无调用方,recall_detector 仅靠手动触发。
业务影响:ETL 每小时同步完新的飞球数据后,系统不会自动检查召回完成情况。客户回店后,助教看不到任务完成,必须有人手动在管理后台触发。
修复方案:ETL api_full pipeline 完成后,通过 HTTP callback 通知后端。
实现:
- 后端新增 API:
POST /api/internal/etl-completed(内部接口,仅限本机调用) - 该接口触发统一编排:
recall_detector.run()→task_generator.run() - ETL orchestrator 在 pipeline 完成后调用此接口
- 安全:校验来源 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_head(settle_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)) - 时间窗口:不限间隔,只要来了就算一次
- 统计时间范围:全量(任务系统上线至今)
完成类型标记(两种都要记录):
| 完成类型 | 触发方式 | 当前状态 |
|---|---|---|
| 自动完成 | 客户到店,系统匹配结算记录 | 逻辑存在但有 Bug(Fix-11 + Fix-12) |
| 手动完成 | 助教在小程序中主动标记 | 当前不存在,需新建 |
手动完成需要:
- 小程序端:任务卡片增加"标记完成"按钮
- 后端 API:
POST /api/xcx/tasks/{task_id}/complete,body:{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_history中action='completed'的任务数(优先+高优先) - 回访完成数:
follow_up_visit类型的完成数(含自动+手动+回溯) - 广义召回(关联客户来店):从
dwd_settlement_head+ 关系表统计
数据来源:biz.coach_tasks + biz.coach_task_history + ETL 关系/结算表
时间范围:全量
后续:更详细的趋势报表作为独立需求
实施依赖关系
Fix-11(时序Bug+编排顺序)──┐
├→ Fix-14(看板展示)
Fix-12(ETL 自动触发)────────┤
│
Fix-13(手动完成+三维度统计)─┘
建议实施顺序:Fix-11 → Fix-12 → Fix-13 → Fix-14