# 需求文档 — RNS1.3：三看板接口

## 简介

RNS1.3 是 NS1 小程序后端 API 补全项目的第四个子 spec，负责实现 3 个看板接口（BOARD-1 助教看板、BOARD-2 客户看板、BOARD-3 财务看板）、CONFIG-1 技能配置接口、以及前端看板筛选修复。看板是管理层视角的核心功能，其中 BOARD-3 财务看板是全项目最复杂的单个接口（6 个独立板块、200+ 字段、60+ 环比数据点）。

### 依赖

- RNS1.0（基础设施与契约重写）必须先完成：全局响应包装中间件（`ResponseWrapperMiddleware`）、camelCase 转换（`CamelModel`）、重写后的 API 契约
- RNS1.1 / RNS1.2 可并行开发，无直接依赖
- 后端已有 `fdw_queries.py`（FDW 查询集中封装）、`task_manager.py`、`note_service.py`
- 前端已有 13 个页面（P5.2 交付），当前使用 mock 数据

### 来源文档

- `docs/prd/Neo_Specs/RNS1-split-plan.md` — 拆分计划主文档（RNS1.3 章节，T3-1 ~ T3-7）
- `docs/miniprogram-dev/API-contract.md` — API 契约（BOARD-1/2/3、CONFIG-1 完整定义）
- `docs/prd/Neo_Specs/NS1-xcx-backend-api.md` — 原始 spec（八¾ 看板筛选交叉矩阵为权威参考）
- `docs/prd/Neo_Specs/miniprogram-storyboard-walkthrough-gaps.md` — 管理层视角走查报告（G1~G10 看板相关 Gap）
- `docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md` — 助教视角走查报告
- `docs/reports/DWD-DOC/` — 金额口径与字段语义权威标杆文档

## 术语表

- **Backend**：FastAPI 后端应用，位于 `apps/backend/`
- **Miniprogram**：微信小程序前端应用，位于 `apps/miniprogram/`
- **BOARD_1_API**：助教看板接口 `GET /api/xcx/board/coaches`，返回助教排行列表（4 维度专属字段）
- **BOARD_2_API**：客户看板接口 `GET /api/xcx/board/customers`，返回客户排行列表（8 维度专属字段）
- **BOARD_3_API**：财务看板接口 `GET /api/xcx/board/finance`，返回 6 个板块的财务数据（overview/recharge/revenue/cashflow/expense/coachAnalysis）
- **CONFIG_1_API**：技能类型列表接口 `GET /api/xcx/config/skill-types`，返回助教技能类型配置
- **FDW**：PostgreSQL Foreign Data Wrapper，后端通过直连 ETL 库查询 `app.v_*` RLS 视图
- **items_sum**：DWD-DOC 强制使用的消费金额口径，= `table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money`
- **assistant_pd_money**：助教陪打费用（基础课），DWD-DOC 强制规则 2 要求的拆分字段
- **assistant_cx_money**：助教超休费用（激励课），DWD-DOC 强制规则 2 要求的拆分字段
- **v_dws_assistant_salary_calc**：ETL RLS 视图，提供助教绩效/档位/收入/工资数据
- **v_dws_assistant_monthly_summary**：ETL RLS 视图，提供助教月度汇总（客户数、储值额等）
- **v_dim_assistant**：ETL RLS 视图，提供助教基本信息（姓名、技能、入职日期等）
- **v_dim_member**：ETL RLS 视图，提供会员基本信息（nickname、mobile），通过 `member_id` 关联，取 `scd2_is_current=1`
- **v_dim_member_card_account**：ETL RLS 视图，提供会员卡余额，通过 `tenant_member_id` 关联，取 `scd2_is_current=1`
- **v_dws_member_assistant_relation_index**：ETL RLS 视图，提供会员与助教的关系指数
- **v_dws_member_consumption_summary**：ETL RLS 视图，提供会员消费汇总
- **v_dws_finance_daily_summary**：ETL RLS 视图，提供财务日报汇总数据（经营一览 8 指标 + 现金流入/流出），BOARD-3 overview/cashflow/expense 板块的主数据源
- **v_dws_finance_income_structure**：ETL RLS 视图，提供收入结构表 + 正价/优惠/渠道明细，BOARD-3 revenue 板块数据源
- **v_dws_finance_recharge_summary**：ETL RLS 视图，提供储值卡 + 赠送卡矩阵数据，BOARD-3 recharge 板块数据源
- **v_dws_finance_discount_detail**：ETL RLS 视图，提供优惠明细（大客户优惠/其他优惠拆分），BOARD-3 revenue 板块辅助数据源
- **v_dws_finance_expense_summary**：ETL RLS 视图，提供现金流出 4 子分组明细，BOARD-3 expense 板块数据源
- **v_dws_platform_settlement**：ETL RLS 视图，提供平台结算数据（汇来米/美团/抖音），BOARD-3 expense.platformItems 数据源
- **coach_tasks**：业务库 `biz.coach_tasks` 表，存储助教任务分配与状态
- **user_assistant_binding**：认证库 `auth.user_assistant_binding` 表，映射小程序用户与助教身份
- **dimType**：BOARD-1 中根据 `sort` 参数映射的维度类型（`perf`/`salary`/`sv`/`task`），决定卡片展示模板
- **环比**：月环比，与上一个相同时间周期对比（本月 vs 上月、本周 vs 上周等），返回百分比字符串 + 方向标记
- **GiftRow**：赠送卡 3×4 矩阵中的一行（新增/消费/余额），每行含 4 列（合计/酒水卡/台费卡/抵用券）
- **RevenueStructureRow**：收入结构表中的一行（9 行含子行），含发生额、优惠、入账金额
- **CoachAnalysisTable**：助教分析子表（基础课或激励课），含汇总行 + 按等级分行（初级/中级/高级/星级）

