docs: add milestone propose planning notes

This commit is contained in:
zhi
2026-03-16 23:36:49 +00:00
parent 74f1ffff7d
commit 569e0e50e0
2 changed files with 1308 additions and 0 deletions

View File

@@ -0,0 +1,718 @@
# HarborForge 需求草案Milestone 状态机与 Propose 流程
> 状态:草案
> 更新时间2026-03-16
> 目的先把业务想法固定下来后续再拆数据库、API、前端和测试实现。
---
## 1. 背景
当前希望把 milestone 的推进过程做成一个更严格的状态机,并把 feature story 的进入方式从“直接创建 task”改为“先提 propose再 accept 进入 milestone”。
核心目标:
- milestone 有明确生命周期
- feature 进入 milestone 要受控
- release 节点要能约束 freeze / complete
- 依赖关系在开始前做严格检查
---
## 2. Milestone 字段调整
Milestone 的 `status` 使用新的枚举集合,替代当前代码库中的旧枚举。
### 2.1 目标枚举
- `open`
- `freeze`
- `undergoing`
- `completed`
- `closed`
### 2.2 替代当前代码中的旧枚举
当前代码里 milestone status 旧枚举为:
- `open`
- `pending`
- `deferred`
- `progressing`
- `closed`
后续应整体替换为新的 milestone 状态集合,不再使用:
- `pending`
- `deferred`
- `progressing`
另增字段:
- `started_at`
- milestone 进入 `undergoing` 时自动记录开始时间
默认:
- 新建 milestone 时,`status = open`
---
## 3. Milestone 状态定义
### 3.1 open
含义:
- milestone 刚创建,仍可接收 feature 范围内的内容
页面按钮:
- `freeze`
- `close`
约束:
- milestone 下的 `task / support / meeting` 在此阶段都只能处于锁定状态,不允许进入真正开始执行的状态
- 当前可认为它们只能停留在 `pending`
- milestone 基本信息仍可编辑
---
### 3.2 freeze
含义:
- milestone 进入冻结,需求范围不再继续扩张,准备开始执行
进入条件:
- 该 milestone **有且仅有一个** `maintenance task`
- 且这个 maintenance task 的 `subtype = release`
- 如果不满足,不能进入 `freeze`
页面按钮:
- `start`
- `close`
约束:
- freeze 之后不再允许做范围调整
- 如果 freeze 之后才发现要调整范围,只能放到未来的 milestone不提供 `unfreeze`
- milestone **不能再新增** `subtype = feature``story task`
- 已存在的 `feature story task` 不能再编辑核心字段
- 例如:`title``description``owner`
- 但允许继续做附属操作
- 例如:新增 comment
- milestone 下的 `task / support / meeting` 仍保持锁定,不允许进入执行中状态
- 当前可认为仍只能停留在 `pending`
---
### 3.3 undergoing
含义:
- milestone 正式开始执行
进入方式:
- 用户点击 `start`
进入前检查:
- milestone 自身的前置依赖必须全部完成
- 其前置依赖中涉及的 milestone / task / 其他依赖对象,如果尚未完成,则不能开始
进入后效果:
- milestone `status = undergoing`
- 自动记录 `started_at`
- detail 页面只显示:`close`
- milestone 下的 `task / support / meeting` 才允许进入可执行状态
- 也就是说,只有在 milestone 为 `undergoing` 之后,这些对象才可以从 `pending` 往后推进
---
### 3.4 completed
含义:
- milestone 正常完成
进入方式:
- 当该 milestone 下**唯一的** `release maintenance task` 完成后milestone 自动进入 `completed`
约束:
- `completed` 是终态
- milestone 一旦进入 `completed`,状态不再允许变更
备注:
- “task 完成”所对应的 task 状态枚举,后续补充
---
### 3.5 closed
含义:
- 废弃该 milestone而不是正常完成
适用场景:
- milestone 不再继续推进
- 即使已经开始,也可以选择废弃
页面入口:
- `open` / `freeze` / `undergoing` 状态下都可以通过 `close` 进入 `closed`
进入 `closed` 后的处理原则:
- 如果 milestone 尚未开始,则直接废弃
- 如果 milestone 已经开始:
- 已完成的 `feature task` 可以被废弃
- 或者移交到其他 `open` 状态的 milestone
- 所有依赖该 milestone 的对象,都需要修改依赖关系,避免继续依赖一个已废弃 milestone
约束:
- `closed` 视为终态
- 当前不考虑 reopen 原 milestone
- milestone 页面不提供状态动作按钮
---
## 4. Milestone 页面按钮草案
所有按钮都按权限可见。
对于需要前置校验的按钮,推荐交互:
- 按钮可见但禁用
- 并给出提示,说明当前为什么不能点击
### 4.1 各状态按钮
- `open`
- `freeze`
- `close`
- `freeze`
- `start`
- `close`
- `undergoing`
- `close`
- `completed`
- 不显示状态动作按钮
- `closed`
- 不显示状态动作按钮
### 4.2 按钮触发条件
#### `freeze`
-`open` 状态显示
- 点击前检查:
- 当前 milestone 下**有且仅有一个** `maintenance/release task`
- 不满足时不可点击,并提示原因
#### `start`
-`freeze` 状态显示
- 点击前检查:
- 当前 milestone 的前置依赖全部完成
- 满足后:
- milestone 进入 `undergoing`
- 自动记录 `started_at`
#### `close`
- `open` / `freeze` / `undergoing` 状态显示
- 需要有对应权限
- 如果 milestone 已经是 `undergoing`,建议弹确认说明:
- 已完成的 feature task 需要废弃或移交
- 依赖该 milestone 的对象需要调整依赖
### 4.3 Milestone 动作权限
将以下三类动作设计为**独立权限**,由 role 控制:
- `freeze milestone`
- `start milestone`
- `close milestone`
规则:
- 拥有对应权限的 role 才可以执行对应动作
- 三者互相独立,不合并
### 4.4 特别说明
- milestone 不提供 `unfreeze`
- 范围调整只能发生在 `freeze` 之前
- 如果 freeze 之后才发现需要调整范围,只能放到未来的 milestone
- milestone 不提供手动 `complete` 按钮
- `completed` 由唯一的 `release maintenance task` 完成后自动触发
---
## 5. 依赖规则
### 4.1 开始前依赖检查
以下对象在进入“开始/执行中”状态前,都要检查依赖是否已完成:
- milestone
- task
- support
- meeting
- 其他有依赖关系的对象
规则:
- 如果任一前置依赖未完成,则当前对象不能开始
- 不需要在依赖完成时批量自动推进下游状态
- 只在“尝试开始”这一刻做校验即可
### 4.2 milestone close 对依赖的影响
当 milestone 被 `closed`
- 所有依赖它的对象都必须调整依赖关系
- 调整后,这些对象未来在开始时仍然通过“开始前依赖检查”判断是否可开始
也就是说:
- **不做统一的自动状态更新**
- **只要求依赖配置保持合法**
---
## 5. Task 创建限制
以下两类 task **不能**通过通用的 `create task` 页面直接创建:
- `feature story task`
- `release maintenance task`
设计意图:
- `feature story task` 应来自 `propose -> accept`
- `release maintenance task` 应通过更受控的 milestone/release 流程创建
---
## 6. Propose 新模型
新增 `propose` 表。
### 6.1 propose 与 project 的关系
- `propose` 通过外键连接到 `project`
### 6.2 propose code
格式:
```text
{proj_code}:P{i:05x}
```
说明:
- `i` 由每个 `project` 独立维护递增序号
- 即每个 project 都有自己的 propose 计数器
### 6.3 propose 状态枚举
当前采用以下状态:
- `open`
- `accepted`
- `rejected`
明确:
- propose **不需要** `closed`
### 6.4 propose 基础字段(当前已明确部分)
至少需要:
- `project_id`
- `propose_code`
- `title`
- `description`
- `status`
- `created_by_id`
- `created_at`
- `updated_at`
### 6.5 feat_task_id 字段
新增字段:
- `feat_task_id`
- 类型:`string`
- 可选
规则:
- 在 accept 生成 `feature story task` 后自动填写
- 不允许手动修改
- 前端页面应显示该字段
---
## 7. Propose 页面草案
### 7.1 页面按钮
前端页面按钮规则采用当前草案:
- `open`
- `accept`
- `reject`
- `accepted`
- 不显示状态动作按钮
- 可显示跳转入口:`View Generated Task`
- `rejected`
- `reopen`
所有按钮都按权限可见。
### 7.2 页面显示字段
前端 detail 页面至少应显示:
- `propose_code`
- `title`
- `description`
- `status`
- `feat_task_id`
- `created_by_id`
- `created_at`
- `updated_at`
---
## 8. Propose 状态流转与动作规则
### 8.1 允许的状态流转
- `open -> accepted`
- `open -> rejected`
- `rejected -> open`
当前不考虑:
- `accepted -> open`
- `accepted -> rejected`
- 任何 `closed` 相关流转(因为 propose 不设 `closed`
### 8.2 accept
前置条件:
- propose 当前必须是 `open`
- 操作者有 `accept propose` 权限
- 用户必须从下拉框中选择一个目标 milestone
- 目标 milestone 必须属于同一个 project
- 目标 milestone 必须是 `open`
accept 后效果:
- propose.status = `accepted`
- 自动在所选 milestone 下创建一个 `feature story task`
- 新 task 的创建者与 propose 创建者保持一致
- 新 task 默认状态建议为 `pending`
- 自动填写 `feat_task_id`
字段继承:
- `title`
- `description`
### 8.3 reject
前置条件:
- propose 当前必须是 `open`
- 操作者有 `reject propose` 权限
reject 后效果:
- propose.status = `rejected`
- 建议要求填写 reject comment / reason便于追踪原因
### 8.4 reopen
前置条件:
- propose 当前必须是 `rejected`
- 操作者有 `reopen rejected propose` 权限
reopen 后效果:
- 不创建新 propose
- 复用当前 propose
- propose.status 回到 `open`
- 系统需要保留一条 reopen 记录
---
## 9. Propose 权限与编辑规则
### 9.1 独立权限
建议将以下动作设计为独立权限:
- `accept propose`
- `reject propose`
- `reopen rejected propose`
### 9.2 编辑规则
- `open`
- creator 可编辑 `title``description`
- admin 可编辑
- 有特定管理权限的 role 可编辑
- `accepted`
- 主体不可编辑
- `rejected`
- 主体不可编辑
备注:
- 主体不可编辑不代表不能追加 comment / activity 记录
---
## 10. 当前推荐的业务流程
### 10.1 feature 进入 milestone
推荐流程:
1. 用户先在 project 下创建 `propose`
2. 负责人在 propose detail 页面审阅
3. 若接受,则选择目标 milestone 并 `accept`
4. 系统自动生成 `feature story task`
5. milestone 处于 `open` 时可继续接纳 feature story
6. milestone 进入 `freeze` 后,不再接受新的 feature story
7. milestone 满足条件后 `start`,进入 `undergoing`
8. milestone 下唯一 `release maintenance task` 完成后milestone 自动 `completed`
### 10.2 废弃 milestone
1. 用户点击 `close`
2. milestone 进入 `closed`
3. 处理已完成 feature task
- 废弃
- 或移交到其他 `open` milestone
4. 修正所有依赖该 milestone 的对象依赖配置
---
## 11. Task 状态枚举调整
Task 的 `status` 也采用新的枚举集合。
### 11.1 目标枚举
- `open`
- `pending`
- `undergoing`
- `completed`
- `closed`
### 11.2 替代当前代码中的旧枚举
当前代码里 task status 旧枚举为:
- `open`
- `pending`
- `progressing`
- `closed`
后续应整体替换为新的 task 状态集合,不再使用:
- `progressing`
并新增:
- `undergoing`
- `completed`
### 11.3 Task 状态语义
- `pending`
- 还不能开始,通常是被 milestone 状态或依赖锁住
- `open`
- 可以开始,但尚未真正开工
- `undergoing`
- 正在处理
- `completed`
- 正常完成
- `closed`
- 废弃 / 取消,不是正常完成
### 11.4 当前认可的 Task 基础状态流转
允许的基础流转:
- `pending -> open`
- `open -> undergoing`
- `undergoing -> completed`
- `pending -> closed`
- `open -> closed`
- `undergoing -> closed`
### 11.5 各状态流转条件
#### `pending -> open`
条件:
- 所有前置依赖都已满足
#### `open -> undergoing`
条件:
- `assignee` 必须非空
- 且只有当前 assignee 可以执行这个开始动作
#### `undergoing -> completed`
条件:
- 不额外要求前置条件
- 但 assignee 需要留下 comment
### 11.6 Reopen 方向
补充决定:
- reopen 时**不创建新 task**
- 直接复用当前 task
- 但系统需要保留一条 reopen 记录
当前已确认:
- reopen 允许从 `closed``completed` 触发
- reopen 后统一回到 `open`
- reopen 记录采用 comment、activity log 还是专门字段/表,后续再定
当前理解:
- `completed``closed` 原本被视为终态
- 但 task 将引入受控的 reopen 机制,使其可以返回 `open`
### 11.7 Task 状态动作权限
将以下三类动作设计为**独立权限**,由 role 控制:
- `close task`
- `reopen closed task`
- `reopen completed task`
规则:
- 拥有对应权限的 role 才可以执行对应动作
- `reopen closed task``reopen completed task` 分开控制,不合并为一个权限
补充:
- `undergoing -> completed` 不走 role 权限控制
- `complete` 只有当前 assignee 可以执行
### 11.8 Task 页面按钮可见性
所有按钮都按权限可见。
当前确认的按钮规则:
-`closed``completed`task 页面始终显示 `close` 按钮
- 也就是:
- `pending``close`
- `open``close`
- `undergoing``close`
- `closed``completed` 状态显示 `reopen` 按钮
- `pending` 状态显示 `open` 按钮
- `open` 状态显示 `start` 按钮
- `undergoing` 状态显示 `finish` 按钮
可理解为:
- `pending``open` + `close`
- `open``start` + `close`
- `undergoing``finish` + `close`
- `completed``reopen`
- `closed``reopen`
其中:
- `finish` 对应 `undergoing -> completed`
- `start` 对应 `open -> undergoing`
- `open` 按钮对应 `pending -> open`
### 11.9 与 Milestone 状态的联动约束
- 当 milestone 为 `open` / `freeze` 时:
- task 原则上只能处于 `pending``closed`
- 不应进入 `open / undergoing / completed`
- 当 milestone 为 `undergoing` 时:
- task 才允许从 `pending` 往执行状态推进
- 当 milestone 为 `completed` / `closed` 时:
- milestone 下 task 原则上不再继续推进
### 11.10 新建 Task 的默认状态
当前倾向:
- 新建 task 默认 `pending`
原因:
- 与 milestone `open / freeze` 阶段的“锁定”语义一致
- 避免 task 一创建就被误认为可执行
### 11.11 Assignee 字段与编辑权限规则
Task 需要一个字段:
- `assignee`
- 类型:`string`
- 可选
- 含义:用户 id
当前业务规则:
#### open 状态
-`assignee = null` 时:
- 任何人都可以编辑
-`assignee != null` 时:
- 仅当前 assignee 和 admin 可以编辑
#### undergoing 以及之后的状态
- `undergoing`
- `completed`
- `closed`
以上状态一律不可编辑。
备注:
- 这里的“不能编辑”指 task 主体内容不可编辑
- `undergoing -> completed` 已明确要求 assignee 留下 comment因此 comment / 记录性动作不等同于主体编辑
- 其他 comment 等附属动作的权限边界,后续可继续细化
---
## 12. Task 类型清理
当前又发现一个需要清理的点:
- 现在创建 task 时,存在一个 `task_type = task` 的类型
- 且它当前只有一个 subtype`defect`
这在语义上比较别扭,也和其它类型存在重叠/混淆。
### 12.1 当前决定
后续应移除这个类型:
- 移除 `task_type = task`
### 12.2 当前代码确认结果
这个问题在当前代码中已经确认存在,而且前后端都写死了:
前端:
- `HarborForge.Frontend/src/components/CreateTaskModal.tsx`
- `HarborForge.Frontend/src/pages/CreateTaskPage.tsx`
- 两处都定义了:
- `task`
- 其 subtype 只有:`defect`
- 当前创建表单默认类型也是 `task`
后端:
- `HarborForge.Backend/app/api/routers/tasks.py`
- `TASK_SUBTYPE_MAP` 中明确存在:
- `'task': {'defect'}`
补充:
- 前端类型定义里也仍包含 `task`
- 后端 schema / enum 里也仍包含 `task`
### 12.3 本轮只记录,不改代码
当前先把它记录为需求与清理项:
- 暂不实现
- 暂不修改代码
- 后续统一与 task type / subtype 体系一起调整
---
## 13. 待补充事项
这些点后续需要进一步定死:
### 13.1 feature task 在 freeze 后的可编辑字段白名单/黑名单
- 当前只明确核心字段不可编辑comment 仍可新增
- 后续要更具体列出:哪些能改,哪些不能改
### 13.2 release maintenance task 的创建入口
- 当前只明确它不能走通用 create task
- 但具体从哪里创建、谁能创建、何时创建,还需要补
### 13.3 close 时的迁移细节
- 已完成 feature task 移交到其他 `open milestone` 时,是否保留原历史链接
- task code 是否需要变化
- 依赖链迁移是否允许批量操作
---
## 14. 一句话总结
这套方案的本质是:
-`propose` 控制 feature 进入 milestone 的入口
-`milestone status` 控制范围冻结与执行节奏
-`release maintenance task` 作为 milestone 完成的关键闸门
- 用“开始前依赖检查”替代大规模自动状态联动
这样业务会更可控,也更容易避免流程混乱。