Files
Neo-ZQYY/.kiro/specs/rns1-board-apis/tasks.md

22 KiB
Raw Blame History

Implementation Plan: RNS1.3 三看板接口

Overview

基于 design.md 的模块结构,增量扩展后端路由、服务层和 FDW 查询层,新增 3 个看板端点 + 1 个配置端点并完成前端筛选修复。BOARD-3 财务看板是最复杂的单个接口6 板块、200+ 字段、60+ 环比数据点),采用板块级独立查询和独立降级策略。

Tasks

  • 1. 通用工具函数(日期范围 + 环比计算)

    • 1.1 在 apps/backend/app/services/board_service.py 中实现 _calc_date_range(time_enum, ref_date=None) 工具函数
      • 支持 BOARD-1 的 6 种时间枚举(month/quarter/last_month/last_3m/last_quarter/last_6m)和 BOARD-3 的 8 种时间枚举(month/lastMonth/week/lastWeek/quarter3/quarter/lastQuarter/half6
      • 返回 (start_date, end_date) 元组,date 类型
      • Requirements: 1.3, 3.2
    • 1.2 在 board_service.py 中实现 _calc_prev_range(start_date, end_date) 计算上期日期范围
      • 上期长度等于当期长度,prev_end <= start_date
      • Requirements: 3.3
    • 1.3 在 board_service.py 中实现 calc_compare(current: Decimal, previous: Decimal) -> dict 环比计算工具
      • 返回 { compare: str, is_down: bool, is_flat: bool }
      • 边界:previous=0, current≠0"新增"previous=0, current=0"持平"
      • Requirements: 8.11, 8.12, 8.13, 8.14
  • 2. Pydantic Schema 定义

    • 2.1 新建 apps/backend/app/schemas/xcx_board.py,定义请求参数枚举
      • CoachSortEnum6 值)、SkillFilterEnum5 值)、BoardTimeEnum6 值)
      • CustomerDimensionEnum8 值)、ProjectFilterEnum5 值)
      • FinanceTimeEnum8 值)、AreaFilterEnum7 值)
      • Requirements: 1.1, 2.1, 3.1
    • 2.2 在 xcx_board.py 中定义 BOARD-1 响应 Schema
      • CoachSkillItemCoachBoardItem(扁平结构,含 perf/salary/sv/task 全部维度字段)、CoachBoardResponseitems + dimType
      • Requirements: 1.4~1.14, 1.16
    • 2.3 在 xcx_board.py 中定义 BOARD-2 响应 Schema
      • CustomerAssistantCustomerBoardItemBase(基础字段)
      • 8 个维度专属 SchemaRecallItemPotentialItemBalanceItemRechargeItemRecentItemSpend60ItemFreq60ItemLoyalItem
      • WeeklyVisitval + pctPotentialTagCoachDetail
      • CustomerBoardResponseitems + total + page + pageSize
      • Requirements: 2.3~2.22
    • 2.4 在 xcx_board.py 中定义 BOARD-3 响应 Schema
      • OverviewPanel8 指标 + 各 3 个环比字段Optional
      • GiftCellGiftRowRechargePanel(储值卡 5 指标 + 赠送卡 3×4 矩阵 + allCardBalance
      • RevenueStructureRowRevenueItemChannelItemRevenuePanel
      • CashflowItemCashflowPanel
      • ExpenseItemExpensePanel4 子分组 + total
      • CoachAnalysisRowCoachAnalysisTableCoachAnalysisPanelbasic + incentive
      • FinanceBoardResponseoverview + recharge|null + revenue + cashflow + expense + coachAnalysis
      • Requirements: 3.53.12, 4.14.7, 5.1~5.8
    • 2.5 新建 apps/backend/app/schemas/xcx_config.py,定义 SkillTypeItemkey/label/emoji/cls
      • Requirements: 6.1
  • 3. FDW 查询层扩展 — BOARD-1

    • 3.1 在 apps/backend/app/services/fdw_queries.py 中实现 get_all_assistants(conn, site_id, skill_filter)
      • 数据源:app.v_dim_assistant,按 skill 筛选
      • Requirements: 1.5
    • 3.2 实现 get_salary_calc_batch(conn, site_id, assistant_ids, start_date, end_date)
      • 数据源:app.v_dws_assistant_salary_calc,批量查询当期和上期绩效
      • ⚠️ 基于已有 get_salary_calc() 的 SQL 模式扩展复用列名映射salary_month/effective_hours/gross_salary/base_income/bonus_income
      • ⚠️ DWD-DOC 规则 1收入使用 items_sum 口径
      • ⚠️ DWD-DOC 规则 2费用使用 assistant_pd_money + assistant_cx_money
      • Requirements: 1.8, 1.10
    • 3.3 实现 get_top_customers_for_coaches(conn, site_id, assistant_ids)
      • 数据源:app.v_dws_member_assistant_relation_index + app.v_dim_member
      • ⚠️ 基于已有 get_relation_index() 的 SQL 模式扩展为按助教维度批量查询
      • 按亲密度降序取 Top 3拼接 P6 AC3 四级 emoji> 8.5💖> 7🧡> 5💛≤ 5💙
      • ⚠️ DQ-6客户姓名通过 member_id JOIN v_dim_member取 scd2_is_current=1
      • ⚠️ 注意:已有 get_coach_top_customers() 按服务次数排序(来自 v_dwd_assistant_service_log本函数按亲密度排序来自 v_dws_member_assistant_relation_index语义不同不可复用
      • Requirements: 1.6
    • 3.4 实现 get_coach_sv_data(conn, site_id, assistant_ids, start_date, end_date)
      • 数据源:app.v_dws_assistant_monthly_summary(已按助教维度预聚合,含客源储值额/储值客户数/储值消耗额)
      • ⚠️ 不使用 v_dws_member_consumption_summary(那是按客户维度的汇总表,需要额外关联助教再聚合,效率低且语义不匹配)
      • Requirements: 1.12
  • 4. FDW 查询层扩展 — BOARD-28 维度)

    • 4.1 实现 get_customer_board_recall(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_winback_index + app.v_dim_memberETL 已计算 WBI 召回指数,含 ideal_days/elapsed_days/overdue_days/visits_30d/wbi_score
      • 按 WBIwbi_score降序LIMIT/OFFSET 分页
      • ⚠️ DQ-6客户姓名通过 member_id JOIN v_dim_member
      • ⚠️ 余额通过 JOIN v_dim_member_card_account 获取
      • Requirements: 2.6, 2.7
    • 4.2 实现 get_customer_board_potential(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_spending_power_indexETL 已计算 SPI 消费潜力指数,含 potential_tags/spend_30d/avg_visits/avg_spend/spi_score
      • 按 SPIspi_score降序
      • Requirements: 2.8, 2.9
    • 4.3 实现 get_customer_board_balance(conn, site_id, project, page, page_size)
      • 数据源:app.v_dim_member_card_account + app.v_dim_member
      • 按 balance_amount 降序
      • ⚠️ DQ-7余额通过 tenant_member_id JOIN取 scd2_is_current=1
      • Requirements: 2.10, 2.11
    • 4.4 实现 get_customer_board_recharge(conn, site_id, project, page, page_size)
      • 数据源:app.v_dwd_recharge_order + app.v_dim_member_card_account(充值记录 + 当前余额)
      • 按 last_recharge_date 降序
      • Requirements: 2.12, 2.13
    • 4.5 实现 get_customer_board_recent(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_visit_detail + app.v_dim_memberETL 已计算到店明细,含 last_visit_date/visit_freq/ideal_days
      • 按 last_visit_date 降序
      • Requirements: 2.14, 2.15
    • 4.6 实现 get_customer_board_spend60(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_consumption_summaryitems_sum_60d 已在汇总表中预计算)
      • ⚠️ DWD-DOC 规则 1使用 items_sum 口径计算 spend60d
      • 按 items_sum_60d 降序
      • Requirements: 2.16, 2.17
    • 4.7 实现 get_customer_board_freq60(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_consumption_summaryvisit_count_60d 已在汇总表中预计算)
      • 含 weeklyVisits 8 周柱状图计算pct 相对最大值百分比 0-100
      • ⚠️ weeklyVisits 需从 app.v_dwd_assistant_service_log 按周分组统计(汇总表无周粒度数据)
      • 按 visit_count_60d 降序
      • Requirements: 2.18, 2.19, 2.20
    • 4.8 实现 get_customer_board_loyal(conn, site_id, project, page, page_size)
      • 数据源:app.v_dws_member_assistant_relation_index
      • 按 max_rs 降序
      • Requirements: 2.21, 2.22
    • 4.9 实现 get_customer_assistants(conn, site_id, member_ids) 批量查询客户关联助教列表
      • 含亲密度计算,当前跟进助教置顶
      • Requirements: 2.5
  • 5. FDW 查询层扩展 — BOARD-36 板块)

    • 5.1 实现 get_finance_overview(conn, site_id, start_date, end_date)
      • 数据源:app.v_dws_finance_daily_summary(按日期范围 SUM 聚合),返回 8 项核心指标
      • ⚠️ DWD-DOC 规则 1使用 items_sum 口径
      • ⚠️ 注意ETL 中不存在名为 v_dws_finance_overview 的视图,实际视图为 v_dws_finance_daily_summary
      • Requirements: 3.5, 3.7
    • 5.2 实现 get_finance_recharge(conn, site_id, start_date, end_date)
      • 数据源:app.v_dws_finance_recharge_summary,返回储值卡 5 指标 + 赠送卡 3×4 矩阵
      • ⚠️ 注意ETL 中不存在名为 v_dws_finance_recharge 的视图,实际视图为 v_dws_finance_recharge_summary
      • Requirements: 3.8, 3.9, 3.10, 3.12
    • 5.3 实现 get_finance_revenue(conn, site_id, start_date, end_date, area)
      • 数据源:app.v_dws_finance_income_structure(收入结构主表)+ app.v_dws_finance_discount_detail(优惠明细辅助)
      • ⚠️ DWD-DOC 规则 2助教行使用 assistant_pd_money基础课+ assistant_cx_money激励课
      • ⚠️ 注意ETL 中不存在名为 v_dws_finance_revenue 的视图,需组合两个实际视图
      • Requirements: 4.1, 4.2, 4.3, 4.4
    • 5.4 实现 get_finance_cashflow(conn, site_id, start_date, end_date)
      • 数据源:app.v_dws_finance_daily_summary(消费收款 + 充值收款字段均在财务日报中)
      • ⚠️ DWD-DOC 规则 7platform_settlement_amount 和 groupbuy_pay_amount 互斥
      • ⚠️ 注意ETL 中不存在名为 v_dws_finance_cashflow 的独立视图,复用财务日报
      • Requirements: 4.5, 4.6, 4.7
    • 5.5 实现 get_finance_expense(conn, site_id, start_date, end_date)
      • 数据源:app.v_dws_finance_expense_summary(支出明细 4 子分组)+ app.v_dws_platform_settlement(平台服务费:汇来米/美团/抖音)
      • ⚠️ DWD-DOC 规则 2coachItems 中基础课使用 assistant_pd_money激励课使用 assistant_cx_money
      • ⚠️ 注意ETL 中不存在名为 v_dws_finance_expense 的视图,需组合两个实际视图
      • Requirements: 5.1, 5.2, 5.3, 5.4
    • 5.6 实现 get_finance_coach_analysis(conn, site_id, start_date, end_date)
      • 数据源:app.v_dws_assistant_salary_calc,按 assistant_level_name 分组聚合
      • 返回 basic基础课/陪打)+ incentive激励课/超休)两个子表
      • Requirements: 5.5, 5.6, 5.7, 5.8
    • 5.7 实现 get_skill_types(conn, site_id) 查询技能类型配置
      • 数据源ETL cfg 表
      • Requirements: 6.2
  • 6. Checkpoint — FDW 查询层验证

    • All FDW query functions compile and type-check correctly (getDiagnostics: 0 errors).
  • 7. 服务层 — BOARD-1 助教看板

    • 7.1 在 board_service.py 中实现 get_coach_board(sort, skill, time, site_id) -> dict
      • 参数互斥校验:time=last_6m + sort=sv_desc → HTTP 400
      • 日期范围计算 → 查询助教列表 → 批量查询绩效/Top 客户/储值/任务 → 排序 → 组装扁平响应
      • topCustomers 查询失败降级为空列表
      • Requirements: 1.1~1.16
    • 7.2 在 board_service.py 中实现 _query_coach_tasks(site_id, assistant_ids, start_date, end_date) 查询任务完成数
      • 数据源:biz.coach_tasks,按 task_type 分类统计 recall/callback
      • Requirements: 1.13, 1.14
  • 8. 服务层 — BOARD-2 客户看板

    • 8.1 在 board_service.py 中实现 get_customer_board(dimension, project, page, page_size, site_id) -> dict
      • 按 dimension 参数路由到对应 FDW 查询函数
      • 批量查询客户关联助教列表
      • 组装分页响应items + total + page + pageSize
      • Requirements: 2.1~2.23
  • 9. 服务层 — BOARD-3 财务看板

    • 9.1 在 board_service.py 中实现 get_finance_board(time, area, compare, site_id) -> dict
      • 日期范围计算 → 6 板块独立查询、独立 try/except 降级
      • area≠all 时 recharge 返回 null
      • compare=1 时计算上期范围并调用 calc_compare
      • compare=0 时环比字段为 None序列化时排除
      • Requirements: 3.13.12, 4.14.7, 5.1~5.8, 8.9, 8.10
    • 9.2 实现 _build_overview(conn, site_id, date_range, prev_range, compare) 经营一览板块构建
      • Requirements: 3.5, 3.6, 3.7
    • 9.3 实现 _build_recharge(conn, site_id, date_range, prev_range, compare) 预收资产板块构建
      • Requirements: 3.8~3.12
    • 9.4 实现 _build_revenue(conn, site_id, date_range, area, prev_range, compare) 应计收入板块构建
      • Requirements: 4.1~4.4
    • 9.5 实现 _build_cashflow(conn, site_id, date_range, prev_range, compare) 现金流入板块构建
      • Requirements: 4.5~4.7
    • 9.6 实现 _build_expense(conn, site_id, date_range, prev_range, compare) 现金流出板块构建
      • Requirements: 5.1~5.4
    • 9.7 实现 _build_coach_analysis(conn, site_id, date_range, prev_range, compare) 助教分析板块构建
      • Requirements: 5.5~5.8
    • 9.8 实现各板块的 _empty_*() 空默认值工厂函数(优雅降级用)
      • Requirements: 8.9, 8.10
  • 10. 路由层 + 路由注册

    • 10.1 新建 apps/backend/app/routers/xcx_board.py,实现 3 个看板端点
      • GET /api/xcx/board/coaches — require_permission("view_board_coach")
      • GET /api/xcx/board/customers — require_permission("view_board_customer")
      • GET /api/xcx/board/finance — require_permission("view_board_finance")response_model_exclude_none=True
      • Requirements: 8.1, 8.2, 8.3
    • 10.2 新建 apps/backend/app/routers/xcx_config.py,实现 CONFIG-1 端点
      • GET /api/xcx/config/skill-types — require_approved()
      • 查询失败降级返回空数组
      • Requirements: 6.1~6.4
    • 10.3 在 apps/backend/app/main.py 中注册 xcx_boardxcx_config 路由
      • Requirements: 8.1
  • 11. Checkpoint — 后端接口验证

    • All backend endpoints compile and type-check correctly (getDiagnostics: 0 errors on all router files and main.py).
  • 12. 前端筛选修复 — BOARD-1T3-7 F1, F6

    • 12.1 修复 apps/miniprogram/miniprogram/pages/board-coach/ 页面的 onSortChangeonSkillChangeonTimeChange 事件处理函数
      • 更新 data 状态后调用 this.loadData() 重新请求 API
      • Requirements: 7.1
    • 12.2 实现 time=last_6m + sort=sv_desc 互斥约束
      • 选择 last_6m 时禁用 sv_desc 选项,或选择 sv_desc 时禁用 last_6m 选项
      • Requirements: 7.2
  • 13. 前端筛选修复 — BOARD-2T3-7 F2, F3

    • 13.1 修复 apps/miniprogram/miniprogram/pages/board-customer/ 页面的 onDimensionChangeonProjectChange 事件处理函数
      • 更新 data 状态后调用 this.loadData() 重新请求 API
      • Requirements: 7.3
    • 13.2 补充分页参数和懒加载逻辑
      • onReachBottom 触发加载下一页,pageSize=20
      • Requirements: 7.4
    • 13.3 修改 services/api.tsfetchBoardCustomers 函数签名,增加 pagepageSize 参数
      • Requirements: 7.5
  • 14. 前端筛选修复 — BOARD-3T3-7 F4, F5

    • 14.1 修改 services/api.tsfetchBoardFinance 函数签名
      • { date?: string } 扩展为 { time: string, area: string, compare: number }
      • Requirements: 7.6
    • 14.2 修复 apps/miniprogram/miniprogram/pages/board-finance/ 页面的 onTimeChangeonAreaChange 事件处理函数
      • 更新 data 状态后使用新参数调用 fetchBoardFinance
      • Requirements: 7.7
    • 14.3 修复 toggleCompare 函数,切换环比开关后使用 compare=0/1 参数重新请求
      • Requirements: 7.8
    • 14.4 area≠all 时隐藏预收资产板块(recharge 为 null 时不渲染该 section
      • Requirements: 7.9
  • 15. Checkpoint — 前端筛选修复验证

    • All frontend filter fixes implemented: event handlers call loadData(), API signatures extended, pagination added to BOARD-2, mutual exclusion constraint for BOARD-1.
  • 16. 属性测试Property-Based Testing

    • 16.1 新建 tests/test_board_properties.py,实现 Property 1: 日期范围计算正确性
      • 生成器:st.dates() + st.sampled_from(BoardTimeEnum/FinanceTimeEnum)
      • 验证:start_date <= end_date,上期 prev_end <= start_date,上期长度 = 当期长度
      • Validates: Requirements 1.3, 3.2, 3.3 — Design Property 1
    • 16.2 实现 Property 2: BOARD-1 排序不变量
      • 生成器:随机助教列表 + st.sampled_from(CoachSortEnum)
      • 验证:相邻元素排序字段满足方向约束
      • Validates: Requirements 1.15, 9.1, 9.2 — Design Property 2
    • 16.3 实现 Property 3: BOARD-2 分页不变量
      • 生成器:随机客户列表 + page/pageSize
      • 验证:items.length <= pageSizetotal 跨页一致,无交集
      • Validates: Requirements 2.2, 9.3, 9.4 — Design Property 3
    • 16.4 实现 Property 4: 亲密度 emoji 四级映射
      • 生成器:st.floats(min_value=0, max_value=10)
      • 验证:> 8.5💖> 7🧡> 5💛≤ 5💙;边界 8.5🧡
      • Validates: Requirements 1.6 — Design Property 4
    • 16.5 实现 Property 5: 环比计算公式正确性
      • 生成器:st.decimals(min_value=0, max_value=1e8) × 2
      • 验证:公式正确、方向标记正确、"新增"/"持平" 边界
      • Validates: Requirements 8.11~8.14 — Design Property 5
    • 16.6 实现 Property 6: 环比开关一致性
      • 生成 BOARD-3 mock 数据 + compare=0序列化后验证 JSON 无 Compare/Down/Flat key
      • Validates: Requirements 3.4, 9.8 — Design Property 6
    • 16.7 实现 Property 7: 预收资产区域约束
      • 生成 area≠all 的请求,验证 recharge=null
      • Validates: Requirements 3.11, 9.7 — Design Property 7
    • 16.8 实现 Property 8+9: 经营一览恒等式
      • 验证 confirmedRevenue ≈ occurrence - abs(discount)±0.01
      • 验证 cashBalance ≈ cashIn - cashOut±0.01
      • Validates: Requirements 9.5, 9.6 — Design Property 8, 9
    • 16.9 实现 Property 10: 支付渠道恒等式
      • 验证 balance_amount = recharge_card_amount + gift_card_amount
      • Validates: Requirements 8.7, 9.9 — Design Property 10
    • 16.10 实现 Property 11: 参数互斥约束
      • 固定 time=last_6m + sort=sv_desc,验证 HTTP 400
      • Validates: Requirements 1.2, 9.11 — Design Property 11
    • 16.11 实现 Property 13: weeklyVisits 百分比范围
      • 生成 8 周到店数据,验证长度=8、pct 0-100、max(pct)=100
      • Validates: Requirements 2.20 — Design Property 13
    • 16.12 实现 Property 14: 优雅降级不变量
      • mock 板块查询抛异常,验证整体 HTTP 200 + 失败板块空默认值
      • Validates: Requirements 8.9, 8.10 — Design Property 14
  • 17. Final Checkpoint — 全量验证

    • Run all property tests: cd C:\NeoZQYY && pytest tests/test_board_properties.py -v
    • Ensure all 12 property tests pass. Ask the user if questions arise.
  • 18. 前端到数据库全链路测试

    • 18.1 启动后端服务,使用测试库(test_zqyy_app)验证 BOARD-1、BOARD-2、BOARD-3、CONFIG-1 四个端点的完整请求-响应链路
      • 使用真实 FDW 连接(test_etl_feiqiu)验证 SQL 查询正确性
      • 验证 JSON 响应结构与 Schema 定义一致camelCase 序列化)
      • 验证权限校验(require_permission() / require_approved())在真实请求中生效
      • 验证 SET LOCAL app.current_site_id 数据隔离在真实请求中生效
    • 18.2 验证 BOARD-3 环比开关行为
      • compare=0 时响应 JSON 中无 Compare/Down/Flat 字段
      • compare=1 时响应 JSON 中包含完整环比数据
      • area≠allrecharge 为 null
    • 18.3 验证 BOARD-1 参数互斥
      • time=last_6m + sort=sv_desc 返回 HTTP 400
    • 18.4 验证 BOARD-2 分页行为
      • page=1, pageSize=20 返回正确分页结构
      • 不同 page 返回的 total 一致
    • 18.5 小程序前端联调验证
      • 前端筛选修复代码已正确接入 API代码审查确认
      • 待联调清单记录在测试文件注释中FDW 列名已修复,可联调)
  • 19. 项目文档更新与落地

    • 19.1 更新 docs/contracts/openapi/backend-api.json,补充 BOARD-1、BOARD-2、BOARD-3、CONFIG-1 四个端点的 OpenAPI 定义
    • 19.2 更新 docs/architecture/backend-architecture.md,补充新增的 board_service 模块、xcx_board / xcx_config 路由注册说明
    • 19.3 更新 docs/database/BD_Manual_biz_tables.md,补充本次引用的 biz.coach_tasks 表在看板场景下的使用说明BOARD-1 task 维度查询)
    • 19.4 更新 docs/DOCUMENTATION-MAP.md,确保新增文档条目已索引
    • 19.5 更新 docs/miniprogram-dev/API-contract.md,补充 BOARD-1、BOARD-2、BOARD-3、CONFIG-1 的接口契约(请求参数/响应示例)
  • 20. 数据库变更审计与 DDL 合并

    • 20.1 审计本次实现中对数据库的改动新建表、新增字段、新增索引、FDW 映射变更等)
      • 结论:无 DDL 变更。全部基于已有 app.v_* RLS 视图的 SELECT 查询,IMPORT FOREIGN SCHEMA app 已自动导入所有视图。biz.coach_tasks 看板查询走已有 idx_coach_tasks_assistant_status 索引,无需新增。
    • 20.2 将所有数据库变更合并到主 DDL 文件
      • 结论:无 DDL 变更需合并。
    • 20.3 更新 BD 手册记录变更
      • docs/database/BD_Manual_biz_tables.md 已补充 RNS1.3 看板引用说明§2.1
      • 审计记录:docs/audit/changes/2026-03-20__rns13-board-apis-e2e-fix.md