api-server/docs/chat-scope-test-plan.md
wangdl fe44dec567
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 46s
feat: M-CHAT ChatScope 会话系统完整实现
## 数据模型
- ChatSession +13 字段 (scopeType/scopeId/parentKnowledgeBaseId/createdFrom/isPinned/isArchived/isDeleted/modelMode/modelId/lastMessageAt)
- ChatMessage +scopeSnapshot (消息级 scope 快照)
- ChatCitation +lineStart/lineEnd +sourceId 索引
- 5 个新查询索引

## 核心能力
- open-or-create: 同 scope 继续会话 (200) / 新建 (201)
- scope 级检索: global/knowledge_base/material/knowledge_item/folder
- listSessions: scope 过滤 + isDeleted 排除 + isPinned 排序 + 分页元数据
- 自动标题: 首条消息截取 + 词边界处理
- 软删除 + 置顶/归档
- scope 字段创建后不可修改
- 全部端点 userId 鉴权

## 文档
- docs/chat-scope-design.md (设计文档 + 决策表)
- docs/chat-scope-api-contract.md (API 契约)
- docs/chat-scope-test-plan.md (33 条测试用例)
- prisma/migrations/backfill_chat_scope.sql (旧数据回填)

## Bug 修复
- #104: KnowledgeItem.sourceRef 填充 (material scope 检索修复)
- #102: sendMessageStream aiGateway null 保护
- listSessions isDeleted/isArchived 过滤 + 分页

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 17:27:40 +08:00

4.2 KiB
Raw Permalink Blame History

ChatScope 测试计划

CHAT-702/703/704 | 2026-06-06


1. Scope 回归测试 (#89 CHAT-702)

1.1 创建会话 — open-or-create

# 测试用例 预期
1 新建 material scope 会话 HTTP 201, scopeType=material, scopeId=sourceId
2 相同 scope 再次调用 HTTP 200, 返回同一个 session id
3 不同 scopeId 调用 HTTP 201, 创建新会话
4 global scope 调用 HTTP 201, scopeId=null, 每次都新建
5 scopeType 不合法 HTTP 400
6 scopeType=material 但 scopeId 为空 HTTP 400

1.2 会话列表 — scope 过滤

# 测试用例 预期
7 scopeType + scopeId 精确过滤 只返回匹配的会话
8 parentKnowledgeBaseId 过滤 返回该 KB 下所有会话
9 无过滤(全局列表) 返回用户所有未删除会话
10 isDeleted 会话不出现在列表 过滤掉

1.3 发送消息 — scope 快照

# 测试用例 预期
11 发消息后检查 scopeSnapshot 用户消息和 AI 消息都有正确的 scopeSnapshot
12 历史消息查询 每条消息都带 scopeSnapshot

1.4 检索范围

# 测试用例 预期
13 material scope: 只检索 sourceRef=scopeId 的内容 检索结果只来自该资料
14 knowledge_item scope: 只检索 id=scopeId 的内容 检索结果只来自该知识点
15 knowledge_base scope: 检索整个知识库 检索结果覆盖整个 KB
16 global scope: 不检索 返回空上下文

1.5 会话管理

# 测试用例 预期
17 PATCH 更新 title 成功更新
18 PATCH 尝试修改 scopeType 静默忽略scopeType 不变
19 PATCH 尝试修改 scopeId 静默忽略scopeId 不变
20 DELETE 软删除 isDeleted=true消息保留
21 软删除后 open-or-create 创建新会话,不返回已删除的

2. 防上下文污染测试 (#90 CHAT-703)

2.1 跨 scope 隔离

# 测试用例 步骤 预期
22 资料 A 和资料 B 不串 1. 在 material/A 会话问"这篇文章讲了什么" 2. 切到 material/B 会话问"和之前那篇比呢" AI 不知道 A 的内容
23 知识点和知识库不串 1. 在 knowledge_item/I 会话问 2. 切到 knowledge_base 会话继续问 AI 应能检索整个 KB
24 全局和绑定不串 1. 在 knowledge_base/K 会话问 2. 切到 global 会话问"刚才那个知识库里有什么" AI 不知道之前的对话

2.2 并发会话

# 测试用例 预期
25 同一 scope 多会话(手动新对话创建多个) 每个会话的消息互不干扰
26 快速切换会话发消息 每条消息写入正确的 sessionId

3. 来源删除测试 (#91 CHAT-704)

3.1 知识库删除

# 测试用例 步骤 预期
27 知识库被删除后 1. 创建 kb/K 的会话 2. 删除知识库 K 3. 打开会话 会话仍存在,需手动处理
28 知识库被删除后检索 同上,发消息 检索结果为空,提示知识库已删除

3.2 资料/知识点删除

# 测试用例 步骤 预期
29 资料被删除后 1. 创建 material/M 的会话 2. 删除资料 M 3. 打开会话 会话仍然存在
30 资料被删除后检索 同上,发消息 检索不到被删资料的内容
31 知识点被删除后 1. 创建 knowledge_item/I 的会话 2. 删除知识点 I 3. 打开会话 会话仍然存在,标题不变
32 知识点被删除后检索 同上,发消息 检索结果为空

3.3 恢复

# 测试用例 预期
33 删除资料后重新导入同名资料 scopeId 不同,不会关联到旧会话

执行方式

# 后端启动后在本地执行
npx jest --config jest.config.ts --testPathPattern="rag-chat"

# 或手动 curl 测试
curl -X POST http://localhost:3000/rag-chat/sessions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"scopeType":"material","scopeId":"test_source_id","createdFrom":"material_detail"}'