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

114 lines
4.2 KiB
Markdown
Raw Permalink 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.

# 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 不同,不会关联到旧会话 |
---
## 执行方式
```bash
# 后端启动后在本地执行
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"}'
```