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

60 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 按钮前置条件检查与禁用提示

2026-03-17 08:00 UTC第 10 轮Task 状态机后端校验 P5.1-P5.6

本轮做了什么:

  • 在后端 tasks.py 实现完整的 task 状态流转校验P5.1-P5.6
  • 新增 VALID_TRANSITIONS 映射表,定义合法流转:
    • pending → open / closed
    • open → undergoing / closed
    • undergoing → completed / closed
    • completed → open (reopen)
    • closed → open (reopen)
  • 新增 _check_transition() 校验函数,非法流转返回 400 + 明确错误信息
  • transition 接口:加入状态机校验 + pending→open 校验 milestone 必须为 undergoing + open→undergoing 校验 assignee 非空 + reopen 时清除 finished_on
  • batch transition 接口:逐条校验,非法转换跳过并返回 skipped 列表(不破坏已有批量行为)
  • PATCH update 接口:通过 PATCH 修改 status 时同样强制状态机校验

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/tasks.py — +65 行

验证结果:

  • Python AST 语法检查通过
  • 已 commit: 589b1cc

当前阻塞/风险:

  • P5.3 assignee 操作者校验("只有当前 assignee 可以 start")未实现——当前只校验 assignee 非空未校验请求者身份transition 接口无 current_user 参数)
  • P5.4 undergoing→completed 需要 comment 的校验尚未加入后端(前端已有弹窗,但后端不拦截)
  • 权限检查close task / reopen closed task / reopen completed task尚未注册和调用
  • 无本地 DB 做运行时集成验证

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

  • P3.6 后端 milestone 编辑限制freeze/completed/closed 时拒绝核心字段 PATCH
  • 或 P8.3 前端 milestone freeze/start 按钮禁用+前置条件提示
  • 或 P5.3 补全 transition 接口的 current_user 依赖注入 + assignee 身份校验

2026-03-17 09:00 UTC第 11 轮P3.6 Milestone 编辑限制 — 前后端完整落地)

本轮做了什么:

  • 实现 P3.6 milestone 编辑限制的后端 + 前端完整守卫
  • 后端 PATCH 接口milestones.py
    • completed / closed 终态:直接拒绝所有 PATCH 修改
    • freeze / undergoing禁止修改范围相关字段title, description, due_date, planned_release_date, depend_on_milestones, depend_on_tasks返回具体被阻止的字段名
    • 禁止通过 PATCH 修改 status强制使用 action endpoints
  • 后端 DELETE 接口milestones.py
    • undergoing / completed 状态禁止删除 milestone
  • 前端 MilestoneDetailPage
    • open 状态:正常显示 Edit Milestone 按钮
    • freeze / undergoing:隐藏编辑按钮,显示 "⚠ scope fields are locked" 提示
    • completed / closed:不显示编辑入口(已有逻辑保持)

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/milestones.py — PATCH 守卫 + DELETE 守卫(+32 行)
  • HarborForge.Frontend/src/pages/MilestoneDetailPage.tsx — 编辑按钮可见性调整

验证结果:

  • Python AST 语法检查通过
  • npx tsc --noEmit 零错误通过
  • 已 commitbackend 314040cfrontend a4b4ffcparent 6b265ea

当前阻塞/风险:

  • feature story task 在 freeze 后的编辑限制只做了"不能新增",但已有 feature task 的核心字段编辑限制尚未加入 task PATCH 接口
  • P2 权限骨架仍未落地,所有动作接口使用通用 role check 占位
  • 无本地 MySQL/Docker 做运行时集成验证

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

  • P8.3 前端 milestone freeze/start 按钮前置条件检查与禁用提示freeze 时检查 release task 存在性start 时检查依赖完成情况)
  • 或 P5.3 后端 task transition 补全 current_user 依赖注入 + assignee 身份校验
  • 或 P5.4 后端 undergoing→completed 强制要求 comment

2026-03-17 10:00 UTC第 12 轮P8.3 Milestone freeze/start 按钮前置条件检查与禁用提示)

