docs(ai): 记录无需求ID拆解分组
This commit is contained in:
@@ -23,9 +23,10 @@
|
|||||||
- 不带引用的草案不允许写入
|
- 不带引用的草案不允许写入
|
||||||
|
|
||||||
3. **AI 输出必须有"对账报告"**
|
3. **AI 输出必须有"对账报告"**
|
||||||
- 拆解任务前,先输出三段对账:
|
- 拆解任务前,先输出结构化对账:
|
||||||
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
|
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
|
||||||
- ⚠️ 仅需求未见原型 / 仅原型未见需求
|
- ⚠️ 需求未见原型
|
||||||
|
- 无需求ID分组(原型有明确功能,但没有匹配到关联需求)
|
||||||
- ❓ 注释含糊无法转化
|
- ❓ 注释含糊无法转化
|
||||||
- 对账报告先呈现给用户,用户审核后才执行写入
|
- 对账报告先呈现给用户,用户审核后才执行写入
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
|
|
||||||
### Agent 1:Prototype Decompose Agent(原型拆解)
|
### Agent 1:Prototype Decompose Agent(原型拆解)
|
||||||
|
|
||||||
**目的**:把"产品方案原型 + 关联需求"拆解成开发任务草案 + 测试用例草案。
|
**目的**:把"产品方案原型 + 关联需求"拆解成开发任务草案 + 测试用例草案。关联需求是正式范围锚点;原型中明确可拆但没有匹配到关联需求的功能,也可以拆成无需求ID分组草案。
|
||||||
|
|
||||||
**输入**:
|
**输入**:
|
||||||
- 当前版本「产品方案」类型 + status=completed 的 VersionPlan,取其 `resultUrl` 作为**原型链接**(约定:产品方案的成果即原型)
|
- 当前版本「产品方案」类型 + status=completed 的 VersionPlan,取其 `resultUrl` 作为**原型链接**(约定:产品方案的成果即原型)
|
||||||
@@ -63,7 +64,7 @@
|
|||||||
- 当前版本至少关联 1 条需求
|
- 当前版本至少关联 1 条需求
|
||||||
|
|
||||||
**输出**:
|
**输出**:
|
||||||
- 对账报告(结构化文本,含"完美对应/单边/含糊"三段)
|
- 对账报告(结构化文本,含"完美对应/需求未见原型/无需求ID分组/含糊")
|
||||||
- DevTask 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
- DevTask 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
||||||
- TestCase 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
- TestCase 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
||||||
- `target = dev_tasks` 时 `testCaseDrafts` 必须为空数组;`target = test_cases` 时 `devTaskDrafts` 必须为空数组
|
- `target = dev_tasks` 时 `testCaseDrafts` 必须为空数组;`target = test_cases` 时 `devTaskDrafts` 必须为空数组
|
||||||
@@ -73,7 +74,8 @@
|
|||||||
- 编号未出现时,再按需求标题和需求概述(`title` / `description`)做语义匹配。
|
- 编号未出现时,再按需求标题和需求概述(`title` / `description`)做语义匹配。
|
||||||
- 有 QY 编号时,`prototype_note` 引用只能使用真实存在的 QY 编号。
|
- 有 QY 编号时,`prototype_note` 引用只能使用真实存在的 QY 编号。
|
||||||
- 没有 QY 编号但原型文本已命中需求编号或需求概述时,不应丢弃;可只引用 `requirement`,并在 `matched.noteIds` 返回空数组。
|
- 没有 QY 编号但原型文本已命中需求编号或需求概述时,不应丢弃;可只引用 `requirement`,并在 `matched.noteIds` 返回空数组。
|
||||||
- 只有既匹配不到需求编号,也匹配不到需求概述语义的原型批注,才进入 `noteOnly` 或 `ambiguous`。
|
- 既匹配不到需求编号,也匹配不到需求概述语义,但能形成明确功能名称和任务范围的原型批注,进入 `prototypeOnly`,对应草案带 `requirementName` 且不带 `requirement` 引用。
|
||||||
|
- 只有无法形成稳定任务/用例的含糊批注才进入 `ambiguous`。
|
||||||
|
|
||||||
**测试用例拆解粒度**:
|
**测试用例拆解粒度**:
|
||||||
- TestCase 要按功能点、UI 交互、表单校验、接口、数据一致性、权限、异常、边界、状态流转、兼容性和回归点拆细。
|
- TestCase 要按功能点、UI 交互、表单校验、接口、数据一致性、权限、异常、边界、状态流转、兼容性和回归点拆细。
|
||||||
@@ -86,6 +88,9 @@
|
|||||||
- 打开采纳弹窗前,前端先过滤当前版本已采纳过的重复 DevTask/TestCase 草案
|
- 打开采纳弹窗前,前端先过滤当前版本已采纳过的重复 DevTask/TestCase 草案
|
||||||
- 写入字段中 `aiDraft: true`、`aiDraftAt: ISO时间戳`
|
- 写入字段中 `aiDraft: true`、`aiDraftAt: ISO时间戳`
|
||||||
- 写入 `aiEstimateHours`,不写入执行人预估 `estimateHours`
|
- 写入 `aiEstimateHours`,不写入执行人预估 `estimateHours`
|
||||||
|
- DevTask / TestCase 必须写入 `versionId` 作为执行归属;`requirementId` 可选
|
||||||
|
- 无正式需求 ID 的草案写入 `requirementName` 作为分组展示名,列表显示为 `无需求ID · {requirementName}`
|
||||||
|
- 无需求ID分组不创建 Requirement,不写入需求池,不加入版本关联需求列表
|
||||||
- DevTask 草案不写预计开始/截止时间,负责人后续排期时再填写
|
- DevTask 草案不写预计开始/截止时间,负责人后续排期时再填写
|
||||||
- 只有用户在采纳弹窗勾选“采纳推荐负责人”时,才把已校验的 `recommendedAssigneeName` 写入 `assigneeId`
|
- 只有用户在采纳弹窗勾选“采纳推荐负责人”时,才把已校验的 `recommendedAssigneeName` 写入 `assigneeId`
|
||||||
|
|
||||||
@@ -242,15 +247,27 @@ interface DecomposeOutput {
|
|||||||
report: {
|
report: {
|
||||||
matched: Array<{ reqId: string; noteIds: string[]; taskCount: number }>;
|
matched: Array<{ reqId: string; noteIds: string[]; taskCount: number }>;
|
||||||
reqOnly: string[]; // 需求 ID 列表
|
reqOnly: string[]; // 需求 ID 列表
|
||||||
noteOnly: string[]; // 原型注释 ID 列表
|
prototypeOnly: Array<{ requirementName: string; noteIds: string[]; taskCount: number }>;
|
||||||
ambiguous: Array<{ noteId: string; reason: string }>;
|
ambiguous: Array<{ noteId: string; reason: string }>;
|
||||||
};
|
};
|
||||||
devTaskDrafts: Array<{ title: string; description?: string; categoryCode: string; priority: Priority; aiEstimateHours: number; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
devTaskDrafts: Array<{ title: string; description?: string; categoryCode: string; priority: Priority; aiEstimateHours: number; requirementName?: string; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
||||||
testCaseDrafts: Array<{ title: string; description: string; categoryCode: string; priority: Priority; aiEstimateHours: number; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
testCaseDrafts: Array<{ title: string; description: string; categoryCode: string; priority: Priority; aiEstimateHours: number; requirementName?: string; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
要求:AI 不输出数据库 `categoryId`,只输出稳定 `categoryCode`。前端确认写入时按 `TaskCategory.code` 映射成 `categoryId`;映射失败时使用对应分组的默认类型兜底。AI 不输出 `estimateHours`、预计开始或预计截止。
|
要求:AI 不输出数据库 `categoryId`,只输出稳定 `categoryCode`。前端确认写入时按 `TaskCategory.code` 映射成 `categoryId`;映射失败时使用对应分组的默认类型兜底。AI 不输出 `estimateHours`、预计开始或预计截止。草案没有 `requirement` 引用时,必须有 `requirementName` 和至少一个 `prototype_note` 引用。
|
||||||
|
|
||||||
|
### 任务/用例分组契约
|
||||||
|
|
||||||
|
```ts
|
||||||
|
interface VersionScopedRequirementGroup {
|
||||||
|
versionId: string; // 执行归属,必填
|
||||||
|
requirementId?: string; // 正式需求 ID,可选
|
||||||
|
requirementName?: string; // 无正式需求 ID 时的展示分组名
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
要求:版本级聚合使用 `versionId`;需求级进度只统计带 `requirementId` 的 DevTask。无需求ID分组只影响版本任务/用例视图,不影响需求池和关联需求列表。
|
||||||
|
|
||||||
## 视觉规范
|
## 视觉规范
|
||||||
|
|
||||||
@@ -258,3 +275,4 @@ AI 草案在 DevTask / TestCase 列表中的视觉区分:
|
|||||||
- 整行加 `border-l-2 border-l-purple-400 bg-purple-50/30`
|
- 整行加 `border-l-2 border-l-purple-400 bg-purple-50/30`
|
||||||
- 标题旁紫色徽章「AI 草案」(`bg-purple-100 text-purple-600`)
|
- 标题旁紫色徽章「AI 草案」(`bg-purple-100 text-purple-600`)
|
||||||
- 用户在详情抽屉里编辑保存任意字段后,徽章和左边线自动消失
|
- 用户在详情抽屉里编辑保存任意字段后,徽章和左边线自动消失
|
||||||
|
- 无需求ID分组不额外显示“原型发现”等标记,只在分组标题中展示 `无需求ID · {requirementName}`
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ Requirement Version TestCase
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Requirement(需求)= 语义层**,解释功能范围和业务原因,不驱动流程。
|
**Requirement(需求)= 语义层**,解释功能范围和业务原因,不驱动流程。
|
||||||
**Version(版本)= 执行主线**,所有任务归属版本,状态由版本派生。
|
**Version(版本)= 执行主线**,所有任务归属版本,状态由版本派生;需求只是可选语义分组。
|
||||||
**TestCase + Bug = 质量闭环**,挂在版本上验收。
|
**TestCase + Bug = 质量闭环**,挂在版本上验收。
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
@@ -97,6 +97,7 @@ apps/web/
|
|||||||
|
|
||||||
修改 A 影响 B 时,**B 通过 filter A 派生**,不要双向写。例:
|
修改 A 影响 B 时,**B 通过 filter A 派生**,不要双向写。例:
|
||||||
- 需求关联到版本:需求设 `versionId`,版本详情 `requirements.filter(r => r.versionId === id)`
|
- 需求关联到版本:需求设 `versionId`,版本详情 `requirements.filter(r => r.versionId === id)`
|
||||||
|
- 任务/用例归属版本:新数据优先使用 `versionId`;旧 DevTask 可通过 `requirementId -> Requirement.versionId` 兼容推导
|
||||||
- 删除版本:清理孤儿数据(PlanTask/DevTask/TestCase/Bug + 释放 Requirement.versionId)
|
- 删除版本:清理孤儿数据(PlanTask/DevTask/TestCase/Bug + 释放 Requirement.versionId)
|
||||||
|
|
||||||
## 状态机概览
|
## 状态机概览
|
||||||
@@ -139,6 +140,7 @@ V2 接入后端后改为基于 `ProjectMember` 表的 RBAC(Owner/Admin/Member/
|
|||||||
- AI Agent 不是一个独立服务,而是嵌在前端的"特定调用入口"。当前 V3.1 仅 Prototype Decompose Agent。
|
- AI Agent 不是一个独立服务,而是嵌在前端的"特定调用入口"。当前 V3.1 仅 Prototype Decompose Agent。
|
||||||
- Agent 写入数据时必须带 `aiDraft: true` 标记,列表中视觉区分(紫色边)。用户编辑后自动清除标记。
|
- Agent 写入数据时必须带 `aiDraft: true` 标记,列表中视觉区分(紫色边)。用户编辑后自动清除标记。
|
||||||
- DevTask / TestCase 加入 `references[]` 字段,记录任务/用例的来源(需求 / 原型批注)。Agent 和人工创建均强制至少 1 条引用。
|
- DevTask / TestCase 加入 `references[]` 字段,记录任务/用例的来源(需求 / 原型批注)。Agent 和人工创建均强制至少 1 条引用。
|
||||||
|
- 原型中有明确功能但没有匹配到关联需求时,AI 可以生成无需求ID分组草案:写入任务/用例的 `requirementName`,不创建 Requirement,不加入关联需求列表。
|
||||||
- 原型链接**不在 Version 上独立存储**,而是来自产品方案 (VersionPlan type=product) 已完成计划的 `resultUrl`。约定:提交产品方案的成果就是原型。
|
- 原型链接**不在 Version 上独立存储**,而是来自产品方案 (VersionPlan type=product) 已完成计划的 `resultUrl`。约定:提交产品方案的成果就是原型。
|
||||||
- AI 服务实现走 **NestJS 后端**(`apps/server/src/modules/ai/`),不走 Next.js API Route。
|
- 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` 作为兜底。
|
- API Key 通过 **`/admin/ai-config` 页面配置**(仅超管可见),存到 `apps/server/data/ai-config.json`,不入 git;环境变量 `ANTHROPIC_API_KEY` 作为兜底。
|
||||||
@@ -147,10 +149,14 @@ V2 接入后端后改为基于 `ProjectMember` 表的 RBAC(Owner/Admin/Member/
|
|||||||
|
|
||||||
| 实体 | 字段 | 类型 | 说明 |
|
| 实体 | 字段 | 类型 | 说明 |
|
||||||
|------|------|------|------|
|
|------|------|------|------|
|
||||||
|
| DevTask | versionId | string | 执行归属版本;无需求ID分组也通过它进入版本 |
|
||||||
|
| DevTask | requirementId | string? | 正式需求 ID;无需求ID分组为空 |
|
||||||
|
| DevTask | requirementName | string? | 无正式需求 ID 时的展示分组名 |
|
||||||
| DevTask | references | Reference[]? | 引用来源(需求/原型批注) |
|
| DevTask | references | Reference[]? | 引用来源(需求/原型批注) |
|
||||||
| DevTask | aiDraft | boolean? | AI 草案标记 |
|
| DevTask | aiDraft | boolean? | AI 草案标记 |
|
||||||
| DevTask | aiDraftAt | string? | AI 生成时间戳 |
|
| DevTask | aiDraftAt | string? | AI 生成时间戳 |
|
||||||
| DevTask | aiEstimateHours | number? | AI 预估耗时;执行人预估仍写 estimateHours |
|
| DevTask | aiEstimateHours | number? | AI 预估耗时;执行人预估仍写 estimateHours |
|
||||||
|
| TestCase | requirementName | string? | 无正式需求 ID 时的展示分组名 |
|
||||||
| TestCase | references | Reference[]? | 同上 |
|
| TestCase | references | Reference[]? | 同上 |
|
||||||
| TestCase | aiDraft | boolean? | 同上 |
|
| TestCase | aiDraft | boolean? | 同上 |
|
||||||
| TestCase | aiDraftAt | string? | 同上 |
|
| TestCase | aiDraftAt | string? | 同上 |
|
||||||
|
|||||||
@@ -165,9 +165,10 @@
|
|||||||
|
|
||||||
**对应风险**:AI 可能把"上版本就有的功能"也当成"本次新做"。
|
**对应风险**:AI 可能把"上版本就有的功能"也当成"本次新做"。
|
||||||
|
|
||||||
**应对**:要求 Agent 输出**对账报告**,三段:
|
**应对**:要求 Agent 输出**对账报告**,结构化呈现:
|
||||||
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
|
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
|
||||||
- ⚠️ 仅需求未见原型 / 仅原型未见需求
|
- ⚠️ 需求未见原型
|
||||||
|
- 无需求ID分组(原型有明确功能但没有匹配到关联需求)
|
||||||
- ❓ 注释含糊无法转化
|
- ❓ 注释含糊无法转化
|
||||||
|
|
||||||
**理由**:让历史版本入库的成本远高于让用户对账的成本。对账报告本来就是 AI 拆解的标配,能同时兜住"拆偏"和"拆漏"两类问题。让团队补需求清单,比让团队补历史原型容易。
|
**理由**:让历史版本入库的成本远高于让用户对账的成本。对账报告本来就是 AI 拆解的标配,能同时兜住"拆偏"和"拆漏"两类问题。让团队补需求清单,比让团队补历史原型容易。
|
||||||
@@ -378,7 +379,7 @@
|
|||||||
- Agent 对账优先按需求编号匹配;原型文本出现 `requirement.id` 或 `requirement.code` 时必须优先归到该需求。
|
- Agent 对账优先按需求编号匹配;原型文本出现 `requirement.id` 或 `requirement.code` 时必须优先归到该需求。
|
||||||
- 没有需求编号时,再按需求标题和需求概述做语义匹配。
|
- 没有需求编号时,再按需求标题和需求概述做语义匹配。
|
||||||
- 没有 QY 编号但命中了需求编号或需求概述时,允许只引用 `requirement`,`matched.noteIds` 返回空数组。
|
- 没有 QY 编号但命中了需求编号或需求概述时,允许只引用 `requirement`,`matched.noteIds` 返回空数组。
|
||||||
- 只有编号和概述都匹配不到的原型批注,才进入 `noteOnly` 或 `ambiguous`。
|
- 编号和概述都匹配不到、但能形成明确功能名称和任务范围的原型批注,进入 `prototypeOnly` 无需求ID分组;只有无法稳定转化为任务/用例的批注才进入 `ambiguous`。
|
||||||
|
|
||||||
**理由**:需求编号是最稳定的对账锚点,需求概述是编号缺失时的业务语义兜底。把匹配证据先送进上下文,再用 prompt 明确优先级,比只依赖模型从截断文本里自由联想更稳定。
|
**理由**:需求编号是最稳定的对账锚点,需求概述是编号缺失时的业务语义兜底。把匹配证据先送进上下文,再用 prompt 明确优先级,比只依赖模型从截断文本里自由联想更稳定。
|
||||||
|
|
||||||
@@ -444,3 +445,18 @@
|
|||||||
- AI 只写入 `xiaobao-risk-insights` 缓存,不修改 Version、DevTask、TestCase、Bug、Requirement 或 Member。
|
- AI 只写入 `xiaobao-risk-insights` 缓存,不修改 Version、DevTask、TestCase、Bug、Requirement 或 Member。
|
||||||
|
|
||||||
**理由**:规则结果可测试、可追溯、可复盘;AI 文案提升可读性,但不能替代系统事实判断。趋势、静默风险和置信度能弥补“当前风险等级”过于静态的问题。
|
**理由**:规则结果可测试、可追溯、可复盘;AI 文案提升可读性,但不能替代系统事实判断。趋势、静默风险和置信度能弥补“当前风险等级”过于静态的问题。
|
||||||
|
|
||||||
|
## 37. AI 拆解支持无需求ID分组,不自动补需求池
|
||||||
|
|
||||||
|
**问题**:0 到 1 项目中,需求池可能只录入一条宽泛需求,例如“做一个充值功能”,而原型批注里已经包含更多细粒度功能。旧规则把“原型里有、关联需求里没有”的批注只放进 `noteOnly` 报告,不拆任务,会漏掉真实开发和测试范围。若让 AI 自动创建 Requirement 又会污染需求池和版本关联需求列表,让“正式需求范围”和“原型推断内容”混在一起。
|
||||||
|
|
||||||
|
**决策**:
|
||||||
|
- AI 拆解继续优先按关联需求匹配;匹配成功的草案带正式 `requirementId`。
|
||||||
|
- 原型中明确可拆、但没有匹配到关联需求的批注,进入 `prototypeOnly`,也可以生成 DevTask / TestCase 草案。
|
||||||
|
- `prototypeOnly` 草案不创建 Requirement,不加入需求池,也不加入版本关联需求列表。
|
||||||
|
- 这类草案写入开发任务/测试用例时,`requirementId` 为空,使用 `requirementName` 作为展示分组名,列表标题为 `无需求ID · {requirementName}`。
|
||||||
|
- 不额外展示“原型发现”标记;只有既有 `aiDraft` 草案视觉状态。
|
||||||
|
- DevTask 需要直接归属版本(`versionId`),`requirementId` 改为可选;旧数据可继续通过 `requirementId -> Requirement.versionId` 兼容推导。
|
||||||
|
- 版本级统计、工作台和风险预警统计包含无需求ID分组任务/用例;需求级进度和需求关闭条件只统计带正式 `requirementId` 的 DevTask。
|
||||||
|
|
||||||
|
**理由**:关联需求代表人为确认的正式范围,不能被 AI 静默扩写;但原型批注也是当前版本真实交付范围的重要证据,不应该因为没有 REQID 被丢掉。无需求ID分组让任务和用例完整进入执行视图,同时保持需求池干净、关联需求列表可信。
|
||||||
|
|||||||
@@ -97,5 +97,8 @@ TestCase + Bug 共同构成的质量验收环路。版本是否能发布的判
|
|||||||
|
|
||||||
## W
|
## W
|
||||||
|
|
||||||
|
### 无需求ID分组
|
||||||
|
AI 拆解时,原型里有明确功能批注但没有匹配到版本关联需求时形成的任务/用例分组。它只有展示用 `requirementName`,没有正式 `requirementId`,不进入需求池,也不加入版本关联需求列表。列表中展示为 `无需求ID · {需求名称}`,不额外显示“原型发现”标记。
|
||||||
|
|
||||||
### WorkItem
|
### WorkItem
|
||||||
工作台聚合实体。把 DevTask / TestCase / Bug / Plan 等不同实体统一为同一形状,给"与我相关"页面用。
|
工作台聚合实体。把 DevTask / TestCase / Bug / Plan 等不同实体统一为同一形状,给"与我相关"页面用。
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ NestJS + Prisma + PostgreSQL 已开始接入。第一阶段先用 `app_data` JSO
|
|||||||
|
|
||||||
### V3.1 — Prototype Decompose Agent(首个 Agent)
|
### V3.1 — Prototype Decompose Agent(首个 Agent)
|
||||||
|
|
||||||
**目标**:从产品方案的原型 + 关联需求,拆解出开发任务草案 + 测试用例草案。
|
**目标**:从产品方案的原型 + 关联需求,拆解出开发任务草案 + 测试用例草案;原型中明确可拆但没有匹配到关联需求的内容,按无需求ID分组进入任务/用例,不补需求池。
|
||||||
|
|
||||||
**已完成的数据底座**(2026-06):
|
**已完成的数据底座**(2026-06):
|
||||||
- DevTask / TestCase 加 references[] + aiDraft + aiDraftAt
|
- DevTask / TestCase 加 references[] + aiDraft + aiDraftAt
|
||||||
@@ -88,9 +88,10 @@ NestJS + Prisma + PostgreSQL 已开始接入。第一阶段先用 `app_data` JSO
|
|||||||
**待实现**:
|
**待实现**:
|
||||||
1. 后端 `AiGateway` + `PrototypeDecomposeService`(NestJS module)
|
1. 后端 `AiGateway` + `PrototypeDecomposeService`(NestJS module)
|
||||||
2. 前端「AI 拆解任务和用例」按钮(产品方案 Tab)
|
2. 前端「AI 拆解任务和用例」按钮(产品方案 Tab)
|
||||||
3. 对账报告组件(弹窗呈现三段:完美对应 / 单边 / 含糊)
|
3. 对账报告组件(弹窗呈现:完美对应 / 需求未见原型 / 无需求ID分组 / 含糊)
|
||||||
4. 用户确认后批量创建 DevTask + TestCase 草案
|
4. 用户确认后批量创建 DevTask + TestCase 草案
|
||||||
5. AiLog 表(调用记录、token 计量、用时)
|
5. DevTask 增加 `versionId`,`requirementId` 改为可选,兼容旧数据通过需求反查版本
|
||||||
|
6. AiLog 表(调用记录、token 计量、用时)
|
||||||
|
|
||||||
**MVP 范围限制**:
|
**MVP 范围限制**:
|
||||||
- 不自动分配 assignee(留给用户在草案上手填)
|
- 不自动分配 assignee(留给用户在草案上手填)
|
||||||
@@ -117,7 +118,8 @@ NestJS + Prisma + PostgreSQL 已开始接入。第一阶段先用 `app_data` JSO
|
|||||||
|
|
||||||
- **不直接动数据**:所有 Agent 写入必须带 `aiDraft: true`,用户编辑后才转正
|
- **不直接动数据**:所有 Agent 写入必须带 `aiDraft: true`,用户编辑后才转正
|
||||||
- **必须有引用**:所有 AI 产物带 references,用户能追溯到源头
|
- **必须有引用**:所有 AI 产物带 references,用户能追溯到源头
|
||||||
- **必须有对账报告**:拆解类 Agent 输出前端展示三段报告,让用户决策
|
- **必须有对账报告**:拆解类 Agent 输出前端展示结构化报告,让用户决策
|
||||||
|
- **不补需求池**:无需求ID分组只进入 DevTask/TestCase,不创建 Requirement,不加入关联需求列表
|
||||||
- **可降级**:原型不可达 / 输入数据不全 / 模型超时,明确告知用户失败原因,不写入任何数据
|
- **可降级**:原型不可达 / 输入数据不全 / 模型超时,明确告知用户失败原因,不写入任何数据
|
||||||
|
|
||||||
## 不在路线图(明确不做)
|
## 不在路线图(明确不做)
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# AI 拆解无需求ID分组设计
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
0 到 1 项目中,需求池可能只录入一条宽泛需求,例如“做一个充值功能”。产品原型里通常会有更多细粒度批注,例如金额输入、支付渠道、支付结果、充值记录、异常提示等。旧规则只拆关联需求命中的内容,原型中未命中关联需求的批注只进入 `noteOnly` 报告,容易漏掉真实要开发和测试的功能点。
|
||||||
|
|
||||||
|
## 决策
|
||||||
|
|
||||||
|
AI 拆解继续以当前版本关联需求为正式范围锚点,但原型中明确可拆、且没有匹配到关联需求的功能批注,也可以生成 DevTask / TestCase 草案。
|
||||||
|
|
||||||
|
这类草案不创建 Requirement,不进入需求池,也不加入版本关联需求列表。它们只在开发任务和测试用例中形成一个展示分组:
|
||||||
|
|
||||||
|
```text
|
||||||
|
无需求ID · 充值记录展示
|
||||||
|
```
|
||||||
|
|
||||||
|
分组只是一段展示用需求名称,不是正式需求实体。列表不额外显示“原型发现”等标记;草案本身仍按既有 AI 草案规则显示 `aiDraft` 视觉状态。
|
||||||
|
|
||||||
|
## 数据契约
|
||||||
|
|
||||||
|
DevTask 需要从“通过 `requirementId` 反查版本”调整为“直接归属版本”:
|
||||||
|
|
||||||
|
- `versionId`:必填,表示执行归属。
|
||||||
|
- `requirementId`:可选。有关联需求时填写;无正式需求 ID 时为空。
|
||||||
|
- `requirementName`:可选。无正式需求 ID 时作为分组展示名。
|
||||||
|
- `references[]`:仍必填,原型独有项至少包含 `prototype_note` 引用。
|
||||||
|
|
||||||
|
TestCase 已经主归属版本,保持同样语义:
|
||||||
|
|
||||||
|
- `versionId`:必填。
|
||||||
|
- `requirementId`:可选。
|
||||||
|
- `requirementName`:可选,用于无需求ID分组。
|
||||||
|
- `references[]`:仍必填。
|
||||||
|
|
||||||
|
旧数据兼容:没有 `versionId` 的 DevTask 可继续通过 `requirementId -> Requirement.versionId` 推导版本归属;新写入必须带 `versionId`。
|
||||||
|
|
||||||
|
## 对账报告
|
||||||
|
|
||||||
|
拆解报告从“匹配 / 单边 / 含糊”细化为:
|
||||||
|
|
||||||
|
- `matched`:关联需求和原型批注匹配,正常生成带 `requirementId` 的任务/用例。
|
||||||
|
- `reqOnly`:关联需求存在,但原型没有看到对应批注,提醒用户确认原型是否遗漏。
|
||||||
|
- `prototypeOnly`:原型有明确功能批注,但没有匹配到关联需求;生成无需求ID分组草案。
|
||||||
|
- `ambiguous`:原型批注含糊,无法形成稳定任务/用例,不自动写入。
|
||||||
|
|
||||||
|
`prototypeOnly` 不再只是提醒,它是可被用户采纳的草案来源。
|
||||||
|
|
||||||
|
## 派生规则
|
||||||
|
|
||||||
|
- 版本进度、阶段耗时、工作台、小宝预警等版本级聚合必须包含无需求ID分组下的 DevTask / TestCase。
|
||||||
|
- 需求进度、需求实际状态和需求关闭条件只统计带正式 `requirementId` 的 DevTask;无需求ID分组不影响任何 Requirement。
|
||||||
|
- 删除版本时,通过 `versionId` 清理对应 DevTask / TestCase / Bug;旧数据仍按 requirement 反查兼容。
|
||||||
|
- AI 重新拆解去重时,签名需要包含 `requirementId` 或 `requirementName`、任务类型、标题规范化和引用来源。
|
||||||
|
|
||||||
|
## UI 行为
|
||||||
|
|
||||||
|
开发任务和测试用例列表按需求分组时:
|
||||||
|
|
||||||
|
1. 正式关联需求分组按版本关联需求顺序展示。
|
||||||
|
2. 无需求ID分组排在正式需求之后,标题格式为 `无需求ID · {requirementName}`。
|
||||||
|
3. 不显示“原型发现”标记。
|
||||||
|
4. 详情抽屉中可以展示引用来源,方便追溯到原型批注。
|
||||||
|
|
||||||
|
## 不做
|
||||||
|
|
||||||
|
- 不自动创建 Requirement。
|
||||||
|
- 不把无需求ID分组加入版本关联需求列表。
|
||||||
|
- 不把无需求ID分组计入需求池统计。
|
||||||
|
- 不用隐藏 Requirement 作为技术兜底。
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
```
|
```
|
||||||
useProductStore → versions
|
useProductStore → versions
|
||||||
useRequirementStore → requirements (with versionId)
|
useRequirementStore → requirements (with versionId)
|
||||||
useDevTaskStore → tasks (with requirementId)
|
useDevTaskStore → tasks (with versionId; legacy with requirementId)
|
||||||
useTestCaseStore → testCases (with versionId)
|
useTestCaseStore → testCases (with versionId)
|
||||||
useBugStore → bugs (with versionId)
|
useBugStore → bugs (with versionId)
|
||||||
useVersionPlanStore → plans (with versionId, owner)
|
useVersionPlanStore → plans (with versionId, owner)
|
||||||
@@ -172,14 +172,17 @@ Workspace 页面(树筛选 + tab 筛选 + 已完成开关)
|
|||||||
↓
|
↓
|
||||||
6. Agent 从 product 类型的 completed 计划取 resultUrl 作为原型,
|
6. Agent 从 product 类型的 completed 计划取 resultUrl 作为原型,
|
||||||
抓取原型 + 关联需求 + 版本成员,输出对账报告 + 任务/用例草案
|
抓取原型 + 关联需求 + 版本成员,输出对账报告 + 任务/用例草案
|
||||||
|
(关联需求优先;原型中明确可拆但没有 REQID 的内容进入“无需求ID”分组)
|
||||||
↓
|
↓
|
||||||
7. 用户审核对账报告
|
7. 用户审核对账报告
|
||||||
├─ 系统先自动过滤已采纳过的重复 DevTask/TestCase 草案
|
├─ 系统先自动过滤已采纳过的重复 DevTask/TestCase 草案
|
||||||
├─ 报告全 ✅:直接确认写入
|
├─ 报告全 ✅:直接确认写入
|
||||||
|
├─ 报告有无需求ID分组:确认后写入任务/用例,但不创建需求池记录
|
||||||
├─ 报告有 ⚠️/❓:选择性放弃部分草案 / 补充信息后重跑
|
├─ 报告有 ⚠️/❓:选择性放弃部分草案 / 补充信息后重跑
|
||||||
└─ 报告全 ❓:放弃 AI 拆解,人工创建
|
└─ 报告全 ❓:放弃 AI 拆解,人工创建
|
||||||
↓
|
↓
|
||||||
8. 确认后,DevTask / TestCase 草案写入对应 Tab,标记 aiDraft: true,并写入 aiEstimateHours
|
8. 确认后,DevTask / TestCase 草案写入对应 Tab,标记 aiDraft: true,并写入 aiEstimateHours;
|
||||||
|
无需求ID草案按 `无需求ID · 需求名称` 分组展示,不额外显示“原型发现”标记
|
||||||
↓
|
↓
|
||||||
9. 团队成员在 DevTask Tab 看到紫色边的 AI 草案任务
|
9. 团队成员在 DevTask Tab 看到紫色边的 AI 草案任务
|
||||||
↓
|
↓
|
||||||
@@ -205,6 +208,7 @@ Workspace 页面(树筛选 + tab 筛选 + 已完成开关)
|
|||||||
- 完成条件:例如子任务是否完成、是否提交成果、是否允许点击完成。
|
- 完成条件:例如子任务是否完成、是否提交成果、是否允许点击完成。
|
||||||
- 候选数据来源:例如关联需求只能来自当前项目已采纳需求,不能从全量需求池随手取。
|
- 候选数据来源:例如关联需求只能来自当前项目已采纳需求,不能从全量需求池随手取。
|
||||||
- AI 写入契约:例如 AI 输出任务类型、引用来源、草案标记。
|
- AI 写入契约:例如 AI 输出任务类型、引用来源、草案标记。
|
||||||
|
- AI 无需求ID分组:原型中明确可拆但没有匹配关联需求的内容,只写入 DevTask/TestCase 的 `requirementName`,不进入需求池或版本关联需求列表。
|
||||||
|
|
||||||
默认落点:
|
默认落点:
|
||||||
|
|
||||||
@@ -223,6 +227,7 @@ AI 估时约束:
|
|||||||
- `version-plan-workflow.ts` 是调研/产品方案/UI 设计完成条件的唯一入口。
|
- `version-plan-workflow.ts` 是调研/产品方案/UI 设计完成条件的唯一入口。
|
||||||
- `requirement-selector.ts` 是版本内关联需求候选的唯一入口。
|
- `requirement-selector.ts` 是版本内关联需求候选的唯一入口。
|
||||||
- `TaskCategory.code` 是 AI 和系统任务类型的稳定映射锚点,`id` 只作为存储主键。
|
- `TaskCategory.code` 是 AI 和系统任务类型的稳定映射锚点,`id` 只作为存储主键。
|
||||||
|
- DevTask 新数据必须有 `versionId`;`requirementId` 作为正式需求语义标签可选。版本级聚合走 `versionId`,需求级进度只统计带 `requirementId` 的任务。
|
||||||
- 产品方案和 UI 设计的引用需求不再用 checkbox 直接标记完成,必须通过 `requirementCoverage[]` 记录 `not_started / partial / completed`、本次已完成内容和剩余内容;只有 `completed` 计入成果提交门禁。
|
- 产品方案和 UI 设计的引用需求不再用 checkbox 直接标记完成,必须通过 `requirementCoverage[]` 记录 `not_started / partial / completed`、本次已完成内容和剩余内容;只有 `completed` 计入成果提交门禁。
|
||||||
- 产品/UI 计划右侧展示计划日志,需求进度更新和 AI 拆解触发/完成/失败都写入 `VersionPlan.logs[]`,页面只消费日志数据,不临时拼历史。
|
- 产品/UI 计划右侧展示计划日志,需求进度更新和 AI 拆解触发/完成/失败都写入 `VersionPlan.logs[]`,页面只消费日志数据,不临时拼历史。
|
||||||
- 调研/产品方案/UI 设计的计划级 `actualStartAt` 只表示计划容器已开始,不直接作为具体任务日报耗时。具体调研方向或引用需求需要先点击「开始任务」,写入当前行的 `currentWorkStartedAt`;提交「记录」时日志和 `work-activities` 保留 `workStartedAt`,日报耗时按 `workStartedAt -> 记录提交时间` 计算,提交后清空当前行的开始时间。完全完成可直接提交结束本次耗时,部分完成才需要填写本次已完成内容和剩余未完成内容。
|
- 调研/产品方案/UI 设计的计划级 `actualStartAt` 只表示计划容器已开始,不直接作为具体任务日报耗时。具体调研方向或引用需求需要先点击「开始任务」,写入当前行的 `currentWorkStartedAt`;提交「记录」时日志和 `work-activities` 保留 `workStartedAt`,日报耗时按 `workStartedAt -> 记录提交时间` 计算,提交后清空当前行的开始时间。完全完成可直接提交结束本次耗时,部分完成才需要填写本次已完成内容和剩余未完成内容。
|
||||||
|
|||||||
Reference in New Issue
Block a user