初始提交: Qihu-AIFlow v2.0.1 完整项目

- 前端 React+TypeScript (源码+构建产物)
- 后端 Python FastAPI
- 数据库迁移 001-015
- Docker部署配置
- 微信ClawBot API频道绑定
- 项目文档 README.md
This commit is contained in:
qyyfw committed 2026-07-02 14:40:46 +08:00
commit 78ff261b5a
199 files changed
+69126

No files matched your search

+449
View File
@@ -0,0 +1,449 @@
# AI自进化第二版 (v2) - 测试用例报告
## 文档信息
| 项目 | 详情 |
|------|------|
| **测试对象** | AIFlow AI自进化模块 v2 迭代 |
| **测试阶段** | 第一阶段 - 测试用例生成 |
| **测试工程师** | QA Engineer |
| **文档日期** | 2026-05-30 |
| **基于文档** | PRD-self-evolution-v2.md |
| **基于代码** | evolution.py (348行), evolution_service.py (1220行), models.py (739-889行), EvolutionDashboard.tsx (1015行), EvolutionDashboard.css, ChatPage.tsx, api/index.ts |
---
## 1. 版本变更概览
### 1.1 PRD vs 实际代码实现对照
PRD v2 规划了 10 大功能、9 个新增 API端点、4 张新增表、5 个现有表新增字段。代码实现了其中大部分功能,但存在具体差异如下:
| PRD规划 | 代码实现状态 |
|----------|-------------|
| xSkill流水线自动调度 (P0) | ✅ 已实现 PipelineScheduler (service层, 54-232行) |
| Watcher线程管理 (P0) | ✅ 已实现 EvolutionWatcherManager 单例 (235-374行) |
| 技能回滚 (P0) | ✅ 已实现 rollback API + 前端UI (evolution.py:229, EvolutionDashboard.tsx:101-114) |
| 萌芽动画 (P1) | ✅ 已实现 baby-sprout/staging-breathe CSS动画 (EvolutionDashboard.css:1020-1580) |
| 时间线导出 (P1) | ✅ 已实现导出菜单+模拟导出 (EvolutionDashboard.tsx:370-383) |
| 画像分享卡片 (P1) | ✅ 已实现3主题卡片+分享动作 (EvolutionDashboard.tsx:572-691) |
| Skill加载提示标签 (P1) | ✅ 已实现 (ChatPage.tsx:710-740, chat.py:238-250) |
| 技能市场联动 (P2) | ✅ 已实现 publish_to_market + 前端发布UI |
| 团队共享进化 (P2) | ✅ 已实现 share_to_team + 前端共享API |
| 进化报告推送 (P2) | ✅ 已实现 EvolutionReport 模型 + generate_report + ReportsPanel 前端 |
### 1.2 API端点对比
PRD v2 规划新增9个端点:
| PRD规划端点 | 方法 | 实际代码路径 | 状态 |
|------------|------|-------------|------|
| `/skills/{name}/rollback/{version}` | POST | `/evolution/skills/{skill_name}/rollback/{version}` (evolution.py:229) | ✅ 已实现 |
| `/skills/{name}/versions` | GET | **不存在**: 仅有 `/skills/{skill_name}/history` (返回事件列表) | ❌ **缺失, GAP** |
| `/skills/{name}/publish` | POST | `/evolution/skills/{skill_name}/publish` (evolution.py:244) | ✅ 已实现 |
| `/reports/generate` | POST | **不存在**: generate_report() 仅在service层定义, 无API暴露 | ❌ **缺失, GAP** |
| `/reports` | GET | `/evolution/reports` (evolution.py:307) | ✅ 已实现 |
| `/reports/{id}` | GET | `/evolution/reports/{report_id}` (evolution.py:318) | ✅ 已实现 |
| `/watcher/status` | GET | `/evolution/watcher/status` (evolution.py:296) | ✅ 已实现 |
| `/watcher/restart` | POST | **不存在**: restart逻辑仅在 `/pipeline/trigger` 中内联调用 (evolution.py:291) | ❌ **缺失, GAP** |
| `/team/sync` | POST | **不存在**: 仅有 `/skills/{name}/share-to-team` (单个技能共享) | ❌ **缺失, GAP** |
**代码额外实现但PRD未要求**:
| 端点 | 方法 | 说明 |
|------|------|------|
| `/evolution/pipeline/status` | GET | 流水线状态查询 - PRD v2 5.2 中规划, 但用户测试范围未列 |
| `/evolution/pipeline/trigger` | POST | 手动触发流水线 - PRD v2 5.2 中规划, 但用户测试范围未列 |
| `/evolution/skills/{name}/share-to-team` | POST | 团队共享 - PRD 5.4 中规划, 替代 team/sync |
| `/evolution/admin/watchers` | GET | 管理员全平台watcher汇总 |
### 1.3 数据库变更对比
| PRD 规划表 | 表名 | 状态 |
|-----------|------|------|
| 现有表新增字段 | `evolution_trajectories.error_msg` | ✅ 模型已定义 (models.py:795) |
| 现有表新增字段 | `evolution_trajectories.retry_count` | ✅ 模型已定义 (models.py:796) |
| 现有表新增字段 | `evolution_trajectories.tasks_extracted` | ✅ 模型已定义 (models.py:797) |
| 现有表新增字段 | `messages.used_skills` | ✅ 模型已定义 (models.py:100) |
| 现有表新增字段 | `user_evolution_config.watcher_error` | ✅ 模型已定义 (models.py:749) |
| 新增表 | `skill_versions` | ✅ 模型已定义 (models.py:818-833), ❌ **数据库中不存在** |
| 新增表 | `evolution_reports` | ✅ 模型已定义 (models.py:836-850), ❌ **数据库中不存在** |
| 新增表 | `skill_publish_records` | ✅ 模型已定义 (models.py:853-871), ❌ **数据库中不存在** |
| 新增表 | `team_shared_skills` | ✅ 模型已定义 (models.py:874-888), ❌ **数据库中不存在** |
**严重问题**: 4张v2新增表在SQLAlchemy models中已定义,但实际MySQL数据库中未创建。这意味着:技能回滚需要 `skill_versions` 表、进化报告需要 `evolution_reports` 表、市场发布需要 `skill_publish_records` 表、团队共享需要 `team_shared_skills` 表。这些功能在表未创建的情况下将无法正常运行。
同样,现有表的5个新字段在模型层面已定义,但数据库层面未通过 `DESC` 验证确认存在(`DESC messages` 未显示 `used_skills`、`DESC evolution_trajectories` 未显示 `error_msg/retry_count/tasks_extracted`、`DESC user_evolution_config` 未显示 `watcher_error`)。
---
## 2. 测试范围与分类
### 2.1 测试分类维度
| 维度 | 说明 |
|------|------|
| **P0 核心引擎** | xSkill流水线调度、Watcher管理、技能回滚 |
| **P1 体验增强** | 萌芽动画、时间线导出、画像分享、Skill标签 |
| **P2 业务联动** | 技能市场联动、进化报告推送 |
| **API端点** | 9个新增API + 流水线/团队共享API |
| **数据库** | 4张新表 + 5个新字段 |
| **前端交互** | 6大前端功能模块 |
### 2.2 统计摘要
| 类别 | 数量 |
|------|------|
| 功能模块 | 10 |
| API端点 | 15(含PRD规划的9个 + 代码额外实现的6个) |
| P0测试用例 | 26 |
| P1测试用例 | 28 |
| P2测试用例 | 21 |
| 数据库测试用例 | 7 |
| 数据隔离测试用例 | 6 |
| **测试用例总计** | **88** |
| PRD未覆盖代码功能 (GAP) | 9 |
| 代码未实现PRD需求 (缺失) | 4 |
---
## 3. P0 核心引擎类 - 测试用例
### 3.1 xSkill流水线自动调度 (PipelineScheduler)
#### API: GET /evolution/pipeline/status
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-001 | P0 | 获取流水线状态 - 正常运行 | 用户已登录, watcher已启动 | GET /app/api/evolution/pipeline/status | 返回200, code=0, data包含scheduler_running/watcher_status/pipeline_status/discovered_count/done_count/total_skills/total_trajectories |
| TC-EVO-V2-P0-002 | P0 | 获取流水线状态 - 未启动 | 用户已登录, watcher未启动 | GET /app/api/evolution/pipeline/status | 返回200, code=0, scheduler_running=false, watcher_status=unknown/stopped |
| TC-EVO-V2-P0-003 | P1 | 未登录访问流水线状态 | 无认证token | GET /app/api/evolution/pipeline/status | 返回401 |
| TC-EVO-V2-P0-004 | P1 | 流水线状态数据隔离 | user_a登录查看 | GET /app/api/evolution/pipeline/status | 返回仅user_a的数据,不包含其他用户的数据 |
#### API: POST /evolution/pipeline/trigger
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-005 | P0 | 手动触发流水线 | 用户已登录 | POST /app/api/evolution/pipeline/trigger | 返回200, code=0, message="流水线已触发", watcher重新启动 |
| TC-EVO-V2-P0-006 | P1 | 未登录触发流水线 | 无认证token | POST /app/api/evolution/pipeline/trigger | 返回401 |
#### PipelineScheduler 功能逻辑
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-007 | P0 | 轨迹自动状态流转 discovered->splitting->split_done->indexed->clustering->done | 创建一条status=discovered的轨迹, watcher运行中 | 等待PipelineScheduler扫描处理 | 轨迹依次经历6个状态, 最终status=done, processed_at非空 |
| TC-EVO-V2-P0-008 | P0 | AtomTask拆分模拟 - tasks_extracted更新 | 轨迹处理中 | 查看轨迹tasks_extracted字段 | tasks_extracted值为2-5(模拟生成的atom数量) |
| TC-EVO-V2-P0-009 | P0 | 轨迹处理创建SkillTrajectoryLink | 轨迹处理完成 | 查询skill_trajectory_links表 | 为每个atom创建了关联记录, skill_name为__pending__或真实技能名 |
| TC-EVO-V2-P0-010 | P0 | 新轨迹归类到已有技能 | 用户已有至少1个技能 | 提交新轨迹并等待处理 | 轨迹的SkillTrajectoryLink指向已有技能, 技能use_count+1 |
| TC-EVO-V2-P0-011 | P0 | 新轨迹创建新baby技能 | 用户无任何技能 | 提交新轨迹并等待处理 | 创建新baby技能new_skill_XXXXXXX, state=baby, version=1 |
| TC-EVO-V2-P0-012 | P0 | 候选轨迹>=3自动baby->staging晋升 | 某baby技能关联轨迹>=3 | PipelineScheduler处理更多轨迹 | 技能state自动从baby变为staging, 记录promoted事件 |
| TC-EVO-V2-P0-013 | P0 | 轨迹处理失败 - error状态 | 模拟处理异常 (数据库连接中断等) | 轨迹处理失败 | 轨迹status=error, error_msg记录失败原因, retry_count递增 |
| TC-EVO-V2-P0-014 | P1 | 轨迹处理重试机制 | 轨迹之前失败过(retry_count<3) | PipelineScheduler再次扫描 | 尝试重新处理该轨迹 |
| TC-EVO-V2-P0-015 | P1 | PipelineScheduler停止信号 | scheduler正在运行 | 调用scheduler.stop() | _stop被设置, _run_loop退出, 线程终止 |
| TC-EVO-V2-P0-016 | P1 | PipelineScheduler扫描间隔 | scheduler运行 | 观察扫描日志间隔 | 扫描间隔为poll_interval(默认30s) |
### 3.2 Watcher线程管理 (EvolutionWatcherManager)
#### API: GET /evolution/watcher/status
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-017 | P0 | 获取Watcher状态 | 用户已登录, watcher已启动 | GET /app/api/evolution/watcher/status | 返回200, data包含watcher_status/pipeline_status/pipeline_processed/scheduler_running/skill_count/trajectory_count |
| TC-EVO-V2-P0-018 | P1 | Watcher状态数据隔离 | user_a和user_b分别查询 | 分别GET /app/api/evolution/watcher/status | 返回各自的数据, 互不包含 |
| TC-EVO-V2-P0-019 | P2 | 管理员查看全平台watcher | 管理员登录 | GET /app/api/evolution/admin/watchers | 返回200, data包含所有在运行scheduler的用户ID和运行状态 |
#### WatcherManager 功能逻辑
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-020 | P0 | 启动用户进化引擎 (start_user_evolution) | 新用户无scheduler | 调用WatcherManager.start_user_evolution() | scheduler被创建并启动, user_evolution_config表watcher_status=running, pipeline_status=running |
| TC-EVO-V2-P0-021 | P0 | 重复启动已运行的进化引擎 | 用户engin已运行 | 再次调用start | 返回False, 提示已在运行 |
| TC-EVO-V2-P0-022 | P0 | 停止用户进化引擎 (stop_user_evolution) | 用户engin运行中 | 调用WatcherManager.stop_user_evolution() | scheduler线程停止, 从_schedulers移除, config表更新为stopped/idle |
| TC-EVO-V2-P0-023 | P0 | 重启用户进化引擎 (restart_user_evolution) | 用户已运行 | 调用restart → 通过POST /evolution/pipeline/trigger触发 | scheduler先停止再启动, pipeline_status重新变为running |
| TC-EVO-V2-P0-024 | P1 | 达到最大scheduler限制 | 已有100个scheduler运行 | 新用户尝试启动 | 返回False, 提示达到数量限制 |
| TC-EVO-V2-P0-025 | P1 | 优雅关闭所有scheduler | 多个scheduler运行中 | 调用shutdown_all() | 所有scheduler依次停止, 日志记录关闭过程 |
| TC-EVO-V2-P0-026 | P1 | watcher_error 字段写入 | 更新用户进化配置失败场景 | 触发配置更新失败 | user_evolution_config.watcher_error 记录异常信息 |
### 3.3 技能回滚 (Skill Rollback)
#### API: POST /evolution/skills/{skill_name}/rollback/{version}
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-027 | P0 | 回滚技能到指定版本 | skill已存在, skill_versions表有目标版本记录, version=3 | POST /app/api/evolution/skills/{name}/rollback/1 | 返回200, code=0, data包含回滚后的技能信息, version变为4 (3+1) |
| TC-EVO-V2-P0-028 | P0 | 回滚后SKILL.md内容恢复 | 同上, skill_md_path存在 | POST rollback | SKILL.md文件被目标版本内容覆盖, 回滚前内容作为快照存入skill_versions |
| TC-EVO-V2-P0-029 | P0 | 回滚后事件记录 | 回滚操作完成 | 查询evolution_events表 | 记录event_type="rolled_back", version_before=回滚前, version_after=回滚后, description含回滚版本信息 |
| TC-EVO-V2-P0-030 | P0 | 技能不存在 | skill不存在 | POST /app/api/evolution/skills/nonexistent_skill/rollback/1 | 返回404, "技能或版本不存在" |
| TC-EVO-V2-P0-031 | P0 | 目标版本不存在 | skill存在但目标版本无记录 | POST rollback to non-existing version | 返回404, "技能或版本不存在" |
| TC-EVO-V2-P0-032 | P1 | 未登录回滚 | 无认证 | POST rollback | 返回401 |
#### 前端: VersionHistoryModal + 回滚确认
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P0-033 | P0 | 版本历史弹窗打开 | 技能详情弹窗中 | 点击「版本历史」按钮 | 弹出版本历史弹窗, 显示事件列表(时间线格式), 每条含版本号/事件类型/时间/描述 |
| TC-EVO-V2-P0-034 | P0 | 版本历史加载中状态 | 点击版本历史 | API请求中 | 显示"加载中..."文字 |
| TC-EVO-V2-P0-035 | P0 | 版本历史空状态 | skill无历史事件 | 打开版本历史 | 显示"暂无版本历史" |
| TC-EVO-V2-P0-036 | P0 | 当前版本标识 | 多个版本存在 | 查看版本历史 | 当前版本行显示"当前"标签, 非当前版本行才显示"回滚到此版本"按钮 |
| TC-EVO-V2-P0-037 | P0 | 回滚确认弹窗 | 点击非当前版本的「回滚到此版本」按钮 | 弹出确认弹窗 | 弹窗标题「确认回滚?」, 显示目标版本和当前版本号对比 |
| TC-EVO-V2-P0-038 | P0 | 确认回滚操作 | 回滚确认弹窗打开 | 点击「确认回滚」按钮 | 调用API, 成功后显示toast提示, 关闭弹窗 |
| TC-EVO-V2-P0-039 | P0 | 取消回滚 | 回滚确认弹窗打开 | 点击「取消」按钮 | 关闭确认弹窗, 不调用API |
| TC-EVO-V2-P0-040 | P1 | 回滚失败toast | API返回错误 | 确认回滚 | 显示红色toast "回滚失败: {错误原因}" |
---
## 4. P1 体验增强类 - 测试用例
### 4.1 萌芽动画 (Baby/Staging Animations)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-001 | P1 | baby技能萌芽脉冲动画 | 存在state=baby的技能, 动画开关=ON | 查看技能图谱面板 | baby技能节点周期性缩放脉冲 scale(1.0→1.15→1.0) 周期2s, 粉色光晕淡入淡出 |
| TC-EVO-V2-P1-002 | P1 | staging技能呼吸动画 | 存在state=staging的技能, 动画开关=ON | 查看技能图谱面板 | staging技能节点呼吸动画 scale(1.0→1.08→1.0) 周期3s, 橙色脉冲 |
| TC-EVO-V2-P1-003 | P1 | 动画被关闭 | 动画开关=OFF | 查看技能图谱面板 | baby/staging技能节点静态显示, 无CSS动画效果 |
| TC-EVO-V2-P1-004 | P1 | 动画开关开关切换 | 默认动画开启 | 点击「动画效果」开关 | 动画立即开/关, CSS class变化 |
| TC-EVO-V2-P1-005 | P1 | 动画偏好持久化 | 关闭动画 | 刷新页面重新加载驾驶舱 | 动画仍保持关闭状态 (localStorage evo_anim_enabled=false) |
| TC-EVO-V2-P1-006 | P2 | 无baby/staging技能时 | 所有技能均为main/frozen | 查看技能图谱面板 | 所有节点静态显示, 无动画播放 |
| TC-EVO-V2-P1-007 | P2 | main/frozen技能无动画 | 各种状态的技能混合 | 检查main/frozen节点 | main和frozen技能节点无CSS animation |
### 4.2 时间线导出 (Timeline Export)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-008 | P1 | 导出按钮显示 | 进化时间线面板激活 | 查看面板右上角 | 显示「导出」按钮 |
| TC-EVO-V2-P1-009 | P1 | 导出下拉菜单 | 点击「导出」按钮 | 展开下拉菜单 | 显示两项: 「导出为 PNG」和「导出为 PDF」 |
| TC-EVO-V2-P1-010 | P1 | PNG导出触发 | 点击「导出为 PNG」 | 触发导出 | 显示"导出中..."按钮状态, 完成后显示toast: "时间线已导出为 PNG 格式: AI进化时间线_{用户名}_{日期}.png" |
| TC-EVO-V2-P1-011 | P1 | PDF导出触发 | 点击「导出为 PDF」 | 触发导出 | 同上, 格式为PDF |
| TC-EVO-V2-P1-012 | P1 | 时间范围选择器 | 时间线面板 | 使用下拉菜单选择 | 有3个选项: 全部时间 / 最近30天 / 最近7天, 选择后时间线自动筛选 |
| TC-EVO-V2-P1-013 | P1 | 导出遵循当前筛选 | 设置时间范围「最近7天」+ 事件类型「promoted」 | 点击导出 | 导出内容仅包含最近7天的promoted事件 (所见即所得) |
| TC-EVO-V2-P1-014 | P2 | 导出时空时间线 | 筛选后无事件 | 点击导出 | toast仍显示成功 (导出空白时间线) |
| TC-EVO-V2-P1-015 | P2 | 导出按钮disabled状态 | 正在导出中 | 查看导出按钮 | 按钮显示"导出中..."且disabled |
### 4.3 画像分享卡片 (Profile Share Card)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-016 | P1 | 分享按钮存在 | AI能力画像面板激活 | 查看面板右上角 | 显示「分享画像」按钮 (share图标) |
| TC-EVO-V2-P1-017 | P1 | 分享弹窗打开 | 点击「分享画像」 | 弹出分享弹窗 | 弹窗标题「AI能力画像分享」, 显示卡片预览+主题切换+操作按钮 |
| TC-EVO-V2-P1-018 | P1 | 3种主题切换 | 分享弹窗内 | 依次点击「深空蓝」「极光绿」「暖阳橙」主题 | 卡片背景色和各元素配色切换为对应主题 |
| TC-EVO-V2-P1-019 | P1 | 卡片内容完整性 | 分享卡片预览 | 查看卡片 | 包含: 平台Logo + 标题「我的AI进化画像」 + 等级环 + 维度条 + 标签云(最多6个) + 日期水印「Qihu-AIFlow」 |
| TC-EVO-V2-P1-020 | P1 | 保存到相册 | 分享弹窗 | 点击「保存到相册」按钮 | 关闭弹窗, toast显示"画像卡片已保存到相册(模拟)" |
| TC-EVO-V2-P1-021 | P1 | 复制图片 | 分享弹窗 | 点击「复制图片」按钮 | 关闭弹窗, toast显示"画像卡片已复制图片(模拟)" |
| TC-EVO-V2-P1-022 | P2 | 关闭分享弹窗 | 分享弹窗打开 | 点击背景或关闭按钮 | 弹窗关闭 |
| TC-EVO-V2-P1-023 | P2 | 隐私保护验证 | 分享卡片预览 | 检查卡片内容 | 卡片仅包含聚合数据(等级/维度/标签), 不包含具体技能名称或对话内容 |
### 4.4 Skill加载提示标签 (Used Skills Tags)
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P1-024 | P1 | 标签显示 | 用户有main状态技能, AI对话回复 | 发送消息等待AI回复 | AI回复气泡下方显示标签, 格式: 图标 + "使用了专属技能:{技能名}" |
| TC-EVO-V2-P1-025 | P1 | 多技能标签展示(<=3个) | AI使用了2-3个技能 | 查看回复下方 | 2-3个标签横向排列 |
| TC-EVO-V2-P1-026 | P1 | 多技能标签展示(>3个) | AI使用了4+个技能 | 查看回复下方 | 显示3个技能标签 + "+N" 折叠标签 |
| TC-EVO-V2-P1-027 | P1 | 标签点击跳转 | 消息下方有技能标签 | 点击技能标签 | 跳转到 #/evolution?skill={技能名} |
| TC-EVO-V2-P1-028 | P1 | 无技能时不显示标签 | 用户无main状态技能, 发送消息 | 查看AI回复 | AI回复下方无标签区域 |
| TC-EVO-V2-P1-029 | P1 | 聊天API返回used_skills字段 | 发送消息 | 检查API响应 | assistant_message.used_skills 存在, 为字符串数组 |
| TC-EVO-V2-P1-030 | P1 | 技能使用后use_count更新 | 某技能被used_skills触发 | 查询该技能详情 | use_count+1, last_used_at更新为当前时间 |
| TC-EVO-V2-P1-031 | P2 | 标签样式 | 有技能标签的消息 | 查看UI | 标签为圆角样式, 左侧图标, 底色半透明 |
---
## 5. P2 业务联动类 - 测试用例
### 5.1 技能市场联动 (Publish to Market)
#### API: POST /evolution/skills/{skill_name}/publish
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-001 | P2 | 发布main技能到市场 | skill state=main, 未发布过 | POST /app/api/evolution/skills/{name}/publish, body: {price: 0, market_description: "测试发布"} | 返回200, code=0, data含market_app_id, price, status="published" |
| TC-EVO-V2-P2-002 | P2 | 非main状态发布失败 | skill state=baby/staging | POST publish | 返回404/error, 提示只有main状态技能可发布 |
| TC-EVO-V2-P2-003 | P2 | 重复发布检测 | skill已发布过 | POST publish | 返回error, "该技能已发布到市场,不能重复发布" |
| TC-EVO-V2-P2-004 | P2 | 发布后在market_apps表创建记录 | 发布成功 | 查询market_apps表 | 创建一条type=skill, source=user的记录, name="{技能名}(进化)" |
| TC-EVO-V2-P2-005 | P2 | 发布后在skill_publish_records表创建记录 | 发布成功 | 查询skill_publish_records表 | 创建一条status=published的记录 |
| TC-EVO-V2-P2-006 | P2 | 发布后事件记录 | 发布成功 | 查询evolution_events | 记录event_type="published" |
| TC-EVO-V2-P2-007 | P2 | 技能不存在 | skill不存在 | POST publish | 返回404 |
| TC-EVO-V2-P2-008 | P2 | 未登录发布 | 无认证 | POST publish | 返回401 |
#### 前端: 发布按钮+发布表单
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-009 | P2 | main技能显示发布按钮 | 技能详情弹窗, skill.state=main | 查看操作按钮区域 | 显示「发布到市场」按钮(金色边框) |
| TC-EVO-V2-P2-010 | P2 | 非main技能不显示发布按钮 | 技能详情弹窗, skill.state=baby/staging/frozen | 查看操作按钮区域 | 不显示「发布到市场」按钮 |
| TC-EVO-V2-P2-011 | P2 | 发布表单弹窗 | 点击「发布到市场」 | 弹窗显示 | 标题「发布到应用市场」, 显示技能名, 包含价格输入框(默认为0)和市场描述文本框 |
| TC-EVO-V2-P2-012 | P2 | 发布表单提交 | 设置价格和市场描述 | 点击「确认发布」 | 调用API, 成功后显示toast "技能已发布到应用市场" |
| TC-EVO-V2-P2-013 | P2 | 发布失败toast | API返回错误 | 提交发布 | 显示toast "发布失败: {错误原因}" |
| TC-EVO-V2-P2-014 | P2 | 取消发布 | 发布弹窗 | 点击「取消」 | 关闭弹窗 |
### 5.2 团队共享进化 (Share to Team)
#### API: POST /evolution/skills/{skill_name}/share-to-team
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-015 | P2 | 分享技能到团队 | 技能存在, 用户是team owner | POST /app/api/evolution/skills/{name}/share-to-team, body: {team_id: "valid_team_id"} | 返回200, code=0, data包含shared_id, skill_name, team_name |
| TC-EVO-V2-P2-016 | P2 | 团队不存在 | team_id无效 | POST share-to-team | 返回error "团队不存在" |
| TC-EVO-V2-P2-017 | P2 | 用户不属于该团队 | 用户不是team owner | POST share-to-team | 返回error "用户不属于该团队" |
| TC-EVO-V2-P2-018 | P2 | 重复分享 | 技能已分享至该团队 | POST share-to-team | 返回error "该技能已分享至此团队" |
| TC-EVO-V2-P2-019 | P2 | 技能不存在 | 技能不存在 | POST share-to-team | 返回error "技能不存在或不属于当前用户" |
| TC-EVO-V2-P2-020 | P2 | 分享后创建team_shared_skills记录 | 分享成功 | 查询team_shared_skills表 | 创建一条记录, 含team_id, skill_id, shared_by, is_public=true |
### 5.3 进化报告 (Evolution Reports)
#### API: GET /evolution/reports
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-021 | P2 | 获取报告列表 | 用户有至少1条报告 | GET /app/api/evolution/reports | 返回200, code=0, data为报告列表(按时间倒序), 每项含id, report_type, period_start, period_end, created_at |
| TC-EVO-V2-P2-022 | P2 | 按类型过滤报告 | 用户有weekly和monthly报告 | GET /app/api/evolution/reports?report_type=weekly | 仅返回weekly类型报告 |
| TC-EVO-V2-P2-023 | P2 | 空报告列表 | 用户无报告 | GET /app/api/evolution/reports | 返回空数组 [] |
#### API: GET /evolution/reports/{report_id}
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-024 | P2 | 获取报告详情 | 报告存在 | GET /app/api/evolution/reports/{id} | 返回200, data含report_data(JSON)包含summary/new_skills/upgrades/top_skills/dimensions |
| TC-EVO-V2-P2-025 | P2 | 报告不存在 | report_id无效 | GET /app/api/evolution/reports/nonexistent_id | 返回404, "报告不存在" |
| TC-EVO-V2-P2-026 | P2 | 数据隔离 | user_a查询user_b的报告 | GET /app/api/evolution/reports/{user_b_report_id} | 返回404或空 (不能看到其他用户报告) |
#### Service: generate_report
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-027 | P2 | 生成周报 (weekly) | 用户有技能/轨迹/事件 | 调用EvolutionService.generate_report("weekly") | 创建evolution_reports记录, 含period_start=7天前, 统计新增技能/升级/调用次数/等级变化 |
| TC-EVO-V2-P2-028 | P2 | 生成月报 (monthly) | 同上 | 调用generate_report("monthly") | 同上但period_start=30天前 |
| TC-EVO-V2-P2-029 | P2 | 报告生成后发送通知 | 生成报告成功 | 查询notifications表 | 创建一条type="evolution_report"的通知 |
| TC-EVO-V2-P2-030 | P2 | 不支持的报告类型 | - | 调用generate_report("daily") | 返回error "不支持的报告类型: daily" |
#### 前端: ReportsPanel
| TC-ID | 优先级 | 测试场景 | 前置条件 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|----------|
| TC-EVO-V2-P2-031 | P2 | 报告列表展示 | 驾驶舱切换到「进化报告」面板 | 进入面板 | 显示报告卡片列表, 每张卡片含报告类型图标+标题+时间段 |
| TC-EVO-V2-P2-032 | P2 | 报告空列表状态 | 无报告 | 进入「进化报告」面板 | 显示"暂无进化报告。系统将在每周一自动生成周报。" |
| TC-EVO-V2-P2-033 | P2 | 点击查看报告详情 | 报告列表有数据 | 点击某条报告 | 弹出报告详情弹窗, 显示概览(新增技能数/技能升级数/总调用次数) + TOP5最活跃技能 |
| TC-EVO-V2-P2-034 | P2 | 关闭报告详情 | 报告详情弹窗 | 点击背景或关闭按钮 | 返回报告列表 |
| TC-EVO-V2-P2-035 | P2 | 报告详情加载中 | 点击报告卡片 | API请求中 | 报告列表页正常显示, 切换到详情时的loading由弹窗内处理 |
---
## 6. 数据库变更 - 测试用例
### 6.1 新增表验证
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-DB-001 | P0 | skill_versions表结构 | DESC aiflow.skill_versions | 表存在, 字段含: id, user_id, skill_name, version, skill_md_content(LONGTEXT), git_commit_sha, description, created_at |
| TC-EVO-V2-DB-002 | P0 | evolution_reports表结构 | DESC aiflow.evolution_reports | 表存在, 字段含: id, user_id, report_type, period_start, period_end, report_data(JSON), created_at |
| TC-EVO-V2-DB-003 | P0 | skill_publish_records表结构 | DESC aiflow.skill_publish_records | 表存在, 字段含: id, skill_id, skill_name, user_id, market_app_id, price, market_description, status, published_at, created_at |
| TC-EVO-V2-DB-004 | P0 | team_shared_skills表结构 | DESC aiflow.team_shared_skills | 表存在, 字段含: id, team_id, skill_id, skill_name, shared_by, shared_by_name, is_public, created_at + uk_tss_team_skill唯一约束 |
### 6.2 现有表新增字段验证
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-DB-005 | P0 | evolution_trajectories新字段 | DESC aiflow.evolution_trajectories | error_msg VARCHAR(500), retry_count INT DEFAULT 0, tasks_extracted INT DEFAULT 0 |
| TC-EVO-V2-DB-006 | P0 | messages.used_skills字段 | DESC aiflow.messages | used_skills JSON 字段存在 |
| TC-EVO-V2-DB-007 | P0 | user_evolution_config.watcher_error | DESC aiflow.user_evolution_config | watcher_error VARCHAR(500) 字段存在 |
---
## 7. 数据隔离 - 测试用例
| TC-ID | 优先级 | 测试场景 | 测试步骤 | 预期结果 |
|-------|--------|----------|----------|----------|
| TC-EVO-V2-ISO-001 | P0 | 回滚操作数据隔离 | user_a对user_b的技能发起rollback | 返回404 (用户只能操作自己的技能) |
| TC-EVO-V2-ISO-002 | P0 | 流水线状态数据隔离 | user_a查询流水线状态 | 仅返回user_a的discovered/done/total数据 |
| TC-EVO-V2-ISO-003 | P0 | 发布操作数据隔离 | user_a对user_b的技能发起publish | 返回404 |
| TC-EVO-V2-ISO-004 | P0 | 报告数据隔离 | user_a查询报告 | 仅返回user_a的报告, 不含其他用户 |
| TC-EVO-V2-ISO-005 | P0 | 团队共享数据隔离 | user_a查询user_b团队的共享技能 | 非团队成员不可见 (由team_shared_skills关联team表约束) |
| TC-EVO-V2-ISO-006 | P1 | Watcher状态数据隔离 | user_a查询watcher状态 | 仅返回user_a的watcher/scheduler/skill_count |
---
## 8. PRD未覆盖的代码功能 (GAP清单)
以下功能在代码中已实现,但PRD v2文档中未覆盖或差异较大:
| GAP编号 | 类型 | 描述 | 严重程度 | 代码位置 |
|---------|------|------|----------|----------|
| GAP-V2-01 | API差异 | PRD规划 `POST /reports/generate` 但未实现API暴露, generate_report()仅在service层定义无路由 | 高 | evolution_service.py:963-1063 |
| GAP-V2-02 | API差异 | PRD规划 `GET /skills/{name}/versions` (版本列表) 未实现, 仅有 `/skills/{name}/history` (事件列表) 复用 | 中 | evolution.py:124-133 |
| GAP-V2-03 | API差异 | PRD规划 `POST /watcher/restart` 独立端点未实现, restart逻辑内联在pipeline/trigger中 | 中 | evolution.py:284-293 |
| GAP-V2-04 | API差异 | PRD规划 `POST /team/sync` (批量团队同步)未实现, 仅有单个技能share-to-team | 中 | evolution.py:259-271 |
| GAP-V2-05 | 前端差异 | 时间线导出为模拟实现 (setTimeout模拟), 未集成html2canvas/jsPDF库实现真实导出 | 高 | EvolutionDashboard.tsx:370-383 |
| GAP-V2-06 | 前端差异 | 画像分享卡片为模拟实现 (toast显示"模拟"), 未集成html2canvas实现真实截图 | 高 | EvolutionDashboard.tsx:582-587 |
| GAP-V2-07 | 数据库差异 | 4张v2新表在models中定义但数据库未创建 | 致命 | models.py:818-888; MySQL confirmed missing |
| GAP-V2-08 | 数据库差异 | 5个现有表新字段在models中定义但数据库未确认存在 | 致命 | models.py:795-797,100,749 |
| GAP-V2-09 | API差异 | PRD未规划但代码实现 `GET /pipeline/status` 和 `POST /pipeline/trigger` 两个流水线端点 - extra code | 信息 | evolution.py:274-293 |
---
## 9. 代码中实现但PRD未覆盖的功能模块
| 编号 | 功能 | 代码位置 | 说明 |
|------|------|----------|------|
| EXTRA-V2-01 | PipelineScheduler 零技能冷启动处理 | evolution_service.py:168-190 | 当用户无任何技能时, 自动创建new_skill_XXXXXXX baby技能 |
| EXTRA-V2-02 | PipelineScheduler promoter 候选>=3自晋升 | evolution_service.py:194-218 | 关联轨迹>=3自动 baby→staging, 记录promoted事件 |
| EXTRA-V2-03 | PipelineScheduler pipeline_processed计数 | evolution_service.py:224-230 | 轨迹处理完成后更新user_evolution_config.pipeline_processed |
---
## 10. 功能优先级分布
| 优先级 | 测试用例数 | 占比 |
|--------|----------|------|
| P0 | 26 | 29.5% |
| P1 | 28 | 31.8% |
| P2 | 21 | 23.9% |
| DB | 7 | 8.0% |
| ISO | 6 | 6.8% |
| **总计** | **88** | **100%** |
---
## 11. 风险与建议
### 11.1 致命问题(阻塞测试)
**1. 数据库表未创建**(GAP-V2-07、GAP-V2-08)
4张v2新增表 (`skill_versions`, `evolution_reports`, `skill_publish_records`, `team_shared_skills`) 在SQLAlchemy models中已定义但在MySQL数据库中不存在。此外 `evolution_trajectories` 的 `error_msg`/`retry_count`/`tasks_extracted`、`messages` 的 `used_skills`、`user_evolution_config` 的 `watcher_error` 字段在数据库中也可能不存在。
**影响范围**: 技能回滚、进化报告、市场发布、团队共享功能将全部失败。PipelineScheduler的error_msg/retry_count写入也会失败。
**建议**: 需开发工程师执行数据库迁移(创建新表和新字段),然后再进入API测试阶段。
### 11.2 高风险问题
**2. 前端导出/分享为模拟实现**(GAP-V2-05、GAP-V2-06)
时间线PNG/PDF导出和画像分享卡片生成均使用`setTimeout`模拟,未集成`html2canvas`/`jsPDF`库。这意味着这两个功能目前只是UI展示,用户无法真正获得导出文件。
**3. 报告生成API缺失**(GAP-V2-01)
`generate_report()` 在service层实现了完整逻辑,但没有对应的API路由端点,前端无法主动触发报告生成。目前只能依赖外部定时任务触发。
### 11.3 中风险问题
**4. 几个PRD规划的端点缺失**(GAP-V2-02, GAP-V2-03, GAP-V2-04)
- `GET /skills/{name}/versions` - 版本列表独立端点
- `POST /watcher/restart` - 独立restart端点
- `POST /team/sync` - 批量团队同步
其中技能版本列表功能有近似的history端点替代但语义不完全一致(history返回事件列表而非版本列表);watcher重启功能有pipeline/trigger替代;团队同步仅有单个技能共享。
---
## 12. 结论
AI自进化 v2 代码实现基本覆盖了PRD v2 规划的10大功能中的核心逻辑,23个API端点中有19个已实现(含PRD未明确规划的pipeline和团队共享端点)。前端6大交互体验功能全部有实现。**当前阻塞测试的关键问题是数据库表未创建**,建议优先修复此项后进入下一测试阶段。
---
> **文档状态**: 已定稿
> **创建日期**: 2026-05-30
> **测试用例总计**: 88 条 (P0: 26, P1: 28, P2: 21, DB: 7, ISO: 6)
> **发现GAP**: 9 项
> **发现PRD未覆盖代码功能**: 3 项