本轮做了什么:

  • 新增后端 GET /projects/{pid}/milestones/{mid}/actions/preflight 端点milestone_actions.py
    • 当 milestone 为 open 时,返回 freeze 是否允许 + 原因(检查 maintenance/release task 数量)
    • 当 milestone 为 freeze 时,返回 start 是否允许 + 原因(检查依赖 milestone/task 是否已 completed
    • 只读接口,不做任何数据变更
  • 前端 MilestoneDetailPage 集成 preflight
    • milestone 加载后自动调用 preflight API
    • freeze 按钮:条件不满足时禁用 + 显示 ⚠ 原因提示(如"No maintenance/release task found"
    • start 按钮:依赖未完成时禁用 + 显示 ⚠ 原因提示
    • 动作执行成功后自动刷新 preflight 状态
    • 鼠标 hover 按钮时 title 也显示原因

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/milestone_actions.py — 新增 preflight endpoint+84 行)
  • HarborForge.Frontend/src/pages/MilestoneDetailPage.tsx — preflight 状态 + 按钮禁用逻辑

验证结果:

  • Python AST 语法检查通过
  • npx tsc --noEmit 零错误通过
  • 已 commitbackend 7a16639frontend faf7842

当前阻塞/风险:

  • P2 权限骨架仍未落地preflight 不检查用户是否有 freeze/start 权限(只检查业务前置条件)
  • 无本地 MySQL/运行环境做集成验证
  • P5.3 task transition 的 assignee 身份校验仍缺失
  • P5.4 后端 undergoing→completed 强制要求 comment 仍缺失

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

  • P5.3 后端 task transition 补全 assignee 身份校验open→undergoing 时校验操作者 == assignee
  • 或 P5.4 后端 undergoing→completed 强制要求 completion comment
  • 或 P10.7 前端 propose 编辑限制open 时允许编辑 title/description

2026-03-17 11:00 UTC第 13 轮P5.3 Assignee 身份校验 + P5.4 完成 Comment 强制要求)

本轮做了什么:

  • 在后端 transition 接口补全 P5.3 和 P5.4 两项关键校验
  • P5.3 Assignee 身份校验
    • transition 接口新增 current_user 依赖注入
    • open → undergoing:除校验 assignee 非空外,新增校验 current_user.id == task.assignee_id,非 assignee 返回 403
    • undergoing → completed:同样校验操作者必须为 assignee
  • P5.4 完成 Comment 强制要求
    • transition 接口新增 TransitionBody 请求体(含可选 comment 字段)
    • undergoing → completed 时强制要求 comment 非空,否则返回 400
    • 后端自动创建 Comment 记录(复用 models.Comment),不再依赖前端单独调用 comment API
  • transition 所有状态变更现在自动写 log_activity,记录 old/new status
  • auto-complete milestone 时传入 current_user.id 替代原先的 None
  • 前端 TaskDetailPage 同步更新
    • doAction 改为接收 body 参数,直接在 transition POST 请求体中传递 { comment }
    • Finish 流程不再单独调用 POST /comments,改为后端统一处理
    • Close 流程的 reason comment 同样通过请求体传递

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/tasks.py — transition 接口重构(+40 行)
  • HarborForge.Frontend/src/pages/TaskDetailPage.tsx — doAction/finish/close 逻辑简化

验证结果:

  • Python AST 语法检查通过
  • npx tsc --noEmit 零错误通过
  • 已 commitbackend ffb0fa6frontend d6a45c3

当前阻塞/风险:

  • P2 权限骨架仍未落地close task / reopen 权限未注册和调用)
  • batch transition 接口尚未同步 P5.3/P5.4 校验(无 current_user无 comment body
  • 无本地 MySQL/运行环境做集成验证

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

  • P10.7 前端 propose 编辑限制open 时允许编辑 title/description其他状态禁止
  • 或 P9.3 前端 task 编辑权限守卫(按 assignee/status 显示/隐藏编辑入口)
  • 或 P5.7 后端 task PATCH 接口编辑权限服务端防守

2026-03-17 12:00 UTC第 14 轮P5.7 Task 编辑权限服务端防守 + P9.3 前端守卫)

