Files
HarborForge/docs/milestone-propose-requirements.md

22 KiB
Raw Blame History

HarborForge 需求草案Milestone 状态机与 Propose 流程

状态:草案 更新时间2026-03-16 目的先把业务想法固定下来后续再拆数据库、API、前端和测试实现。


0. 开发状态

2026-03-16 23:49 UTC第 1 轮:基线盘点 + 自动开发调度)

当前进度:已启动按小时推进的开发节奏,先完成一轮代码基线盘点,方便后续按模块逐步落地。

本轮已确认:

  • 后端 milestone 旧状态枚举仍在使用:open / pending / deferred / progressing / closed
    • 位置:HarborForge.Backend/app/models/milestone.py
  • 后端 task 旧状态枚举仍在使用:open / pending / progressing / closed
    • 位置:HarborForge.Backend/app/models/task.pyHarborForge.Backend/app/models/models.pyHarborForge.Backend/app/schemas/schemas.py
  • 后端与前端都还有多处写死 progressing / pending / deferred
    • 典型位置:
      • 后端:app/api/routers/milestones.pyapp/api/routers/tasks.pycli.py
      • 前端:src/types/index.tssrc/components/MilestoneFormModal.tsxsrc/pages/MilestoneDetailPage.tsxsrc/pages/TaskDetailPage.tsx
  • task_type = task 仍真实存在,且当前主要表现为 subtype = defect
    • 后端:HarborForge.Backend/app/api/routers/tasks.pyTASK_SUBTYPE_MAP
    • 前端:HarborForge.Frontend/src/components/CreateTaskModal.tsxHarborForge.Frontend/src/pages/CreateTaskPage.tsx

当前判断:

  • 下一步最合适的是先做 P0/P1 之间的“状态枚举与迁移骨架”,否则后续 milestone / task / propose 的接口实现会反复返工。
  • 具体优先级建议:
    1. 先统一后端 milestone/task 新旧状态枚举与 schema
    2. 再补 migration / 兼容映射
    3. 然后推进动作接口、权限、前端按钮与页面

阻塞项:

  • 暂无硬阻塞;但 closed / completed 的终态与 task reopen 已写入需求,后续实现时要一次性考虑兼容,避免先做死状态流转。

2026-03-17 00:00 UTC第 2 轮:后端状态枚举全量替换)

本轮做了什么:

  • 将 milestone 和 task 的后端状态枚举全部替换为新值
  • Milestone: open/pending/deferred/progressing/closedopen/freeze/undergoing/completed/closed
  • Task: open/pending/progressing/closedopen/pending/undergoing/completed/closed
  • 新增 MilestoneStatusEnum 到 schemas.pymilestone 的 create/update/response 现在使用类型化枚举而非裸字符串
  • 新增 started_at 字段到 Milestone model 和 MilestoneResponse
  • 更新所有 routermilestones.py, tasks.py, misc.pyprogressingundergoing 引用
  • 更新 task transition 逻辑支持 completed 状态自动记录 finished_on
  • 更新 CLI status icon 映射和 choices 参数

改了哪些关键文件:

  • HarborForge.Backend/app/models/milestone.py — enum + started_at
  • HarborForge.Backend/app/models/task.py — enum
  • HarborForge.Backend/app/models/models.py — enum
  • HarborForge.Backend/app/schemas/schemas.py — MilestoneStatusEnum + TaskStatusEnum + started_at
  • HarborForge.Backend/app/api/routers/milestones.py — progressing→undergoing
  • HarborForge.Backend/app/api/routers/tasks.py — progressing→undergoing, completed handling
  • HarborForge.Backend/app/api/routers/misc.py — progressing→undergoing (3处)
  • HarborForge.Backend/cli.py — status icons + choices

验证结果:

  • 全部 8 个文件 Python AST 语法检查通过
  • 后端无 sqlalchemy 环境无法做运行时验证,但枚举定义和引用已全部对齐
  • grep 确认后端代码中不再有 progressing/deferred 残留

当前阻塞/风险:

  • 数据库迁移脚本尚未编写MySQL enum 列需要 ALTER TABLE 才能接受新值)
  • 前端仍使用旧状态值,需要同步更新
  • 没有本地 DB/Docker 环境做集成验证