## 需求

### 需求 1：实现 BOARD-1 助教看板（T3-1）

**用户故事：** 作为管理者，我希望在助教看板中按不同维度（定档业绩/工资/客源储值/任务完成）查看助教排行，并支持技能筛选和时间范围切换，以便评估和对比各助教的工作表现。

#### 验收标准

#### 1.1 请求参数与筛选

1. THE BOARD_1_API SHALL 接受 3 个查询参数：`sort`（排序维度，6 种枚举：`perf_desc`/`perf_asc`/`salary_desc`/`salary_asc`/`sv_desc`/`task_desc`）、`skill`（技能筛选，5 种枚举：`all`/`chinese`/`snooker`/`mahjong`/`karaoke`）、`time`（时间范围，6 种枚举：`month`/`quarter`/`last_month`/`last_3m`/`last_quarter`/`last_6m`）
2. IF `time=last_6m` 且 `sort=sv_desc`，THEN THE BOARD_1_API SHALL 返回 HTTP 400 `{ code: 400, message: "最近6个月不支持客源储值排序" }`
3. THE BOARD_1_API SHALL 根据 `time` 参数计算对应的日期范围（本月=当月1日~末日、上月=上月1日~末日、本季度=季度首日~末日、前3个月=不含本月的前3个月、上季度=上季度、最近6个月=不含本月的前6个月）

#### 1.2 基础字段（所有维度共享）

4. THE BOARD_1_API SHALL 为每个助教 item 返回基础字段：`id`（助教 ID）、`name`（助教姓名）、`initial`（姓名首字）、`avatarGradient`（头像渐变色标识）、`level`（等级 key：`star`/`senior`/`middle`/`junior`）、`skills`（技能列表，`Array<{ text: string, cls: string }>`）、`topCustomers`（Top 客户列表，含亲密度 emoji 前缀，如 `['💖 王先生', '💛 李女士']`）
5. THE BOARD_1_API SHALL 从 `v_dim_assistant` 获取助教基本信息，从 `v_dws_assistant_salary_calc` 获取等级（`assistant_level_name`）
6. THE BOARD_1_API SHALL 从 `v_dws_member_assistant_relation_index` 按亲密度降序取 Top 3 客户，拼接亲密度 emoji（P6 AC3 四级映射：`rs_display > 8.5` → 💖，`> 7` → 🧡，`> 5` → 💛，`≤ 5` → 💙）+ 客户姓名作为 `topCustomers`

#### 1.3 perf 维度专属字段

7. WHEN `sort` 为 `perf_desc` 或 `perf_asc` 时，THE BOARD_1_API SHALL 返回 perf 维度字段：`perfHours`（当期定档工时）、`perfHoursBefore`（上期定档工时，可选）、`perfGap`（距升档差距描述，如 `"距升档 13.8h"`，已达标时不返回）、`perfReached`（是否已达标）
8. THE BOARD_1_API SHALL 从 `v_dws_assistant_salary_calc` 查询当期和上期的定档工时数据，根据档位阈值计算 `perfGap` 和 `perfReached`

