Files
HarborForge/docs/milestone-propose-requirements.md
2026-03-17 07:10:33 +00:00

34 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

2026-03-17 02:00 UTC第 4 轮Propose 模型 + DB 枚举迁移脚本)

本轮做了什么:

  • 新建 Propose 后端模型P1.3app/models/propose.py,包含 ProposeStatus 枚举open/accepted/rejected和完整字段propose_code, title, description, status, project_id, created_by_id, feat_task_id, timestamps
  • 新增 Propose Pydantic schemasP1.3ProposeStatusEnumProposeCreateProposeUpdateProposeResponsefeat_task_id 仅在 Response 中输出(只读)
  • 编写 MySQL 枚举迁移脚本P1.5):在 main.py_migrate_schema() 中新增:
    • milestone status 列:先扩宽 ENUM 接受新旧值 → UPDATE 旧值映射 → 收缩为新枚举
    • task status 列同样三步迁移progressing→undergoing
    • milestones 表 started_at 列自动添加
  • 在 startup 的 create_all 引入 propose model新部署会自动建表

改了哪些关键文件:

  • HarborForge.Backend/app/models/propose.py — 新增
  • HarborForge.Backend/app/schemas/schemas.py — 新增 Propose schemas
  • HarborForge.Backend/app/main.py — import propose + 枚举迁移 SQL

验证结果:

  • 3 个文件 Python AST 语法检查全部通过
  • 前端 tsc --noEmit 零错误(无回归)
  • 后端无旧枚举残留grep 确认)
  • 已 commit: backend 2bea75e, parent 7afa8cd

当前阻塞/风险:

  • 无本地 MySQL 环境,枚举迁移 SQL 未做实际 DB 验证
  • Propose CRUD router 尚未创建P6.1
  • Propose 编码生成逻辑P1.4 {proj_code}:P{i:05x})尚未实现
  • 前端 Propose 类型定义和页面尚未开始

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

  • P6.1 Propose 基础 CRUD routercreate/list/get/update含 propose_code 自动生成
  • 这是让 Propose 功能可用的最小后端闭环

2026-03-17 03:00 UTC第 5 轮Propose CRUD Router + Accept/Reject/Reopen 动作)

本轮做了什么:

  • 新建 app/api/routers/proposes.py,完整实现 Propose 后端 CRUD + 状态动作P6.1-P6.4
  • CRUDlist / create / get / update遵循 project-scoped 路由 /projects/{project_id}/proposes
  • propose_code 自动生成P1.4{proj_code}:P{i:05x} 格式,按 project 独立递增
  • accept 动作P6.2
    • 接收 milestone_id 参数,校验 milestone 属同 project 且 status=open
    • 自动创建 story/feature task继承 title/description/created_by默认 pending
    • 自动回填 feat_task_id
  • reject 动作P6.3):校验 propose 为 open支持 reason 参数,记录 activity log
  • reopen 动作P6.4):仅 rejected 可 reopen 回 open复用原 propose 不新建
  • feat_task_id 只读保护P6.5update 接口中 pop 掉客户端传入的 feat_task_id
  • main.py 注册 proposes_router
  • 所有动作均写 activity log

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/proposes.py — 新增280 行)
  • HarborForge.Backend/app/main.py — 注册 proposes_router

验证结果:

  • Python AST 语法检查 proposes.py / main.py 均通过
  • 已 commitbackend 75ccbcbparent 5602b1b

当前阻塞/风险:

  • 权限检查暂用 check_project_role(min_role="mgr") 占位,待 P2 权限骨架落地后替换为细粒度 permission
  • propose_code 生成使用 max(id)+1,并发场景理论上有微小重复风险(但有 unique 约束保底)
  • 无本地 MySQL 环境做运行时验证
  • 前端 Propose 页面尚未开始P10

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

  • P10.1-P10.3 前端 Propose 类型定义 + 列表页 + 详情页骨架(让 propose 功能在 UI 上可见)
  • 或 P3.1 Milestone 动作接口freeze/start/close使 milestone 状态机真正可用

2026-03-17 04:00 UTC第 6 轮Milestone 动作接口 freeze/start/close + auto-complete