本轮做了什么:

  • 实现 P5.7 后端 task PATCH 接口的 status+assignee 编辑限制
  • 实现 P9.3 前端 task 编辑按钮的 status+assignee 可见性守卫
  • 后端 PATCH 接口tasks.py
    • undergoing / completed / closed:禁止修改 body 字段status 字段仍可通过 PATCH 传递以走状态机)
    • open + assignee_id 非空:仅 assignee 本人或 admin 可编辑 body 字段,否则返回 403
    • open + assignee_id 为空 / pending:沿用原有 ensure_can_edit_task 通用权限
  • 前端 TaskDetailPageP9.3
    • canEditTask 重构为考虑 status + assignee 的完整守卫
    • undergoing/completed/closedEdit Task 按钮不显示
    • open + assigned:仅 assignee 和 admin 看到编辑按钮
    • open + unassigned / pending:项目成员均可编辑
    • 移除冗余的 !isTerminal && task.status !== 'undergoing' 外层条件(已内化到 canEditTask

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/tasks.py — PATCH 接口新增 P5.7 守卫(+31 行)
  • HarborForge.Frontend/src/pages/TaskDetailPage.tsx — canEditTask 重构

验证结果:

  • Python AST 语法检查通过
  • npx tsc --noEmit 零错误通过
  • 已 commitbackend 7542f2dfrontend 638427d

当前阻塞/风险:

  • P2 权限骨架仍未落地close/reopen 权限未注册)
  • feature story task 在 freeze 后的编辑限制P3.6 补充)尚未加入 task PATCH 接口
  • batch transition 接口尚未同步 P5.3/P5.4 校验
  • 无本地 MySQL/运行环境做集成验证

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

  • P10.7 前端 propose 编辑限制open 时允许编辑 title/description其他状态禁止
  • 或 P9.6 前端创建 task 限制(禁止通用 create 创建 feature story / release maintenance task
  • 或 P5.2 补全 pending→open 依赖检查(通用依赖检查 helper

2026-03-17 13:00 UTC第 15 轮P9.6 Task 创建限制 — 前后端完整落地)

本轮做了什么:

  • 实现 P9.6:禁止通过通用 create task 创建 story/featuremaintenance/release 类型的 task
  • 后端 tasks.py
    • 新增 RESTRICTED_TYPE_SUBTYPES 集合,定义受限类型组合
    • _validate_task_type_subtype() 增加 allow_restricted 参数,默认阻止受限组合
    • 通用 POST /tasks 端点自动拦截,返回 400 + 明确错误信息
    • propose accept 内部创建走 ORM 直接写入,不受此限制
  • 后端 milestones.py
    • POST /{milestone_id}/tasks 端点增加 P9.6 守卫:直接拒绝 story/feature 创建
    • maintenance/release 不受限milestone endpoint 是其合法创建入口)
  • 前端 CreateTaskModal + CreateTaskPage
    • Story subtypes 移除 feature(仅保留 improvement、refactor
    • Maintenance subtypes 移除 release(仅保留 deploy
    • 两个创建表单同步更新

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/tasks.py — RESTRICTED_TYPE_SUBTYPES + 校验增强
  • HarborForge.Backend/app/api/routers/milestones.py — story/feature 创建拦截
  • HarborForge.Frontend/src/components/CreateTaskModal.tsx — 移除受限 subtypes
  • HarborForge.Frontend/src/pages/CreateTaskPage.tsx — 移除受限 subtypes

验证结果:

  • Python AST 语法检查 tasks.py / milestones.py 均通过
  • npx tsc --noEmit 零错误通过
  • 已 commitbackend c18b8f3frontend 2897172parent 6441ea5

当前阻塞/风险:

  • maintenance/release task 的受控创建入口尚未明确实现(当前通过 milestone endpoint 可创建,但无专门的 release setup 流程)
  • P2 权限骨架仍未落地
  • batch transition 接口尚未同步 P5.3/P5.4 校验
  • 无本地 MySQL/运行环境做集成验证

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

  • P10.7 前端 propose 编辑限制open 时显示编辑入口accepted/rejected 禁止编辑主体)
  • 或 P2.1 后端权限枚举注册freeze/start/close milestone + close/reopen task + accept/reject/reopen propose
  • 或 P5.2 补全 pending→open 通用依赖检查 helper

2026-03-17 14:00 UTC第 16 轮P10.7 前端 Propose 编辑限制)