#### 1.4 salary 维度专属字段

9. WHEN `sort` 为 `salary_desc` 或 `salary_asc` 时，THE BOARD_1_API SHALL 返回 salary 维度字段：`salary`（预估工资总额，元）、`salaryPerfHours`（定档工时）、`salaryPerfBefore`（上期定档工时，可选）
10. THE BOARD_1_API SHALL 使用 `items_sum` 口径计算 `salary` 字段（DWD-DOC 强制规则 1）

#### 1.5 sv 维度专属字段

11. WHEN `sort` 为 `sv_desc` 时，THE BOARD_1_API SHALL 返回 sv 维度字段：`svAmount`（客源储值总额，元）、`svCustomerCount`（储值客户数）、`svConsume`（储值消耗额，元）
12. THE BOARD_1_API SHALL 从 `v_dws_assistant_monthly_summary` 获取助教月度储值汇总数据（客源储值额、储值客户数、储值消耗额），该视图已按助教维度预聚合

#### 1.6 task 维度专属字段

13. WHEN `sort` 为 `task_desc` 时，THE BOARD_1_API SHALL 返回 task 维度字段：`taskRecall`（召回任务完成数）、`taskCallback`（回访任务完成数）
14. THE BOARD_1_API SHALL 从 `biz.coach_tasks` 查询指定时间范围内 `status='completed'` 的任务，按 `task_type` 分类统计

#### 1.7 排序与返回策略

15. THE BOARD_1_API SHALL 根据 `sort` 参数对结果排序（`perf_desc` 按定档工时降序、`perf_asc` 按定档工时升序、`salary_desc` 按工资降序、`salary_asc` 按工资升序、`sv_desc` 按储值额降序、`task_desc` 按任务完成总数降序）
16. THE BOARD_1_API SHALL 始终返回所有维度的字段（扁平结构），前端根据当前 `sort` 选择性渲染对应卡片模板，切换维度时无需重新请求

### 需求 2：实现 BOARD-2 客户看板（T3-2）

**用户故事：** 作为管理者，我希望在客户看板中按 8 个维度（最应召回/最大消费潜力/最高余额/最近充值/最近到店/最高消费60天/最频繁60天/最专一60天）查看客户排行，每个维度展示不同的专属字段卡片和关联助教信息，以便从多角度评估客户价值和服务需求。

#### 验收标准

#### 2.1 请求参数与分页

1. THE BOARD_2_API SHALL 接受 4 个查询参数：`dimension`（维度，8 种枚举：`recall`/`potential`/`balance`/`recharge`/`recent`/`spend60`/`freq60`/`loyal`）、`project`（项目筛选，5 种枚举：`all`/`chinese`/`snooker`/`mahjong`/`karaoke`）、`page`（页码，默认 1）、`pageSize`（每页条数，默认 20，上限 100）
2. THE BOARD_2_API SHALL 返回分页结构：`items`（客户列表）、`total`（总数）、`page`（当前页）、`pageSize`（每页条数），支持前端 20 条懒加载

#### 2.2 基础字段（所有维度共享）

3. THE BOARD_2_API SHALL 为每个客户 item 返回基础字段：`id`（客户 member_id）、`name`（客户姓名）、`initial`（姓名首字）、`avatarCls`（头像样式类）、`assistants`（关联助教列表，`Array<{ name, cls, heartScore, badge?, badgeCls? }>`）
4. THE BOARD_2_API SHALL 通过 `member_id` LEFT JOIN `v_dim_member`（取 `scd2_is_current=1`）获取客户姓名（DQ-6）
5. THE BOARD_2_API SHALL 从 `biz.coach_tasks` + 亲密度计算获取 `assistants` 列表，按亲密度降序排列，当前跟进助教（`cls='assistant--assignee'`）置顶

#### 2.3 recall 维度专属字段

6. WHEN `dimension=recall` 时，THE BOARD_2_API SHALL 返回：`idealDays`（理想到店间隔天数）、`elapsedDays`（已过天数）、`overdueDays`（超期天数 = elapsedDays - idealDays）、`visits30d`（近30天到店次数）、`balance`（余额，格式化字符串）、`recallIndex`（召回指数）
7. THE BOARD_2_API SHALL 按 WBI（召回指数）降序排列 recall 维度结果

