Files
Neo-ZQYY/.kiro/specs/rns1-chat-integration/requirements.md

202 lines
18 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.4CHAT 对齐与联调收尾
## 简介
RNS1.4 是 NS1 小程序后端 API 补全项目的最后一个子 spec负责 CHAT 模块路径迁移和功能补全、FDW 端到端验证、以及全量前后端联调。本 spec 依赖 RNS1.0-1.3 全部完成,是整个 RNS1 系列的收尾阶段,确保 13 个页面全部连接真实后端运行,无 mock 数据残留。
### 依赖
- RNS1.0(基础设施与契约重写)— 全局响应包装中间件、camelCase 转换、重写后的 API 契约
- RNS1.1(任务与绩效接口)— TASK-1/2、PERF-1/2、PIN 接口已实现
- RNS1.2(客户与助教接口)— CUST-1/2、COACH-1 接口已实现
- RNS1.3(三看板接口)— BOARD-1/2/3、CONFIG-1 接口已实现
- 后端已有 `xcx_ai.py`(现有 `/api/ai/*` 路由,需迁移)
- 前端已有 chat.ts 和 chat-history.ts 页面P5.2 交付),当前使用 mock 数据和模拟流式输出
### 来源文档
- `docs/prd/Neo_Specs/RNS1-split-plan.md` — 拆分计划主文档
- `docs/miniprogram-dev/API-contract.md` — API 契约RNS1.0 T0-5 重写后版本)
- `docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md` — 助教视角走查报告GAP-45~51
## 术语表
- **Backend**FastAPI 后端应用,位于 `apps/backend/`
- **Miniprogram**:微信小程序前端应用,位于 `apps/miniprogram/`
- **CHAT_1_API**:对话历史列表接口 `GET /api/xcx/chat/history`,返回分页的对话列表
- **CHAT_2_API**:对话消息接口 `GET /api/xcx/chat/{chatId}/messages``GET /api/xcx/chat/messages?customerId={customerId}`,返回指定对话的消息列表
- **CHAT_3_API**:发送消息接口 `POST /api/xcx/chat/{chatId}/messages`,发送用户消息并获取 AI 同步回复
- **CHAT_4_SSE**SSE 流式端点 `POST /api/xcx/chat/stream`,通过 Server-Sent Events 逐 token 返回 AI 回复
- **SSE**Server-Sent Events服务端推送事件协议用于 AI 流式回复的逐 token 输出
- **referenceCard**:引用卡片,消息中附带的结构化上下文数据(类型/标题/摘要/键值对),用于展示客户概览等信息
- **FDW**PostgreSQL Foreign Data Wrapper用于从业务库 `zqyy_app` 访问 ETL 库 `etl_feiqiu` 的数据
- **chat_sessions**:业务库 `zqyy_app` 中的对话会话表,存储对话元数据
- **chat_messages**:业务库 `zqyy_app` 中的消息表,存储对话消息内容
- **Response_Wrapper**RNS1.0 实现的全局响应包装中间件,`text/event-stream` 响应自动跳过包装
- **items_sum**DWD-DOC 强制使用的消费金额口径
- **联调**:前后端联合调试,验证所有页面使用真实后端数据正常运行
## 需求
### 需求 1CHAT 路径迁移T4-1
**用户故事:** 作为前后端开发者,我希望 CHAT 模块的 API 路径从 `/api/ai/*` 统一迁移到 `/api/xcx/chat/*`,以便与其他小程序接口保持一致的路径命名规范。
#### 验收标准
1. THE Backend SHALL 将现有 `/api/ai/*` 路由全部迁移到 `/api/xcx/chat/*` 路径下,包括同步端点和 SSE 流式端点
2. THE Backend SHALL 在迁移后移除原 `/api/ai/*` 路径,不保留旧路径的兼容映射
3. THE Backend SHALL 将迁移后的路由注册到 `xcx_chat` router或等效命名与其他 `xcx_*` 路由模块保持一致的组织结构
4. THE Miniprogram SHALL 更新 `services/api.ts` 中所有 CHAT 相关的 API 调用路径,从 `/api/ai/*` 改为 `/api/xcx/chat/*`
5. WHEN CHAT_4_SSE 端点迁移到 `/api/xcx/chat/stream`THE Response_Wrapper SHALL 继续对 `text/event-stream` 响应跳过包装RNS1.0 已实现的行为不受路径变更影响)
### 需求 2实现 CHAT-1 对话历史列表T4-2 历史列表部分)
**用户故事:** 作为助教,我希望在对话历史页面看到所有对话记录(含对话标题和最后消息摘要),以便快速找到并继续之前的对话。
#### 验收标准
1. THE CHAT_1_API SHALL 实现 `GET /api/xcx/chat/history` 端点,接受 `page`(默认 1`pageSize`(默认 20查询参数返回分页的对话历史列表
2. THE CHAT_1_API SHALL 为每条对话记录返回以下字段:`id`(对话 ID`title`(对话标题)、`customerName`(关联客户姓名,可选)、`lastMessage`(最后一条消息摘要)、`timestamp`最后消息时间ISO 8601 格式)、`unreadCount`(未读消息数)
3. THE CHAT_1_API SHALL 从 `zqyy_app.chat_sessions` 查询对话列表,按最后消息时间倒序排列
4. THE CHAT_1_API SHALL 为 `title` 字段生成对话标题:优先使用对话会话中存储的自定义标题,若无自定义标题则使用关联客户姓名,若均无则使用首条消息内容的前 20 个字符作为标题
5. THE CHAT_1_API SHALL 返回标准分页字段:`total`(总记录数)、`page`(当前页码)、`pageSize`(每页条数)
6. THE CHAT_1_API SHALL 通过当前登录用户的身份过滤对话列表,确保每位助教只能看到自己的对话记录
### 需求 3实现 CHAT-2 对话消息查看T4-2 消息查看部分)
**用户故事:** 作为助教,我希望查看指定对话的消息列表,以便回顾与 AI 助手的对话内容。
#### 验收标准
1. THE CHAT_2_API SHALL 实现两个等效的消息查询端点:`GET /api/xcx/chat/{chatId}/messages`(通过对话 ID 查询)和 `GET /api/xcx/chat/messages?contextType={type}&contextId={id}`(通过上下文类型和 ID 查询)
2. THE CHAT_2_API SHALL 接受 `page`(默认 1`pageSize`(默认 50查询参数返回分页的消息列表
3. THE CHAT_2_API SHALL 为每条消息返回以下字段:`id`(消息 ID`role``user``assistant`)、`content`(消息内容)、`createdAt`创建时间ISO 8601 格式)、`referenceCard`(引用卡片,可选)
4. THE CHAT_2_API SHALL 统一使用 `createdAt` 作为消息时间字段名(替代前端使用的 `timestamp` 和旧契约的 `created_at`,遵循 camelCase 规范)
5. THE CHAT_2_API SHALL 从 `zqyy_app.chat_messages` 查询消息列表,按 `createdAt` 正序排列(最早的消息在前)
6. THE CHAT_2_API SHALL 在响应中返回 `chatId` 字段,供前端后续发送消息时使用(尤其是通过上下文入口时,前端需要获取对应的 `chatId`
7. THE CHAT_2_API SHALL 返回标准分页字段:`total`(总记录数)、`page`(当前页码)、`pageSize`(每页条数)
#### 3.2 上下文对话复用规则
8. WHEN 通过 `contextType``contextId` 查询参数调用消息端点时THE CHAT_2_API SHALL 按以下规则查找或创建对话:
- `contextType='task'`:查找同一用户、同一 `contextId`taskId的已有对话找到则复用无时限找不到则新建
- `contextType='customer'``contextType='coach'`:查找同一用户、同一 `contextId` 的已有对话,若最后消息时间 ≤ 3 天则复用,> 3 天或不存在则新建
- `contextType='general'`:始终新建对话
9. THE CHAT_2_API SHALL 在 `ai_conversations` 中记录 `context_type``context_id` 字段,用于后续对话查找
10. THE CHAT_2_API SHALL 确保对话复用查找基于 `(user_id, site_id, context_type, context_id)` 组合,不同用户的对话互不影响
### 需求 4CHAT referenceCard 支持T4-3
**用户故事:** 作为助教,我希望在与 AI 助手对话时,消息中能附带客户概览卡片(含余额、消费、到店频次等键值对数据),以便在对话上下文中快速查看客户关键信息。
#### 验收标准
1. THE CHAT_2_API SHALL 为消息返回可选的 `referenceCard` 字段,结构包含:`type`(引用类型,`customer``record` 枚举)、`title`(卡片标题,如 `"张伟 — 消费概览"`)、`summary`(摘要文字)、`data``Record<string, string>` 键值对详情,如 `{ "近30天消费": "¥2,380", "到店次数": "8次" }`
2. WHEN AI 助手回复消息涉及特定客户时THE Backend SHALL 从 FDW 查询该客户的关键指标(余额、近期消费、到店频次等),组装为 `referenceCard` 附加到 AI 回复消息中
3. THE Backend SHALL 将 `referenceCard` 数据持久化存储到 `chat_messages` 表中(作为 JSON 字段),以便历史消息查看时仍能展示引用卡片
4. THE Miniprogram SHALL 在 chat 页面的消息列表中,检测消息的 `referenceCard` 字段,若存在则渲染为结构化卡片组件(标题 + 摘要 + 键值对列表)
#### 4.2 多入口参数路由GAP-50
5. THE Miniprogram SHALL 在 chat 页面的 `onLoad(options)` 中实现多入口参数路由逻辑,按以下优先级处理入口参数:
-`options.historyId` 存在(从 chat-history 跳转),使用 `historyId` 作为 `chatId` 直接加载历史消息
-`options.taskId` 存在(从 task-detail 跳转),使用 `contextType=task` + `contextId=taskId` 调用 CHAT_2_API由后端查找同一任务的已有对话始终复用无时限
-`options.customerId` 存在(从 customer-detail 跳转),使用 `contextType=customer` + `contextId=customerId` 调用 CHAT_2_API由后端按 3 天时限判断复用或新建
-`options.coachId` 存在(从 coach-detail 跳转),使用 `contextType=coach` + `contextId=coachId` 调用 CHAT_2_API由后端按 3 天时限判断复用或新建
6. WHEN 通过上下文入口进入对话后THE Miniprogram SHALL 将后端返回的 `chatId` 缓存到页面 data 中,后续发送消息和 SSE 流式请求均使用该 `chatId`
7. IF chat 页面未收到任何入口参数(`historyId`/`taskId`/`customerId`/`coachId` 均为空THEN THE Miniprogram SHALL 使用 `contextType=general` 调用 CHAT_2_API 创建一个通用对话
### 需求 5CHAT-3 发送消息T4-2 发送部分)
**用户故事:** 作为助教,我希望在对话页面发送消息后能立即收到 AI 的同步回复,以便在不支持 SSE 的场景下也能正常使用 AI 助手。
#### 验收标准
1. THE CHAT_3_API SHALL 实现 `POST /api/xcx/chat/{chatId}/messages` 端点,接受请求体 `{ content: string }`
2. THE CHAT_3_API SHALL 将用户消息存入 `chat_messages` 表,调用 AI 服务获取回复,将 AI 回复也存入 `chat_messages`
3. THE CHAT_3_API SHALL 返回包含用户消息和 AI 回复的响应:`userMessage`(含 `id`/`content`/`createdAt`)和 `aiReply`(含 `id`/`content`/`createdAt`
4. THE CHAT_3_API SHALL 在发送消息后更新 `chat_sessions` 表的 `lastMessage` 和最后消息时间字段
5. IF AI 服务调用失败或超时THEN THE CHAT_3_API SHALL 仍保存用户消息,并返回 AI 回复为错误提示消息(如 `{ content: "抱歉AI 助手暂时无法回复,请稍后重试" }`HTTP 状态码保持 200
6. THE CHAT_3_API SHALL 验证请求的 `chatId` 属于当前登录助教,不属于时返回 HTTP 403
### 需求 6CHAT-4 SSE 流式端点T4-1 SSE 部分)
**用户故事:** 作为助教,我希望 AI 助手的回复能以流式方式逐字显示,以便获得更自然的对话体验,减少等待感。
#### 验收标准
1. THE CHAT_4_SSE SHALL 实现 `POST /api/xcx/chat/stream` 端点,接受请求体 `{ chatId: string, content: string }`,响应内容类型为 `text/event-stream`
2. THE CHAT_4_SSE SHALL 发送以下三种 SSE 事件类型:
- `event: message` — 逐 token 输出,`data``{"token": "<文本片段>"}`
- `event: done` — 流结束,`data``{"messageId": "<完整消息ID>", "createdAt": "<ISO 8601>"}`
- `event: error` — 错误,`data``{"message": "<错误描述>"}`
3. THE CHAT_4_SSE SHALL 在流开始前将用户消息存入 `chat_messages` 表,在流结束后将完整的 AI 回复存入 `chat_messages`
4. THE CHAT_4_SSE SHALL 在流结束后更新 `chat_sessions` 表的 `lastMessage` 和最后消息时间字段
5. THE Response_Wrapper SHALL 对 `text/event-stream` 响应跳过全局包装,直接透传 SSE 事件流RNS1.0 已实现)
6. THE CHAT_4_SSE SHALL 验证请求的 `chatId` 属于当前登录助教,不属于时返回 HTTP 403此时响应为普通 JSON 错误,非 SSE
7. THE Miniprogram SHALL 将 chat 页面现有的 `simulateStreamOutput()`(模拟逐字输出)替换为真实的 SSE 连接,通过 `wx.request` 或兼容方案接收 `text/event-stream` 响应
### 需求 7FDW 端到端验证T4-4
**用户故事:** 作为后端开发者,我希望验证所有 FDW 查询在测试环境链路(`test_zqyy_app``test_etl_feiqiu`)上正常工作,以便确保 RNS1.1-1.3 实现的所有接口在真实数据链路上不会因 FDW 连接、权限或性能问题而失败。
#### 验收标准
1. THE Backend SHALL 验证所有 `fdw_etl.*` 视图在 `test_zqyy_app` 数据库中可正常访问,包括但不限于:`v_dws_assistant_salary_calc``v_dwd_assistant_service_log``v_dim_member``v_dim_assistant``v_dws_member_consumption_summary``v_dws_member_assistant_relation_index``v_dws_finance_*` 系列视图
2. THE Backend SHALL 验证每个 FDW 视图的查询响应时间在可接受范围内(单次查询不超过 3 秒),对超时的查询记录慢查询日志并评估是否需要添加索引
3. THE Backend SHALL 验证 FDW 查询在带有典型过滤条件(如 `assistant_id``member_id`、日期范围)时能正确返回数据,且结果集与直接查询 `test_etl_feiqiu` 的结果一致
4. IF 某个 FDW 视图不存在或权限不足THEN THE Backend SHALL 记录具体的错误信息(视图名、错误类型),并在验证报告中标注需要 DBA 介入修复
5. THE Backend SHALL 检查 FDW 链路上的关键索引是否存在:`chat_sessions` 表的 `(assistant_id, customer_id)` 索引、`chat_messages` 表的 `(session_id, created_at)` 索引
### 需求 8前端联调修复 — notes 页触底加载T4-5 F11
**用户故事:** 作为助教,我希望在备注列表页面滚动到底部时自动加载更多备注,以便查看全部备注记录而不需要手动翻页。
#### 验收标准
1. THE Miniprogram SHALL 在 notes 页面实现 `onReachBottom()` 生命周期函数,当用户滚动到页面底部时自动请求下一页备注数据
2. WHEN 触底加载触发时THE Miniprogram SHALL 将 `page` 参数加 1调用 `fetchNotes({ page, pageSize })` 接口,将返回的备注追加到已有列表末尾
3. WHEN 后端返回的 `hasMore``false` 或返回的备注数量小于 `pageSize`THE Miniprogram SHALL 停止触底加载,显示"没有更多了"提示
4. THE Miniprogram SHALL 在触底加载过程中显示加载状态指示器,防止重复触发请求
### 需求 9前端联调修复 — customer-service-records 按月请求T4-5 F10
**用户故事:** 作为助教,我希望客户服务记录页面在切换月份时向后端请求对应月份的数据,以便在数据量大时页面仍能快速响应,而不是全量加载后本地过滤。
#### 验收标准
1. THE Miniprogram SHALL 修改 customer-service-records 页面的月份切换逻辑,从当前的"全量加载后本地过滤"改为"按月请求 API"
2. WHEN 用户切换月份时THE Miniprogram SHALL 使用新的 `year`/`month` 参数调用 `fetchCustomerRecords({ customerId, year, month })` 接口,加载对应月份的服务记录
3. THE Miniprogram SHALL 在月份切换时清空已有记录列表,显示加载状态,待新数据返回后渲染
4. THE Miniprogram SHALL 在首次加载时默认请求当前月份的数据,而非全量数据
5. THE Backend SHALL 确保 CUST-2 接口支持 `year``month` 查询参数仅返回指定月份的服务记录RNS1.2 T2-4 已实现按月查询能力)
### 需求 10全量前后端联调T4-5 联调部分)
**用户故事:** 作为开发团队,我们希望 13 个小程序页面全部连接真实后端运行,无 mock 数据残留,以便确认整个应用在真实数据环境下功能完整、交互正常。
#### 验收标准
1. THE Miniprogram SHALL 移除所有页面中的内联 mock 数据和 mock 数据导入(`import { mockXxx } from '../../utils/mock-data'`),全部替换为真实 API 调用
2. THE Miniprogram SHALL 确保以下 13 个页面均能使用真实后端数据正常渲染:`task-list``task-detail``notes``performance``performance-records``customer-detail``customer-service-records``coach-detail``board-coach``board-customer``board-finance``chat-history``chat`
3. WHEN 某个页面的 API 调用失败时THE Miniprogram SHALL 显示友好的错误提示(如 Toast 或空状态占位),不出现白屏或未捕获异常
4. THE Miniprogram SHALL 验证所有页面间的跳转参数传递正确RNS1.0 T0-6 已修复的跨页面参数),确保目标页面能正确加载对应数据
5. THE Miniprogram SHALL 验证 chat 页面从 4 个入口task-detail、customer-detail、coach-detail、chat-history进入时均能正确关联上下文并加载对应对话
6. IF 联调过程中发现新的 Bug 或数据不一致问题THEN THE Miniprogram 和 Backend SHALL 在本 spec 范围内修复,修复内容记录到联调问题清单中
### 需求 11全局约束与权限控制
**用户故事:** 作为系统管理员,我希望所有 CHAT 接口遵循统一的权限控制和数据隔离规则,以确保每位助教只能访问自己的对话数据。
#### 验收标准
1. THE Backend SHALL 对所有 RNS1.4 CHAT 接口CHAT-1、CHAT-2、CHAT-3、CHAT-4执行 `require_approved()` 权限检查,确保用户状态为 `approved`
2. THE Backend SHALL 通过当前登录用户的身份信息过滤对话数据,确保每位助教只能访问自己创建的或与自己关联的对话
3. IF 当前用户未通过审核(状态非 `approved`THEN THE Backend SHALL 返回 HTTP 403 `{ code: 403, message: "用户未通过审核,无法访问此资源" }`
4. THE Backend SHALL 对所有 CHAT 接口的响应字段名统一使用 camelCase 格式(与 RNS1.0 的 CamelCase_Converter 一致)
5. THE Backend SHALL 确保 CHAT 模块的错误响应格式与全局异常处理器一致:`{ code: <HTTP状态码>, message: <错误详情> }`
6. WHEN CHAT 模块查询 FDW 数据(如为 referenceCard 获取客户指标THE Backend SHALL 遵循 DWD-DOC 强制规则:金额使用 `items_sum` 口径,会员信息通过 `member_id` JOIN `dim_member` 获取