本轮做了什么:

  • 实现 P10.7Propose 详情页编辑功能,仅 open 状态可编辑 title 和 description
  • ProposeDetailPage 新增
    • ✏️ Edit 按钮:仅 open 状态显示(与 Accept/Reject 同行)
    • 编辑弹窗title 输入框 + description 多行文本框
    • 调用 PATCH /projects/{pid}/proposes/{id} 提交修改
    • title 不能为空时 Save 按钮禁用
    • 保存成功后自动刷新详情
    • loading 状态和错误提示完整
  • accepted / rejected 状态下不显示 Edit 按钮(按钮渲染在 open 条件分支内),实现主体不可编辑

改了哪些关键文件:

  • HarborForge.Frontend/src/pages/ProposeDetailPage.tsx — +75 行(编辑状态 + 弹窗 + handler

验证结果:

  • npx tsc --noEmit 零错误通过
  • 已 commitfrontend 208538f

当前阻塞/风险:

  • 编辑权限仅在后端校验creator / admin / 项目管理员),前端未根据当前用户身份隐藏按钮
  • P2 权限骨架仍未落地(所有动作接口使用通用 role check 占位)
  • batch transition 接口尚未同步 P5.3/P5.4 校验
  • 无本地 MySQL/运行环境做集成验证

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

  • P2.1 后端权限枚举注册freeze/start/close milestone + close/reopen task + accept/reject/reopen propose这是剩余功能中最基础的依赖项
  • 或 P4.1 通用依赖检查 helper 抽取milestone start 和 task pending→open 复用)
  • 或 P5.4 补全后端 undergoing→completed 强制 comment 校验(前端已有弹窗,后端尚缺校验)

2026-03-17 15:00 UTC第 17 轮P2.1 权限枚举注册 + 全动作接口权限接入)

本轮做了什么:

  • 实现 P2.1:在 DEFAULT_PERMISSIONS 注册 9 个新权限,并将所有动作接口从占位 check_project_role 切换为真正的 check_permission
  • 新增权限init_wizard.py
    • milestone.freeze / milestone.start / milestone.closecategory: milestone
    • task.close / task.reopen_closed / task.reopen_completedcategory: task
    • propose.accept / propose.reject / propose.reopencategory: propose
  • milestone_actions.py:将旧字符串 "freeze milestone" 等替换为点分权限名 "milestone.freeze"
  • proposes.pyaccept/reject/reopen 三个端点从 check_project_role(min_role="mgr") 替换为 check_permission(..., "propose.accept/reject/reopen"),移除所有 TODO 占位注释
  • tasks.pytransition 接口新增:
    • new_status == "closed" 时调用 check_permission(..., "task.close")
    • reopen 时根据来源区分 task.reopen_completed / task.reopen_closed
  • admin 角色通过 init_admin_role() 自动获得所有新权限(无需手动配置)

改了哪些关键文件:

  • HarborForge.Backend/app/init_wizard.py — 新增 9 个权限定义
  • HarborForge.Backend/app/api/routers/milestone_actions.py — 权限名标准化
  • HarborForge.Backend/app/api/routers/proposes.py — 替换为 check_permission
  • HarborForge.Backend/app/api/routers/tasks.py — 新增 close/reopen 权限检查

验证结果:

  • 4 个文件 Python AST 语法检查全部通过
  • grep 确认无残留旧权限字符串和 TODO 占位
  • 已 commitbackend 3afbbc2parent 054cf43