#### 2.4 potential 维度专属字段

8. WHEN `dimension=potential` 时，THE BOARD_2_API SHALL 返回：`potentialTags`（潜力标签列表，`Array<{ text, theme }>`）、`spend30d`（近30天消费）、`avgVisits`（月均到店）、`avgSpend`（次均消费）
9. THE BOARD_2_API SHALL 按 SPI（消费潜力指数）降序排列 potential 维度结果

#### 2.5 balance 维度专属字段

10. WHEN `dimension=balance` 时，THE BOARD_2_API SHALL 返回：`balance`（当前余额）、`lastVisit`（最近到店描述，如 `"3天前"`）、`monthlyConsume`（月均消耗）、`availableMonths`（可用月数，如 `"约0.8个月"`）
11. THE BOARD_2_API SHALL 按 `balance_amount` 降序排列 balance 维度结果

#### 2.6 recharge 维度专属字段

12. WHEN `dimension=recharge` 时，THE BOARD_2_API SHALL 返回：`lastRecharge`（最后充值日期）、`rechargeAmount`（充值金额）、`recharges60d`（近60天充值次数）、`currentBalance`（当前余额）
13. THE BOARD_2_API SHALL 按 `last_recharge_date` 降序排列 recharge 维度结果

#### 2.7 recent 维度专属字段

14. WHEN `dimension=recent` 时，THE BOARD_2_API SHALL 返回：`daysAgo`（距今天数）、`visitFreq`（到店频率，如 `"6.2次/月"`）、`idealDays`（理想间隔）、`visits30d`（近30天到店）、`avgSpend`（次均消费）
15. THE BOARD_2_API SHALL 按 `last_visit_date` 降序排列 recent 维度结果

#### 2.8 spend60 维度专属字段

16. WHEN `dimension=spend60` 时，THE BOARD_2_API SHALL 返回：`spend60d`（近60天消费总额）、`visits60d`（近60天到店次数）、`highSpendTag`（是否高消费标记）、`avgSpend`（次均消费）
17. THE BOARD_2_API SHALL 使用 `items_sum` 口径计算 `spend60d`（DWD-DOC 强制规则 1），按 `items_sum_60d` 降序排列

#### 2.9 freq60 维度专属字段

18. WHEN `dimension=freq60` 时，THE BOARD_2_API SHALL 返回：`visits60d`（近60天到店次数）、`avgInterval`（平均到店间隔，如 `"5.0天"`）、`weeklyVisits`（最近8周到店柱状图，`Array<{ val: number, pct: number }>`，固定长度 8）、`spend60d`（近60天消费）
19. THE BOARD_2_API SHALL 按 `visit_count_60d` 降序排列 freq60 维度结果
20. THE BOARD_2_API SHALL 计算 `weeklyVisits` 中每周的 `pct` 为相对于 8 周最大值的百分比（0-100）

#### 2.10 loyal 维度专属字段

21. WHEN `dimension=loyal` 时，THE BOARD_2_API SHALL 返回：`intimacy`（专一度指数）、`topCoachName`（最亲密助教姓名）、`topCoachHeart`（最亲密助教亲密度分数）、`topCoachScore`（最亲密助教关系指数）、`coachName`（主助教姓名）、`coachRatio`（主助教占比，如 `"78%"`）、`coachDetails`（助教明细列表，`Array<{ name, cls, heartScore, badge?, avgDuration, serviceCount, coachSpend, relationIdx }>`）
22. THE BOARD_2_API SHALL 按 `max_rs`（最大关系指数）降序排列 loyal 维度结果

#### 2.11 维度切换策略

23. THE BOARD_2_API SHALL 按 `dimension` 参数仅返回对应维度的专属字段（减少传输量和查询开销），切换维度时前端重新请求

### 需求 3：实现 BOARD-3 经营一览 + 预收资产（T3-3）

**用户故事：** 作为管理者，我希望在财务看板中查看经营一览（8 项核心指标及环比）和预收资产（储值卡 + 赠送卡矩阵），并支持时间范围、区域筛选和环比开关，以便全面掌握门店的经营状况和预收资产变动。

#### 验收标准

#### 3.1 请求参数