本轮做了什么:

  • 新建 app/api/routers/milestone_actions.py313 行),实现 P3.1-P3.5 的核心后端逻辑
  • freeze 接口P3.2
    • 校验 milestone 为 open
    • 校验有且仅有 1 个 maintenance/release task否则拒绝并给出明确错误
    • 调用 check_permission("freeze milestone")
  • start 接口P3.3
    • 校验 milestone 为 freeze
    • 解析 depend_on_milestones / depend_on_tasks JSON校验所有依赖已 completed
    • 写入 started_at,状态改为 undergoing
    • 调用 check_permission("start milestone")
  • close 接口P3.4
    • 允许从 open/freeze/undergoing → closed
    • 支持 reason 参数
    • 调用 check_permission("close milestone")
  • auto-complete hookP3.5
    • try_auto_complete_milestone() 在 task 完成时检测是否为唯一 release task若是则自动将 milestone 置为 completed
    • 已在 tasks.py 的 transition 和 update 两个入口调用
  • freeze 后限制P3.6 partial
    • milestones.py 的 create_milestone_task 现在禁止在 freeze 状态下添加 feature story task
    • 同时禁止在 undergoing/completed/closed 下添加任何 task
  • milestone 序列化新增 started_at 字段
  • 所有动作均写 activity log

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/milestone_actions.py — 新增
  • HarborForge.Backend/app/api/routers/milestones.py — freeze 限制 + started_at 序列化
  • HarborForge.Backend/app/api/routers/tasks.py — auto-complete hook2 处)
  • HarborForge.Backend/app/main.py — 注册 milestone_actions_router

验证结果:

  • 4 个文件 Python AST 语法检查全部通过
  • 已 commitbackend 7d8c448

当前阻塞/风险:

  • P2 权限骨架尚未落地(freeze/start/close milestone permission 需要注册到 permission 表 + 默认角色种子)
  • milestone 编辑限制P3.6只做了部分freeze 后禁新 feature taskcompleted/closed 禁编辑还需在 update 接口加守卫
  • 前端 milestone 按钮P8.2)尚未开始
  • 无本地 MySQL 做运行时验证

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

  • P3.6 补全 milestone 编辑限制update 接口在 freeze/completed/closed 时拒绝核心字段修改)
  • 或 P10.1-P10.3 前端 Propose 类型 + 列表/详情页骨架
  • 或 P8.1-P8.2 前端 milestone 状态 badge + 动作按钮

2026-03-17 05:00 UTC第 7 轮:前端 Propose 完整页面骨架 P10.1-P10.5

本轮做了什么:

  • 新增 Propose 类型定义到 types/index.tsP10.1
  • 新建 ProposesPage.tsx — 按 project 筛选的 propose 列表页 + 创建弹窗P10.1-P10.2
    • 项目下拉选择
    • propose 卡片展示 status badge / propose_code / title / description / feat_task_id / created_at
    • 内联创建弹窗title + description
  • 新建 ProposeDetailPage.tsx — 完整详情页 + 状态动作按钮P10.3-P10.6
    • 展示所有必要字段propose_code / title / description / status / created_by / feat_task_id / timestamps
    • open 状态显示 Accept + Reject 按钮
    • Accept 弹窗:列出当前 project 下 open 的 milestone 供选择,确认后调用 accept API
    • Rejectprompt 填写 reason调用 reject API
    • rejected 状态显示 Reopen 按钮
    • accepted 状态显示 View Generated Task 跳转按钮
    • 所有动作带 loading 状态和错误提示
  • App.tsx 注册 /proposes/proposes/:id 路由
  • Sidebar.tsx 新增 💡 Proposes 导航链接

改了哪些关键文件:

  • src/types/index.ts — 新增 Propose 接口
  • src/pages/ProposesPage.tsx — 新增
  • src/pages/ProposeDetailPage.tsx — 新增
  • src/App.tsx — 路由注册
  • src/components/Sidebar.tsx — 侧边栏链接

验证结果:

  • npx tsc --noEmit 零错误通过
  • 已 commit: 35e7d3a

