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

20 KiB
Raw Blame History

实施计划RNS1.4 CHAT 对齐与联调收尾

概述

按照设计文档的 8 个组件将实施拆分为DDL 迁移 → 后端 Schema/Service/Router → FDW 验证 → 前端改造 → 联调收尾。每个任务增量构建确保无孤立代码。属性测试Hypothesis和单元测试作为可选子任务紧跟实现步骤。

任务

  • 1. DDL 迁移:扩展 ai_conversations 和 ai_messages 表

    • 1.1 创建 DDL 迁移脚本 db/zqyy_app/migrations/2026-03-20__rns14_chat_module_extend.sql
      • ALTER TABLE biz.ai_conversations 新增 context_type varchar(20)context_id varchar(50)title varchar(200)last_message textlast_message_at timestamptz 五个字段
      • ALTER TABLE biz.ai_messages 新增 reference_card jsonb 字段
      • 创建索引 idx_ai_conv_context ON (user_id, site_id, context_type, context_id, last_message_at DESC NULLS LAST) WHERE context_type IS NOT NULL
      • 创建排序索引 idx_ai_conv_last_msg ON (user_id, site_id, last_message_at DESC NULLS LAST)
      • 添加 COMMENT ON COLUMN 注释
      • 需求: R2.3, R3.8, R3.10, R4.3, R7.5
  • 2. 后端 Pydantic Schema 定义(组件 3

    • 2.1 创建 apps/backend/app/schemas/xcx_chat.py
      • 继承 CamelModel 基类,定义 ChatHistoryItemChatHistoryResponseReferenceCardChatMessageItemChatMessagesResponseSendMessageRequestSendMessageResponseMessageBriefChatStreamRequest
      • 字段类型和可选性严格遵循设计文档组件 3 定义
      • 需求: R2.2, R3.3, R4.1, R5.1, R5.3, R6.1, R11.4
    • 2.2 编写 Schema 序列化单元测试 apps/backend/tests/unit/test_xcx_chat_schema.py
      • 验证 ChatHistoryItem / ChatMessageItem / SendMessageResponse 的 camelCase 序列化输出
      • 验证 ReferenceCard 可选字段为 None 时不报错
      • 需求: R2.2, R3.3, R5.3, R11.4
  • 3. 后端 chat_service 业务逻辑层(组件 2

    • 3.1 创建 apps/backend/app/services/chat_service.py

      • 实现 ChatService 类,包含 get_chat_historyget_or_create_sessionget_messagessend_message_syncbuild_reference_cardgenerate_title 方法
      • get_chat_history:查询 biz.ai_conversations,按 last_message_at 倒序JOIN v_dim_member 获取 customerName,分页返回
      • get_or_create_session:按 (user_id, site_id, context_type, context_id) 查找或创建对话。复用规则task 入口始终复用无时限customer/coach 入口 ≤ 3 天复用、> 3 天新建general 入口始终新建
      • get_messages:查询 biz.ai_messages,按 created_at 正序,验证 chatId 归属当前用户
      • send_message_sync:存入用户消息 → 调用 AI → 存入 AI 回复 → 更新 session 元数据AI 失败时返回错误提示消息HTTP 200
      • ⚠️ P5 PRD 合规:对话落库必须遵循 docs/prd/specs/P5-miniapp-ai-integration.md 数据写入规则:
        • app_id 固定为 app1_chat
        • 用户消息发送时即写入 ai_messagesrole=user
        • 流式完成后完整 assistant 回复写入 ai_messagesrole=assistanttokens_used
        • 首条消息为页面上下文 JSONcurrent_time/source_page/page_context/screen_content
        • get_or_create_session 仅用于 task/customer/coach 入口的对话复用task 无时限customer/coach 3 天时限general 入口始终新建(保持 P5 PRD 兼容)
      • build_reference_card:从 FDW 查询客户指标(items_sum 口径),组装 referenceCard JSON
      • generate_title:自定义标题 > 客户姓名 > 首条消息前 20 字
      • 需求: R2.1-R2.6, R3.1-R3.10, R4.1-R4.3, R5.1-R5.6, R11.2, R11.6
    • 3.2 编写属性测试:标题生成优先级

      • Property 4: 对话标题生成优先级
      • 使用 Hypothesis st.fixed_dictionaries 生成随机 title/customer_name/first_message 组合
      • 验证:有 title 用 title否则用 customer_name否则用首条消息前 20 字,结果始终非空
      • 验证: 需求 R2.4
    • 3.3 编写属性测试:对话复用规则正确性

      • Property 6: 对话复用规则正确性
      • 使用 Hypothesis 生成随机 context_type/context_id/last_message_at 组合
      • 验证task 入口同一 context_id 始终返回同一 chatIdcustomer/coach 入口 ≤ 3 天复用、> 3 天新建general 入口每次返回不同 chatId
      • 验证: 需求 R3.8, R3.9, R3.10
    • 3.4 编写属性测试referenceCard Round Trip

      • Property 7: referenceCard 持久化 Round Trip
      • 使用 Hypothesis 生成随机 referenceCard JSONtype/title/summary/data
      • 验证JSON 序列化→存储→读取→反序列化等于原始对象
      • 验证: 需求 R4.1, R4.3
    • 3.5 编写属性测试:消息持久化与会话元数据更新

      • Property 8: 消息持久化与会话元数据更新
      • 使用 Hypothesis st.text(min_size=1, max_size=500) 生成随机消息内容
      • 验证:发送后 ai_messages 包含用户消息和 AI 回复session 的 last_message 和 last_message_at 已更新
      • 验证: 需求 R5.2, R5.4, R6.3, R6.4
    • 3.6 编写单元测试AI 失败降级

      • 测试文件 apps/backend/tests/unit/test_xcx_chat_ai_fallback.py
      • 验证 AI 服务超时/异常时用户消息仍保存AI 回复为错误提示消息HTTP 200
      • 需求: R5.5
  • 4. 后端路由迁移与 CHAT-1/2/3/4 端点实现(组件 1

    • 4.1 创建 apps/backend/app/routers/xcx_chat.py,实现 CHAT-1/2/3/4 五个端点

      • GET /history — CHAT-1 对话历史列表,调用 chat_service.get_chat_history
      • GET /{chat_id}/messages — CHAT-2a 通过 chatId 查询消息
      • GET /messages?contextType=&contextId= — CHAT-2b 通过上下文查询消息(按复用规则自动查找/创建对话)
      • POST /{chat_id}/messages — CHAT-3 发送消息(同步回复)
      • POST /stream — CHAT-4 SSE 流式端点,返回 StreamingResponse(media_type="text/event-stream")
      • 所有端点使用 Depends(require_approved()) 权限检查
      • chatId 归属验证CHAT-3/4 不属于当前用户返回 HTTP 403
      • 需求: R1.1, R1.3, R2.1, R3.1, R5.1, R6.1, R11.1, R11.2
    • 4.2 在 apps/backend/app/main.py 中注册 xcx_chat.router,移除 xcx_ai_chat.router

      • 删除 xcx_ai_chat.py 文件(不保留旧路径兼容)
      • 需求: R1.2, R1.3
    • 4.3 编写属性测试SSE 事件类型有效性

      • Property 9: SSE 事件类型有效性
      • 使用 Hypothesis st.sampled_from(["message", "done", "error"]) + 对应 data 结构
      • 验证事件类型为三者之一data 结构符合定义message→token, done→messageId+createdAt, error→message
      • 验证: 需求 R6.2
    • 4.4 编写属性测试:列表排序不变量

      • Property 3: 列表排序不变量
      • 使用 Hypothesis st.lists(st.datetimes()) 生成随机时间戳列表
      • 验证CHAT-1 对话列表按时间倒序CHAT-2 消息列表按时间正序
      • 验证: 需求 R2.3, R3.5
    • 4.5 编写单元测试:路由迁移与权限控制

      • 测试文件 apps/backend/tests/unit/test_xcx_chat_routes.py
      • 验证 /api/xcx/chat/history 返回 200需认证/api/ai/conversations 返回 404
      • 验证未审核用户收到 403chatId 不属于当前用户收到 403
      • Property 1: 路由迁移完整性 / Property 5: 权限控制与数据隔离
      • 验证: 需求 R1.1, R1.2, R5.6, R6.6, R11.1, R11.3
  • 5. 检查点 — 后端实现验证

    • 确保所有后端测试通过ask the user if questions arise.
  • 6. FDW 端到端验证脚本(组件 7

    • 6.1 创建 scripts/ops/verify_fdw_e2e.py
      • 验证所有 fdw_etl.* 视图在 test_zqyy_app 中可访问SELECT 1 FROM ... LIMIT 1
      • 验证带典型过滤条件assistant_id、member_id、日期范围的查询响应时间 < 3s
      • 检查关键索引存在:chat_sessions(assistant_id, customer_id)chat_messages(session_id, created_at)
      • 输出结构化 JSON 报告,失败项标注需 DBA 介入
      • 使用 load_dotenv 加载根 .env,连接 test_zqyy_app(遵循 testing-env.md 规范)
      • 需求: R7.1, R7.2, R7.3, R7.4, R7.5
  • 7. 前端 services/api.ts CHAT 模块对接(组件 6

    • 7.1 修改 apps/miniprogram/miniprogram/services/api.ts
      • fetchChatHistory():调用 GET /api/xcx/chat/history
      • fetchChatMessages(chatId):调用 GET /api/xcx/chat/{chatId}/messages
      • 新增 fetchChatMessagesByContext(contextType, contextId):调用 GET /api/xcx/chat/messages?contextType={type}&contextId={id}
      • sendChatMessage(chatId, content):调用 POST /api/xcx/chat/{chatId}/messages
      • 移除所有 CHAT 相关 mock 数据导入,USE_REAL_API 对 CHAT 模块设为 true
      • 需求: R1.4, R10.1
  • 8. 前端 chat 页面改造(组件 4

    • 8.1 修改 apps/miniprogram/miniprogram/pages/chat/chat.ts 实现多入口参数路由

      • onLoad(options) 中按优先级处理:historyIdtaskIdcustomerIdcoachId → 无参数(通用对话)
      • historyId 入口:直接用作 chatId 加载历史消息
      • taskId 入口:调用 fetchChatMessagesByContext('task', taskId),同一 taskId 始终复用同一对话(无时限)
      • customerId 入口:调用 fetchChatMessagesByContext('customer', customerId),≤ 3 天复用、> 3 天新建
      • coachId 入口:调用 fetchChatMessagesByContext('coach', coachId),≤ 3 天复用、> 3 天新建
      • 无参数入口:调用 fetchChatMessagesByContext('general', ''),始终新建
      • 需求: R4.5, R4.6, R4.7
    • 8.2 修改 chat.ts 将 simulateStreamOutput() 替换为真实 SSE 连接

      • 使用 wx.request + enableChunked: true 接收 POST /api/xcx/chat/stream 的 SSE 响应
      • 解析 event: message(逐 token 追加)、event: done(流结束)、event: error(错误处理)
      • 移除 simulateStreamOutput()mockAIReplies 相关代码
      • SSE 连接中断时显示"连接中断"提示,允许重试
      • 需求: R6.7, R10.1
    • 8.3 确保 chat 页面 referenceCard 渲染与真实 API 数据兼容

      • 验证 toDataList() 和 WXML 模板能正确渲染后端返回的 referenceCard 结构
      • 需求: R4.4
  • 9. 前端 chat-history 页面改造(组件 5

    • 9.1 修改 apps/miniprogram/miniprogram/pages/chat-history/chat-history.ts
      • 移除 mockChatHistory 导入,调用 fetchChatHistory() 获取真实数据
      • 响应字段映射:后端 timestampISO 8601formatRelativeTime() 处理
      • 点击对话项跳转 chat 页面时传递 historyId 参数
      • 需求: R2.1, R10.1, R10.2
  • 10. 前端联调修复(组件 8

    • 10.1 修改 notes 页面实现触底加载

      • apps/miniprogram/miniprogram/pages/notes/notes.ts 实现 onReachBottom() 生命周期函数
      • 维护 page 状态,触底时 page++ 调用 fetchNotes({ page, pageSize })
      • 追加数据到已有列表,hasMore === false 时停止加载并显示"没有更多了"
      • 加载过程中显示加载状态指示器,防止重复触发
      • 需求: R8.1, R8.2, R8.3, R8.4
    • 10.2 修改 customer-service-records 页面实现按月请求

      • apps/miniprogram/miniprogram/pages/customer-service-records/customer-service-records.ts 修改月份切换逻辑
      • 月份切换时调用 fetchCustomerRecords({ customerId, year, month }),清空列表 → loading → 渲染
      • 首次加载默认当前月份数据
      • 需求: R9.1, R9.2, R9.3, R9.4
  • 11. 检查点 — 前端改造验证

    • 确保所有前端改造完成chat 页面 4 个入口task-detail、customer-detail、coach-detail、chat-history均能正确进入并加载对话。ask the user if questions arise.
  • 12. Mock 数据移除与全量联调

    • 12.1 移除所有页面中的 mock 数据残留

      • 搜索并移除所有 import { mockXxx } from '../../utils/mock-data' 引用
      • 确保 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均使用真实 API
      • 需求: R10.1, R10.2
    • 12.2 验证全量联调

      • 确保所有页面 API 调用失败时显示友好错误提示Toast 或空状态占位),不出现白屏
      • 验证页面间跳转参数传递正确RNS1.0 T0-6 已修复的跨页面参数)
      • 验证 chat 页面从 4 个入口进入时均能正确关联上下文
      • 需求: R10.2, R10.3, R10.4, R10.5
  • 13. 全链路端到端测试(真实 AI 接口)

    • 13.1 后端全链路测试:使用真实百炼 API 验证 CHAT-3同步和 CHAT-4SSE 流式)

      • 启动后端服务连接 test_zqyy_app,使用真实测试用户 token
      • 调用 POST /api/xcx/chat/{chatId}/messages 发送真实消息,验证:
        • AI 回复内容质量(非乱码、语义相关、中文正常)
        • 用户消息和 AI 回复均已持久化到 biz.ai_messages
        • biz.ai_conversationslast_messagelast_message_at 已更新
        • tokens_used 字段已记录
      • 调用 POST /api/xcx/chat/stream 验证 SSE 流式返回:
        • 逐 token 事件格式正确(event: messageevent: done
        • 完整回复拼接后语义通顺
        • 流结束后消息已落库
      • 手动评估 AI 返回内容质量(至少 3 轮对话),记录评估结果
      • 需求: R5.2, R5.4, R6.2, R6.3, R6.4, AC1, AC9
    • 13.2 前端→后端→AI→数据库全链路验证

      • 在微信开发者工具中启动小程序,连接本地后端
      • 从 4 个入口task-detail、customer-detail、coach-detail、chat-history进入 chat 页面
      • 每个入口发送至少 1 条消息,验证:
        • SSE 流式逐字显示正常
        • 消息发送后页面状态正确loading → 显示回复)
        • 返回 chat-history 页面能看到刚才的对话记录
        • referenceCard 在有客户关联时正确渲染(如有数据)
      • 验证错误场景:网络断开时的提示、空消息拦截
      • 需求: R6.7, R10.5, R4.4
    • 13.3 AI 对话落库合规性验证(对照 P5 PRD + 用户确认的复用规则)

      • 验证对话复用规则task 入口同一 taskId 始终复用customer/coach 入口 ≤ 3 天复用、> 3 天新建general 入口始终新建
      • 验证首条消息格式:应用 1 的首条消息应为页面上下文 JSONsource_page/page_context/screen_content/current_time),对照 P5 PRD 应用 1 Prompt 数据结构
      • 验证 app_id 字段CHAT 模块对话的 app_id 应为 app1_chat
      • 验证 ai_messages.role 值:仅 user/assistant/system 三种CHECK 约束)
      • 验证 tokens_used 记录AI 回复消息应记录 token 消耗量
      • 验证 source_pagesource_context:从不同入口进入时应正确记录来源页面和上下文
      • 验证 context_typecontext_id:不同入口写入正确的上下文类型和 ID
      • 需求: AC9, P5-PRD 数据写入规则
  • 14. DDL 迁移合并到主 DDL 基线

    • 14.1 执行迁移脚本到 test_zqyy_app

      • 运行 db/zqyy_app/migrations/2026-03-20__rns14_chat_module_extend.sql(任务 1 创建的脚本)
      • 验证新字段和索引已正确创建(使用 BD 手册中的验证 SQL
      • 需求: R2.3, R3.8, R3.10, R4.3, R7.5
    • 14.2 合并到主 DDL 基线 docs/database/ddl/zqyy_app__biz.sql

      • biz.ai_conversations 表定义中追加 5 个新字段:context_type varchar(20)context_id varchar(50)title varchar(200)last_message textlast_message_at timestamptz
      • biz.ai_messages 表定义中追加 1 个新字段:reference_card jsonb
      • 在索引区追加 2 个新索引:idx_ai_conv_context条件索引WHERE context_type IS NOT NULLidx_ai_conv_last_msg
      • 更新文件头部的"生成日期"注释
      • 需求: DDL 基线同步
  • 15. 文档更新落地

    • 15.1 更新 BD 手册 docs/database/BD_Manual_ai_tables.md

      • biz.ai_conversations 字段明细中追加 5 个新字段context_type/context_id/title/last_message/last_message_at
      • biz.ai_messages 字段明细中追加 reference_card 字段
      • 在约束与索引表中追加 2 个新索引idx_ai_conv_context、idx_ai_conv_last_msg
      • 更新兼容性影响:标注 RNS1.4 CHAT 模块依赖新字段
      • 更新验证 SQL追加新字段和索引的验证查询
      • 更新回滚策略:追加 DROP INDEX 和 ALTER TABLE DROP COLUMN
      • 规范: db-docs.md 强制要求
    • 15.2 更新 API 契约 docs/miniprogram-dev/API-contract.md

      • CHAT 部分路径从 /api/ai/* 更新为 /api/xcx/chat/*
      • 补充 CHAT-1历史列表、CHAT-2a/2b消息查询含 customerId 参数、CHAT-3发送消息端点定义
      • 补充 referenceCard 结构定义
      • 补充 SSE 事件类型定义message/done/error
      • 需求: R1.1, R1.4
    • 15.3 更新后端 API 参考 apps/backend/docs/API-REFERENCE.md

      • 新增 xcx_chat 路由模块文档5 个端点)
      • 移除 xcx_ai_chat 路由模块文档(已删除)
      • 需求: R1.2, R1.3
    • 15.4 更新后端 README apps/backend/README.md

      • 路由模块摘要中:移除 xcx_ai_chat,新增 xcx_chatCHAT-1/2/3/4
      • 服务层中:新增 chat_service.py 说明
      • 需求: R1.3
    • 15.5 更新文档地图 docs/DOCUMENTATION-MAP.md

      • 在 3.1 FastAPI 后端部分新增 RNS1.4 模块xcx_chat.py、chat_service.py、xcx_chat schema
      • 在 5.6 Spec 文件表中新增 rns1-chat-integration 条目
      • 更新"最后更新"日期
      • 规范: doc-map.md 归档规则
    • 15.6 更新 RNS1 拆分计划 docs/prd/Neo_Specs/RNS1-split-plan.md

      • 标注 RNS1.4 状态为"实施中"或"已完成"(视进度)
      • 需求: 项目追踪
  • 16. 最终检查点 — 全量验证

    • 确保所有测试通过13 个页面均连接真实后端运行,无 mock 数据残留
    • 确保 DDL 迁移已合并到主基线BD 手册已同步更新
    • 确保 API 契约、后端 README、文档地图均已更新
    • 确保 AI 对话落库符合 P5 PRD 规范
    • ask the user if questions arise.

备注

  • 标记 * 的子任务为可选,可跳过以加速 MVP 交付
  • 每个任务引用了具体的需求编号R1-R11以确保可追溯性
  • 属性测试验证通用正确性属性Property 1-9单元测试验证具体边界条件
  • 检查点任务确保增量验证,避免问题累积
  • 后端使用 PythonFastAPI + Pydantic前端使用 TypeScript微信小程序

PRD 合规注意事项

  • P5 PRD 数据写入规则docs/prd/specs/P5-miniapp-ai-integration.md
    • 流式返回完成后,完整 assistant 回复写入 ai_messagesrole=assistant
    • 用户消息在发送时即写入role=user
    • 所有 AI 调用记录写入 ai_conversations + ai_messages(含 tokens_used 统计)
    • 首条消息为页面上下文 JSONsource_page/page_context/screen_content/current_time
    • app_id 固定为 app1_chat
  • 对话复用规则(用户已确认,覆盖 P5 PRD 的"始终新建"规则):
    • task 入口:同一 taskId 始终复用同一对话(无时限)
    • customer / coach 入口:最后消息 ≤ 3 天复用,> 3 天新建
    • general 入口(无参数):始终新建
    • chat-history 入口:直接打开已有对话(传 historyId

文档更新清单

文档 更新内容 任务
docs/database/ddl/zqyy_app__biz.sql 合并 5+1 新字段、2 新索引 14.2
docs/database/BD_Manual_ai_tables.md 新字段context_type/context_id/title/last_message/last_message_at/reference_card/索引/兼容性/回滚/验证 SQL 15.1
docs/miniprogram-dev/API-contract.md CHAT 路径迁移 + 新端点定义 15.2
apps/backend/docs/API-REFERENCE.md xcx_chat 路由模块文档 15.3
apps/backend/README.md 路由模块 + 服务层更新 15.4
docs/DOCUMENTATION-MAP.md RNS1.4 模块 + spec 条目 15.5
docs/prd/Neo_Specs/RNS1-split-plan.md RNS1.4 状态更新 15.6