下一轮最建议继续做什么:

  • P1.5 数据库迁移骨架:编写 Alembic 或手写 SQL 迁移脚本,处理 MySQL enum 列的 ALTER 和旧数据映射
  • 或者先做前端 TypeScript 类型定义更新(影响面小、独立性强)

2026-03-17 01:00 UTC第 3 轮:前端状态枚举全量替换)

本轮做了什么:

  • 将前端所有 TypeScript 类型定义和组件中的旧状态枚举替换为新值
  • Task status: progressingundergoing + 新增 completed
  • Milestone status: pending/deferred/progressingfreeze/undergoing/completed + 新增 started_at 字段
  • 更新 TaskDetailPage 状态流转映射表,匹配新状态机
  • 更新 MilestoneFormModal 下拉选项
  • 清理 MilestoneDetailPage / MilestonesPage 中的 badge class 映射

改了哪些关键文件:

  • HarborForge.Frontend/src/types/index.ts — Task/Milestone 接口类型
  • HarborForge.Frontend/src/components/MilestoneFormModal.tsx — status 下拉选项
  • HarborForge.Frontend/src/pages/MilestoneDetailPage.tsx — isProgressing→isUndergoing, badge class
  • HarborForge.Frontend/src/pages/MilestonesPage.tsx — badge class
  • HarborForge.Frontend/src/pages/TaskDetailPage.tsx — statusActions 流转表

验证结果:

  • npx tsc --noEmit 零错误通过
  • grep -rn "progressing|deferred" 确认前端无旧枚举残留
  • 已 commit: e60763b

当前阻塞/风险:

  • 数据库迁移脚本仍未编写MySQL enum 列 ALTER
  • 前端 CSS badge class 可能需要新增 status-freeze / status-undergoing / status-completed 样式
  • 没有本地运行环境做视觉验证

下一轮最建议继续做什么:

  • P1.5 数据库迁移骨架:编写 SQL 迁移脚本处理 MySQL enum 列 ALTER + 旧数据映射milestone: pending→open, deferred→closed, progressing→undergoing; task: progressing→undergoing
  • 或 P1.3 Propose 模型新增(后端新建 propose model + schema

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 = featurestory task
  • 已存在的 feature story task 不能再编辑核心字段
    • 例如:titledescriptionowner
  • 但允许继续做附属操作
    • 例如:新增 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

格式:

{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 可编辑 titledescription
    • 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 允许从 closedcompleted 触发
  • reopen 后统一回到 open
  • reopen 记录采用 comment、activity log 还是专门字段/表,后续再定

当前理解:

  • completedclosed 原本被视为终态
  • 但 task 将引入受控的 reopen 机制,使其可以返回 open

11.7 Task 状态动作权限

将以下三类动作设计为独立权限,由 role 控制:

  • close task
  • reopen closed task
  • reopen completed task

规则:

  • 拥有对应权限的 role 才可以执行对应动作
  • reopen closed taskreopen completed task 分开控制,不合并为一个权限

补充:

  • undergoing -> completed 不走 role 权限控制
  • complete 只有当前 assignee 可以执行

11.8 Task 页面按钮可见性

所有按钮都按权限可见。

当前确认的按钮规则:

  • closedcompletedtask 页面始终显示 close 按钮
    • 也就是:
      • pendingclose
      • openclose
      • undergoingclose
  • closedcompleted 状态显示 reopen 按钮
  • pending 状态显示 open 按钮
  • open 状态显示 start 按钮
  • undergoing 状态显示 finish 按钮

可理解为:

  • pendingopen + close
  • openstart + close
  • undergoingfinish + close
  • completedreopen
  • closedreopen

其中:

  • finish 对应 undergoing -> completed
  • start 对应 open -> undergoing
  • open 按钮对应 pending -> open

11.9 与 Milestone 状态的联动约束

  • 当 milestone 为 open / freeze 时:
    • task 原则上只能处于 pendingclosed
    • 不应进入 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 的类型
  • 且它当前只有一个 subtypedefect

这在语义上比较别扭,也和其它类型存在重叠/混淆。

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 完成的关键闸门
  • 用“开始前依赖检查”替代大规模自动状态联动

这样业务会更可控,也更容易避免流程混乱。