当前阻塞/风险:

  • P2.2 默认角色权限种子尚未细化(当前只有 admin 全量、guest 只读dev/mgr 等自定义角色需要手动配置新权限)
  • 前端按钮尚未根据用户权限做可见性控制(当前所有按钮对所有项目成员可见)
  • batch transition 接口尚未同步权限检查
  • 无本地 MySQL/运行环境做集成验证

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

  • P4.1 通用依赖检查 helper 抽取milestone start 和 task pending→open 复用),减少重复逻辑
  • 或 P2.2 默认角色权限种子配置(为 dev/mgr 等常用角色预置合理的新权限组合)
  • 或 P7.1 移除 task_type = task(代码清理项,独立性强)

2026-03-17 16:00 UTC第 18 轮P7.1-P7.2 移除 task_type='task' — 前后端 + DB 迁移)

本轮做了什么:

  • 完整实现 P7.1(后端)和 P7.2(前端):移除 task_type = task 类型
  • 后端 schemas.py:从 TaskTypeEnum 中移除 TASK = "task",默认值改为 ISSUE
  • 后端 tasks.py:从 TASK_SUBTYPE_MAP 中移除 'task': {'defect'} 条目
  • 后端 task.pymodel:列默认值从 "task" 改为 "issue"
  • 后端 misc.pyimport 默认值从 "task" 改为 "issue"
  • 后端 main.pyDB 迁移)
    • 新增迁移步骤:UPDATE tasks SET task_type='issue' WHERE task_type='task'
    • 新表创建默认值改为 'issue'
  • 前端 types/index.tsTask 类型联合移除 'task'
  • 前端 CreateTaskModal.tsx:移除 task 类型条目,默认 task_type 改为 'issue'
  • 前端 CreateTaskPage.tsx:同上

改了哪些关键文件:

  • HarborForge.Backend/app/schemas/schemas.py — 移除 TASK enum
  • HarborForge.Backend/app/models/task.py — 默认值改为 issue
  • HarborForge.Backend/app/api/routers/tasks.py — 移除 task subtype map
  • HarborForge.Backend/app/api/routers/misc.py — 默认值改为 issue
  • HarborForge.Backend/app/main.py — DB 迁移脚本
  • HarborForge.Frontend/src/types/index.ts — 类型联合更新
  • HarborForge.Frontend/src/components/CreateTaskModal.tsx — 移除 task 类型
  • HarborForge.Frontend/src/pages/CreateTaskPage.tsx — 移除 task 类型

验证结果:

  • 5 个后端文件 Python AST 语法检查全部通过
  • npx tsc --noEmit 零错误通过
  • grep 确认前后端无残留 task_type='task' 引用
  • 已 commitbackend 89e3bcdfrontend d399668

当前阻塞/风险:

  • P7.3 历史数据处理DB 迁移脚本已自动将 task_type='task' 转为 'issue',但无本地 MySQL 做实际验证
  • defect subtype 现在仅属于 issue 类型(原先 taskissue 都有 defect语义上更清晰
  • 无本地运行环境做集成验证

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

  • P4.1 通用依赖检查 helper 抽取milestone start 和 task pending→open 复用)
  • 或 P2.2 默认角色权限种子配置(为 dev/mgr 等常用角色预置合理的新权限组合)
  • 或 P11.1 前端权限列表展示新增权限

2026-03-17 17:00 UTC第 19 轮P4.1 通用依赖检查 Helper 抽取)

本轮做了什么:

  • 新建 app/services/dependency_check.py,实现 P4.1 通用依赖检查能力
  • check_milestone_deps() 函数:接收 depend_on_milestones + depend_on_tasks JSON 字段,返回结构化 DepCheckResultok/blockers/reason
  • 内部 helper _parse_json_ids() 安全解析 JSON ID 列表,消除重复的 try/except 模式
  • 重构 milestone_actions.pypreflight 和 start 两个端点的依赖检查从 ~50 行内联代码缩减为各 ~5 行调用
  • 移除了 milestone_actions.py 中不再需要的 import json