1. THE BOARD_3_API SHALL 接受 3 个查询参数：`time`（时间范围，8 种枚举：`month`/`lastMonth`/`week`/`lastWeek`/`quarter3`/`quarter`/`lastQuarter`/`half6`）、`area`（区域筛选，7 种枚举：`all`/`hall`/`hallA`/`hallB`/`hallC`/`mahjong`/`teamBuilding`）、`compare`（环比开关，`0` 或 `1`，默认 `0`）
2. THE BOARD_3_API SHALL 根据 `time` 参数计算当期日期范围（`month`=当月1日~末日、`lastMonth`=上月1日~末日、`week`=本周一~本周日、`lastWeek`=上周一~上周日、`quarter3`=前3个月不含本月、`quarter`=本季度首日~末日、`lastQuarter`=上季度、`half6`=最近6个月不含本月）
3. WHEN `compare=1` 时，THE BOARD_3_API SHALL 计算上期日期范围（与当期相同长度的前一个周期），分别查询当期和上期数据后计算环比百分比
4. WHEN `compare=0` 时，THE BOARD_3_API SHALL 不返回任何环比字段（`xxxCompare`/`isDown`/`isFlat`），减少查询开销

#### 3.2 经营一览 overview（8 指标 + 8 环比）

5. THE BOARD_3_API SHALL 返回 `overview` 板块，包含 8 项核心指标：`occurrence`（发生额/正价）、`discount`（总优惠，负值）、`discountRate`（折扣率）、`confirmedRevenue`（成交/确认收入）、`cashIn`（实收/现金流入）、`cashOut`（现金支出）、`cashBalance`（现金结余）、`balanceRate`（结余率）
6. WHEN `compare=1` 时，THE BOARD_3_API SHALL 为 overview 每项指标返回 3 个环比字段：`xxxCompare`（环比百分比字符串，如 `"12.5%"` 或 `"持平"`）、`xxxDown`（是否下降，boolean）、`xxxFlat`（是否持平，boolean）
7. THE BOARD_3_API SHALL 从 `v_dws_finance_daily_summary` 查询经营一览数据（按日期范围聚合），使用 `items_sum` 口径计算所有金额（DWD-DOC 强制规则 1）

#### 3.3 预收资产 recharge（储值卡 + 赠送卡矩阵）

8. WHEN `area=all` 时，THE BOARD_3_API SHALL 返回 `recharge` 板块，包含储值卡 5 项指标：`actualIncome`（充值实收）、`firstCharge`（首充）、`renewCharge`（续费）、`consumed`（消耗）、`cardBalance`（储值卡总余额）
9. THE BOARD_3_API SHALL 返回 `recharge.giftRows`（赠送卡 3×4 矩阵），3 行（新增/消费/余额）× 4 列（合计/酒水卡/台费卡/抵用券），每个单元格含值和环比字段，共 24 个数据字段 + 24 个环比字段
10. THE BOARD_3_API SHALL 返回 `recharge.allCardBalance`（全类别会员卡余额合计 = 储值卡 + 赠送卡）
11. WHEN `area` 不等于 `all` 时，THE BOARD_3_API SHALL 将 `recharge` 板块返回 `null`（储值卡数据不按区域拆分，选中具体区域时无意义）
12. THE BOARD_3_API SHALL 从 `v_dws_finance_recharge_summary` 查询预收资产数据

### 需求 4：实现 BOARD-3 应计收入 + 现金流入（T3-4）

**用户故事：** 作为管理者，我希望在财务看板中查看应计收入确认（收入结构表含区域子行、正价/优惠/渠道明细）和现金流入（消费收款 + 充值收款），以便分析收入构成和现金来源。

#### 验收标准

#### 4.1 应计收入确认 revenue

