- 前端 React+TypeScript (源码+构建产物) - 后端 Python FastAPI - 数据库迁移 001-015 - Docker部署配置 - 微信ClawBot API频道绑定 - 项目文档 README.md
635 lines
28 KiB
Markdown
635 lines
28 KiB
Markdown
# 测试用例 — AI自进化功能模块
|
||
|
||
## 1. 需求依据
|
||
|
||
- **PRD路径**:`/data/share/project/docs/PRD-self-evolution.md`
|
||
- **文档版本**:v1.0(2026-05-26)
|
||
- **功能概述**:Qihu-AIFlow平台AI自进化功能。每个用户的AI在对话中持续学习进化,前端通过「AI进化驾驶舱」展示进化过程。深度整合xSkill开源框架,实现对话轨迹→原子任务→技能聚类→技能生成→灰度验证的完整流水线。
|
||
|
||
### 需求侧功能模块(共6大模块)
|
||
|
||
| 编号 | 需求模块 | PRD章节 | 功能点数 |
|
||
|------|----------|---------|----------|
|
||
| R1 | 默认全局持续进化 | 7.2-功能一 | 5 |
|
||
| R2 | 对话自动分析(xSkill流水线) | 7.2-功能二 | 7 |
|
||
| R3 | 技能库管理 | 7.2-功能三 | 6 |
|
||
| R4 | AI进化驾驶舱(4个子面板) | 7.2-功能四 | 14 |
|
||
| R5 | 与AI聊天无缝衔接 | 7.2-功能五 | 5 |
|
||
| R6 | 数据隔离(用户级别) | 7.2-功能六 | 6 |
|
||
|
||
---
|
||
|
||
## 2. 代码功能模块概览
|
||
|
||
### 2.1 后端代码模块
|
||
|
||
| 模块 | 说明 | 主要代码位置 |
|
||
|------|------|-------------|
|
||
| 技能管理API | 技能CRUD、冻结/解冻、历史/轨迹查询 | `backend/python/app/api/evolution.py:33-139` |
|
||
| 进化事件API | 进化事件列表查询 | `backend/python/app/api/evolution.py:143-157` |
|
||
| 驾驶舱数据API | 技能树/时间线/统计/画像4面板数据 | `backend/python/app/api/evolution.py:160-202` |
|
||
| 轨迹提交API | 对话轨迹提交入口 | `backend/python/app/api/evolution.py:205-214` |
|
||
| EvolutionService | 核心业务逻辑层,12个公开方法 | `backend/python/app/services/evolution_service.py` |
|
||
| 数据模型(ORM) | 4张表定义 | `backend/python/app/models.py:741-792` |
|
||
| 路由注册 | prefix="/app/api/evolution" | `backend/python/main.py:140` |
|
||
|
||
### 2.2 前端代码模块
|
||
|
||
| 模块 | 说明 | 主要代码位置 |
|
||
|------|------|-------------|
|
||
| AI进化驾驶舱页面 | 主页面组件(4面板切换+数据加载) | `frontend/src/pages/front/EvolutionDashboard.tsx` (631行) |
|
||
| 驾驶舱样式 | 完整CSS样式 | `frontend/src/pages/front/EvolutionDashboard.css` (1019行) |
|
||
| 技能图谱面板 | Panel A:按分类分组展示技能节点 | `EvolutionDashboard.tsx:48-152` |
|
||
| 进化时间线面板 | Panel B:垂直时间线+事件筛选 | `EvolutionDashboard.tsx:155-201` |
|
||
| 技能使用统计面板 | Panel C:排行+趋势图+饼图+提醒 | `EvolutionDashboard.tsx:205-340` |
|
||
| AI能力画像面板 | Panel D:等级环+雷达图+标签云+建议 | `EvolutionDashboard.tsx:344-500` |
|
||
| evolutionAPI | 前端API调用定义(15个方法) | `frontend/src/api/index.ts:415-455` |
|
||
| 类型定义 | TypeScript interfaces | `frontend/src/types/index.ts:381-478` |
|
||
| 路由配置 | `#/evolution` | `frontend/src/App.tsx:98` |
|
||
| 导航入口 | 侧边栏"AI进化" | `frontend/src/components/layout/FrontLayout.tsx:14` |
|
||
|
||
---
|
||
|
||
## 3. 需求与代码差异说明
|
||
|
||
### 3.1 PRD中未在代码中体现的内容
|
||
|
||
| 编号 | PRD功能点 | 状态 | 说明 |
|
||
|------|-----------|------|------|
|
||
| GAP-01 | **技能回滚**:POST /skills/{name}/rollback/{version} | ❌ 未实现 | PRD明确要求回滚到历史版本,但API中无此端点,前端无回滚UI |
|
||
| GAP-02 | **对话溯源跳转**:点击来源对话可跳转到原始对话记录 | ❌ 未实现 | PRD要求"点击可跳转到原始对话记录",前端技能详情弹窗中有来源轨迹按钮但仅调用API(`evolutionAPI.getSkillTrajectories`),后端 `get_skill_trajectories` 返回的是用户最近20条轨迹而非该技能的关联轨迹 |
|
||
| GAP-03 | **新技能萌芽动画** | ❌ 未实现 | PRD面板A中要求"新技能生成时,技能树上有「萌芽」动画效果",前端代码中未找到相关CSS动画 |
|
||
| GAP-04 | **时间线导出** | ❌ 未实现 | PRD面板B要求"支持将进化时间线导出为图片或PDF分享",前端代码中无导出功能 |
|
||
| GAP-05 | **画像分享卡片** | ❌ 未实现 | PRD面板D要求"支持将AI能力画像生成为分享卡片",前端代码中无此功能 |
|
||
| GAP-06 | **Skill加载提示标签** | ❌ 未实现 | PRD功能五要求"在消息下方显示小标签:🚀 使用了你的专属技能:XXX",代码中未见此实现 |
|
||
| GAP-07 | **对话结束钩子(自动提交轨迹)** | ❌ 未自动触发 | PRD要求对话结束时自动提交轨迹,但当前仅提供手动API入口 `/trajectory/submit`,前端ChatPage中未见对话结束自动调用的钩子 |
|
||
| GAP-08 | **Watcher线程管理** | ❌ 未实现 | PRD要求用户注册后自动启动watcher线程持续进化,`UserEvolutionConfig`模型已定义但服务层无读写该表的代码,watcher状态管理未实现 |
|
||
| GAP-09 | **xSkill管线自动调度** | ❌ 未实现 | PRD要求轨迹进入xSkill流水线自动处理,但后端仅实现轨迹落盘(status=discovered),后续状态流转(splitting→...→done)依赖外部xSkill进程 |
|
||
| GAP-10 | **统计图表的交互联动** | ❌ 未实现 | PRD面板C要求"点击统计图表中的任意项可跳转到对应技能详情",前端StatisticsPanel中无此交互 |
|
||
|
||
### 3.2 PRD中未覆盖但代码中存在的功能模块
|
||
|
||
| 编号 | 代码模块 | 位置 | 说明 | 建议产品确认 |
|
||
|------|----------|------|------|-------------|
|
||
| EXTRA-01 | **evolutionAPI.submitTrajectory** 提供独立的手动轨迹提交入口 | `api/index.ts:453` | 前端API层暴露了轨迹提交方法,但在当前驾驶舱页面中未被任何组件调用 | 是否需要在驾驶舱中增加手动提交轨迹的入口? |
|
||
| EXTRA-02 | **能力维度雷达图使用内联SVG实现** | `EvolutionDashboard.tsx:398-466` | 前端用内联SVG而非第三方图表库绘制雷达图,包含5层参考多边形、轴线、数据多边形 | 技术决策,无需产品确认 |
|
||
|
||
---
|
||
|
||
## 4. 测试用例
|
||
|
||
### 4.1 技能管理 API
|
||
|
||
#### TC-SKILL-01 [P0] 验证获取当前用户技能列表
|
||
- **前置条件**:用户已登录;数据库中存在该用户的技能数据
|
||
- **步骤**:
|
||
[1] 使用有效JWT Token调用 `GET /app/api/evolution/skills`
|
||
[2] 检查响应状态码和结构
|
||
- **预期结果**:
|
||
- HTTP 200,响应包含 `code: 0`
|
||
- `data` 为数组,每项包含 `id, skill_name, description, tags, category, state, use_count, version, created_at, updated_at`
|
||
- 仅返回当前用户的技能数据,不包含其他用户的技能
|
||
- **备注**:默认按 `updated_at` 降序排列
|
||
|
||
#### TC-SKILL-02 [P0] 验证按状态过滤技能
|
||
- **前置条件**:数据库中存在不同状态的技能
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills?state=baby`
|
||
[2] 调用 `GET /app/api/evolution/skills?state=main`
|
||
[3] 调用 `GET /app/api/evolution/skills?state=frozen`
|
||
[4] 调用 `GET /app/api/evolution/skills?state=staging`
|
||
- **预期结果**:
|
||
- 每次返回的技能 `state` 字段均匹配查询参数
|
||
- 传入无效状态值时系统行为一致(返回空列表或400错误)
|
||
- **备注**:P0 覆盖核心过滤逻辑
|
||
|
||
#### TC-SKILL-03 [P0] 验证按关键词搜索技能
|
||
- **前置条件**:数据库中存在技能名包含"python"和"写作"的技能
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills?keyword=python`
|
||
[2] 调用 `GET /app/api/evolution/skills?keyword=写作`
|
||
[3] 调用 `GET /app/api/evolution/skills?keyword=不存在的关键词`
|
||
- **预期结果**:
|
||
- [1][2] 返回 `skill_name` 包含关键词的技能
|
||
- [3] 返回空列表
|
||
- **备注**:模糊匹配
|
||
|
||
#### TC-SKILL-04 [P1] 验证技能列表排序功能
|
||
- **前置条件**:数据库中存在多条技能记录
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills?sort_by=use_count&order=desc`
|
||
[2] 调用 `GET /app/api/evolution/skills?sort_by=created_at&order=asc`
|
||
[3] 调用 `GET /app/api/evolution/skills?sort_by=invalid_field`
|
||
- **预期结果**:
|
||
- [1] 按使用次数降序排列
|
||
- [2] 按创建时间升序排列
|
||
- [3] 返回错误或默认排序回退
|
||
|
||
#### TC-SKILL-05 [P0] 验证获取技能详情
|
||
- **前置条件**:数据库中存在技能名为"fix_python_bug"的技能
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills/fix_python_bug`
|
||
[2] 调用 `GET /app/api/evolution/skills/不存在的技能名`
|
||
- **预期结果**:
|
||
- [1] HTTP 200,返回完整技能信息(含 `skill_md_content` 字段)
|
||
- [2] HTTP 404,提示技能不存在
|
||
- **备注**:如果 `skill_md_path` 文件存在,`skill_md_content` 应包含文件内容
|
||
|
||
#### TC-SKILL-06 [P0] 验证编辑技能元数据
|
||
- **前置条件**:存在可编辑的技能
|
||
- **步骤**:
|
||
[1] 调用 `PUT /app/api/evolution/skills/{skill_name}`,body: `{"description": "新描述", "tags": ["新标签"], "category": "新分类"}`
|
||
[2] 再次获取该技能详情,检查变更
|
||
[3] 检查进化事件表中是否记录了编辑事件
|
||
- **预期结果**:
|
||
- [1] HTTP 200,返回更新后的技能对象,`version` 字段 +1
|
||
- [2] 技能详情反映变更
|
||
- [3] `evolution_events` 表中新增一条 event_type="edited" 的记录,含 version_before/version_after
|
||
- **备注**:仅可编辑 description, tags, category
|
||
|
||
#### TC-SKILL-07 [P0] 验证删除技能
|
||
- **前置条件**:存在可删除的技能
|
||
- **步骤**:
|
||
[1] 记录删除前的技能列表总数 N
|
||
[2] 调用 `DELETE /app/api/evolution/skills/{skill_name}`
|
||
[3] 调用 `GET /app/api/evolution/skills` 检查技能列表
|
||
[4] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认已不存在
|
||
[5] 检查进化事件表中是否记录了删除事件
|
||
- **预期结果**:
|
||
- [2] HTTP 200
|
||
- [3] 技能列表总数为 N-1
|
||
- [4] HTTP 404
|
||
- [5] `evolution_events` 表中新增 event_type="deleted" 的记录
|
||
- **备注**:删除后事件表仍保留历史记录
|
||
|
||
#### TC-SKILL-08 [P0] 验证冻结技能
|
||
- **前置条件**:存在一个 state 为 "main" 的技能
|
||
- **步骤**:
|
||
[1] 调用 `POST /app/api/evolution/skills/{skill_name}/freeze`
|
||
[2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态
|
||
[3] 对已冻结的技能再次调用 freeze
|
||
- **预期结果**:
|
||
- [1] HTTP 200,state 变为 "frozen"
|
||
- [2] state 为 "frozen"
|
||
- [3] 幂等操作,不报错(state 保持 "frozen")
|
||
- 事件表中新增 event_type="frozen" 的记录
|
||
|
||
#### TC-SKILL-09 [P0] 验证解冻技能
|
||
- **前置条件**:存在一个 state 为 "frozen" 的技能
|
||
- **步骤**:
|
||
[1] 调用 `POST /app/api/evolution/skills/{skill_name}/unfreeze`
|
||
[2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态
|
||
- **预期结果**:
|
||
- [1] HTTP 200,state 变为 "main"
|
||
- [2] state 为 "main"
|
||
- 事件表中新增 event_type="unfrozen" 的记录
|
||
|
||
#### TC-SKILL-10 [P1] 验证技能版本历史查询
|
||
- **前置条件**:某技能经历多次编辑/冻结/解冻操作
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills/{skill_name}/history`
|
||
[2] 检查返回的事件列表
|
||
- **预期结果**:
|
||
- HTTP 200,返回按照 `created_at` 排序的事件列表
|
||
- 每项包含 event_type, description, version_before, version_after, created_at
|
||
- 支持未操作过的技能(返回空数组)
|
||
|
||
#### TC-SKILL-11 [P1] 验证技能来源轨迹查询
|
||
- **前置条件**:存在技能和对应的轨迹数据
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/skills/{skill_name}/trajectories`
|
||
- **预期结果**:
|
||
- HTTP 200
|
||
- 返回该技能的关联轨迹列表(最多20条)
|
||
- **备注**:后端 `get_skill_trajectories` 当前仅按 user_id 过滤,未按 skill_name 过滤——此为缺陷,已记录在 3.1 GAP-02
|
||
|
||
---
|
||
|
||
### 4.2 进化事件 API
|
||
|
||
#### TC-EVENT-01 [P0] 验证获取进化事件列表
|
||
- **前置条件**:数据库中已有多条进化事件记录
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/events`
|
||
[2] 检查返回的事件列表
|
||
- **预期结果**:
|
||
- HTTP 200,最多返回50条(默认 limit)
|
||
- 每项包含 id, skill_name, event_type, description, version_before, version_after, created_at
|
||
- 仅返回当前用户的进化事件
|
||
|
||
#### TC-EVENT-02 [P1] 验证按事件类型筛选
|
||
- **前置条件**:数据库中有不同类型的进化事件
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/events?event_type=created`
|
||
[2] 调用 `GET /app/api/evolution/events?event_type=frozen`
|
||
[3] 调用 `GET /app/api/evolution/events?event_type=edited`
|
||
- **预期结果**:每次返回的事件类型均匹配筛选条件
|
||
|
||
#### TC-EVENT-03 [P1] 验证按技能名筛选事件
|
||
- **前置条件**:某技能有多个关联事件
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/events?skill_name={skill_name}`
|
||
- **预期结果**:仅返回该技能相关的进化事件
|
||
|
||
#### TC-EVENT-04 [P2] 验证limit参数边界
|
||
- **前置条件**:数据库中有大量事件记录
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/events?limit=1`
|
||
[2] 调用 `GET /app/api/evolution/events?limit=200`
|
||
[3] 调用 `GET /app/api/evolution/events?limit=201`
|
||
[4] 调用 `GET /app/api/evolution/events?limit=0`
|
||
- **预期结果**:
|
||
- [1] 返回1条
|
||
- [2] 返回最多200条
|
||
- [3] 返回错误或限制到200
|
||
- [4] 返回错误或默认50条
|
||
|
||
---
|
||
|
||
### 4.3 驾驶舱面板 API
|
||
|
||
#### TC-DASH-01 [P0] 验证技能图谱数据 (dashboard/skill-tree)
|
||
- **前置条件**:用户拥有多个分类的技能
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/dashboard/skill-tree`
|
||
[2] 检查返回结构
|
||
- **预期结果**:
|
||
- HTTP 200
|
||
- `data.categories` 为数组,每组包含 `name` 和 `skills[]`
|
||
- `data` 包含统计字段:`total_count, main_count, baby_count, staging_count, frozen_count`
|
||
- 技能数据仅限当前用户
|
||
|
||
#### TC-DASH-02 [P0] 验证进化时间线数据 (dashboard/timeline)
|
||
- **前置条件**:用户有进化事件记录
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/dashboard/timeline`
|
||
[2] 检查返回数据
|
||
- **预期结果**:
|
||
- HTTP 200
|
||
- 返回事件列表,按 created_at 降序
|
||
- 支持 `event_type` 筛选参数
|
||
- 无事件时返回空数组
|
||
|
||
#### TC-DASH-03 [P0] 验证技能使用统计 (dashboard/statistics)
|
||
- **前置条件**:用户有使用统计的历史数据
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/dashboard/statistics`
|
||
[2] 检查返回数据结构
|
||
- **预期结果**:
|
||
- HTTP 200
|
||
- `data` 包含字段:`ranking[]`(TOP N排行)、`total_use_count`、`category_distribution[]`、`daily_trend[]`、`low_use_skills[]`
|
||
- `ranking` 中每项含 `skill_name, category, use_count, state, last_used_at`
|
||
- `daily_trend` 数据点含 `date, count`
|
||
|
||
#### TC-DASH-04 [P0] 验证AI能力画像 (dashboard/profile)
|
||
- **前置条件**:用户有足够的技能数据支撑画像计算
|
||
- **步骤**:
|
||
[1] 调用 `GET /app/api/evolution/dashboard/profile`
|
||
[2] 检查返回结构
|
||
- **预期结果**:
|
||
- HTTP 200
|
||
- `data` 包含字段:`level`(1-10的等级)、`level_title`(等级称号)、`total_skills`、`active_skills`、`staging_skills`、`baby_skills`、`total_use_count`
|
||
- `data.dimensions` 为数组,每项含 `label, value, maxValue`
|
||
- `data.tags` 为能力标签数组
|
||
- `data.growth_suggestions` 为成长建议数组
|
||
|
||
#### TC-DASH-05 [P1] 验证驾驶舱数据空态响应
|
||
- **前置条件**:用户为新用户,无任何进化数据
|
||
- **步骤**:
|
||
[1] 分别调用4个驾驶舱API端点
|
||
[2] 检查响应
|
||
- **预期结果**:均返回 HTTP 200,数据字段为空数组或零值,不报错
|
||
|
||
---
|
||
|
||
### 4.4 轨迹提交 API
|
||
|
||
#### TC-TRAJ-01 [P0] 验证提交对话轨迹
|
||
- **前置条件**:用户已登录
|
||
- **步骤**:
|
||
[1] 调用 `POST /app/api/evolution/trajectory/submit`
|
||
body: `{"conversation_id": "conv-001", "messages": [{"role": "user", "content": "帮我写一个Python函数"}, {"role": "assistant", "content": "好的..."}]}`
|
||
[2] 检查响应
|
||
[3] 检查数据库 `evolution_trajectories` 表中新增记录
|
||
[4] 检查文件系统中轨迹文件是否生成
|
||
- **预期结果**:
|
||
- [1] HTTP 200,`message` 为"轨迹已提交"
|
||
- [2] `data` 包含 id, conversation_id, file_path, status="discovered", atom_count=0
|
||
- [3] 数据库中有新记录,`user_id` 为当前用户
|
||
- [4] 轨迹文件存在于 `/data/share/project/data/users/{user_id}/trajectories/traj_{id}/traj_{id}.md`
|
||
|
||
#### TC-TRAJ-02 [P1] 验证提交轨迹消息格式兼容性
|
||
- **前置条件**:用户已登录
|
||
- **步骤**:
|
||
[1] 提交包含多条轮次对话的轨迹
|
||
[2] 读取生成的轨迹文件内容
|
||
- **预期结果**:
|
||
- 轨迹文件格式为xSkill兼容的Markdown:`# Conversation Trajectory` + `## User` / `## Assistant` 交替分段
|
||
- `token_used` 正确累计所有消息的 tokens 字段
|
||
|
||
#### TC-TRAJ-03 [P1] 验证轨迹提交数据隔离
|
||
- **前置条件**:两个不同用户(userA 和 userB)
|
||
- **步骤**:
|
||
[1] userA 提交一个轨迹
|
||
[2] userB 调用 `GET /app/api/evolution/events` 查询事件
|
||
[3] userB 调用 `GET /app/api/evolution/skills` 查询技能
|
||
- **预期结果**:
|
||
- [2] userB 看不到 userA 的轨迹数据
|
||
- [3] userB 的技能数据不包含 userA 的技能
|
||
|
||
#### TC-TRAJ-04 [P2] 验证提交空消息列表
|
||
- **前置条件**:用户已登录
|
||
- **步骤**:
|
||
[1] 调用 `POST /app/api/evolution/trajectory/submit`,body: `{"conversation_id": "conv-empty", "messages": []}`
|
||
- **预期结果**:
|
||
- 返回成功(或合理的错误提示"消息列表不能为空")
|
||
- 轨迹状态正确记录
|
||
|
||
---
|
||
|
||
### 4.5 数据隔离
|
||
|
||
#### TC-ISOL-01 [P0] 验证用户A不能访问用户B的技能
|
||
- **前置条件**:userA 和 userB 各自有技能数据
|
||
- **步骤**:
|
||
[1] 使用 userA 的Token调用 `GET /app/api/evolution/skills`
|
||
[2] 使用 userB 的Token调用 `GET /app/api/evolution/skills`
|
||
[3] 使用 userA 的Token调用 `GET /app/api/evolution/skills/{userB的skill_name}`
|
||
- **预期结果**:
|
||
- [1] 仅返回 userA 的技能
|
||
- [2] 仅返回 userB 的技能
|
||
- [3] HTTP 404,userA 无法通过猜解技能名获取 userB 的数据
|
||
|
||
#### TC-ISOL-02 [P0] 验证用户A不能操作用户B的技能
|
||
- **前置条件**:userA 和 userB 各自有技能
|
||
- **步骤**:
|
||
[1] 使用 userA 的Token调用 `PUT /app/api/evolution/skills/{userB的skill_name}` 尝试编辑
|
||
[2] 使用 userA 的Token调用 `DELETE /app/api/evolution/skills/{userB的skill_name}` 尝试删除
|
||
[3] 使用 userA 的Token调用 `POST /app/api/evolution/skills/{userB的skill_name}/freeze` 尝试冻结
|
||
- **预期结果**:所有操作返回 HTTP 404(技能不存在),不修改 userB 的数据
|
||
|
||
#### TC-ISOL-03 [P1] 验证用户A不能查看用户B的进化事件
|
||
- **前置条件**:两个用户都有进化事件
|
||
- **步骤**:
|
||
[1] 使用 userA 的Token调用 `GET /app/api/evolution/events`
|
||
[2] 检查返回列表中是否出现 userB 的技能名
|
||
- **预期结果**:不包含任何 userB 相关的事件
|
||
|
||
#### TC-ISOL-04 [P1] 验证用户A不能查看用户B的驾驶舱数据
|
||
- **前置条件**:两个用户都有进化数据
|
||
- **步骤**:
|
||
[1] 使用 userA 的Token分别调用4个驾驶舱API
|
||
[2] 检查返回数据中是否包含 userB 的技能/事件信息
|
||
- **预期结果**:所有驾驶舱API仅返回当前用户的数据
|
||
|
||
---
|
||
|
||
### 4.6 前端—AI进化驾驶舱页面
|
||
|
||
#### TC-FE-01 [P0] 验证驾驶舱页面加载
|
||
- **前置条件**:用户已登录(admin账号)
|
||
- **步骤**:
|
||
[1] 导航到 `#/evolution`
|
||
[2] 观察页面加载过程
|
||
[3] 检查页面标题和统计摘要
|
||
- **预期结果**:
|
||
- 页面正常渲染,显示"AI进化驾驶舱"标题
|
||
- 加载过程中显示 loading spinner + "正在加载进化数据..." 文字
|
||
- 加载完成后显示统计数字(技能总数/已成熟/萌芽中)
|
||
- Console 无JS错误
|
||
|
||
#### TC-FE-02 [P0] 验证技能图谱面板(Panel A)
|
||
- **前置条件**:用户有技能数据
|
||
- **步骤**:
|
||
[1] 切换到"技能图谱"面板
|
||
[2] 检查技能节点展示
|
||
[3] 鼠标悬停在技能节点上
|
||
[4] 点击某个技能节点
|
||
- **预期结果**:
|
||
- 技能按 category 分组展示,不同状态用不同颜色标识(baby=粉色/main=绿色/staging=橙色/frozen=灰色)
|
||
- hover 显示 tooltip(技能名+描述+版本+更新时间)
|
||
- 点击弹出详情弹窗(名称/状态/版本/使用次数/分类/标签/操作按钮)
|
||
- 底部有状态色标图例
|
||
- 无技能时显示空态
|
||
|
||
#### TC-FE-03 [P0] 验证进化时间线面板(Panel B)
|
||
- **前置条件**:用户有进化事件数据
|
||
- **步骤**:
|
||
[1] 切换到"进化时间线"面板
|
||
[2] 检查时间线布局
|
||
[3] 点击不同的筛选按钮(全部/诞生/晋升/里程碑/更新/冻结/退回)
|
||
[4] 检查事件卡片内容
|
||
- **预期结果**:
|
||
- 垂直时间线展示,左侧圆点+连接线,右侧卡片
|
||
- 卡片显示:事件类型+技能名+描述+时间戳
|
||
- 筛选按钮正常工作,筛选结果正确
|
||
- 无事件时显示空态
|
||
|
||
#### TC-FE-04 [P0] 验证技能使用统计面板(Panel C)
|
||
- **前置条件**:用户有使用统计数据
|
||
- **步骤**:
|
||
[1] 切换到"技能使用统计"面板
|
||
[2] 检查技能使用排行
|
||
[3] 检查调用趋势图
|
||
[4] 检查类别分布饼图
|
||
[5] 检查低使用技能提醒(如有)
|
||
- **预期结果**:
|
||
- 排行条形图正常渲染,Top 3 带紫色渐变标记
|
||
- 趋势柱状图显示 Top 4 技能
|
||
- 饼图中心显示总调用次数,图例显示各分类占比
|
||
- 超过30天未使用的技能显示黄色警告提醒
|
||
- 无数据时显示"暂无数据"
|
||
- Panel切换时按需加载统计数据
|
||
|
||
#### TC-FE-05 [P0] 验证AI能力画像面板(Panel D)
|
||
- **前置条件**:用户有足够的技能数据
|
||
- **步骤**:
|
||
[1] 切换到"AI能力画像"面板
|
||
[2] 检查等级卡片
|
||
[3] 检查能力雷达图
|
||
[4] 检查能力标签云
|
||
[5] 检查成长建议
|
||
- **预期结果**:
|
||
- 等级卡片显示环形进度条(level/10)+ 等级数字 + 称号 + 四项统计
|
||
- 雷达图显示能力维度(文字创作/数据分析/代码能力/知识问答/流程自动化/创意生成等)
|
||
- 标签云有4级尺寸和6种颜色循环
|
||
- 成长建议列表以黄色星标开头
|
||
- 无画像数据时显示空态
|
||
|
||
#### TC-FE-06 [P1] 验证面板切换
|
||
- **前置条件**:页面已加载
|
||
- **步骤**:
|
||
[1] 依次点击4个面板切换按钮
|
||
[2] 来回切换 panels
|
||
[3] 切换过程中检查加载状态
|
||
- **预期结果**:
|
||
- 面板切换流畅,当前面板高亮
|
||
- statistics 和 profile 面板首次进入时显示"加载中..."
|
||
- 返回已加载过的面板不重新请求数据
|
||
|
||
#### TC-FE-07 [P1] 验证错误状态和重试
|
||
- **前置条件**:页面已加载
|
||
- **步骤**:
|
||
[1] 模拟后端API返回错误(或断开网络)
|
||
[2] 观察页面反应
|
||
[3] 点击"重试"按钮
|
||
- **预期结果**:
|
||
- 页面显示错误消息
|
||
- "重试"按钮可见且可用
|
||
- 点击"重试"重新发起API请求
|
||
|
||
#### TC-FE-08 [P1] 验证未登录状态
|
||
- **前置条件**:用户未登录
|
||
- **步骤**:
|
||
[1] 清除 localStorage 中的 token
|
||
[2] 导航到 `#/evolution`
|
||
- **预期结果**:自动重定向到 `#/login`
|
||
|
||
#### TC-FE-09 [P2] 验证CSS样式完整性
|
||
- **前置条件**:页面正常加载
|
||
- **步骤**:
|
||
[1] 检查所有面板的CSS类名是否存在
|
||
[2] 检查loading spinner动画是否流畅
|
||
[3] 检查响应式布局(不同分辨率下)
|
||
- **预期结果**:
|
||
- 所有CSS类在 `EvolutionDashboard.css` 中有定义
|
||
- 旋转动画正常工作
|
||
- 各分辨率下布局正常
|
||
|
||
---
|
||
|
||
### 4.7 前端—技能管理UI(技能详情弹窗中的操作)
|
||
|
||
#### TC-FE-MGR-01 [P1] 验证技能详情弹窗中显示操作按钮
|
||
- **前置条件**:在技能图谱面板中点击某技能节点
|
||
- **步骤**:
|
||
[1] 检查弹窗内容
|
||
[2] 确认操作按钮可见
|
||
- **预期结果**:
|
||
- 弹窗显示技能完整信息
|
||
- 包含编辑/删除/冻结(或解冻)等操作按钮
|
||
- 操作按钮根据技能状态正确切换(已冻结显示"解冻",否则显示"冻结")
|
||
|
||
#### TC-FE-MGR-02 [P1] 验证前端调用冻结API
|
||
- **前置条件**:弹窗中显示"冻结"按钮
|
||
- **步骤**:
|
||
[1] 点击"冻结"按钮
|
||
[2] 观察反馈
|
||
[3] 刷新技能列表确认状态变化
|
||
- **预期结果**:
|
||
- API调用 `/app/api/evolution/skills/{name}/freeze` 成功
|
||
- 技能状态变为"frozen"
|
||
- 前端显示操作成功提示
|
||
|
||
#### TC-FE-MGR-03 [P1] 验证前端调用删除API
|
||
- **前置条件**:弹窗中显示"删除"按钮
|
||
- **步骤**:
|
||
[1] 点击"删除"按钮
|
||
[2] 确认删除(如有确认弹窗)
|
||
[3] 观察技能列表变化
|
||
- **预期结果**:
|
||
- API调用 `DELETE /app/api/evolution/skills/{name}` 成功
|
||
- 技能从列表中移除
|
||
- 前端显示删除成功提示
|
||
|
||
---
|
||
|
||
### 4.8 数据库表结构验证
|
||
|
||
#### TC-DB-01 [P0] 验证 evolution_skills 表结构
|
||
- **前置条件**:数据库连接正常
|
||
- **步骤**:
|
||
[1] 查询表结构
|
||
[2] 验证所有字段存在且类型正确
|
||
- **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), skill_name, description, tags(JSON), category, state, use_count, version, skill_md_path, git_commit_sha, last_used_at, created_at, updated_at
|
||
|
||
#### TC-DB-02 [P0] 验证 evolution_events 表结构
|
||
- **前置条件**:数据库连接正常
|
||
- **步骤**:
|
||
[1] 查询表结构
|
||
- **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), skill_name, event_type, description, version_before, version_after, created_at
|
||
|
||
#### TC-DB-03 [P0] 验证 evolution_trajectories 表结构
|
||
- **前置条件**:数据库连接正常
|
||
- **步骤**:
|
||
[1] 查询表结构
|
||
- **预期结果**:表包含字段: id(PK), user_id(FK+INDEX), conversation_id, file_path, status, atom_count, token_used, created_at, processed_at
|
||
|
||
#### TC-DB-04 [P0] 验证 user_evolution_config 表结构
|
||
- **前置条件**:数据库连接正常
|
||
- **步骤**:
|
||
[1] 查询表结构
|
||
- **预期结果**:表包含字段: id(PK), user_id(FK+UNIQUE+INDEX), skill_dir_path, trajectory_dir_path, watcher_status, created_at, updated_at
|
||
|
||
---
|
||
|
||
### 4.9 技能状态流转验证
|
||
|
||
#### TC-STATE-01 [P0] 验证技能状态 baby → main
|
||
- **前置条件**:存在 state="baby" 的技能
|
||
- **步骤**:
|
||
[1] 通过数据层直接更新该技能 state="main"
|
||
[2] 调用 `GET /app/api/evolution/skills/{skill_name}` 确认状态
|
||
- **预期结果**:状态成功变更为 main
|
||
|
||
#### TC-STATE-02 [P0] 验证技能状态 main → staging → main
|
||
- **前置条件**:存在 state="main" 的技能
|
||
- **步骤**:
|
||
[1] 更新 state="staging"
|
||
[2] 查询确认
|
||
[3] 更新 state="main"
|
||
[4] 查询确认
|
||
- **预期结果**:状态变更成功
|
||
|
||
#### TC-STATE-03 [P0] 验证技能状态 main → frozen → main
|
||
- **前置条件**:存在 state="main" 的技能
|
||
- **步骤**:
|
||
[1] 调用 freeze API
|
||
[2] 确认 state="frozen"
|
||
[3] 调用 unfreeze API
|
||
[4] 确认 state="main"
|
||
- **预期结果**:完整走通 freeze→unfreeze 循环,事件表记录完整
|
||
|
||
---
|
||
|
||
## 5. 测试用例统计
|
||
|
||
| 类别 | P0 | P1 | P2 | 合计 |
|
||
|------|----|----|----|------|
|
||
| 技能管理 API | 7 | 2 | 0 | 9 |
|
||
| 进化事件 API | 1 | 2 | 1 | 4 |
|
||
| 驾驶舱面板 API | 4 | 1 | 0 | 5 |
|
||
| 轨迹提交 API | 1 | 2 | 1 | 4 |
|
||
| 数据隔离 | 2 | 2 | 0 | 4 |
|
||
| 前端驾驶舱页面 | 4 | 3 | 1 | 8 |
|
||
| 前端技能管理UI | 0 | 3 | 0 | 3 |
|
||
| 数据库表结构 | 4 | 0 | 0 | 4 |
|
||
| 技能状态流转 | 3 | 0 | 0 | 3 |
|
||
| **合计** | **26** | **15** | **3** | **44** |
|
||
|
||
---
|
||
|
||
## 6. PRD未覆盖的代码功能模块(需产品确认)
|
||
|
||
| 编号 | 模块 | 代码位置 | 建议确认项 |
|
||
|------|------|----------|-----------|
|
||
| EXTRA-01 | 独立轨迹提交API | `api/index.ts:453` | 驾驶舱页面是否需要手动轨迹提交入口? |
|
||
| EXTRA-02 | SVG内联雷达图 | `EvolutionDashboard.tsx:398-466` | 技术决策,无需产品确认 |
|
||
|
||
---
|
||
|
||
## 7. 测试环境要求
|
||
|
||
- **后端服务**:Python FastAPI 服务运行于 localhost:18080
|
||
- **前端服务**:React 应用通过 Nginx 代理运行于 8080 端口
|
||
- **数据库**:MySQL 8 (localhost:3306, root/pwd2026)
|
||
- **认证方式**:JWT Bearer Token,通过 POST /app/api/auth/login 获取
|
||
- **测试用户**:admin (管理员), demo_user (普通用户)
|
||
|
||
---
|
||
|
||
> **文档生成时间**:2026-05-29
|
||
> **文档版本**:v1.0
|
||
> **基于代码版本**:evolution.py (215行) + evolution_service.py (473行) + EvolutionDashboard.tsx (631行)
|
||
> **PRD版本**:v1.0 (2026-05-26)
|