改了哪些关键文件:

  • HarborForge.Backend/app/services/dependency_check.py — 新增(~95 行)
  • HarborForge.Backend/app/api/routers/milestone_actions.py — 重构,净减 ~50 行

验证结果:

  • 2 个文件 Python AST 语法检查通过
  • 已 commitbackend c6b14acparent 0bc2379

当前阻塞/风险:

  • task pending→open 的依赖检查尚未接入此 helper当前 tasks.py 只校验 milestone 为 undergoing不检查 task 自身的 depend_on 字段)
  • P2.2 默认角色权限种子仍未细化dev/mgr 角色无预置新权限)
  • 无本地 MySQL/运行环境做集成验证

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

  • P4.3 在 task transition pending→open 中接入 check_milestone_deps 检查 task 自身依赖
  • 或 P2.2 默认角色权限种子配置
  • 或 P11.1 前端权限列表展示新增权限

2026-03-17 18:00 UTC第 20 轮P4.3 Task depend_on 依赖检查接入 pending→open

本轮做了什么:

  • 实现 P4.3:在 task pending→open transition 中接入 check_task_deps() 依赖检查
  • dependency_check.py 新增 check_task_deps() 函数,专门处理 task 的 depend_on 字段JSON 编码的 task ID 列表)
  • tasks.py transition 接口的 pending→open 分支中milestone 状态校验通过后,继续检查 task 自身的 depend_on 依赖是否全部 completed
  • 不满足时返回 400 + 具体未完成的 task ID 列表

改了哪些关键文件:

  • HarborForge.Backend/app/services/dependency_check.py — 新增 check_task_deps()+33 行)
  • HarborForge.Backend/app/api/routers/tasks.py — import + pending→open 新增依赖检查(+7 行)

验证结果:

  • 2 个文件 Python AST 语法检查通过
  • 已 commit0c75045

当前阻塞/风险:

  • batch transition 接口尚未同步 P4.3 依赖检查
  • P2.2 默认角色权限种子仍未细化dev/mgr 角色无预置新权限)
  • 无本地 MySQL/运行环境做集成验证

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

  • P2.2 默认角色权限种子配置(为 dev/mgr 等常用角色预置合理的新权限组合)
  • 或 P11.1 前端权限列表展示新增权限
  • 或 P12.1 CLI 更新 propose 子命令

2026-03-17 19:00 UTC第 21 轮P2.2 默认角色权限种子 — mgr + dev 角色)

本轮做了什么:

  • 实现 P2.2:在 init_wizard.py 新增 mgrdev 两个默认角色,各带预置权限
  • mgrManager权限
    • 项目管理project.read/write/manage_members
    • 全量 task/milestone CRUD
    • 所有新增动作权限milestone.freeze/start/close、task.close/reopen_closed/reopen_completed、propose.accept/reject/reopen
    • monitor.read
  • devDeveloper权限
    • project.read只读项目信息
    • task.create/read/write日常 task 操作)
    • milestone.read只读 milestone
    • task.close/reopen_closed/reopen_completedtask 状态管理)
    • monitor.read
    • 不含 milestone 动作权限和 propose 审批权限(这些归 mgr/admin
  • 重构 init_admin_role() 为统一的角色种子系统:
    • _DEFAULT_ROLES 列表定义所有默认角色 + 权限集
    • _ensure_role() 幂等创建角色
    • _sync_role_permissions() 增量同步权限(只加不删,不影响手动配置)
  • admin 仍获全量权限guest 仍仅获 *.read 权限

改了哪些关键文件:

  • HarborForge.Backend/app/init_wizard.py — 重构角色种子系统(+84 行,-52 行)

验证结果:

  • Python AST 语法检查通过
  • 前端 tsc --noEmit 零错误(无回归)
  • 已 commitbackend 8e38d4c

当前阻塞/风险:

  • 权限同步是增量模式(只加不删),已有部署中手动配置的权限不会被移除,但也意味着降级角色需手动操作
  • 前端按钮尚未根据用户权限做可见性控制P11
  • batch transition 接口尚未同步 P5.3/P5.4 校验
  • 无本地 MySQL/运行环境做集成验证

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

  • P11.1 前端权限列表展示新增权限(让管理界面能看到和管理 9 个新权限)
  • 或 P12.1 CLI 更新 propose 子命令
  • 或 P5.4 补全后端 batch transition 的 P5.3/P5.4 校验同步

2026-03-17 22:00 UTC第 22 轮:收口 milestone 内建 task 的旧默认值残留)