1. THE BOARD_3_API SHALL 返回 `revenue.structureRows`（收入结构表），包含 9 行含子行标记：主行（开台与包厢、助教基础课、助教激励课、食品酒水）+ 子行（A区/B区/C区/团建区/麻将区，属于"开台与包厢"的子行，`isSub=true`），每行含 `id`、`name`、`desc`（可选）、`amount`（发生额）、`discount`（优惠金额）、`booked`（入账金额）、`bookedCompare`（入账环比，可选）
2. THE BOARD_3_API SHALL 对收入结构表中助教行使用 `assistant_pd_money`（基础课/陪打）和 `assistant_cx_money`（激励课/超休）拆分（DWD-DOC 强制规则 2），禁止使用 `service_fee`
3. THE BOARD_3_API SHALL 返回 `revenue.priceItems`（正价明细，4 项）、`revenue.totalOccurrence`（发生额合计）、`revenue.discountItems`（优惠明细，4 项）、`revenue.confirmedTotal`（确认收入合计）、`revenue.channelItems`（渠道明细，3 项：储值卡结算冲销/现金线上支付/团购核销确认收入）
4. THE BOARD_3_API SHALL 从 `v_dws_finance_income_structure`（收入结构主表）+ `v_dws_finance_discount_detail`（优惠明细辅助）查询应计收入数据

#### 4.2 现金流入 cashflow

5. THE BOARD_3_API SHALL 返回 `cashflow` 板块，包含 `consumeItems`（消费收款，3 项：纸币现金/线上收款/团购平台）、`rechargeItems`（充值收款，1 项：会员充值到账）、`total`（现金流入合计）
6. THE BOARD_3_API SHALL 确保 `consumeItems` 中 `platform_settlement_amount` 和 `groupbuy_pay_amount` 互斥（DWD-DOC 强制规则 8：现金流互斥）
7. THE BOARD_3_API SHALL 从 `v_dws_finance_daily_summary` 查询现金流入数据（消费收款 + 充值收款字段均在财务日报中）

### 需求 5：实现 BOARD-3 现金流出 + 助教分析（T3-5）

**用户故事：** 作为管理者，我希望在财务看板中查看现金流出（经营/固定/助教分成/平台服务费 4 个子分组）和助教分析（基础课 + 激励课各按 4 等级分行），以便分析支出结构和助教成本。

#### 验收标准

#### 5.1 现金流出 expense

1. THE BOARD_3_API SHALL 返回 `expense` 板块，包含 4 个子分组：`operationItems`（经营支出，3 项：食品饮料/耗材/报销）、`fixedItems`（固定支出，4 项：房租/水电/物业/人员工资）、`coachItems`（助教分成，4 项：基础课分成/激励课分成/充值提成/额外奖金）、`platformItems`（平台服务费，3 项：汇来米/美团/抖音）
2. THE BOARD_3_API SHALL 返回 `expense.total`（现金流出合计）及其环比字段
3. THE BOARD_3_API SHALL 对 `coachItems` 中基础课分成使用 `assistant_pd_money`，激励课分成使用 `assistant_cx_money`（DWD-DOC 强制规则 2）
4. THE BOARD_3_API SHALL 从 `v_dws_finance_expense_summary`（支出明细 4 子分组，含助教分成）+ `v_dws_platform_settlement`（平台服务费：汇来米/美团/抖音）查询现金流出数据

#### 5.2 助教分析 coachAnalysis

5. THE BOARD_3_API SHALL 返回 `coachAnalysis` 板块，包含 `basic`（基础课/陪打）和 `incentive`（激励课/超休）两个子表，结构完全相同
6. THE BOARD_3_API SHALL 为每个子表返回汇总行：`totalPay`（总课时费）、`totalShare`（总分成）、`avgHourly`（平均时薪），各含环比字段
7. THE BOARD_3_API SHALL 为每个子表返回 `rows`（按等级分行，4 行：初级/中级/高级/星级），每行含 `level`（等级名）、`pay`（课时费）、`share`（分成）、`hourly`（时薪），各含环比字段和方向标记（`payDown`/`shareDown`/`hourlyFlat`）
8. THE BOARD_3_API SHALL 从 `v_dws_assistant_salary_calc` 按 `assistant_level_name` 分组聚合助教分析数据

### 需求 6：实现 CONFIG-1 技能类型列表（T3-6）

**用户故事：** 作为管理者，我希望助教看板的技能筛选选项从后端配置表动态获取（而非前端硬编码），以便在新增技能类型时无需发版更新前端。

#### 验收标准

1. THE CONFIG_1_API SHALL 实现 `GET /api/xcx/config/skill-types` 端点，返回技能类型列表，每项含 `key`（枚举值，如 `chinese`/`snooker`/`mahjong`/`karaoke`）、`label`（中文标签）、`emoji`（表情符号）、`cls`（前端样式类）
2. THE CONFIG_1_API SHALL 从 ETL cfg 表读取技能类型配置数据
3. IF ETL cfg 表查询失败或无数据，THEN THE CONFIG_1_API SHALL 返回空数组，前端 `api.ts` 中的硬编码列表作为 mock 回退
4. THE CONFIG_1_API SHALL 对响应设置合理的缓存策略（技能类型变更频率极低）