当前阻塞/风险:

  • ProposeDetailPage 中 "View Generated Task" 跳转使用 feat_task_id 作为路径,需确认后端返回的是 task id 数字还是 task code 字符串
  • Propose 编辑功能P10.7 open 时编辑 title/description尚未实现
  • CSS badge class status-completed / status-closed 可能需要新增样式
  • 权限可见性控制(按钮仅对有权限的用户显示)尚未实现,当前所有按钮对所有用户可见

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

  • P8.1-P8.2 前端 milestone 状态 badge + 动作按钮freeze/start/close让 milestone 状态机在 UI 上可操作
  • 或 P3.6 补全 milestone 编辑限制(后端 update 接口守卫)

2026-03-17 06:00 UTC第 8 轮:前端 Milestone 状态动作按钮 P8.1-P8.2

本轮做了什么:

  • 在 MilestoneDetailPage 实现 freeze/start/close 三个状态动作按钮P8.2
    • Freeze 按钮:仅 open 状态显示,调用 POST /projects/{pid}/milestones/{mid}/actions/freeze
    • Start 按钮:仅 freeze 状态显示,调用 POST .../actions/start
    • Close 按钮open/freeze/undergoing 状态显示,带确认步骤 + reason 输入框
  • 所有按钮有 loading 状态和错误提示(后端返回的 detail 直接展示)
  • 新增 started_at 显示在 milestone 元数据区域P8.1
  • completed/closed 终态下隐藏编辑按钮和创建 item 按钮
  • 新增 CSS badge 样式:status-freeze(紫色)、status-undergoing(琥珀)、status-completed(绿色)

改了哪些关键文件:

  • HarborForge.Frontend/src/pages/MilestoneDetailPage.tsx — 动作按钮 + started_at + 终态守卫
  • HarborForge.Frontend/src/index.css — 新状态 badge 样式

验证结果:

  • npx tsc --noEmit 零错误通过
  • 已 commit: 18703d9

当前阻塞/风险:

  • 按钮权限可见性未实现(当前所有用户都能看到按钮,前端无细粒度权限检查机制)
  • freeze/start 按钮的"禁用+提示"未实现P8.3,如缺少 release task 时应禁用 freeze 并提示)
  • 后端 milestone 编辑限制P3.6)仍未补全

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

  • P9.2 前端 Task 状态动作按钮open/start/finish/close/reopen让 task 状态机在 UI 可操作
  • 或 P8.3 freeze/start 按钮的前端前置条件检查与禁用提示
  • 或 P3.6 后端 milestone 编辑限制守卫

2026-03-17 07:00 UTC第 9 轮:前端 Task 动作按钮 P9.2 + P9.4

本轮做了什么:

  • 在 TaskDetailPage 实现完整的 task 状态动作按钮P9.2),替代旧的裸状态名按钮
  • pending 状态:▶ Open + ✕ Close
  • open 状态:⏵ Start + ✕ Close
  • undergoing 状态:✓ Finish + ✕ Close
  • completed / closed 状态:↺ Reopen
  • 实现 Finish 弹窗P9.4):点击 Finish 时弹出模态框,必须填写完成 comment 才能确认comment 先写入再 transition
  • 实现 Close 弹窗:可选填写关闭原因,原因以 [Close reason] 前缀写入 comment
  • 所有按钮有 loading 状态和错误提示(后端 detail 直接展示)
  • 终态completed/closed和 undergoing 下隐藏 Edit Task 按钮,匹配 P9.3 编辑限制

改了哪些关键文件:

  • HarborForge.Frontend/src/pages/TaskDetailPage.tsx — 全量重写 actions 区块

验证结果:

  • npx tsc --noEmit 零错误通过
  • 已 commit: frontend e6b91e9, parent cc2086e

当前阻塞/风险:

  • 后端 transition 接口暂无状态流转合法性校验(如 pending→completed 也能通过),需要 P5.1-P5.6 补强
  • 按钮权限可见性未实现close/reopen 应按权限控制,当前所有用户可见)
  • Start 按钮未校验 assignee 和 milestone 状态P5.3 后端校验 + P9.3 前端守卫)

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

  • P5.1-P5.2 后端 task transition 合法性校验(加状态流转守卫到 transition 接口,拒绝非法转换)
  • 或 P3.6 后端 milestone 编辑限制freeze/completed/closed 时拒绝核心字段修改)
  • 或 P8.3 前端 milestone freeze/start 按钮前置条件检查与禁用提示

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

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