本轮做了什么:

  • 先检查了 HarborForge 主仓库和相关子模块 git 状态;当前没有新的未提交遗留改动,父仓库是 ahead 21,各子模块工作区也干净
  • 在后端 create_milestone_task 端点里收口一个残留兼容问题:
    • 默认 task_type 从旧的 task 改为 issue
    • 默认 statusopen 改为 pending
  • 这样 milestone 详情页/相关入口即使未显式传值,也不会再产出已移除的 task_type=task,并且与需求文档“新建 task 默认 pending”保持一致

改了哪些关键文件:

  • HarborForge.Backend/app/api/routers/milestones.py
  • HarborForge/docs/milestone-propose-requirements.md

验证结果:

  • python3 -m compileall HarborForge.Backend/app/api/routers/milestones.py 通过
  • grep 复查确认 milestones.py 内已无 task_type 默认回落到 task 的代码

当前阻塞/风险:

  • 后端仍有一个旧残留:HarborForge.Backend/app/models/models.py 里的 TaskType 还保留 TASK = "task",虽当前主流程未直接使用,但建议继续清理,避免后续误用
  • 这轮只做了静态验证,未做数据库/接口级运行验证

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

  • 继续做一个同样小的后端收口:清理 app/models/models.py 中残留的 TaskType.TASK,并顺手排查类似旧常量/默认值
  • 或进入 P11.1,把新增 milestone/task/propose 权限在前端角色编辑页中明确分组展示

2026-03-17 23:00 UTC第 23 轮:清理 models.py TaskType.TASK 残留 + P3.6 feature story freeze 编辑锁)

本轮做了什么:

  • app/models/models.py 移除 TaskType.TASK = "task" 枚举成员(第 22 轮标记的残留问题)
  • 清理 docstring 中的旧描述
  • 提交第 22 轮遗留的 milestones.py 默认值修复task_type → issue, status → pending
  • 实现 P3.6 补充feature story task 在 milestone freeze/undergoing/completed/closed 后禁止编辑 body 字段
    • tasks.py PATCH 接口中新增 milestone 状态检查story/feature 类型的 task 在 milestone 非 open 时返回 400

改了哪些关键文件:

  • HarborForge.Backend/app/models/models.py — 移除 TaskType.TASK
  • HarborForge.Backend/app/api/routers/milestones.py — 默认值修复(上轮遗留)
  • HarborForge.Backend/app/api/routers/tasks.py — P3.6 feature story freeze 编辑锁

验证结果:

  • 3 个文件 Python AST 语法检查全部通过
  • grep 确认后端无残留 TaskType.TASK 引用
  • 已 commitec91a15models.py + milestones.py586e06ftasks.py P3.6

当前阻塞/风险:

  • batch transition 接口尚未同步 P5.3/P5.4 校验(无 current_user, 无 comment body
  • P11 前端权限展示、P12 CLI/文档、P13 测试均未开始
  • 无本地 MySQL/运行环境做集成验证

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

  • P11.1 前端权限列表展示新增的 9 个权限(让管理界面能看到和管理 milestone/task/propose 权限)
  • 或 P12.1 CLI 更新milestone/task status choices 已在第 2 轮更新,但 propose 子命令未加)
  • 或 P5.4 后端 batch transition 同步 assignee/comment 校验

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

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