### 需求 7：前端看板筛选修复（T3-7）

**用户故事：** 作为管理者，我希望在看板页面切换筛选条件时能立即看到更新后的数据（而非停留在旧数据），以便实时对比不同维度和时间范围的数据。

#### 验收标准

#### 7.1 BOARD-1 筛选修复（F1, F6）

1. THE Miniprogram SHALL 修复 `board-coach` 页面的 `onSortChange`、`onSkillChange`、`onTimeChange` 事件处理函数，在更新 data 状态后调用 `this.loadData()` 重新请求 API
2. THE Miniprogram SHALL 在 `board-coach` 页面实现 `time=last_6m` + `sort=sv_desc` 的互斥约束：选择 `last_6m` 时禁用 `sv_desc` 选项，或选择 `sv_desc` 时禁用 `last_6m` 选项

#### 7.2 BOARD-2 筛选修复 + 分页补充（F2, F3）

3. THE Miniprogram SHALL 修复 `board-customer` 页面的 `onDimensionChange`、`onProjectChange` 事件处理函数，在更新 data 状态后调用 `this.loadData()` 重新请求 API
4. THE Miniprogram SHALL 为 `board-customer` 页面补充分页参数（`page`/`pageSize`）和"加载更多"懒加载逻辑（`onReachBottom` 触发加载下一页，`pageSize=20`）
5. THE Miniprogram SHALL 修改 `services/api.ts` 中 `fetchBoardCustomers` 函数签名，增加 `page` 和 `pageSize` 参数

#### 7.3 BOARD-3 筛选修复 + 签名扩展（F4, F5）

6. THE Miniprogram SHALL 修改 `services/api.ts` 中 `fetchBoardFinance` 函数签名，从 `{ date?: string }` 扩展为 `{ time: string, area: string, compare: number }`
7. THE Miniprogram SHALL 修复 `board-finance` 页面的 `onTimeChange`、`onAreaChange` 事件处理函数，在更新 data 状态后使用新参数调用 `fetchBoardFinance` 重新请求 API
8. THE Miniprogram SHALL 修复 `board-finance` 页面的 `toggleCompare` 函数，切换环比开关后使用 `compare=0` 或 `compare=1` 参数重新请求 API
9. WHEN `area` 不等于 `all` 时，THE Miniprogram SHALL 隐藏预收资产板块（`recharge` 为 `null` 时不渲染该 section）

### 需求 8：全局约束与数据隔离

**用户故事：** 作为系统管理员，我希望所有看板和配置接口都遵循统一的权限控制、数据隔离和数据质量规则，以确保数据安全和口径一致。

#### 验收标准

#### 8.1 权限与认证

1. THE Backend SHALL 对所有 RNS1.3 接口（BOARD_1_API、BOARD_2_API、BOARD_3_API、CONFIG_1_API）执行 `require_approved()` 权限检查，确保用户状态为 `approved`
2. THE Backend SHALL 对 BOARD_1_API 验证用户具有 `view_board_coach` 权限，对 BOARD_2_API 验证用户具有 `view_board_customer` 权限，对 BOARD_3_API 验证用户具有 `view_board_finance` 权限
3. THE Backend SHALL 对所有 RNS1.3 接口通过 `SET LOCAL app.current_site_id` 实现门店级数据隔离（FDW 查询通过 `_fdw_context` 上下文管理器统一执行）

#### 8.2 DWD-DOC 强制规则

4. THE Backend SHALL 对所有涉及金额的字段统一使用 `items_sum` 口径（DWD-DOC 强制规则 1），禁止使用 `consume_money`
5. THE Backend SHALL 对所有涉及助教费用的字段使用 `assistant_pd_money`（陪打/基础课）+ `assistant_cx_money`（超休/激励课）拆分（DWD-DOC 强制规则 2），禁止使用 `service_fee`
6. THE Backend SHALL 对所有涉及会员信息的查询通过 `member_id` LEFT JOIN `v_dim_member`（取 `scd2_is_current=1`）获取姓名和手机号（DWD-DOC 强制规则 DQ-6），禁止直接使用 `settlement_head.member_phone` 或 `member_name`
7. THE Backend SHALL 确保支付渠道恒等式 `balance_amount = recharge_card_amount + gift_card_amount`（DWD-DOC 强制规则 3），三者不可重复计算
8. THE Backend SHALL 确保现金流互斥：`platform_settlement_amount` 和 `groupbuy_pay_amount` 互斥（DWD-DOC 强制规则 8）

