Files
Neo-ZQYY/.kiro/specs/rns1-infra-contract-rewrite/tasks.md

13 KiB
Raw Blame History

实现计划RNS1.0 基础设施与契约重写

概述

按依赖关系排序实现 6 个主任务T0-1全局中间件和 T0-2CamelModel为基础设施层必须先行T0-3路由修正和 T0-4前端解包为适配层T0-5契约重写为文档层T0-6参数修复为前端修复层。属性测试使用 Hypothesis单元测试使用 pytest。

任务

  • 1. 全局响应包装中间件 + 异常处理器T0-1

    • 1.1 实现 ResponseWrapperMiddleware ASGI 中间件

      • 创建 apps/backend/app/middleware/response_wrapper.py
      • 实现 ASGI 中间件类,拦截 http.response.starthttp.response.body
      • JSON 成功响应2xx + application/json包装为 { "code": 0, "data": <原始body> }
      • 跳过条件:text/event-streamSSE、非 application/json、非 2xx 状态码
      • 需求: 1.1, 1.5, 1.6
    • 1.2 实现异常处理器函数

      • 在同一文件中实现 http_exception_handlerunhandled_exception_handler
      • HTTPException → { "code": <status_code>, "message": <detail> }
      • 未捕获异常 → { "code": 500, "message": "Internal Server Error" } + logger.exception 写入完整堆栈
      • 需求: 1.2, 1.3
    • 1.3 在 main.py 中注册中间件和异常处理器

      • app.add_exception_handler(HTTPException, http_exception_handler)
      • app.add_exception_handler(Exception, unhandled_exception_handler)
      • app.add_middleware(ResponseWrapperMiddleware)(在 CORS 之后添加)
      • 验证现有 16 个端点Auth/Tasks/Notes/AI Chat在包装后行为正常
      • 需求: 1.4
    • 1.4 编写属性测试:响应包装-解包 Round Trip

      • Property 1: 响应包装-解包 Round Trip
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.from_type(dict|list|str|int|float|bool|None) 生成随机 JSON 可序列化数据
      • 验证:包装后 JSON 包含 code=0data;解包 data 等于原始输入
      • 验证需求: 1.1, 4.1
    • 1.5 编写属性测试:异常响应保持 code 和 message

      • Property 2: 异常响应保持 code 和 message
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.integers(min_value=400, max_value=599) × st.text(min_size=1)
      • 验证:输出 JSON 的 code 等于输入状态码,message 等于输入 detail
      • 验证需求: 1.2, 1.3
    • 1.6 编写属性测试:非 JSON 响应透传

      • Property 3: 非 JSON 响应透传
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.sampled_from(["text/event-stream", "application/octet-stream", "text/html"]) × st.binary()
      • 验证:中间件输出的响应体与输入完全相同
      • 验证需求: 1.5, 1.6
    • 1.7 编写单元测试:中间件跳过逻辑

      • 测试文件:apps/backend/tests/unit/test_response_wrapper.py
      • 用例SSE 端点不包装health 端点包装;非 2xx 不二次包装;中间件自身异常时透传原始响应
      • 需求: 1.5, 1.6
  • 2. Pydantic Schema 统一 camelCaseT0-2

    • 2.1 创建 CamelModel 基类

      • 创建 apps/backend/app/schemas/base.py
      • 实现 CamelModel(BaseModel) 配置 alias_generator=to_camelpopulate_by_name=Truefrom_attributes=True
      • 需求: 2.1
    • 2.2 迁移现有 schema 到 CamelModel

      • schemas/xcx_tasks.pyTaskListItemAbandonRequest 等所有类的 BaseModelCamelModel
      • schemas/xcx_auth.py:所有 Auth schema 迁移
      • schemas/xcx_notes.py:所有 Notes schema 迁移
      • 确认路由函数 response_model 无需修改Pydantic 自动使用 alias 序列化)
      • 需求: 2.2, 2.3
    • 2.3 编写属性测试camelCase 转换 Round Trip

      • Property 4: camelCase 转换 Round Trip
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.fixed_dictionaries 生成随机 snake_case 字段名和值
      • 验证:model_dump(by_alias=True)Model(**camel_dict) → 等于原始实例
      • 验证需求: 2.2, 2.4
    • 2.4 编写单元测试CamelModel 基类

      • 测试文件:apps/backend/tests/unit/test_camel_model.py
      • 用例:TaskListItem 序列化输出 camelCase 字段名;反序列化同时接受 snake_case 和 camelCase
      • 需求: 2.2, 2.4
  • 3. 检查点 — 基础设施层验证

    • 确保所有测试通过ask the user if questions arise.
    • 验证现有 16 个端点在中间件 + CamelModel 迁移后行为正常
    • 确认 JSON 响应格式为 { code: 0, data: { camelCaseFields... } }
  • 4. 后端路由路径修正T0-3

    • 4.1 修改路由路径和函数名

      • 文件:apps/backend/app/routers/xcx_tasks.py
      • @router.post("/{task_id}/cancel-abandon")@router.post("/{task_id}/restore")
      • 函数名 cancel_abandonrestore_task(业务逻辑不变)
      • 移除旧路径,不保留兼容映射
      • 需求: 3.1, 3.2, 3.3
    • 4.2 编写单元测试:路由路径修正

      • 测试文件:apps/backend/tests/unit/test_xcx_tasks_route.py
      • 用例:POST /restore 返回 200POST /cancel-abandon 返回 404/405
      • 需求: 3.1, 3.3
  • 5. 前端 request() 解包适配T0-4

    • 5.1 修改 request() 函数添加 .data 解包逻辑

      • 文件:apps/miniprogram/miniprogram/utils/request.ts(或 services/api.ts,视实际位置)
      • code === 0 → 返回 res.data.data(业务数据)
      • code !== 0 → 抛出 { code, message } 错误对象
      • code 字段 → 直接返回原始响应体SSE 等非标准格式)
      • 确保所有现有 API 调用Auth/Tasks/Notes/AI Chat解包后行为不变
      • 需求: 4.1, 4.2, 4.3, 4.4
    • 5.2 编写属性测试:错误码解包抛出

      • Property 5: 错误码解包抛出
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.integers().filter(lambda x: x != 0) × st.text()
      • 验证:解包函数对 { code: n, message: m } 抛出异常,异常包含 code 和 message
      • 验证需求: 4.2
    • 5.3 编写属性测试:非标准格式响应透传

      • Property 6: 非标准格式响应透传
      • 测试文件:tests/test_rns1_properties.py
      • 生成器:st.dictionaries(st.text(), st.text()).filter(lambda d: "code" not in d)
      • 验证:解包函数直接返回原始 dict
      • 验证需求: 4.3
  • 6. 检查点 — 适配层验证

    • 确保所有测试通过ask the user if questions arise.
    • 验证后端路由 /restore 可正常调用
    • 验证前端 request() 解包逻辑对成功/错误/非标准格式三种场景均正确
  • 7. API 契约完全重写T0-5

    • 7.1 重写 BOARD-3 财务看板契约

      • 文件:docs/miniprogram-dev/API-contract.md
      • 定义 6 板块嵌套结构overview / recharge / revenue / cashflow / expense / coachAnalysis
      • 定义请求参数枚举time8 种、area7 种、compare0/1
      • 标注 area≠all 时 recharge 不返回;标注 items_sum 口径和助教费用拆分规则
      • 每个指标附带环比字段(xxxCompare + isDown + isFlat
      • 需求: 5.1.1 ~ 5.1.10, 7.1 ~ 7.5
    • 7.2 重写 BOARD-1 助教看板契约

      • 定义基础字段 + 4 维度专属字段perf/salary/sv/task
      • skills 类型为 Array<{ text, cls }>topCustomers 类型为 string[]
      • 定义请求参数枚举sort6 种、skill5 种、time6 种)
      • 标注交叉约束:time=last_6msort=sv_desc 不兼容 → HTTP 400
      • 需求: 5.2.1 ~ 5.2.8, 7.1, 7.6
    • 7.3 重写 BOARD-2 客户看板契约

      • 定义基础字段 + 8 维度专属字段recall/potential/balance/recharge/recent/spend60/freq60/loyal
      • assistants 含 heartScore/badge 等字段
      • 定义请求参数dimension8 种、project5 种、page/pageSize分页
      • 需求: 5.3.1 ~ 5.3.11, 7.1
    • 7.4 重写 CUST-1 客户详情契约

      • 补充 Banner 字段balance/consumption60d/idealInterval/daysSinceVisit
      • 补充 aiInsight / coachTasks / favoriteCoaches / notes 模块
      • 消费记录重写为嵌套结构(含 coaches 子数组、tableFee/foodAmount 分项)
      • 标注会员信息 JOIN 规则DQ-6items_sum 口径
      • 需求: 5.4.1 ~ 5.4.7, 7.1 ~ 7.4
    • 7.5 重写 COACH-1 助教详情契约

      • 补充 performance6 指标)/ income本月/上月各 4 项)/ tierNodes / historyMonths
      • 扩展 topCustomersheartEmoji/score/balance
      • 补充近期服务明细 perfHours/customerId
      • 任务分组补充 noteCount/pinned/notes/reason
      • 补充 notes 模块
      • 需求: 5.5.1 ~ 5.5.9, 7.1 ~ 7.4
    • 7.6 重写 PERF-1 绩效概览契约

      • thisMonthRecords 改为 DateGroup 分组结构
      • 补充收入档位数据currentTier/nextTier/upgradeHoursNeeded/upgradeBonus
      • 补充 lastMonthIncome、incomeItems.desc
      • 补充 newCustomers 和 regularCustomers 扩展字段
      • 需求: 5.6.1 ~ 5.6.5, 7.1
    • 7.7 重写 TASK-1 绩效概览字段契约

      • performance 从 4 字段扩展为 15+ 字段
      • 补充 tierNodes/basicHours/bonusHours/currentTier/nextTierHours/tierCompleted/bonusMoney/incomeTrend/incomeTrendDir/prevMonth
      • 任务 item 补充 lastVisitDays/balance/aiSuggestion
      • 需求: 5.7.1, 5.7.2
    • 7.8 重写 CHAT-1/2 对话模块契约

      • 统一时间字段名为 createdAt
      • CHAT-1 补充 title 字段
      • CHAT-2 补充 referenceCard 可选字段
      • 补充 SSE 流式端点定义:POST /api/xcx/chat/stream
      • 标注 customerId 查询参数支持
      • 需求: 5.8.1 ~ 5.8.5
    • 7.9 契约一致性审查

      • 确保所有字段名统一 camelCase
      • 确保所有金额字段标注 items_sum 口径
      • 确保所有助教费用标注 assistant_pd_money + assistant_cx_money 拆分
      • 确保所有会员信息标注 member_id JOIN dim_member 规则
      • 每个接口标注数据源FDW 表名或业务表名)
      • 对照前端 mock 数据结构逐字段比对,确保无遗漏或类型不匹配
      • 需求: 7.1 ~ 7.6
  • 8. 检查点 — 契约文档验证

    • 确保所有测试通过ask the user if questions arise.
    • 确认 8 个接口契约定义完整、字段名 camelCase、金额口径标注正确
    • 确认契约文档可作为后续子 specRNS1.1-1.4)的唯一实现基准
  • 9. 前端跨页面参数修复T0-6

    • 9.1 修复 task-detail 页面跳转参数

      • 文件:apps/miniprogram/miniprogram/pages/task-detail/task-detail.ts
      • 跳转 chat 时传 customerId={detail.customerId}(而非 detail.id
      • 跳转 customer-service-records 时传 customerId={detail.customerId}(而非 detail.id
      • 需求: 6.1.1, 6.1.2
    • 9.2 修复 customer-detail 页面跳转参数和 ID 获取方式

      • 文件:apps/miniprogram/miniprogram/pages/customer-detail/customer-detail.ts
      • 跳转 customer-service-records 时传 customerId={detail.id}
      • 跳转 chat 时传 customerId={detail.id}
      • loadDetail()onLoad(options)options.id 获取客户 ID替代 __route__ 解析
      • 需求: 6.2.1, 6.2.2, 6.2.3
    • 9.3 修复 coach-detail 页面跳转参数

      • 文件:apps/miniprogram/miniprogram/pages/coach-detail/coach-detail.ts
      • 任务项跳转 customer-detail 时传 id={customerId}(而非 name={customerName}
      • 依赖 COACH-1 响应中 TaskItem 包含 customerId 字段
      • 需求: 6.3.1
    • 9.4 修复 performance 页面跳转参数

      • 文件:apps/miniprogram/miniprogram/pages/performance/performance.ts
      • 跳转 task-detail 时传 id={taskId}(而非 customerName={name}
      • 依赖 PERF-1 响应中记录包含 taskId 字段
      • 需求: 6.4.1
    • 9.5 实现 chat 页面多入口参数路由

      • 文件:apps/miniprogram/miniprogram/pages/chat/chat.ts
      • 支持 customerId 入口:使用 customerId 查询参数调用 CHAT 端点
      • 支持 historyId 入口:使用 historyId 作为 chatId 加载历史消息
      • 支持 coachId 入口:使用 coachId 作为上下文参数
      • 需求: 6.5.1, 6.5.2, 6.5.3
    • 9.6 扩展 globalData.authUser 字段

      • 文件:apps/miniprogram/miniprogram/app.ts
      • 登录成功后将 role/storeName/coachLevel/avatar 存入 globalData.authUser
      • 各页面 Banner 直接从 globalData.authUser 读取,不再单独请求 /me
      • 需求: 6.6.1, 6.6.2
  • 10. 最终检查点 — 全量验证

    • 确保所有测试通过ask the user if questions arise.
    • 验证后端:中间件包装 + CamelModel + 路由修正 + 异常处理器全部生效
    • 验证前端request() 解包 + 8 个跳转场景参数正确 + globalData 字段完整
    • 验证契约8 个接口定义完整,可作为 RNS1.1-1.4 实现基准

备注

  • 标记 * 的子任务为可选测试任务,可跳过以加速 MVP
  • 每个任务引用具体需求编号,确保可追溯
  • 属性测试使用 Hypothesistests/test_rns1_properties.py),单元测试使用 pytestapps/backend/tests/unit/
  • 检查点确保增量验证,避免问题累积
  • T0-5 契约重写为文档任务,产出物为 docs/miniprogram-dev/API-contract.md
  • T0-6 前端参数修复中部分跳转依赖后续子 spec 的 API 响应字段(如 COACH-1 的 customerId、PERF-1 的 taskId),当前先修改跳转代码,待后端实现后联调验证