24 KiB
需求文档 — RNS1.2:客户与助教接口
简介
RNS1.2 是 NS1 小程序后端 API 补全项目的第三个子 spec,负责实现客户详情(CUST-1)、客户服务记录(CUST-2)、助教详情(COACH-1)3 个接口。这三个接口覆盖客户视角和助教视角的详情查看需求,是走查报告中 Gap 最集中的区域(GAP-2330、GAP-3235、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-2330、GAP-3235、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 基础部分)
用户故事: 作为管理者或助教,我希望在客户详情页顶部看到客户的基本信息和关键指标(余额、近期消费、到店间隔、距上次到店天数),以便快速评估客户价值和活跃度。
验收标准
- THE CUST_1_API SHALL 返回客户基础信息字段:
id(客户唯一 ID)、name(客户姓名)、phone(脱敏手机号,如"139****5678")、phoneFull(完整手机号)、avatar(头像 URL)、memberLevel(会员等级)、relationIndex(关系指数)、tags(客户标签列表) - THE CUST_1_API SHALL 通过
member_idLEFT JOINv_dim_member(取scd2_is_current=1)获取name(nickname字段)和phone/phoneFull(mobile字段),禁止使用settlement_head.member_phone(DQ-6) - THE CUST_1_API SHALL 通过
member_idLEFT JOINv_dim_member_card_account(tenant_member_id=member_id,取scd2_is_current=1)获取memberLevel,禁止使用member_card_type_name(DQ-7) - THE CUST_1_API SHALL 返回 Banner 概览字段:
balance(客户余额,元)、consumption60d(近 60 天消费金额,元)、idealInterval(理想到店间隔,天)、daysSinceVisit(距上次到店天数) - THE CUST_1_API SHALL 使用
items_sum口径计算balance和consumption60d(DWD-DOC 强制规则 1),禁止使用consume_money - THE CUST_1_API SHALL 从
v_dwd_assistant_service_log查询客户最后到店日期(MAX(create_time),过滤is_delete=0),计算daysSinceVisit(当前日期与最后到店日期的天数差) - IF 某个 Banner 字段的数据源查询失败或无数据,THEN THE CUST_1_API SHALL 对该字段返回
null,不影响其他字段和整体响应
需求 2:实现 CUST-1 AI 洞察模块(T2-1 AI 部分)
用户故事: 作为管理者或助教,我希望在客户详情页看到 AI 生成的客户分析洞察和策略建议,以便制定针对性的服务策略。
验收标准
- THE CUST_1_API SHALL 返回
aiInsight字段,包含summary(AI 分析摘要文本)和strategies(策略建议列表,每项含color和text) - THE CUST_1_API SHALL 从
biz.ai_cache查询cache_type='app4_analysis'且target_id=customerId的缓存记录,解析cache_valueJSON 生成aiInsight数据 - IF
biz.ai_cache中无对应缓存记录,THEN THE CUST_1_API SHALL 返回aiInsight: { summary: "", strategies: [] }
需求 3:实现 CUST-1 维客线索与备注(T2-1 线索与备注部分)
用户故事: 作为管理者或助教,我希望在客户详情页看到维客线索和历史备注,以便了解客户的留存风险和过往沟通记录。
验收标准
- THE CUST_1_API SHALL 返回
retentionClues字段(维客线索列表),从public.member_retention_clue查询,按created_at倒序排列,格式与 TASK-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 消费记录部分)
用户故事: 作为管理者或助教,我希望在客户详情页看到消费记录的完整拆分(台费、酒水、助教服务明细),以便分析客户的消费构成和偏好。
验收标准
- 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 - THE CUST_1_API SHALL 为每条消费记录的
coaches子数组返回助教服务明细,每项含name、level、levelColor、courseType("基础课"或"激励课")、hours(服务时长)、perfHours(折算工时,可选)、fee(服务费用) - THE CUST_1_API SHALL 对
coaches子数组中的fee字段使用assistant_pd_money(基础课)和assistant_cx_money(激励课)拆分(DWD-DOC 强制规则 2),禁止使用service_fee - THE CUST_1_API SHALL 对
totalAmount使用items_sum口径(DWD-DOC 强制规则 1),对tableFee使用table_charge_money,对foodAmount使用goods_money - THE CUST_1_API SHALL 仅查询正向交易记录(
settle_type IN (1, 3)) - THE CUST_1_API SHALL 使用
v_dwd_assistant_service_log的is_delete=0排除废单记录
需求 5:实现 CUST-1 coachTasks 模块(T2-2)
用户故事: 作为管理者或助教,我希望在客户详情页看到所有关联助教的任务信息和近期服务统计,以便了解该客户被哪些助教跟进、服务频率和质量如何。
验收标准
- THE CUST_1_API SHALL 返回
coachTasks字段(关联助教任务列表),从biz.coach_tasks查询该客户(member_id=customerId)的所有任务记录 - THE CUST_1_API SHALL 为每位关联助教返回以下字段:
name(助教姓名)、level(助教等级:star/senior/middle/junior)、levelColor(等级对应颜色)、taskType(任务类型,如"回访"、"召回")、taskColor(任务类型对应颜色)、bgClass(背景样式类)、status(任务状态)、lastService(最后服务日期)、metrics(指标列表) - THE CUST_1_API SHALL 为每位助教的
metrics返回近 60 天统计:服务次数、总时长、次均时长,从v_dwd_assistant_service_log按助教+客户聚合近 60 天数据(过滤is_delete=0) - THE CUST_1_API SHALL 从
v_dws_assistant_salary_calc获取助教等级(assistant_level_name),从v_dim_member获取助教姓名(DQ-6)
需求 6:实现 CUST-1 favoriteCoaches 模块(T2-3)
用户故事: 作为管理者或助教,我希望在客户详情页看到该客户最亲密的助教排名和详细服务统计,以便了解客户的助教偏好和关系深度。
验收标准
- THE CUST_1_API SHALL 返回
favoriteCoaches字段(最亲密助教列表),从v_dws_member_assistant_relation_index获取关系指数,按关系指数降序排列 - THE CUST_1_API SHALL 为每位亲密助教返回:
emoji(亲密度 emoji)、name(助教姓名)、relationIndex(关系指数,如"0.92")、indexColor(关系指数对应颜色)、bgClass(背景样式类)、stats(统计指标列表) - THE CUST_1_API SHALL 为
stats返回 4 项指标:基础课时(对应assistant_pd_money)、激励课时(对应assistant_cx_money)、上课次数、充值金额,使用 DWD-DOC 强制规则 2 拆分助教费用 - 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)
用户故事: 作为管理者或助教,我希望按月查看客户的服务记录(替代前端全量加载本地过滤),以便高效浏览大量历史数据并查看月度统计汇总。
验收标准
- THE CUST_2_API SHALL 接受
year、month、table(可选,台桌筛选)查询参数,返回指定月份的客户服务记录 - THE CUST_2_API SHALL 返回客户基础信息:
customerName(客户姓名)、customerPhone(脱敏手机号)、customerPhoneFull(完整手机号)、relationIndex(关系指数)、tables(可选台桌列表) - THE CUST_2_API SHALL 通过
member_idLEFT JOINv_dim_member(取scd2_is_current=1)获取customerName和customerPhone/customerPhoneFull(DQ-6) - THE CUST_2_API SHALL 返回
totalServiceCount(累计服务总次数,跨所有月份) - THE CUST_2_API SHALL 为每条服务记录返回
recordType(course或recharge)和isEstimate(是否预估数据,boolean)字段 - THE CUST_2_API SHALL 返回月度统计汇总:
monthCount(当月服务次数)和monthHours(当月总工时) - THE CUST_2_API SHALL 使用
items_sum口径计算服务记录中的income字段(DWD-DOC 强制规则 1) - THE CUST_2_API SHALL 使用
is_delete=0排除废单记录 - THE CUST_2_API SHALL 按
create_time倒序排列服务记录,返回hasMore标记指示是否有更多数据
需求 8:实现 COACH-1 助教详情基础信息与绩效(T2-5 基础部分)
用户故事: 作为管理者,我希望在助教详情页看到助教的基本信息和 6 项绩效指标,以便快速评估助教的工作表现和产出。
验收标准
- THE COACH_1_API SHALL 返回助教基础信息字段:
id、name、avatar、level(初级/中级/高级/星级)、skills(技能标签列表)、workYears(工龄,年)、customerCount(客户数)、hireDate(入职日期) - THE COACH_1_API SHALL 从
v_dim_assistant获取助教基本信息,从v_dws_assistant_salary_calc获取等级(assistant_level_name) - THE COACH_1_API SHALL 返回
performance字段,包含 6 项绩效指标:monthlyHours(本月定档工时)、monthlySalary(本月工资预估)、customerBalance(客源储值余额合计)、tasksCompleted(本月任务完成数)、perfCurrent(当前绩效值)、perfTarget(绩效目标值) - THE COACH_1_API SHALL 从
v_dws_assistant_salary_calc查询monthlyHours(effective_hours)和monthlySalary(gross_salary),使用items_sum口径(DWD-DOC 强制规则 1) - THE COACH_1_API SHALL 从
biz.coach_tasks查询tasksCompleted(当月status='completed'的任务数)
需求 9:实现 COACH-1 收入明细与档位节点(T2-5 收入部分)
用户故事: 作为管理者,我希望在助教详情页看到本月和上月的收入明细拆分(基础课时费、激励课时费、充值提成、酒水提成)以及档位进度节点,以便了解助教的收入构成和升档进度。
验收标准
- THE COACH_1_API SHALL 返回
income字段,包含thisMonth和lastMonth两个子数组,各含 4 项收入分类:基础课时费(assistant_pd_money)、激励课时费(assistant_cx_money)、充值提成、酒水提成 - THE COACH_1_API SHALL 使用
assistant_pd_money(基础课/陪打)和assistant_cx_money(激励课/超休)拆分助教费用(DWD-DOC 强制规则 2),禁止使用service_fee - THE COACH_1_API SHALL 从
v_dws_assistant_salary_calc分别查询当月和上月的收入数据(salary_month字段为 date 类型,存储为YYYY-MM-01) - THE COACH_1_API SHALL 返回
tierNodes字段(档位节点数组,如[0, 100, 130, 160, 190, 220]),供前端绩效进度条组件使用
需求 10:实现 COACH-1 TOP 客户与近期服务记录(T2-5 客户部分)
用户故事: 作为管理者,我希望在助教详情页看到该助教的 TOP 客户排名(含关系指数、余额、消费)和近期服务明细(含折算工时),以便评估助教的客户关系质量和服务产出。
验收标准
- THE COACH_1_API SHALL 返回
topCustomers字段(TOP 客户列表,最多 20 条),每项含扩展字段:id、name、initial(姓氏首字)、avatarGradient(头像渐变色)、heartEmoji(关系 emoji,P6 AC3 四级映射:💖/🧡/💛/💙)、relationScore(关系指数,0-10)、scoreColor(分数颜色)、serviceCount(服务次数)、balance(余额,格式化)、consume(消费总额,格式化) - THE COACH_1_API SHALL 对
topCustomers[].consume使用items_sum口径(DWD-DOC 强制规则 1) - THE COACH_1_API SHALL 对
topCustomers[].balance通过member_idLEFT JOINv_dim_member_card_account(取scd2_is_current=1)获取(DQ-7) - THE COACH_1_API SHALL 通过
member_idLEFT JOINv_dim_member(取scd2_is_current=1)获取客户姓名(DQ-6) - THE COACH_1_API SHALL 返回
serviceRecords字段(近期服务记录列表),每项含customerId、customerName、initial、avatarGradient、type(课程类型)、typeClass(样式类)、table(台桌名)、duration(时长)、income(收入)、date(日期时间)、perfHours(折算工时,可选) - THE COACH_1_API SHALL 对
serviceRecords[].income使用ledger_amount(对应items_sum口径,DWD-DOC 强制规则 1) - THE COACH_1_API SHALL 使用
is_delete=0排除废单记录
需求 11:实现 COACH-1 任务分组与备注(T2-5 任务部分)
用户故事: 作为管理者,我希望在助教详情页看到该助教的任务按状态分组展示(进行中/已过期/已放弃),每个任务含关联备注和放弃原因,以便全面了解助教的任务执行情况。
验收标准
- THE COACH_1_API SHALL 返回任务分为三组:
visibleTasks(active 状态任务)、hiddenTasks(inactive 状态任务)、abandonedTasks(abandoned 状态任务),从biz.coach_tasks查询该助教的所有任务 - THE COACH_1_API SHALL 为
visibleTasks和hiddenTasks每项返回:typeLabel(任务类型标签)、typeClass(样式类)、customerName(客户姓名)、customerId(客户 ID,用于跳转)、noteCount(备注数量)、pinned(是否置顶)、notes(备注列表,可选,每项含pinned、text、date) - THE COACH_1_API SHALL 为
abandonedTasks每项返回:customerName(客户姓名)、reason(放弃原因,来自coach_tasks.abandon_reason) - THE COACH_1_API SHALL 从
biz.notes查询每个任务关联的备注(task_id关联),按created_at倒序排列 - THE COACH_1_API SHALL 返回
notes字段(助教相关备注列表),每项含id、content、timestamp、score、customerName、tagLabel、createdAt,按created_at倒序排列,最多返回 20 条
需求 12:实现 COACH-1 historyMonths 模块(T2-6)
用户故事: 作为管理者,我希望在助教详情页看到该助教最近 5 个以上月份的历史统计(客户数、工时、工资、回访/召回完成数),以便追踪助教的长期表现趋势。
验收标准
- THE COACH_1_API SHALL 返回
historyMonths字段(历史月份统计列表),包含最近 5 个以上月份的汇总数据,第一条为本月 - THE COACH_1_API SHALL 为每个月份返回:
month(月份标签,如"本月"、"上月"、"4月")、estimated(是否为预估数据,boolean)、customers(客户数,格式化,如"22人")、hours(工时,格式化,如"87.5h")、salary(工资,格式化,如"¥6,950")、callbackDone(回访任务完成数)、recallDone(召回任务完成数) - THE COACH_1_API SHALL 从
v_dws_assistant_salary_calc查询各月的工时(effective_hours)和工资(gross_salary)数据 - 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') - THE COACH_1_API SHALL 将本月标记为
estimated: true(预估数据),历史月份标记为estimated: false - THE COACH_1_API SHALL 从
v_dwd_assistant_service_log按月统计不重复的tenant_member_id数量作为客户数(过滤is_delete=0)
需求 13:全局约束与数据隔离
用户故事: 作为系统管理员,我希望所有客户和助教接口都遵循统一的权限控制、数据隔离和数据质量规则,以确保数据安全和口径一致。
验收标准
13.1 权限与认证
- THE Backend SHALL 对所有 RNS1.2 接口(CUST_1_API、CUST_2_API、COACH_1_API)执行
require_approved()权限检查,确保用户状态为approved - THE Backend SHALL 对所有 RNS1.2 接口通过
SET LOCAL app.current_site_id实现门店级数据隔离(FDW 查询通过_fdw_context上下文管理器统一执行)
13.2 DWD-DOC 强制规则
- THE Backend SHALL 对所有涉及金额的字段统一使用
items_sum口径(DWD-DOC 强制规则 1),禁止使用consume_money - THE Backend SHALL 对所有涉及助教费用的字段使用
assistant_pd_money(陪打/基础课)+assistant_cx_money(超休/激励课)拆分(DWD-DOC 强制规则 2),禁止使用service_fee - THE Backend SHALL 对所有涉及会员信息的查询通过
member_idLEFT JOINv_dim_member(取scd2_is_current=1)获取姓名和手机号(DWD-DOC 强制规则 DQ-6),禁止直接使用settlement_head.member_phone或member_name - THE Backend SHALL 对所有涉及会员卡信息的查询通过
member_idLEFT JOINv_dim_member_card_account(tenant_member_id=member_id,取scd2_is_current=1)获取(DWD-DOC 强制规则 DQ-7),禁止使用member_card_type_name - THE Backend SHALL 使用
v_dwd_assistant_service_log的is_delete=0排除废单记录,禁止使用已废弃的dwd_assistant_trash_event表
13.3 优雅降级
- IF 某个扩展模块(
aiInsight/coachTasks/favoriteCoaches/historyMonths)的数据源查询失败,THEN THE Backend SHALL 对该模块返回空默认值(空数组或空对象),不影响其他模块和整体响应 - THE Backend SHALL 对所有 FDW 查询异常进行捕获和日志记录,返回降级响应而非 HTTP 500
13.4 列名映射
- 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 金额口径不变量
- FOR ALL 消费记录,THE CUST_1_API 返回的
totalAmountSHALL 等于tableFee + foodAmount + SUM(coaches[].fee)(在浮点精度范围内),验证items_sum口径拆分的一致性 - FOR ALL 助教费用拆分,
coaches[].fee中基础课记录 SHALL 对应assistant_pd_money,激励课记录 SHALL 对应assistant_cx_money,两者之和 SHALL 等于该结算单的助教费用总额
14.2 数据隔离不变量
- FOR ALL CUST_1_API 响应中的
coachTasks,每条任务的member_idSHALL 等于请求路径中的customerId,验证客户-任务关联的正确性 - FOR ALL COACH_1_API 响应中的
serviceRecords,每条记录的assistant_idSHALL 等于请求路径中的coachId,验证助教数据隔离
14.3 排序与分组不变量
- FOR ALL CUST_1_API 响应中的
favoriteCoaches,列表 SHALL 按relationIndex降序排列(前一项的relationIndex≥ 后一项的relationIndex) - FOR ALL COACH_1_API 响应中的
historyMonths,列表 SHALL 按月份降序排列(最近月份在前),且第一条的estimatedSHALL 为true
14.4 幂等性
- FOR ALL 相同参数的 CUST_2_API 请求(相同
customerId、year、month),在数据未变更的情况下,两次请求 SHALL 返回相同的monthCount和monthHours值
14.5 废单排除一致性
- FOR ALL 服务记录查询,返回的记录集合中 SHALL 不包含
is_delete != 0的记录,验证废单排除规则在所有接口中一致执行