#### 8.3 优雅降级

9. IF 某个看板板块的数据源查询失败，THEN THE Backend SHALL 对该板块返回空默认值（空对象或空数组），不影响其他板块和整体响应
10. THE Backend SHALL 对所有 FDW 查询异常进行捕获和日志记录，返回降级响应而非 HTTP 500

#### 8.4 环比计算通用规则

11. THE Backend SHALL 对所有环比计算采用统一公式：`compareValue = (当期值 - 上期值) / 上期值 × 100%`，格式化为百分比字符串（如 `"12.5%"`）
12. WHEN 上期值为 0 且当期值不为 0 时，THE Backend SHALL 返回 `xxxCompare: "新增"`，`xxxDown: false`，`xxxFlat: false`
13. WHEN 上期值和当期值均为 0 时，THE Backend SHALL 返回 `xxxCompare: "持平"`，`xxxDown: false`，`xxxFlat: true`
14. THE Backend SHALL 根据环比值设置方向标记：正值 → `isDown=false`，负值 → `isDown=true`，零值 → `isFlat=true`

### 需求 9：正确性属性（Property-Based Testing）

**用户故事：** 作为开发者，我希望通过属性测试验证看板接口的数据一致性和业务规则正确性，以便在开发阶段发现口径错误和数据异常。

#### 验收标准

#### 9.1 BOARD-1 排序不变量

1. FOR ALL BOARD_1_API 响应（`sort=perf_desc`），列表 SHALL 按 `perfHours` 降序排列（前一项的 `perfHours` ≥ 后一项的 `perfHours`）
2. FOR ALL BOARD_1_API 响应（`sort=salary_asc`），列表 SHALL 按 `salary` 升序排列（前一项的 `salary` ≤ 后一项的 `salary`）

#### 9.2 BOARD-2 分页不变量

3. FOR ALL 相同参数的 BOARD_2_API 请求（相同 `dimension`、`project`），`page=1` 返回的 `total` SHALL 等于 `page=2` 返回的 `total`（总数在分页间保持一致）
4. FOR ALL BOARD_2_API 响应，`items.length` SHALL 小于等于 `pageSize`

#### 9.3 BOARD-3 经营一览恒等式

5. FOR ALL BOARD_3_API 响应中的 `overview`，`confirmedRevenue` SHALL 近似等于 `occurrence` 减去 `discount` 的绝对值（在浮点精度范围内），验证收入确认公式
6. FOR ALL BOARD_3_API 响应中的 `overview`，`cashBalance` SHALL 近似等于 `cashIn` 减去 `cashOut`（在浮点精度范围内），验证现金结余公式

#### 9.4 BOARD-3 预收资产区域约束

7. FOR ALL BOARD_3_API 响应（`area` 不等于 `all`），`recharge` SHALL 为 `null`，验证预收资产区域隐藏规则

#### 9.5 BOARD-3 环比开关一致性

8. FOR ALL BOARD_3_API 响应（`compare=0`），响应 JSON 中 SHALL 不包含任何以 `Compare`、`Down`、`Flat` 结尾的字段，验证环比开关关闭时不返回环比数据

#### 9.6 BOARD-3 支付渠道恒等式

9. FOR ALL BOARD_3_API 响应中涉及支付渠道的数据，`balance_amount` SHALL 等于 `recharge_card_amount + gift_card_amount`（DWD-DOC 强制规则 3），验证支付渠道恒等式

#### 9.7 幂等性

10. FOR ALL 相同参数的 BOARD_3_API 请求（相同 `time`、`area`、`compare`），在数据未变更的情况下，两次请求 SHALL 返回相同的 `overview.occurrence` 和 `overview.cashBalance` 值

#### 9.8 BOARD-1 交叉约束

11. FOR ALL BOARD_1_API 请求（`time=last_6m` 且 `sort=sv_desc`），响应 SHALL 为 HTTP 400，验证不兼容参数组合的拒绝规则
