24 KiB
24 KiB
需求文档 — RNS1.0:基础设施与契约重写
简介
RNS1.0 是 NS1 小程序后端 API 补全项目的第一个子 spec,负责建立全局基础设施(响应包装、camelCase 转换)、修正路由路径、适配前端解包逻辑、完全重写 API 契约响应定义、以及修复前端跨页面参数传递问题。本 spec 阻塞所有后续子 spec(RNS1.1-1.4),必须最先完成。
来源文档
docs/prd/Neo_Specs/RNS1-split-plan.md— 拆分计划主文档docs/prd/Neo_Specs/NS1-xcx-backend-api.md— NS1 原始 spec(含八½前置审查决策 R1-R8)docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md— 助教视角走查报告(51 Gap)docs/prd/Neo_Specs/miniprogram-storyboard-walkthrough-gaps.md— 管理层视角走查报告(31 Gap)
术语表
- Response_Wrapper:全局响应包装中间件,将 FastAPI 路由返回值统一封装为
{ code: 0, data: ... }格式 - Exception_Handler:全局异常处理器,将 HTTPException 和未捕获异常统一封装为
{ code: <status_code>, message: <detail> }格式 - CamelCase_Converter:Pydantic schema 的
alias_generator=to_camel配置,使 JSON 响应字段名从 snake_case 转为 camelCase - API_Contract:
docs/miniprogram-dev/API-contract.md,定义前后端接口的请求/响应格式基准文档 - Frontend_Unpacker:前端
services/api.ts中request()工具函数的.data解包逻辑,从全局包装中提取业务数据 - Backend:FastAPI 后端应用,位于
apps/backend/ - Miniprogram:微信小程序前端应用,位于
apps/miniprogram/ - FDW:PostgreSQL Foreign Data Wrapper,用于从业务库
zqyy_app访问 ETL 库etl_feiqiu的数据 - DateGroup:按日期分组的数据结构,包含日期标签、当日汇总、记录列表
- DWD-DOC:
docs/reports/DWD-DOC/标杆文档,金额口径和字段语义的权威参考 - items_sum:DWD-DOC 强制使用的消费金额口径,=
table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money - 环比:月环比,当期值与上一个相同时间周期的对比百分比
需求
需求 1:全局响应包装中间件(T0-1)
用户故事: 作为后端开发者,我希望所有 API 响应自动包装为统一格式,以便前端可以用一致的方式解析成功和错误响应。
验收标准
- THE Response_Wrapper SHALL 将所有成功响应(HTTP 2xx)封装为
{ "code": 0, "data": <原始响应体> }格式 - THE Exception_Handler SHALL 将 HTTPException 封装为
{ "code": <HTTP状态码>, "message": <错误详情> }格式 - THE Exception_Handler SHALL 将未捕获的服务端异常封装为
{ "code": 500, "message": "Internal Server Error" }格式,同时将完整异常堆栈写入服务端日志 - WHEN 已有接口(Auth、Tasks、Notes、AI Chat 共 16 个端点)返回响应时,THE Response_Wrapper SHALL 对这些接口同样生效,保持向后兼容
- WHEN 响应内容类型为
text/event-stream(SSE 流式端点)时,THE Response_Wrapper SHALL 跳过包装,直接透传原始响应 - WHEN 响应内容类型为非 JSON 格式(如文件下载)时,THE Response_Wrapper SHALL 跳过包装,直接透传原始响应
需求 2:Pydantic Schema 统一 camelCase 输出(T0-2)
用户故事: 作为前端开发者,我希望后端 API 响应的 JSON 字段名统一为 camelCase 格式,以便前端无需手动转换 snake_case 字段。
验收标准
- THE CamelCase_Converter SHALL 为所有 Pydantic 响应 schema 配置
alias_generator=to_camel和populate_by_name=True - WHEN Backend 返回 JSON 响应时,THE CamelCase_Converter SHALL 将所有字段名从 snake_case 转换为 camelCase(例如
user_id→userId,store_name→storeName) - THE CamelCase_Converter SHALL 同时应用于所有现有 schema(Auth、Tasks、Notes、AI Chat 模块)和所有新增 schema
- WHEN Backend 接收请求体时,THE CamelCase_Converter SHALL 同时接受 camelCase 和 snake_case 格式的字段名(通过
populate_by_name=True实现)
需求 3:后端路由路径修正(T0-3)
用户故事: 作为前端开发者,我希望后端任务恢复端点的路径与 API 契约和前端调用一致,以便联调时不会因路径不匹配而失败。
验收标准
- THE Backend SHALL 将
POST /api/xcx/tasks/{taskId}/cancel-abandon端点的路径修改为POST /api/xcx/tasks/{taskId}/restore - WHEN 前端调用
POST /api/xcx/tasks/{taskId}/restore时,THE Backend SHALL 执行与原/cancel-abandon端点相同的业务逻辑(将任务状态从abandoned恢复为pending) - THE Backend SHALL 移除原
/cancel-abandon路径,不保留旧路径的兼容映射
需求 4:前端请求工具函数适配全局包装(T0-4)
用户故事: 作为前端开发者,我希望 request() 工具函数自动从全局包装中提取业务数据,以便各页面调用 API 后无需手动解包。
验收标准
- THE Frontend_Unpacker SHALL 在
services/api.ts的request()函数中,对成功响应自动提取.data字段并返回给调用方 - WHEN 响应的
code字段不为 0 时,THE Frontend_Unpacker SHALL 抛出包含code和message的错误对象,供调用方的 catch 块处理 - WHEN 响应不包含
code字段(非标准格式,如 SSE 流式响应)时,THE Frontend_Unpacker SHALL 直接返回原始响应体,不做解包处理 - THE Frontend_Unpacker SHALL 确保所有现有 API 调用(Auth、Tasks、Notes、AI Chat)在解包后行为不变
需求 5:API 契约完全重写(T0-5)
用户故事: 作为前后端开发者,我希望 API 契约文档准确反映前端实际需要的响应结构,以便后续子 spec(RNS1.1-1.4)的后端实现有明确的、与前端一致的接口定义作为基准。
5.1 BOARD-3 财务看板契约重写
验收标准
- THE API_Contract SHALL 将 BOARD-3 响应从扁平
metrics数组重写为 6 个独立板块的嵌套结构:overview(经营一览)、recharge(预收资产)、revenue(应计收入确认)、cashflow(现金流入)、expense(现金流出)、coachAnalysis(助教分析) - THE API_Contract SHALL 为
overview板块定义 8 个指标字段(occurrence/discount/discountRate/confirmedRevenue/cashIn/cashOut/cashBalance/balanceRate),每个指标附带对应的环比字段(xxxCompare: string)和方向标记(isDown: boolean、isFlat: boolean) - THE API_Contract SHALL 为
recharge板块定义储值卡 5 个指标(actualIncome/firstCharge/renewCharge/consumed/cardBalance)及各自环比字段,以及赠送卡 3×4 矩阵(行:新增/消费/余额,列:合计/酒水卡/台费卡/抵用券),每个单元格含值和环比字段,以及全类别会员卡余额合计(allCardBalance)及环比 - THE API_Contract SHALL 为
revenue板块定义收入结构表(structureRows:9 行含子行标记isSub,每行含name/desc/amount/discount/booked/bookedCompare)、正价明细(priceItems:4 项)、优惠明细(discountItems:4 项)、渠道明细(channelItems:3 项),以及确认收入合计及环比 - THE API_Contract SHALL 为
cashflow板块定义消费收款(consumeItems:3 项)、充值收款(rechargeItems:1 项)、合计及环比,每项含name/desc/value/compare/isDown - THE API_Contract SHALL 为
expense板块定义 4 个子分组:经营支出(operationItems:3 项)、固定支出(fixedItems:4 项)、助教分成(coachItems:4 项)、平台服务费(platformItems:3 项),以及合计及环比 - THE API_Contract SHALL 为
coachAnalysis板块定义基础课(basic)和激励课(incentive)两个子表,每个子表含汇总行(totalPay/totalShare/avgHourly及各自环比)和按等级分行的数组(rows:初级/中级/高级/星级,每行含level/pay/payCompare/share/shareCompare/hourly/hourlyCompare及payDown/shareDown/hourlyFlat布尔标记) - THE API_Contract SHALL 为 BOARD-3 定义请求参数:
time(8 种时间范围枚举:month/lastMonth/week/lastWeek/quarter3/quarter/lastQuarter/half6)、area(7 种区域枚举:all/hall/hallA/hallB/hallC/mahjong/teamBuilding)、compare(0/1,控制是否返回环比数据) - WHEN
area不为all时,THE API_Contract SHALL 标注recharge(预收资产)板块不返回数据(储值卡数据不按区域拆分) - THE API_Contract SHALL 标注所有金额字段使用
items_sum口径(DWD-DOC 强制规则 1),助教费用使用assistant_pd_money+assistant_cx_money拆分(DWD-DOC 强制规则 2)
5.2 BOARD-1 助教看板契约重写
验收标准
- THE API_Contract SHALL 将 BOARD-1 响应从 10 个通用字段扩展为包含基础字段和 4 维度专属字段的结构
- THE API_Contract SHALL 为每个助教 item 定义基础字段:
id/name/initial/avatarGradient/level/skills/topCustomers,其中skills类型为Array<{ text: string, cls: string }>(含 emoji 和样式类),topCustomers类型为string[](含 P6 AC3 四级 emoji 前缀,如'💖 王先生'/'🧡 李女士'/'💛 张先生'/'💙 赵女士') - THE API_Contract SHALL 为
perf维度定义专属字段:perfHours(当期定档工时)、perfHoursBefore(上期定档工时,可选)、perfGap(距升档差距描述,可选)、perfReached(是否已达标) - THE API_Contract SHALL 为
salary维度定义专属字段:salary(工资总额)、salaryPerfHours(定档工时)、salaryPerfBefore(上期定档工时,可选) - THE API_Contract SHALL 为
sv维度定义专属字段:svAmount(客源储值总额)、svCustomerCount(储值客户数)、svConsume(储值消耗额) - THE API_Contract SHALL 为
task维度定义专属字段:taskRecall(召回任务完成数)、taskCallback(回访任务完成数) - THE API_Contract SHALL 为 BOARD-1 定义请求参数:
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) - THE API_Contract SHALL 标注交叉约束:
time=last_6m与sort=sv_desc不兼容,后端收到此组合时返回 HTTP 400
5.3 BOARD-2 客户看板契约重写
验收标准
- THE API_Contract SHALL 将 BOARD-2 响应从 8 个通用字段扩展为包含基础字段和 8 维度专属字段的结构
- THE API_Contract SHALL 为每个客户 item 定义基础字段:
id/name/initial/avatarCls/assistants,其中assistants类型为Array<{ name: string, cls: string, heartScore: number, badge?: string, badgeCls?: string }>,heartScore范围 0-10,前端通过 heart-icon 组件按 P6 AC3 四级映射渲染(💖>8.5 / 🧡>7 / 💛>5 / 💙≤5) - THE API_Contract SHALL 为
recall(最应召回)维度定义专属字段:idealDays/elapsedDays/overdueDays/visits30d/balance/recallIndex - THE API_Contract SHALL 为
potential(最大消费潜力)维度定义专属字段:potentialTags(Array<{ text: string, theme: string }>)/spend30d/avgVisits/avgSpend - THE API_Contract SHALL 为
balance(最高余额)维度定义专属字段:balance/lastVisit/monthlyConsume/availableMonths - THE API_Contract SHALL 为
recharge(最近充值)维度定义专属字段:lastRecharge/rechargeAmount/recharges60d/currentBalance - THE API_Contract SHALL 为
recent(最近到店)维度定义专属字段:daysAgo/visitFreq/idealDays/visits30d/avgSpend - THE API_Contract SHALL 为
spend60(最高消费近60天)维度定义专属字段:spend60d/visits60d/highSpendTag/avgSpend - THE API_Contract SHALL 为
freq60(最频繁近60天)维度定义专属字段:visits60d/avgInterval/weeklyVisits(Array<{ val: number, pct: number }>,8 周柱状图数据)/spend60d - THE API_Contract SHALL 为
loyal(最专一近60天)维度定义专属字段:intimacy/topCoachName/topCoachHeart/topCoachScore/coachName/coachRatio/coachDetails(Array<{ name, cls, heartScore, badge?, avgDuration, serviceCount, coachSpend, relationIdx }>) - THE API_Contract SHALL 为 BOARD-2 定义请求参数:
dimension(8 种维度枚举)、project(5 种项目枚举:all/chinese/snooker/mahjong/karaoke)、page(页码,默认 1)、pageSize(每页条数,默认 20)
5.4 CUST-1 客户详情契约重写
验收标准
- THE API_Contract SHALL 为 CUST-1 响应补充客户 Banner 字段:
balance(余额)、consumption60d(近60天消费)、idealInterval(理想到店间隔)、daysSinceVisit(距上次到店天数) - THE API_Contract SHALL 为 CUST-1 响应补充
aiInsight模块:summary(AI 分析摘要,string)和strategies(策略建议列表,Array<{ color: string, text: string }>),数据来源标注为biz.ai_cache(cache_type=app4_analysis) - THE API_Contract SHALL 为 CUST-1 响应补充
coachTasks模块(关联助教任务列表):每个助教含name/level/levelColor/taskType/taskColor/bgClass/status/lastService/metrics(Array<{ label, value, color? }>,含近60天次数/总时长/次均时长) - THE API_Contract SHALL 为 CUST-1 响应补充
favoriteCoaches模块(最亲密助教):每位助教含emoji/name/relationIndex/indexColor/bgClass/stats(Array<{ label, value, color? }>,含基础课时/激励课时/上课次数/充值金额) - THE API_Contract SHALL 将 CUST-1 消费记录从扁平结构重写为嵌套结构:每条记录含
id/type(table/shop/recharge枚举)/date/tableName/startTime/endTime/duration/tableFee/tableOrigPrice/coaches(Array<{ name, level, levelColor, courseType, hours, perfHours?, fee }>)/foodAmount/foodOrigPrice/totalAmount/totalOrigPrice/payMethod/rechargeAmount - THE API_Contract SHALL 为 CUST-1 响应补充
notes模块(备注列表):每条备注含id/tagLabel/createdAt/content - THE API_Contract SHALL 标注会员信息获取规则:通过
member_idJOINdim_member获取手机号和昵称(DWD-DOC 强制规则 DQ-6),禁止直接使用settlement_head.member_phone
5.5 COACH-1 助教详情契约重写
验收标准
- THE API_Contract SHALL 为 COACH-1 响应补充基本信息字段:
workYears(工龄)、customerCount(客户数)、hireDate(入职日期) - THE API_Contract SHALL 为 COACH-1 响应补充
performance模块(6 个绩效指标):monthlyHours/monthlySalary/customerBalance/tasksCompleted/perfCurrent/perfTarget - THE API_Contract SHALL 为 COACH-1 响应补充
income模块(收入明细):thisMonth和lastMonth各含 4 项收入分类(基础课时费/激励课时费/充值提成/酒水提成),每项含label/amount/color - THE API_Contract SHALL 为 COACH-1 响应补充
tierNodes字段(档位节点数组,如[0, 100, 130, 160, 190, 220]),供前端绩效进度条组件使用 - THE API_Contract SHALL 为 COACH-1 响应补充
historyMonths模块(历史月份统计,最近 5+ 个月):每月含month(标签)/estimated(是否预估)/customers/hours/salary/callbackDone/recallDone - THE API_Contract SHALL 扩展 COACH-1 的
topCustomers字段结构,从 5 个字段扩展为 10 个字段:补充initial/avatarGradient/heartEmoji(P6 AC3 四级映射:💖/🧡/💛/💙)/relationScore(关系指数,0-10)/scoreColor/balance - THE API_Contract SHALL 为 COACH-1 响应补充近期服务明细中的
perfHours(折算工时)和customerId字段 - THE API_Contract SHALL 为 COACH-1 的任务分组(
visibleTasks/hiddenTasks/abandonedTasks)补充字段:TaskItem 补充noteCount/pinned/notes(Array<{ pinned?, text, date }>),AbandonedTask 补充reason - THE API_Contract SHALL 为 COACH-1 响应补充
notes模块(备注列表):每条备注含id/content/timestamp/aiScore(AI 应用 6 评分,1-10,展示用)/customerName/tagLabel/createdAt
5.6 PERF-1 绩效概览契约重写
验收标准
- THE API_Contract SHALL 将 PERF-1 的
thisMonthRecords从扁平数组重写为按日期分组的 DateGroup 结构:每组含date(日期标签)/totalHours(当日总工时)/totalIncome(当日总收入)/records(记录列表),每条记录含customerName/timeRange/hours/courseType/courseTypeClass/location/income - THE API_Contract SHALL 为 PERF-1 响应补充收入档位数据:
currentTier(当前档,含basicRate/incentiveRate)、nextTier(下一档,含basicRate/incentiveRate)、upgradeHoursNeeded(距升档所需工时)、upgradeBonus(升档奖金) - THE API_Contract SHALL 为 PERF-1 响应补充
lastMonthIncome(上月收入)字段 - THE API_Contract SHALL 为 PERF-1 的
incomeItems每项补充desc字段(费率×工时的拆分描述,如"80元/h × 75h") - THE API_Contract SHALL 为 PERF-1 的
newCustomers补充lastService(最后服务日期)和count(服务次数)字段;为regularCustomers补充hours(总工时)和income(总收入)字段
5.7 TASK-1 绩效概览字段契约重写
验收标准
- THE API_Contract SHALL 将 TASK-1 响应中的
performance从 4 个字段(totalHours/totalIncome/totalCustomers/monthLabel)扩展为 15+ 个字段,补充:tierNodes(档位节点数组)/basicHours(基础课时)/bonusHours(激励课时)/currentTier(当前档位索引)/nextTierHours(下一档位工时阈值)/tierCompleted(是否已达标)/bonusMoney(升档奖金)/incomeTrend(收入趋势,如"↓368")/incomeTrendDir(up/down)/prevMonth(上月标签) - THE API_Contract SHALL 为 TASK-1 的任务 item 补充可选扩展字段:
lastVisitDays(距上次到店天数)、balance(客户余额)、aiSuggestion(AI 建议摘要)
5.8 CHAT-1/2 对话模块契约重写
验收标准
- THE API_Contract SHALL 统一 CHAT-2 消息的时间字段名为
createdAt(替代前端使用的timestamp和契约定义的created_at,遵循 camelCase 规范) - THE API_Contract SHALL 为 CHAT-1 历史列表的每条记录补充
title(对话标题)字段 - THE API_Contract SHALL 为 CHAT-2 消息补充
referenceCard可选字段:含type(customer/record枚举)/title/summary/data(Record<string, string>键值对) - THE API_Contract SHALL 补充 SSE 流式端点定义:
POST /api/xcx/chat/stream,请求体含chatId/content,响应为text/event-stream - THE API_Contract SHALL 标注 CHAT 消息查询端点支持
customerId查询参数:后端根据customerId自动查找或创建对话,返回对应的chatId和消息列表
需求 6:前端跨页面参数修复(T0-6)
用户故事: 作为助教或管理层用户,我希望在小程序中从一个页面跳转到另一个页面时,目标页面能正确加载对应的数据,而不会因为参数传递错误导致页面空白或加载错误数据。
6.1 task-detail 页面跳转修复
验收标准
- WHEN 用户从 task-detail 页面点击"问问助手"跳转到 chat 页面时,THE Miniprogram SHALL 传递
customerId={detail.customerId}参数(而非当前错误传递的detail.id即 taskId) - WHEN 用户从 task-detail 页面点击"查看全部服务记录"跳转到 customer-service-records 页面时,THE Miniprogram SHALL 传递
customerId={detail.customerId}参数(而非当前错误传递的detail.id即 taskId) - IF TASK-2 响应中不包含
customerId字段,THEN THE Miniprogram SHALL 无法完成上述跳转修复,因此本需求依赖 API 契约中 TASK-2 响应包含customerId字段的定义
6.2 customer-detail 页面跳转修复
验收标准
- WHEN 用户从 customer-detail 页面点击"查看服务记录"跳转到 customer-service-records 页面时,THE Miniprogram SHALL 传递
customerId={detail.id}参数(当前未传任何参数) - WHEN 用户从 customer-detail 页面点击"问问助手"跳转到 chat 页面时,THE Miniprogram SHALL 传递
customerId={detail.id}参数(当前未传任何参数) - THE Miniprogram SHALL 修复 customer-detail 页面的
loadDetail()函数,从onLoad(options)的options.id获取客户 ID,替代当前通过__route__解析的错误方式
6.3 coach-detail 页面跳转修复
验收标准
- WHEN 用户从 coach-detail 页面点击任务项跳转到 customer-detail 页面时,THE Miniprogram SHALL 传递
id={customerId}参数(而非当前错误传递的name={customerName}),此修复依赖 COACH-1 响应中 TaskItem 包含customerId字段
6.4 performance 页面跳转修复
验收标准
- WHEN 用户从 performance 页面点击客户卡片或服务记录跳转到 task-detail 页面时,THE Miniprogram SHALL 传递
id={taskId}参数(而非当前错误传递的customerName={name}),此修复依赖 PERF-1 响应中记录包含taskId字段
6.5 chat 页面多入口参数路由
验收标准
- WHEN chat 页面从 task-detail 或 customer-detail 跳转进入(携带
customerId参数)时,THE Miniprogram SHALL 使用customerId查询参数调用 CHAT 消息端点,由后端自动查找或创建对话 - WHEN chat 页面从 chat-history 跳转进入(携带
historyId参数)时,THE Miniprogram SHALL 使用historyId作为chatId直接加载历史消息 - WHEN chat 页面从 coach-detail 跳转进入(携带
coachId参数)时,THE Miniprogram SHALL 使用coachId作为上下文参数传递给 CHAT 端点
6.6 globalData.authUser 字段扩展
验收标准
- THE Miniprogram SHALL 在登录成功后(
/api/xcx/me响应)将role、storeName、coachLevel、avatar字段存入globalData.authUser,供 task-list Banner、performance Banner、performance-records Banner 等多个页面使用 - WHEN
globalData.authUser已包含上述字段时,THE Miniprogram SHALL 不再需要各页面单独请求/me接口获取这些信息
需求 7:契约文档一致性与完整性
用户故事: 作为后续子 spec(RNS1.1-1.4)的开发者,我希望重写后的 API 契约文档内部一致、无歧义,以便直接作为后端实现的唯一基准。
验收标准
- THE API_Contract SHALL 确保所有接口的响应字段名统一使用 camelCase 格式(与需求 2 的 CamelCase_Converter 输出一致)
- THE API_Contract SHALL 确保所有涉及金额的字段标注使用
items_sum口径,禁止使用consume_money(DWD-DOC 强制规则 1) - THE API_Contract SHALL 确保所有涉及助教费用的字段标注使用
assistant_pd_money(陪打)+assistant_cx_money(超休)拆分,禁止使用service_fee(DWD-DOC 强制规则 2) - THE API_Contract SHALL 确保所有涉及会员信息的字段标注通过
member_idJOINdim_member获取,禁止直接使用member_phone/member_name(DWD-DOC 强制规则 DQ-6/DQ-7) - THE API_Contract SHALL 为每个接口标注数据源(FDW 表名或业务表名),供后续子 spec 实现时参考
- THE API_Contract SHALL 确保重写后的 8 个接口响应定义(BOARD-1/2/3、CUST-1、COACH-1、PERF-1、TASK-1 performance、CHAT-1/2)与前端内联 mock 数据结构完全对齐,无字段遗漏或类型不匹配