Files
Neo-ZQYY/.kiro/specs/rns1-customer-coach-api/requirements.md

254 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 需求文档 — RNS1.2:客户与助教接口
## 简介
RNS1.2 是 NS1 小程序后端 API 补全项目的第三个子 spec负责实现客户详情CUST-1、客户服务记录CUST-2、助教详情COACH-13 个接口。这三个接口覆盖客户视角和助教视角的详情查看需求,是走查报告中 Gap 最集中的区域GAP-23~30、GAP-32~35、GAP-38~44数据结构最为复杂。
### 依赖
- RNS1.0(基础设施与契约重写)已完成:全局响应包装中间件(`ResponseWrapperMiddleware`、camelCase 转换(`CamelModel`)、重写后的 API 契约
- RNS1.1(任务与绩效接口)可并行开发,无直接依赖
- 后端已有 `fdw_queries.py`FDW 查询集中封装)、`task_manager.py``note_service.py`
- 前端已有 13 个页面P5.2 交付),当前使用 mock 数据
### 来源文档
- `docs/prd/Neo_Specs/RNS1-split-plan.md` — 拆分计划主文档RNS1.2 章节)
- `docs/miniprogram-dev/API-contract.md` — API 契约CUST-1、CUST-2、COACH-1 完整定义)
- `docs/reports/storyboard-walkthrough-assistant-view.md` — 助教视角走查报告GAP-23~30、GAP-32~35、GAP-38~44
- `docs/reports/miniprogram-storyboard-walkthrough-gaps.md` — 管理层视角走查报告G4、G5
- `docs/reports/DWD-DOC/` — 金额口径与字段语义权威标杆文档
- `docs/architecture/backend-architecture.md` — 后端架构文档
## 术语表
- **Backend**FastAPI 后端应用,位于 `apps/backend/`
- **Miniprogram**:微信小程序前端应用,位于 `apps/miniprogram/`
- **CUST_1_API**:客户详情接口 `GET /api/xcx/customers/{customerId}`返回客户完整详情Banner 概览、AI 洞察、关联助教任务、最亲密助教、消费记录、备注)
- **CUST_2_API**:客户服务记录接口 `GET /api/xcx/customers/{customerId}/records`,返回按月查询的服务记录列表
- **COACH_1_API**:助教详情接口 `GET /api/xcx/coaches/{coachId}`返回助教完整详情绩效、收入、档位、TOP 客户、历史月份、任务分组、备注)
- **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_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_dwd_assistant_service_log**ETL RLS 视图,提供助教服务记录明细(基于 `dwd_assistant_service_log` 基表,废单字段为 `is_delete`
- **v_dws_member_assistant_relation_index**ETL RLS 视图,提供会员与助教的关系指数
- **v_dws_member_consumption_summary**ETL RLS 视图,提供会员消费汇总
- **v_dws_assistant_salary_calc**ETL RLS 视图,提供助教绩效/档位/收入数据
- **v_dim_assistant**ETL RLS 视图,提供助教基本信息
- **v_dwd_table_fee_log**ETL RLS 视图,提供台费明细
- **ai_cache**:业务库 `biz.ai_cache` 表,按 `cache_type` 存储不同类型的 AI 分析缓存
- **coach_tasks**:业务库 `biz.coach_tasks` 表,存储助教任务分配与状态
- **member_retention_clue**:业务库 `public.member_retention_clue` 表,存储维客线索
- **user_assistant_binding**:认证库 `auth.user_assistant_binding` 表,映射小程序用户与助教身份
- **settle_type**:结算类型字段,正向交易取 `IN (1, 3)`
- **is_delete**RLS 视图中的废单标记字段整数类型0=正常),对应 design.md 中的 `is_trash`
## 需求
### 需求 1实现 CUST-1 客户详情 Banner 概览T2-1 基础部分)
**用户故事:** 作为管理者或助教,我希望在客户详情页顶部看到客户的基本信息和关键指标(余额、近期消费、到店间隔、距上次到店天数),以便快速评估客户价值和活跃度。
#### 验收标准
1. THE CUST_1_API SHALL 返回客户基础信息字段:`id`(客户唯一 ID`name`(客户姓名)、`phone`(脱敏手机号,如 `"139****5678"`)、`phoneFull`(完整手机号)、`avatar`(头像 URL`memberLevel`(会员等级)、`relationIndex`(关系指数)、`tags`(客户标签列表)
2. THE CUST_1_API SHALL 通过 `member_id` LEFT JOIN `v_dim_member`(取 `scd2_is_current=1`)获取 `name``nickname` 字段)和 `phone`/`phoneFull``mobile` 字段),禁止使用 `settlement_head.member_phone`DQ-6
3. THE CUST_1_API SHALL 通过 `member_id` LEFT JOIN `v_dim_member_card_account``tenant_member_id=member_id`,取 `scd2_is_current=1`)获取 `memberLevel`,禁止使用 `member_card_type_name`DQ-7
4. THE CUST_1_API SHALL 返回 Banner 概览字段:`balance`(客户余额,元)、`consumption60d`(近 60 天消费金额,元)、`idealInterval`(理想到店间隔,天)、`daysSinceVisit`(距上次到店天数)
5. THE CUST_1_API SHALL 使用 `items_sum` 口径计算 `balance``consumption60d`DWD-DOC 强制规则 1禁止使用 `consume_money`
6. THE CUST_1_API SHALL 从 `v_dwd_assistant_service_log` 查询客户最后到店日期(`MAX(create_time)`,过滤 `is_delete=0`),计算 `daysSinceVisit`(当前日期与最后到店日期的天数差)
7. IF 某个 Banner 字段的数据源查询失败或无数据THEN THE CUST_1_API SHALL 对该字段返回 `null`,不影响其他字段和整体响应
### 需求 2实现 CUST-1 AI 洞察模块T2-1 AI 部分)
**用户故事:** 作为管理者或助教,我希望在客户详情页看到 AI 生成的客户分析洞察和策略建议,以便制定针对性的服务策略。
#### 验收标准
1. THE CUST_1_API SHALL 返回 `aiInsight` 字段,包含 `summary`AI 分析摘要文本)和 `strategies`(策略建议列表,每项含 `color``text`
2. THE CUST_1_API SHALL 从 `biz.ai_cache` 查询 `cache_type='app4_analysis'``target_id=customerId` 的缓存记录,解析 `cache_value` JSON 生成 `aiInsight` 数据
3. IF `biz.ai_cache` 中无对应缓存记录THEN THE CUST_1_API SHALL 返回 `aiInsight: { summary: "", strategies: [] }`
### 需求 3实现 CUST-1 维客线索与备注T2-1 线索与备注部分)
**用户故事:** 作为管理者或助教,我希望在客户详情页看到维客线索和历史备注,以便了解客户的留存风险和过往沟通记录。
#### 验收标准
1. THE CUST_1_API SHALL 返回 `retentionClues` 字段(维客线索列表),从 `public.member_retention_clue` 查询,按 `created_at` 倒序排列,格式与 TASK-2 一致
2. THE CUST_1_API SHALL 返回 `notes` 字段(备注列表),从 `biz.notes` 查询 `target_type='member'``target_id=customerId` 的记录,每项含 `id``tagLabel``createdAt``content`,按 `created_at` 倒序排列,最多返回 20 条
### 需求 4实现 CUST-1 消费记录嵌套结构T2-1 消费记录部分)
**用户故事:** 作为管理者或助教,我希望在客户详情页看到消费记录的完整拆分(台费、酒水、助教服务明细),以便分析客户的消费构成和偏好。
#### 验收标准
1. THE CUST_1_API SHALL 返回 `consumptionRecords` 字段(消费记录列表),每条记录包含嵌套结构:`id``type``table`/`shop`/`recharge`)、`date``tableName``startTime``endTime``duration``tableFee``tableOrigPrice``coaches`(助教服务子数组)、`foodAmount``foodOrigPrice``totalAmount``totalOrigPrice``payMethod``rechargeAmount`
2. THE CUST_1_API SHALL 为每条消费记录的 `coaches` 子数组返回助教服务明细,每项含 `name``level``levelColor``courseType``"基础课"``"激励课"`)、`hours`(服务时长)、`perfHours`(折算工时,可选)、`fee`(服务费用)
3. THE CUST_1_API SHALL 对 `coaches` 子数组中的 `fee` 字段使用 `assistant_pd_money`(基础课)和 `assistant_cx_money`激励课拆分DWD-DOC 强制规则 2禁止使用 `service_fee`
4. THE CUST_1_API SHALL 对 `totalAmount` 使用 `items_sum` 口径DWD-DOC 强制规则 1`tableFee` 使用 `table_charge_money`,对 `foodAmount` 使用 `goods_money`
5. THE CUST_1_API SHALL 仅查询正向交易记录(`settle_type IN (1, 3)`
6. THE CUST_1_API SHALL 使用 `v_dwd_assistant_service_log``is_delete=0` 排除废单记录
### 需求 5实现 CUST-1 coachTasks 模块T2-2
**用户故事:** 作为管理者或助教,我希望在客户详情页看到所有关联助教的任务信息和近期服务统计,以便了解该客户被哪些助教跟进、服务频率和质量如何。
#### 验收标准
1. THE CUST_1_API SHALL 返回 `coachTasks` 字段(关联助教任务列表),从 `biz.coach_tasks` 查询该客户(`member_id=customerId`)的所有任务记录
2. THE CUST_1_API SHALL 为每位关联助教返回以下字段:`name`(助教姓名)、`level`(助教等级:`star`/`senior`/`middle`/`junior`)、`levelColor`(等级对应颜色)、`taskType`(任务类型,如 `"回访"``"召回"`)、`taskColor`(任务类型对应颜色)、`bgClass`(背景样式类)、`status`(任务状态)、`lastService`(最后服务日期)、`metrics`(指标列表)
3. THE CUST_1_API SHALL 为每位助教的 `metrics` 返回近 60 天统计:服务次数、总时长、次均时长,从 `v_dwd_assistant_service_log` 按助教+客户聚合近 60 天数据(过滤 `is_delete=0`
4. THE CUST_1_API SHALL 从 `v_dws_assistant_salary_calc` 获取助教等级(`assistant_level_name`),从 `v_dim_member` 获取助教姓名DQ-6
### 需求 6实现 CUST-1 favoriteCoaches 模块T2-3
**用户故事:** 作为管理者或助教,我希望在客户详情页看到该客户最亲密的助教排名和详细服务统计,以便了解客户的助教偏好和关系深度。
#### 验收标准
1. THE CUST_1_API SHALL 返回 `favoriteCoaches` 字段(最亲密助教列表),从 `v_dws_member_assistant_relation_index` 获取关系指数,按关系指数降序排列
2. THE CUST_1_API SHALL 为每位亲密助教返回:`emoji`(亲密度 emoji`name`(助教姓名)、`relationIndex`(关系指数,如 `"0.92"`)、`indexColor`(关系指数对应颜色)、`bgClass`(背景样式类)、`stats`(统计指标列表)
3. THE CUST_1_API SHALL 为 `stats` 返回 4 项指标:基础课时(对应 `assistant_pd_money`)、激励课时(对应 `assistant_cx_money`)、上课次数、充值金额,使用 DWD-DOC 强制规则 2 拆分助教费用
4. THE CUST_1_API SHALL 根据关系指数(`rs_display`0-10 范围)阈值映射 `emoji`P6 AC3 四级映射):`> 8.5``"💖"``> 7``"🧡"``> 5``"💛"``≤ 5``"💙"`,复用后端 `compute_heart_icon()` 函数
### 需求 7实现 CUST-2 客户服务记录T2-4
**用户故事:** 作为管理者或助教,我希望按月查看客户的服务记录(替代前端全量加载本地过滤),以便高效浏览大量历史数据并查看月度统计汇总。
#### 验收标准
1. THE CUST_2_API SHALL 接受 `year``month``table`(可选,台桌筛选)查询参数,返回指定月份的客户服务记录
2. THE CUST_2_API SHALL 返回客户基础信息:`customerName`(客户姓名)、`customerPhone`(脱敏手机号)、`customerPhoneFull`(完整手机号)、`relationIndex`(关系指数)、`tables`(可选台桌列表)
3. THE CUST_2_API SHALL 通过 `member_id` LEFT JOIN `v_dim_member`(取 `scd2_is_current=1`)获取 `customerName``customerPhone`/`customerPhoneFull`DQ-6
4. THE CUST_2_API SHALL 返回 `totalServiceCount`(累计服务总次数,跨所有月份)
5. THE CUST_2_API SHALL 为每条服务记录返回 `recordType``course``recharge`)和 `isEstimate`是否预估数据boolean字段
6. THE CUST_2_API SHALL 返回月度统计汇总:`monthCount`(当月服务次数)和 `monthHours`(当月总工时)
7. THE CUST_2_API SHALL 使用 `items_sum` 口径计算服务记录中的 `income` 字段DWD-DOC 强制规则 1
8. THE CUST_2_API SHALL 使用 `is_delete=0` 排除废单记录
9. THE CUST_2_API SHALL 按 `create_time` 倒序排列服务记录,返回 `hasMore` 标记指示是否有更多数据
### 需求 8实现 COACH-1 助教详情基础信息与绩效T2-5 基础部分)
**用户故事:** 作为管理者,我希望在助教详情页看到助教的基本信息和 6 项绩效指标,以便快速评估助教的工作表现和产出。
#### 验收标准
1. THE COACH_1_API SHALL 返回助教基础信息字段:`id``name``avatar``level`(初级/中级/高级/星级)、`skills`(技能标签列表)、`workYears`(工龄,年)、`customerCount`(客户数)、`hireDate`(入职日期)
2. THE COACH_1_API SHALL 从 `v_dim_assistant` 获取助教基本信息,从 `v_dws_assistant_salary_calc` 获取等级(`assistant_level_name`
3. THE COACH_1_API SHALL 返回 `performance` 字段,包含 6 项绩效指标:`monthlyHours`(本月定档工时)、`monthlySalary`(本月工资预估)、`customerBalance`(客源储值余额合计)、`tasksCompleted`(本月任务完成数)、`perfCurrent`(当前绩效值)、`perfTarget`(绩效目标值)
4. THE COACH_1_API SHALL 从 `v_dws_assistant_salary_calc` 查询 `monthlyHours``effective_hours`)和 `monthlySalary``gross_salary`),使用 `items_sum` 口径DWD-DOC 强制规则 1
5. THE COACH_1_API SHALL 从 `biz.coach_tasks` 查询 `tasksCompleted`(当月 `status='completed'` 的任务数)
### 需求 9实现 COACH-1 收入明细与档位节点T2-5 收入部分)
**用户故事:** 作为管理者,我希望在助教详情页看到本月和上月的收入明细拆分(基础课时费、激励课时费、充值提成、酒水提成)以及档位进度节点,以便了解助教的收入构成和升档进度。
#### 验收标准
1. THE COACH_1_API SHALL 返回 `income` 字段,包含 `thisMonth``lastMonth` 两个子数组,各含 4 项收入分类:基础课时费(`assistant_pd_money`)、激励课时费(`assistant_cx_money`)、充值提成、酒水提成
2. THE COACH_1_API SHALL 使用 `assistant_pd_money`(基础课/陪打)和 `assistant_cx_money`(激励课/超休拆分助教费用DWD-DOC 强制规则 2禁止使用 `service_fee`
3. THE COACH_1_API SHALL 从 `v_dws_assistant_salary_calc` 分别查询当月和上月的收入数据(`salary_month` 字段为 date 类型,存储为 `YYYY-MM-01`
4. THE COACH_1_API SHALL 返回 `tierNodes` 字段(档位节点数组,如 `[0, 100, 130, 160, 190, 220]`),供前端绩效进度条组件使用
### 需求 10实现 COACH-1 TOP 客户与近期服务记录T2-5 客户部分)
**用户故事:** 作为管理者,我希望在助教详情页看到该助教的 TOP 客户排名(含关系指数、余额、消费)和近期服务明细(含折算工时),以便评估助教的客户关系质量和服务产出。
#### 验收标准
1. THE COACH_1_API SHALL 返回 `topCustomers` 字段TOP 客户列表,最多 20 条),每项含扩展字段:`id``name``initial`(姓氏首字)、`avatarGradient`(头像渐变色)、`heartEmoji`(关系 emojiP6 AC3 四级映射:💖/🧡/💛/💙)、`relationScore`关系指数0-10`scoreColor`(分数颜色)、`serviceCount`(服务次数)、`balance`(余额,格式化)、`consume`(消费总额,格式化)
2. THE COACH_1_API SHALL 对 `topCustomers[].consume` 使用 `items_sum` 口径DWD-DOC 强制规则 1
3. THE COACH_1_API SHALL 对 `topCustomers[].balance` 通过 `member_id` LEFT JOIN `v_dim_member_card_account`(取 `scd2_is_current=1`获取DQ-7
4. THE COACH_1_API SHALL 通过 `member_id` LEFT JOIN `v_dim_member`(取 `scd2_is_current=1`获取客户姓名DQ-6
5. THE COACH_1_API SHALL 返回 `serviceRecords` 字段(近期服务记录列表),每项含 `customerId``customerName``initial``avatarGradient``type`(课程类型)、`typeClass`(样式类)、`table`(台桌名)、`duration`(时长)、`income`(收入)、`date`(日期时间)、`perfHours`(折算工时,可选)
6. THE COACH_1_API SHALL 对 `serviceRecords[].income` 使用 `ledger_amount`(对应 `items_sum` 口径DWD-DOC 强制规则 1
7. THE COACH_1_API SHALL 使用 `is_delete=0` 排除废单记录
### 需求 11实现 COACH-1 任务分组与备注T2-5 任务部分)
**用户故事:** 作为管理者,我希望在助教详情页看到该助教的任务按状态分组展示(进行中/已过期/已放弃),每个任务含关联备注和放弃原因,以便全面了解助教的任务执行情况。
#### 验收标准
1. THE COACH_1_API SHALL 返回任务分为三组:`visibleTasks`active 状态任务)、`hiddenTasks`inactive 状态任务)、`abandonedTasks`abandoned 状态任务),从 `biz.coach_tasks` 查询该助教的所有任务
2. THE COACH_1_API SHALL 为 `visibleTasks``hiddenTasks` 每项返回:`typeLabel`(任务类型标签)、`typeClass`(样式类)、`customerName`(客户姓名)、`customerId`(客户 ID用于跳转`noteCount`(备注数量)、`pinned`(是否置顶)、`notes`(备注列表,可选,每项含 `pinned``text``date`
3. THE COACH_1_API SHALL 为 `abandonedTasks` 每项返回:`customerName`(客户姓名)、`reason`(放弃原因,来自 `coach_tasks.abandon_reason`
4. THE COACH_1_API SHALL 从 `biz.notes` 查询每个任务关联的备注(`task_id` 关联),按 `created_at` 倒序排列
5. THE COACH_1_API SHALL 返回 `notes` 字段(助教相关备注列表),每项含 `id``content``timestamp``score``customerName``tagLabel``createdAt`,按 `created_at` 倒序排列,最多返回 20 条
### 需求 12实现 COACH-1 historyMonths 模块T2-6
**用户故事:** 作为管理者,我希望在助教详情页看到该助教最近 5 个以上月份的历史统计(客户数、工时、工资、回访/召回完成数),以便追踪助教的长期表现趋势。
#### 验收标准
1. THE COACH_1_API SHALL 返回 `historyMonths` 字段(历史月份统计列表),包含最近 5 个以上月份的汇总数据,第一条为本月
2. THE COACH_1_API SHALL 为每个月份返回:`month`(月份标签,如 `"本月"``"上月"``"4月"`)、`estimated`是否为预估数据boolean`customers`(客户数,格式化,如 `"22人"`)、`hours`(工时,格式化,如 `"87.5h"`)、`salary`(工资,格式化,如 `"¥6,950"`)、`callbackDone`(回访任务完成数)、`recallDone`(召回任务完成数)
3. THE COACH_1_API SHALL 从 `v_dws_assistant_salary_calc` 查询各月的工时(`effective_hours`)和工资(`gross_salary`)数据
4. THE COACH_1_API SHALL 从 `biz.coach_tasks` 查询各月的回访完成数(`task_type='follow_up_visit' AND status='completed'`)和召回完成数(`task_type IN ('high_priority_recall', 'priority_recall') AND status='completed'`
5. THE COACH_1_API SHALL 将本月标记为 `estimated: true`(预估数据),历史月份标记为 `estimated: false`
6. THE COACH_1_API SHALL 从 `v_dwd_assistant_service_log` 按月统计不重复的 `tenant_member_id` 数量作为客户数(过滤 `is_delete=0`
### 需求 13全局约束与数据隔离
**用户故事:** 作为系统管理员,我希望所有客户和助教接口都遵循统一的权限控制、数据隔离和数据质量规则,以确保数据安全和口径一致。
#### 验收标准
#### 13.1 权限与认证
1. THE Backend SHALL 对所有 RNS1.2 接口CUST_1_API、CUST_2_API、COACH_1_API执行 `require_approved()` 权限检查,确保用户状态为 `approved`
2. THE Backend SHALL 对所有 RNS1.2 接口通过 `SET LOCAL app.current_site_id` 实现门店级数据隔离FDW 查询通过 `_fdw_context` 上下文管理器统一执行)
#### 13.2 DWD-DOC 强制规则
3. THE Backend SHALL 对所有涉及金额的字段统一使用 `items_sum` 口径DWD-DOC 强制规则 1禁止使用 `consume_money`
4. THE Backend SHALL 对所有涉及助教费用的字段使用 `assistant_pd_money`(陪打/基础课)+ `assistant_cx_money`(超休/激励课拆分DWD-DOC 强制规则 2禁止使用 `service_fee`
5. THE Backend SHALL 对所有涉及会员信息的查询通过 `member_id` LEFT JOIN `v_dim_member`(取 `scd2_is_current=1`获取姓名和手机号DWD-DOC 强制规则 DQ-6禁止直接使用 `settlement_head.member_phone``member_name`
6. THE Backend SHALL 对所有涉及会员卡信息的查询通过 `member_id` LEFT JOIN `v_dim_member_card_account``tenant_member_id=member_id`,取 `scd2_is_current=1`获取DWD-DOC 强制规则 DQ-7禁止使用 `member_card_type_name`
7. THE Backend SHALL 使用 `v_dwd_assistant_service_log``is_delete=0` 排除废单记录,禁止使用已废弃的 `dwd_assistant_trash_event`
#### 13.3 优雅降级
8. IF 某个扩展模块(`aiInsight`/`coachTasks`/`favoriteCoaches`/`historyMonths`的数据源查询失败THEN THE Backend SHALL 对该模块返回空默认值(空数组或空对象),不影响其他模块和整体响应
9. THE Backend SHALL 对所有 FDW 查询异常进行捕获和日志记录,返回降级响应而非 HTTP 500
#### 13.4 列名映射
10. THE Backend SHALL 在 SQL 中使用 AS 别名将 RLS 视图原始列名转换为代码语义名(如 `site_assistant_id AS assistant_id``tenant_member_id AS member_id``create_time AS settle_time``ledger_amount AS income``income_seconds / 3600.0 AS service_hours`),统一在 `fdw_queries.py` 中封装
### 需求 14正确性属性Property-Based Testing
**用户故事:** 作为开发者,我希望通过属性测试验证接口的数据一致性和业务规则正确性,以便在开发阶段发现口径错误和数据异常。
#### 验收标准
#### 14.1 金额口径不变量
1. FOR ALL 消费记录THE CUST_1_API 返回的 `totalAmount` SHALL 等于 `tableFee + foodAmount + SUM(coaches[].fee)`(在浮点精度范围内),验证 `items_sum` 口径拆分的一致性
2. FOR ALL 助教费用拆分,`coaches[].fee` 中基础课记录 SHALL 对应 `assistant_pd_money`,激励课记录 SHALL 对应 `assistant_cx_money`,两者之和 SHALL 等于该结算单的助教费用总额
#### 14.2 数据隔离不变量
3. FOR ALL CUST_1_API 响应中的 `coachTasks`,每条任务的 `member_id` SHALL 等于请求路径中的 `customerId`,验证客户-任务关联的正确性
4. FOR ALL COACH_1_API 响应中的 `serviceRecords`,每条记录的 `assistant_id` SHALL 等于请求路径中的 `coachId`,验证助教数据隔离
#### 14.3 排序与分组不变量
5. FOR ALL CUST_1_API 响应中的 `favoriteCoaches`,列表 SHALL 按 `relationIndex` 降序排列(前一项的 `relationIndex` ≥ 后一项的 `relationIndex`
6. FOR ALL COACH_1_API 响应中的 `historyMonths`,列表 SHALL 按月份降序排列(最近月份在前),且第一条的 `estimated` SHALL 为 `true`
#### 14.4 幂等性
7. FOR ALL 相同参数的 CUST_2_API 请求(相同 `customerId``year``month`),在数据未变更的情况下,两次请求 SHALL 返回相同的 `monthCount``monthHours`
#### 14.5 废单排除一致性
8. FOR ALL 服务记录查询,返回的记录集合中 SHALL 不包含 `is_delete != 0` 的记录,验证废单排除规则在所有接口中一致执行