docs(版本模块): 规则引擎与任务类型设计

This commit is contained in:
Script Generator
2026-06-25 09:52:05 +08:00
parent d0fd390bd0
commit 4a567da762
6 changed files with 729 additions and 42 deletions

212
docs/agent-spec.md Normal file
View File

@@ -0,0 +1,212 @@
# Agent 规范
本文件是 FTB 系统中所有 AI Agent 的**唯一权威定义**。任何对 agent 的能力、职责、权限、协作方式的修改,必须先在本文件落地,再同步到 architecture / decisions / workflow / roadmap / glossary。
## 何时更新本文件
1. **新增 agent**:新建一个独立 agent
2. **agent 职责变化**:输入/输出/调用条件变了
3. **agent 权限变化**:可读哪些数据、可写哪些数据变了
4. **多 agent 协作方式变化**:编排顺序、依赖关系、出错回退策略变了
不影响以上四类的 prompt 微调、模型版本切换、性能优化不需要更新本文件。
## 全局原则
1. **AI 不直接动数据,先生草案,用户确认**
- 所有写入实体DevTask / TestCase必须带 `aiDraft: true` 标记
- 用户编辑保存后,标记自动清除(在 `useDevTaskStore.updateTask` / `useTestCaseStore.updateTestCase` 里实现)
2. **每条产物强制带引用**
- DevTask / TestCase 必须有 `references: Reference[]`,至少 1 条
- 引用类型:`requirement` / `prototype_note` / `external`
- 不带引用的草案不允许写入
3. **AI 输出必须有"对账报告"**
- 拆解任务前,先输出三段对账:
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
- ⚠️ 仅需求未见原型 / 仅原型未见需求
- ❓ 注释含糊无法转化
- 对账报告先呈现给用户,用户审核后才执行写入
4. **历史版本不强制存储**
- 系统不要求历史原型 URL 作为基准
- 拆偏问题靠"对账报告"暴露给用户,由人工补救
- 这条决定见 decisions.md #17
## Agent 列表
### Agent 1Prototype Decompose Agent原型拆解
**目的**:把"产品方案原型 + 关联需求"拆解成开发任务草案 + 测试用例草案。
**输入**
- 当前版本「产品方案」类型 + status=completed 的 VersionPlan取其 `resultUrl` 作为**原型链接**(约定:产品方案的成果即原型)
- 当前版本关联需求列表(已被加进 Version 的 Requirement[]
- 版本成员清单(带角色:前端/后端/UI/测试)
**调用入口**:版本详情页 → 产品方案 Tab → 计划状态 = completed 后按钮「AI 拆解任务和用例」
**触发条件**
- 当前版本至少有 1 条 type=product 的 VersionPlan 处于 `completed` 且 resultUrl 非空(提交了原型)
- 当前版本至少关联 1 条需求
**输出**
- 对账报告(结构化文本,含"完美对应/单边/含糊"三段)
- DevTask 草案数组(每条带 `aiDraft: true` + `references[]`
- TestCase 草案数组(每条带 `aiDraft: true` + `references[]`
**写入**
- 用户确认后,调用 `useDevTaskStore.createTask``useTestCaseStore.createTestCase`
- 写入字段中 `aiDraft: true``aiDraftAt: ISO时间戳`
**权限**
-Version, Requirement, VersionPlan, Member
-DevTask仅 aiDraft 草案、TestCase仅 aiDraft 草案)
- 不得修改Requirement、Version、VersionPlan、Member、Bug
**失败回退**
- 原型 URL 不可达 → 报告"原型无法访问",不写入任何数据
- 没有已完成的产品方案计划 → 报告"请先完成产品方案并提交原型成果",不写入
- 关联需求为空 → 报告"无关联需求,无法对照",不写入
- 对账报告全是 ❓ → 报告"原型注释含糊度过高,建议人工拆解",不写入
**MVP 阶段限制**V3.1
- 只生成 DevTask 和 TestCase 草案
- 不自动分配 assigneeassignee 留给用户从草案编辑时手填)
- 不做"上一版基准 diff"
### Agent 2Risk Watch Agent风险预警— 待规划
仅占位,正式规划见 roadmap.md V3.2。
### Agent 3Schedule Suggest Agent排期建议— 待规划
仅占位,正式规划见 roadmap.md V3.2。
## 多 Agent 协作V3.2 规划)
当前 V3.1 只有 Prototype Decompose Agent 单独运行。
未来 Risk Watch / Schedule Suggest 引入后,编排策略另行设计。
## 实现位置
V3.1 起,所有 Agent **走 NestJS 后端**(不走 Next.js API Route原因
- 与现有 `product` / `requirement` 模块架构一致
- 共享 Prisma 实例便于后续 AiLog 持久化
- 多 Agent 引入时统一在 `AiGateway` 管理 prompt / 降级 / 重试
代码位置:
```
apps/server/src/modules/
├── ai/
│ ├── ai.module.ts
│ ├── ai.controller.ts # POST /api/v1/ai/decompose
│ ├── ai.service.ts # 抓原型 + 调 LLM + 解析
│ ├── ai-gateway.service.ts # Anthropic 客户端单例懒加载key 改了重建)
│ ├── prompts/decompose.ts # System Prompt + Tool Schema
│ └── dto/decompose.dto.ts # 入参校验
└── config/
├── config.module.ts
├── ai-config.controller.ts # GET/PATCH /api/v1/config/ai, POST /test
├── ai-config.service.ts # 读写 data/ai-config.json
└── dto/update-ai-config.dto.ts
```
共享类型:`packages/shared/src/agent.ts`(前后端通用)
## 配置管理
**多提供商支持V3.1.5 起)**:系统支持配置任意数量的 AI 提供商,每个独立的 baseURL / apiKey / model运行时切换激活。
**支持的 API 格式**
- `anthropic` — Anthropic 官方 + 兼容 Anthropic Messages API 格式的中转站(如 ikuncode 的 anthropic 端点)
- `openai` — OpenAI 官方 + 兼容 OpenAI Chat Completions 格式的中转站
**API Key 优先级**:当前激活提供商的 apiKey → 环境变量 `ANTHROPIC_API_KEY`(兜底,仅 anthropic 格式可用)
**前端配置入口**`/admin/ai-config`,仅超管(`role.permissions``'*'`)可见
**字段(每个 Provider**
- `id`:用户自定义唯一 ID`ikuncode`
- `name`:显示名
- `format``anthropic` / `openai`
- `baseURL`:完整 API endpoint
- `apiKey`:完整 Key 仅在服务端持有;前端只能拿到 mask 视图
- `model`:该提供商上使用的模型 ID
- `remark`:可选备注
**全局字段**
- `activeProviderId`:当前激活哪个 provider
- `updatedAt` / `updatedBy`:审计
**测试连接**`POST /api/v1/config/ai/test``{ id }`,用 16 token 极简调用验证目标 provider 可用性
**激活**`POST /api/v1/config/ai/activate``{ id }`,切换激活 providerAiGateway 缓存自动失效,下次调用重新构建客户端
**安全约束**
- 配置文件路径在 .gitignore 里(`apps/server/data/`),不进入版本控制
- 前端 GET 接口永远不返回完整 Key
- 修改 Key 只能从前端 PATCH 上传新值,不支持读出旧值
- 编辑提供商时若不传 apiKey则保留原值
**数据迁移**旧版V3.1)的 `{ anthropicApiKey, model }` 单 key 结构,自动迁移为多 providers 结构id 为 `anthropic-official`,自动激活)。
## 数据契约
### Reference 类型
```ts
interface Reference {
type: 'requirement' | 'prototype_note' | 'external';
id: string; // REQ-008 / QY0007 / 自由文本
label: string; // 展示用
url?: string; // 可选跳转链接
}
```
### AI 草案标记
```ts
// DevTask 和 TestCase 共有
aiDraft?: boolean;
aiDraftAt?: string; // ISO 时间戳
references?: Reference[];
```
### Agent 输入预期
```ts
interface DecomposeInput {
version: VersionWithContext; // 上下文(不含 prototypeUrl原型从产品方案成果取
prototypeUrl: string; // 从产品方案 completed 计划的 resultUrl 派生
requirements: Requirement[]; // 当前版本所属项目下已采纳、可用于本次拆解的需求
members: VersionMember[]; // 该版本参与人员(带角色)
}
```
要求:`requirements` 不能从产品级全量需求池直接取,必须经过项目维度和已采纳状态过滤。
### Agent 输出预期
```ts
interface DecomposeOutput {
report: {
matched: Array<{ reqId: string; noteIds: string[]; taskCount: number }>;
reqOnly: string[]; // 需求 ID 列表
noteOnly: string[]; // 原型注释 ID 列表
ambiguous: Array<{ noteId: string; reason: string }>;
};
devTaskDrafts: Array<Omit<DevTask, 'id' | 'taskNo' | 'createdAt' | 'updatedAt' | 'isBlocked' | 'categoryId'> & { categoryCode: string; aiDraft: true; aiDraftAt: string; references: Reference[] }>;
testCaseDrafts: Array<Omit<TestCase, 'id' | 'caseNo' | 'createdAt' | 'updatedAt' | 'status' | 'categoryId'> & { categoryCode: string; aiDraft: true; aiDraftAt: string; references: Reference[] }>;
}
```
要求AI 不输出数据库 `categoryId`,只输出稳定 `categoryCode`。前端确认写入时按 `TaskCategory.code` 映射成 `categoryId`;映射失败时使用对应分组的默认类型兜底。
## 视觉规范
AI 草案在 DevTask / TestCase 列表中的视觉区分:
- 整行加 `border-l-2 border-l-purple-400 bg-purple-50/30`
- 标题旁紫色徽章「AI 草案」(`bg-purple-100 text-purple-600`
- 用户在详情抽屉里编辑保存任意字段后,徽章和左边线自动消失

View File

@@ -33,8 +33,8 @@ Requirement Version TestCase
| 前端 | Next.js 14 (App Router) | TypeScript + 客户端组件为主 |
| UI | Tailwind CSS + Shadcn/ui | 紧凑信息密度、现代风格 |
| 状态 | Zustand | 每个领域一个 store |
| 持久化 | localStorageV1 | 后端 NestJS + Prisma 已搭好但未启用 |
| 后端 | NestJS + Prisma + PostgreSQLV2 | 暂未启用 |
| 持久化 | PostgreSQL AppDataV2.1 | 业务数据走 NestJS `/data/:key`,不再以浏览器存储为主 |
| 后端 | NestJS + Prisma + PostgreSQLV2 | 已接入通用数据文档层,后续再逐表关系化 |
| AI | Anthropic SDKV3 远景) | 健康度/风险预警/排期建议 |
## 模块结构
@@ -113,17 +113,14 @@ DevTask 没有"已完成"状态,"已提测"就是终态——开发交付完
## 数据持久化
**V1当前** 全部 localStorage每个 store 独立 key
- `ftb_overview_v1` - 产品/项目/版本树
- `ftb_requirements_v3`
- `ftb_version_plans_v1`
- `ftb_dev_tasks_v1`
- `ftb_test_cases_v1`
- `ftb_bugs_v1`
- `ftb_overtime_v1`
- `ftb_task_categories_v1`
**V2.1当前** 通用服务端文档表 `app_data`
- 后端:`apps/server/src/modules/data/` 提供 `GET/PUT /api/v1/data/:key`
- 数据库Prisma `AppData` 模型,表名 `app_data``key` 为主键,`value` 为 JSONB
- 前端:各 Zustand store 保持现有数据形状,通过 `apps/web/lib/server-data.ts` 读写服务端
- 覆盖范围:产品/项目/版本树、需求池、调研/产品方案/UI 计划、开发任务、测试用例、Bug、成员/角色/部门、任务类型、任务工时日志、加班记录
- 浏览器仅保留登录会话(`ftb_auth_session` / `ftb_auth_persist`),不再作为业务数据主存储
**V2计划** NestJS + Prisma + PostgreSQLSchema 已设计但尚未运行 migration
**后续 V2.2计划** `app_data` 中稳定的数据形状逐步拆成关系表和领域 CRUD API。拆表前不要恢复业务 localStorage 缓存,避免线上部署后出现多端数据分叉
## 权限模型(轻量)
@@ -134,3 +131,35 @@ V1 仅做前端校验,无后端鉴权:
- 版本 `members` 为空时所有人可见(兼容旧数据)
V2 接入后端后改为基于 `ProjectMember` 表的 RBACOwner/Admin/Member/Viewer
## AI Agent 层
详细规范见 `agent-spec.md`。要点:
- AI Agent 不是一个独立服务,而是嵌在前端的"特定调用入口"。当前 V3.1 仅 Prototype Decompose Agent。
- Agent 写入数据时必须带 `aiDraft: true` 标记,列表中视觉区分(紫色边)。用户编辑后自动清除标记。
- DevTask / TestCase 加入 `references[]` 字段,记录任务/用例的来源(需求 / 原型批注。Agent 和人工创建均强制至少 1 条引用。
- 原型链接**不在 Version 上独立存储**,而是来自产品方案 (VersionPlan type=product) 已完成计划的 `resultUrl`。约定:提交产品方案的成果就是原型。
- AI 服务实现走 **NestJS 后端**`apps/server/src/modules/ai/`),不走 Next.js API Route。
- API Key 通过 **`/admin/ai-config` 页面配置**(仅超管可见),存到 `apps/server/data/ai-config.json`,不入 git环境变量 `ANTHROPIC_API_KEY` 作为兜底。
新增涉及 AI 的实体字段:
| 实体 | 字段 | 类型 | 说明 |
|------|------|------|------|
| DevTask | references | Reference[]? | 引用来源(需求/原型批注) |
| DevTask | aiDraft | boolean? | AI 草案标记 |
| DevTask | aiDraftAt | string? | AI 生成时间戳 |
| TestCase | references | Reference[]? | 同上 |
| TestCase | aiDraft | boolean? | 同上 |
| TestCase | aiDraftAt | string? | 同上 |
## 版本模块规则层V2.2 设计约束)
版本详情里的计划完成、需求候选和任务类型映射必须走规则层:
- `version-plan-workflow.ts`:调研/产品方案/UI 设计的子任务、需求覆盖、成果提交和完成条件。
- `requirement-selector.ts`:当前版本所属项目下可关联需求的候选筛选,默认只返回 `status === 'adopted'` 的项目需求。
- `task-category.ts`DevTask/TestCase 共用任务类型字典,`id` 用于存储,`code` 用于 AI 语义映射。
页面组件只消费规则层输出,不直接拼完成条件或候选筛选条件。

