227 lines
8.2 KiB
Markdown
227 lines
8.2 KiB
Markdown
# 版本模块规则引擎与任务类型设计
|
||
|
||
## 背景
|
||
|
||
版本详情里的调研、产品方案、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. 跑类型检查和核心测试。
|