View File

@@ -155,3 +155,117 @@
4. 简单文案/样式调整
**理由**brainstorming 适合新功能设计bug fix 强行套流程浪费时间。
## 17. AI 拆解不存历史原型,靠对账报告兜底
**问题**FTB 接入时,禅道里项目可能已经迭代到 V1.6前面历史原型不在系统里。AI 拆解 V1.6 时如果做"V1.5 → V1.6 diff",需要用户额外提供历史原型 URL。
**决策****不要求用户提供历史原型 URL**。AI 拆解只用三样输入:当前版本原型 + 关联需求 + 版本成员。
**对应风险**AI 可能把"上版本就有的功能"也当成"本次新做"。
**应对**:要求 Agent 输出**对账报告**,三段:
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
- ⚠️ 仅需求未见原型 / 仅原型未见需求
- ❓ 注释含糊无法转化
**理由**:让历史版本入库的成本远高于让用户对账的成本。对账报告本来就是 AI 拆解的标配,能同时兜住"拆偏"和"拆漏"两类问题。让团队补需求清单,比让团队补历史原型容易。
## 18. AI 写入必须带 aiDraft 标记 + 引用来源
**问题**AI 直接写入开发任务/用例,团队无法分辨"这是 AI 拆的还是人手填的",出错时找不到来源。
**决策**
- DevTask / TestCase 加 `aiDraft: boolean` 字段
- AI 写入时强制 `aiDraft: true`
- 列表中 AI 草案视觉区分(紫色左边线 + AI 草案徽章)
- 用户编辑保存后 `aiDraft` 自动清除(在 store 的 update 方法里实现)
- 同时加 `references: Reference[]` 字段,记录引用来源(需求 / 原型批注)
**理由**
- 可识别性:团队一眼分辨 AI 产出 vs 人工产出
- 可追溯性:每条任务知道是从哪条需求 + 哪条原型批注来的
- 可信任:用户编辑即认可,自动转正常状态
## 19. 引用机制对 AI 和人工一致
**问题**:如果只有 AI 任务带 references人工任务不带会出现两套规则用户看到 AI 任务有引用、人工没有,体验割裂;做"任务可追溯"功能时数据缺失。
**决策**:人工创建 DevTask / TestCase 时也强制带 references。
- 表单加「关联需求」(从版本已加需求里多选,自动转 requirement 类型 reference
- 表单加「原型批注」(手填编号或自由文本,逗号/空格分隔,自动转 prototype_note 类型 reference
- AI 草案唯一区别只剩 `aiDraft: true` 这一个状态字段
**理由**单一数据形状UI 复用;可追溯性是任务本身的属性,不该由"谁创建"决定。
## 20. AI 配置走页面不走 .env
**问题**:早期 ANTHROPIC_API_KEY 只能写到 `apps/server/.env`,配置流程对非技术人员不友好;切换 key 要重启 NestJS。
**决策**
-`apps/server/src/modules/config/` 模块,提供 GET/PATCH/POST `/api/v1/config/ai` 接口
- 配置存到 `apps/server/data/ai-config.json`(在 .gitignore 里)
- 前端 `/admin/ai-config` 页面(仅超管可见)支持修改 Key、切换模型、测试连接
- AiGateway 优先读文件,其次读环境变量;切换 key 后客户端单例自动重建
- 前端 GET 接口永远不返回完整 Key只返回 mask`sk-ant...xxxx`
**理由**
- 运营/管理可以自助维护,不依赖工程师改代码
- Key 在服务器存储,前端永远拿不到完整内容,安全等同 .env
- 走 .env 的兜底保留,给 CI / 早期部署留路径
## 21. 多 AI 提供商抽象,支持中转站
**问题**:早期 AiGateway 硬绑定 Anthropic 官方 SDK无法走 ikuncode 等中转站,也不能切换到 OpenAI 格式提供商。
**决策**:引入 Provider 抽象层。
- `apps/server/src/modules/ai/providers/` 下两个实现:`AnthropicProvider` / `OpenAIProvider`
- 共同实现 `AiProvider` 接口(`callTool` / `ping`),把厂商差异封装在 provider 内部
- `prompts/decompose.ts` 用格式无关的 JSON Schema由各 provider 包装成 Anthropic 的 `input_schema` 或 OpenAI 的 `parameters`
- 配置数据结构升级为 `{ providers: [], activeProviderId }`,支持配置多个 provider 运行时切换
- 旧的单 key 配置自动迁移成 `providers[0]`
**支持范围**:当前两类格式覆盖 99% 中转站
- `anthropic`Anthropic 官方 / 中转站(兼容 Messages API + tool_use
- `openai`OpenAI 官方 / 中转站(兼容 Chat Completions + tool calling
**理由**
- 用户可以自由选择厂家或中转站,不被一家锁死
- 每个 provider 独立 model 字段,因为不同提供商上同名模型不一定可用
- "激活"概念让多套配置同时存在,方便 A/B 切换
- 抽象层让上层 AiService 完全不感知厂商差异,未来加 Risk Watch / Schedule Suggest Agent 时复用
## 22. 业务数据先迁到 PostgreSQL AppData再逐步关系化
**问题**V1 业务数据存在浏览器 localStorage 中,用户在 Application Storage 执行 Clear site data 后,产品、项目、版本、需求池、版本详情里的调研/产品方案/UI/开发任务/测试用例/Bug以及成员、任务类型等都会丢失。系统未来要部署到服务器浏览器不能作为业务数据主存储。
**决策**:先引入服务端通用数据文档层:
- Prisma 增加 `AppData` 模型(表 `app_data``key` + JSONB `value`
- NestJS 增加 `DataModule`,通过 `GET/PUT /api/v1/data/:key` 读写允许的业务数据 key
- 前端 store 保持现有数据形状和业务逻辑,只把持久化从 localStorage 切换到 `/data/:key`
- 覆盖 key`products-overview``requirements``version-plans``dev-tasks``test-cases``bugs``members``task-categories``task-worklogs``overtime`
- 浏览器只保留登录态,不保存业务主数据
**理由**
- 当前模块多、数据形状仍在快速调整,一次性全量关系化风险高、改动面大
- JSONB 文档表能立刻解决“清浏览器数据导致业务数据丢失”的线上部署问题
- 保持 store 数据形状不变,能降低迁移对现有 UI、AI 拆解、工作台聚合的冲击
- 后续等字段稳定后,再把 `app_data` 中的文档逐步迁入关系表和领域 CRUD API
## 23. 版本计划完成条件进入工作流引擎,任务类型使用稳定语义码
**问题**:版本模块里,调研/产品方案/UI 设计的完成动作散在 `PlanTab``PlanDetailDrawer`右上角勾选按钮会绕过子任务和成果提交。开发任务的任务类型太粗测试用例没有任务类型AI 拆解只输出 `role`,无法稳定映射到业务分类。
**决策**
- 新增 `version-plan-workflow.ts`,统一判断计划是否可勾选子任务、是否可提交成果、是否可完成、缺少什么条件。
- 取消计划卡片右上角的“直接完成”勾选按钮,完成只能通过提交成果触发。
- 调研/产品方案/UI 设计都使用子任务清单;完成时必须满足规则引擎要求并提交链接或文件成果。
- 新增 `requirement-selector.ts`,所有关联需求候选都从当前版本所属项目下的已采纳需求中取,不从全量需求池取。
- DevTask 和 TestCase 共用 `TaskCategory` 字典,`TestCase` 增加 `categoryId`
- `TaskCategory` 增加稳定 `code`AI 输出 `categoryCode`,前端再映射为当前系统的 `categoryId`
**理由**
- 完成条件属于业务规则,不属于按钮组件;集中到工作流引擎后,列表和抽屉能保持一致。
- 需求候选来源属于领域边界;统一 selector 能避免从需求池、项目需求、版本需求之间误取数据。
- AI 不应该猜数据库 id稳定语义码能兼容管理员调整展示名称也方便后续扩展更多模型。
- 测试用例带任务类型后才能知道测试覆盖范围AI 拆解和人工创建的数据形状也一致。

View File

@@ -1,11 +1,17 @@
# 开发路线图
## 当前阶段V1 — 前端 Mock + 业务流程打磨
## 当前阶段V2.1 — 服务端持久化第一阶段
所有数据用 localStorage 持久化,重点验证业务模型和交互
业务流程仍保持 V1 的前端 store 形状,但业务数据主存储已切到 NestJS + PostgreSQL `app_data` 文档表。浏览器只保留登录态,不再保存产品、项目、版本、需求、版本详情、成员、任务类型等业务数据
### 已完成(按时间倒序)
**2026-06-24**
- 新增 NestJS `DataModule` + Prisma `AppData`,提供 `GET/PUT /api/v1/data/:key`
- 产品/项目/版本树、需求池、调研/产品方案/UI、开发任务、测试用例、Bug 改为服务端持久化
- 成员/角色/部门、任务类型、任务工时日志、加班记录改为服务端持久化
- 登录改为读取服务端成员数据;浏览器只保留登录会话
**2026-06-16**
- 项目模块顶部卡片(总版本数/已开发/需求数/Bug 总数)
- 项目模块版本记录与版本详情数据联动(耗时 + 状态胶囊)
@@ -47,38 +53,70 @@
## V2 — 后端接入
NestJS + Prisma + PostgreSQL Schema 已设计,等业务流程稳定后开始迁移
NestJS + Prisma + PostgreSQL 已开始接入。第一阶段先用 `app_data` JSONB 文档表承接现有 store 数据形状,避免浏览器清站点数据导致业务数据丢失;第二阶段再逐步拆成关系表
### 关键任务
1. **运行 Prisma migration**:把现有的 lib/*.ts 类型转为 Prisma schema
2. **API **每个 store 对应一组 CRUD endpoint
3. **localStorage → API 切换**:保留 localStorage 作为离线缓存
4. **认证**NextAuth.js + JWT
5. **权限**RBACOwner/Admin/Member/Viewer按项目/版本级别
1. **服务端文档层**`app_data` + `/api/v1/data/:key`(第一阶段已实现)
2. **localStorage → API 切换**业务主数据不再写浏览器(第一阶段已实现)
3. **运行 Prisma 同步/迁移**:本地和服务器数据库都需要创建 `app_data`
4. **关系化拆表**:把稳定模块从 JSONB 拆成 Product/Project/Version/Task 等领域表
5. **认证**NextAuth.js + JWT
6. **权限**RBACOwner/Admin/Member/Viewer按项目/版本级别
7. **版本规则引擎收敛**VersionPlan 完成条件、关联需求候选、TaskCategory 语义码、TestCase.categoryId 统一收束到规则层
### 数据迁移策略
提供管理员脚本把当前用户的 localStorage 数据导出为 SQL导入到 PostgreSQL
当前不做本地导入导出。清站点数据后浏览器旧数据无法恢复,后续新增数据直接写入 PostgreSQL。若以后需要迁移旧浏览器数据再单独做管理员导入工具
## V3 — AI 集成
## V3 — AI Agent 集成
### 已规划场景
详细 Agent 规范见 `agent-spec.md`。本节只列规划,不重复 Agent 实现细节。
1. **需求智能分解**输入需求描述AI 拆解为子任务(技术分析+UI 调整+联调+测试
2. **风险预警**:自动识别延期/阻塞集中/工时偏差大的任务,提前预警
3. **排期建议**:基于成员负载和历史耗时,建议下一阶段任务分配
4. **需求转任务**:需求采纳后一键生成 DevTask 草稿
5. **健康度智能解读**:把数据指标转化为自然语言报告
### V3.1 — Prototype Decompose Agent首个 Agent
### 落地方式
**目标**:从产品方案的原型 + 关联需求,拆解出开发任务草案 + 测试用例草案。
`apps/server/src/modules/ai/`
- `AiGateway` — 统一 prompt 管理、token 计量、降级
- `AiTaskService.decompose(description)`
- `AiRiskService.analyze(projectId)`
- `AiScheduleService.suggest(projectId)`
- `AiLog` 表存调用记录,便于审计
**已完成的数据底座**2026-06
- DevTask / TestCase 加 references[] + aiDraft + aiDraftAt
- 创建表单加「原型批注」字段
- 列表中 AI 草案视觉区分(紫色边 + 徽章)
- 编辑后自动清除 aiDraft 标记
- agent-spec.md / glossary.md 文档落地
- 约定:原型链接 = 产品方案 (VersionPlan type=product) 已完成计划的 resultUrl不在 Version 上独立存储
**待实现**
1. 后端 `AiGateway` + `PrototypeDecomposeService`NestJS module
2. 前端「AI 拆解任务和用例」按钮(产品方案 Tab
3. 对账报告组件(弹窗呈现三段:完美对应 / 单边 / 含糊)
4. 用户确认后批量创建 DevTask + TestCase 草案
5. AiLog 表调用记录、token 计量、用时)
**MVP 范围限制**
- 不自动分配 assignee留给用户在草案上手填
- 不做"上一版基准 diff"(按 decisions.md #17 决议)
- 单 Agent 单 Round不做多 Agent 编排
### V3.2 — Risk Watch Agent + Schedule Suggest Agent
**Risk Watch Agent**:自动识别延期/阻塞集中/工时偏差大的任务,提前预警
**Schedule Suggest Agent**:基于成员负载和历史耗时,建议下一阶段任务分配
**多 Agent 协作设计**:到 V3.2 才真正涉及,当前 agent-spec.md 仅占位
### V3.3 — 其他场景候选
1. 需求智能分类(自动归档到产品 / 项目)
2. 健康度智能解读(数据指标 → 自然语言报告)
3. 需求转任务(需求采纳后一键生成 DevTask 草稿)
### 落地约束
- **不直接动数据**:所有 Agent 写入必须带 `aiDraft: true`,用户编辑后才转正
- **必须有引用**:所有 AI 产物带 references用户能追溯到源头
- **必须有对账报告**:拆解类 Agent 输出前端展示三段报告,让用户决策
- **可降级**:原型不可达 / 输入数据不全 / 模型超时,明确告知用户失败原因,不写入任何数据
## 不在路线图(明确不做)
@@ -95,6 +133,6 @@ NestJS + Prisma + PostgreSQL Schema 已设计,等业务流程稳定后开始
|------|------|
| V1 业务流程打磨 | 进行中 |
| V1 朋友试用反馈 | 持续中 |
| V2 后端接入 | 等 V1 稳定 |
| V2 后端接入 | 进行中V2.1 AppData 已实现) |
| V3 AI 集成 | 等 V2 数据沉淀 |
| 公开发布 | TBD |

View File

@@ -0,0 +1,226 @@
# 版本模块规则引擎与任务类型设计
## 背景
版本详情里的调研、产品方案、UI 设计、开发任务、测试用例已经形成一条执行链路,但有几处规则还散在 UI 组件里:
- 开发任务的任务类型太粗,测试用例还没有任务类型。
- AI 拆解只输出 `role`,不能稳定落到当前系统的任务类型字典。
- 计划任务可以通过右上角勾选直接完成,绕过子任务和成果提交。
- 关联需求的候选来源不够明确,容易误用全量需求池。
- 调研、产品方案、UI 设计的关联需求选择缺少全选能力。
这次设计的目标是把这些规则收敛到字典、选择器和工作流引擎里,而不是继续在页面组件里散写条件。
## 目标
1. 任务类型能支撑更细的开发与测试范围。
2. DevTask 和 TestCase 共用同一套任务类型字典。
3. AI 拆解必须输出任务类型,并能稳定映射到系统字典。
4. VersionPlan 的完成条件由统一规则函数判断。
5. 所有关联需求入口只从当前版本所属项目下的已采纳需求中选择,不从全量需求池选择。
6. 调研、产品方案、UI 设计的关联需求选择支持全选。
7. 项目文档明确约束跨模块联动、状态流转、完成条件、AI 契约必须优先考虑引擎、状态机或统一规则函数。
## 非目标
- 不做本地数据导入导出。
- 不在这一步把 `app_data` 全量拆成关系表。
- 不让 AI 自动分配负责人。
- 不让 AI 直接写入正式 DevTask/TestCase仍然只写入草案。
## 方案概览
新增或调整三个规则层:
1. `task-category.ts`:任务类型字典扩展为开发、测试、实施、其他,并增加稳定语义码。
2. `requirement-selector.ts`:统一筛选当前项目下可用于关联的需求。
3. `version-plan-workflow.ts`:统一计算计划进度、是否能提交成果、是否能完成、缺少什么条件。
页面组件只负责展示和触发动作,不直接决定业务规则。
## 任务类型字典
`TaskCategory` 继续作为开发任务和测试用例的共享字典,但增加一个稳定字段:
```ts
interface TaskCategory {
id: string; // 存储主键,仍用于 DevTask.categoryId / TestCase.categoryId
code: string; // 稳定语义码,给 AI 和映射逻辑使用
name: string; // 展示名称,可被管理员调整
group: 'development' | 'testing' | 'implementation' | 'other';
color?: string;
sortOrder: number;
isSystem: boolean;
}
```
推荐预置分类示例:
- 开发:前端页面、前端交互、后端接口、后端业务逻辑、数据库/数据结构、权限/流程、第三方集成、接口联调
- 测试:功能测试、接口测试、异常场景、兼容性测试、回归测试、数据校验
- 实施:数据处理、实施支持、配置部署
- 其他:文档、协调、待确认
`id` 用于系统存储,`code` 用于 AI 输出和迁移兼容。管理员可以改名称,但不建议随意修改系统预置 `code`
## 测试用例任务类型
`TestCase` 增加 `categoryId`
```ts
interface TestCase {
categoryId: string;
}
```
影响范围:
- `TestCaseCreateModal` 增加任务类型必填项。
- `TestCaseRow``TestCaseDetailDrawer` 展示类型标签。
- `useTestCaseStore.fetchTestCases` 对旧数据做兼容补齐,默认映射到测试分组的第一个系统类型。
- AI 草案写入 TestCase 时也要映射 `categoryCode -> categoryId`
## 关联需求选择规则
所有关联需求入口统一使用同一套候选规则:
```ts
requirements.filter((r) =>
r.projectId === version.projectId &&
r.status === 'adopted'
)
```
含义:
- 候选来自当前版本所属项目下的需求,不从产品级全量需求池直接取。
- 只有已采纳需求可被新选择。
- 如果历史计划已经关联了某条需求,但该需求后来不再满足候选条件,编辑时保留旧关联并标记为“历史关联”,避免悄悄丢数据。
- 版本需求 Tab、调研计划、产品方案、UI 设计、开发任务和测试用例中的需求选择都复用该规则函数。
调研、产品方案、UI 设计的关联需求控件增加:
- 全选当前候选。
- 清空选择。
- 已选数量 / 候选数量提示。
- 候选为空时说明需要先在项目下采纳需求。
## VersionPlan 工作流引擎
新增 `apps/web/lib/version-plan-workflow.ts`,作为计划完成规则的唯一入口。
建议导出:
```ts
interface PlanCompletionState {
checklistTotal: number;
checklistCompleted: number;
requirementTotal: number;
requirementCompleted: number;
hasResult: boolean;
canSubmitResult: boolean;
canComplete: boolean;
missingReasons: string[];
}
function getPlanCompletionState(plan: VersionPlan): PlanCompletionState;
function canTogglePlanChecklist(plan: VersionPlan, now?: Date): boolean;
function canEditPlanRequirementCoverage(plan: VersionPlan, now?: Date): boolean;
```
完成规则:
- 调研、产品方案、UI 设计都使用 `tasks` 作为子任务清单。
- 子任务必须全部勾选完成。
- 完成时必须提交成果,成果可以是链接或文件。
- 产品方案和 UI 设计如果有关联需求覆盖清单,也必须全部勾选覆盖完成。
- 右上角“直接完成”的勾选按钮取消。
- `PlanTab``PlanDetailDrawer` 都只调用工作流引擎,不再各自写完成条件。
状态写入仍保持:
- `pending -> in_progress -> completed`
- `actualStartAt` 在开始时写入。
- `completedAt` 只能通过提交成果完成时写入。
## AI 拆解契约
AI 输出不直接返回数据库 `categoryId`,而是返回稳定语义码:
```ts
interface AgentDevTaskDraft {
title: string;
description?: string;
categoryCode: string;
priority: 'P0' | 'P1' | 'P2' | 'P3';
estimateHours: number;
references: AgentReference[];
}
interface AgentTestCaseDraft {
title: string;
description: string;
categoryCode: string;
priority: 'P0' | 'P1' | 'P2' | 'P3';
references: AgentReference[];
}
```
映射规则:
1. 优先按 `TaskCategory.code` 匹配。
2. 匹配不到时按名称做宽松匹配。
3. 仍匹配不到时,开发任务落到开发分组默认类型,测试用例落到测试分组默认类型。
4. 映射失败不阻断 AI 报告展示,但确认写入前必须能得到 `categoryId`
`prompts/decompose.ts` 的 tool schema 要求 devTaskDrafts 和 testCaseDrafts 都必须带 `categoryCode`
## UI 行为
- 计划卡片右上角不再显示直接完成的勾选按钮。
- 完成入口改为“提交成果”,按钮在条件不足时禁用并展示缺失原因。
- 完成弹窗保留链接/文件两种结果类型。
- 调研、产品方案、UI 设计新建/编辑时都展示关联需求选择,并支持全选。
- 测试用例新建弹窗增加任务类型选择。
- AI 草案确认弹窗展示每条任务/用例的任务类型。
## 兼容与迁移
当前业务数据仍存于 PostgreSQL `app_data` JSONB。
- 新增字段时在 store fetch 阶段做轻量兼容补齐。
- 旧 TestCase 没有 `categoryId` 时补齐默认测试类型。
- 旧 TaskCategory 没有 `code` 时按系统预置映射补齐;自定义类型生成稳定 code。
- 不恢复业务 localStorage 缓存。
## 验证计划
实现时至少覆盖:
- `version-plan-workflow` 单元测试:
- 子任务未完成不能完成。
- 未提交成果不能完成。
- 子任务完成 + 成果存在才可完成。
- 产品方案/UI 设计有关联需求覆盖时,未覆盖完不能完成。
- 任务类型映射测试:
- `categoryCode` 能映射系统类型。
- 未知 `categoryCode` 有合理 fallback。
- TestCase 旧数据能补齐类型。
- AI schema 测试:
- devTaskDrafts 和 testCaseDrafts 都要求 `categoryCode`
- 手工 UI 验证:
- 调研/产品/UI 关联需求全选可用。
- 候选需求只来自当前项目已采纳需求。
- 顶部直接完成按钮消失。
- 测试用例创建必须选择任务类型。
## 后续实现顺序
1. 写规则引擎和选择器测试。
2. 实现任务类型字典扩展和旧数据兼容。
3. 给 TestCase 增加 `categoryId`
4. 接入 VersionPlan 工作流引擎。
5. 接入需求选择器和全选 UI。
6. 升级 AI schema、共享类型和草案写入映射。
7. 跑类型检查和核心测试。

View File

@@ -39,7 +39,8 @@
- [ ] 是否需要在 `workspace-engine.ts` 加聚合?
- [ ] 删除版本时是否需要清理这类数据?
- [ ] 工作台 / 版本详情 / 项目详情三处的统计是否同步?
- [ ] localStorage 旧数据是否需要兼容处理
- [ ] 是否需要新增 `app_data` key后端 `data-keys.ts` + 前端 `server-data.ts`
- [ ] 是否需要从旧浏览器数据做一次性迁移?(当前不做本地导入导出)
## Drawer侧边详情规范
@@ -85,15 +86,19 @@
朋友拉新代码出现"显示问题"时,按顺序排查:
1. 旧 localStorage 数据格式不兼容 → 让朋友清缓存
2. 类型定义和实际数据不一致(缺字段)
3. 列宽溢出导致裁切
4. 派生计算错误filter 条件错)
5. 跨模块联动断了store 的 store.getState() 调用时机
1. 后端是否启动:`GET http://localhost:3001/api/v1/config/ai` 应返回 200
2. 数据库是否启动并完成 Prisma 同步:`app_data` 表必须存在
3. 对应 `app_data.key` 是否有值,例如 `products-overview` / `requirements` / `dev-tasks`
4. 前端 store 是否已经调用对应 `fetch*` 方法
5. 类型定义和实际 JSON 数据不一致(缺字段
6. 列宽溢出导致裁切
7. 派生计算错误filter 条件错)
8. 跨模块联动断了store 的 store.getState() 调用时机)
## 测试 / 验证流程
- 改动后必须 `npx tsc --noEmit` 通过
- 涉及服务端数据持久化:`pnpm --filter server exec prisma validate --schema prisma/schema.prisma`
- 涉及 UI 改动:`curl http://localhost:3000/<path>` 检查 200
- 不会自动跑 dev server假定它已经运行
@@ -116,3 +121,66 @@ Workspace 页面(树筛选 + tab 筛选 + 已完成开关)
```
新增模块时,只需在 `aggregateWorkItems` 中添加聚合逻辑,工作台自动展示。
## AI 拆解工作流V3.1
详细 Agent 规范见 `agent-spec.md`。这里是用户视角的工作流:
```
1. 创建版本(不需要单独填原型链接)
2. 在版本详情 → 产品方案 Tab 创建一条 product 计划
3. 完成产品方案计划,提交「成果」(成果链接即原型链接,附成果标题)
4. 从当前项目已采纳需求中关联需求到本版本
5. 点击「AI 拆解任务和用例」按钮(位于产品方案 Tab
6. Agent 从 product 类型的 completed 计划取 resultUrl 作为原型,
抓取原型 + 关联需求 + 版本成员,输出对账报告 + 任务/用例草案
7. 用户审核对账报告
├─ 报告全 ✅:直接确认写入
├─ 报告有 ⚠️/❓:选择性放弃部分草案 / 补充信息后重跑
└─ 报告全 ❓:放弃 AI 拆解,人工创建
8. 确认后DevTask / TestCase 草案写入对应 Tab标记 aiDraft: true
9. 团队成员在 DevTask Tab 看到紫色边的 AI 草案任务
10. 任意成员编辑任务(改标题/描述/负责人/优先级/时间/分类),保存后 aiDraft 自动清除
changeStatus / setBlocked 等用户主动操作也会清除)
```
**触发条件**AI 拆解按钮可点):
- 至少有 1 条 type=product 的产品方案计划处于 completed 且 resultUrl 非空
- 至少 1 条需求关联到本版本
**人工创建任务/用例的引用要求**
- 创建 DevTask 时已选「关联需求」自动作为 reference 写入
- 创建表单加「原型批注」字段(手填,逗号或空格分隔,如 `QY0007, QY0023`
- 至少一类引用非空才能保存V3.1 暂未做强校验,靠 UI 引导)
## 高级开发约束:规则先归位
涉及以下任意类型的改动时,先判断规则应该放在哪一层,不允许直接在页面组件里散写临时判断:
- 跨模块联动:例如 Requirement、VersionPlan、DevTask、TestCase、Bug 互相派生状态。
- 状态流转:例如 `pending -> in_progress -> completed``todo -> testing -> submitted`
- 完成条件:例如子任务是否完成、是否提交成果、是否允许点击完成。
- 候选数据来源:例如关联需求只能来自当前项目已采纳需求,不能从全量需求池随手取。
- AI 写入契约:例如 AI 输出任务类型、引用来源、草案标记。
默认落点:
- 可派生数据进 `*-engine.ts` 或纯函数 helper。
- 有状态流转的实体要有状态机或 workflow helper。
- 多个组件共用的候选筛选规则进 selector/helper。
- AI 输入输出字段先更新 `agent-spec.md` 和 shared type再改 prompt/schema。
版本模块新增规则:
- `version-plan-workflow.ts` 是调研/产品方案/UI 设计完成条件的唯一入口。
- `requirement-selector.ts` 是版本内关联需求候选的唯一入口。
- `TaskCategory.code` 是 AI 和系统任务类型的稳定映射锚点,`id` 只作为存储主键。