72 KiB
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.py、HarborForge.Backend/app/models/models.py、HarborForge.Backend/app/schemas/schemas.py
- 位置:
- 后端与前端都还有多处写死
progressing/pending/deferred- 典型位置:
- 后端:
app/api/routers/milestones.py、app/api/routers/tasks.py、cli.py - 前端:
src/types/index.ts、src/components/MilestoneFormModal.tsx、src/pages/MilestoneDetailPage.tsx、src/pages/TaskDetailPage.tsx
- 后端:
- 典型位置:
task_type = task仍真实存在,且当前主要表现为subtype = defect- 后端:
HarborForge.Backend/app/api/routers/tasks.py的TASK_SUBTYPE_MAP - 前端:
HarborForge.Frontend/src/components/CreateTaskModal.tsx、HarborForge.Frontend/src/pages/CreateTaskPage.tsx
- 后端:
当前判断:
- 下一步最合适的是先做 P0/P1 之间的“状态枚举与迁移骨架”,否则后续 milestone / task / propose 的接口实现会反复返工。
- 具体优先级建议:
- 先统一后端 milestone/task 新旧状态枚举与 schema
- 再补 migration / 兼容映射
- 然后推进动作接口、权限、前端按钮与页面
阻塞项:
- 暂无硬阻塞;但
closed/completed的终态与 task reopen 已写入需求,后续实现时要一次性考虑兼容,避免先做死状态流转。
2026-03-17 00:00 UTC(第 2 轮:后端状态枚举全量替换)
本轮做了什么:
- 将 milestone 和 task 的后端状态枚举全部替换为新值
- Milestone:
open/pending/deferred/progressing/closed→open/freeze/undergoing/completed/closed - Task:
open/pending/progressing/closed→open/pending/undergoing/completed/closed - 新增
MilestoneStatusEnum到 schemas.py,milestone 的 create/update/response 现在使用类型化枚举而非裸字符串 - 新增
started_at字段到 Milestone model 和 MilestoneResponse - 更新所有 router(milestones.py, tasks.py, misc.py)中
progressing→undergoing引用 - 更新 task transition 逻辑支持
completed状态自动记录finished_on - 更新 CLI status icon 映射和 choices 参数
改了哪些关键文件:
HarborForge.Backend/app/models/milestone.py— enum + started_atHarborForge.Backend/app/models/task.py— enumHarborForge.Backend/app/models/models.py— enumHarborForge.Backend/app/schemas/schemas.py— MilestoneStatusEnum + TaskStatusEnum + started_atHarborForge.Backend/app/api/routers/milestones.py— progressing→undergoingHarborForge.Backend/app/api/routers/tasks.py— progressing→undergoing, completed handlingHarborForge.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:
progressing→undergoing+ 新增completed - Milestone status:
pending/deferred/progressing→freeze/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 classHarborForge.Frontend/src/pages/MilestonesPage.tsx— badge classHarborForge.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.3):
app/models/propose.py,包含ProposeStatus枚举(open/accepted/rejected)和完整字段(propose_code, title, description, status, project_id, created_by_id, feat_task_id, timestamps) - 新增 Propose Pydantic schemas(P1.3):
ProposeStatusEnum、ProposeCreate、ProposeUpdate、ProposeResponse,feat_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 schemasHarborForge.Backend/app/main.py— import propose + 枚举迁移 SQL
验证结果:
- 3 个文件 Python AST 语法检查全部通过
- 前端
tsc --noEmit零错误(无回归) - 后端无旧枚举残留(grep 确认)
- 已 commit: backend
2bea75e, parent7afa8cd
当前阻塞/风险:
- 无本地 MySQL 环境,枚举迁移 SQL 未做实际 DB 验证
- Propose CRUD router 尚未创建(P6.1)
- Propose 编码生成逻辑(P1.4
{proj_code}:P{i:05x})尚未实现 - 前端 Propose 类型定义和页面尚未开始
下一轮最建议继续做什么:
- P6.1 Propose 基础 CRUD router(create/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) - CRUD:list / 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/featuretask(继承 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.5):update 接口中 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 均通过
- 已 commit:backend
75ccbcb,parent5602b1b
当前阻塞/风险:
- 权限检查暂用
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.py(313 行),实现 P3.1-P3.5 的核心后端逻辑 - freeze 接口(P3.2):
- 校验 milestone 为 open
- 校验有且仅有 1 个
maintenance/releasetask,否则拒绝并给出明确错误 - 调用
check_permission("freeze milestone")
- start 接口(P3.3):
- 校验 milestone 为 freeze
- 解析
depend_on_milestones/depend_on_tasksJSON,校验所有依赖已 completed - 写入
started_at,状态改为 undergoing - 调用
check_permission("start milestone")
- close 接口(P3.4):
- 允许从 open/freeze/undergoing → closed
- 支持 reason 参数
- 调用
check_permission("close milestone")
- auto-complete hook(P3.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
- milestones.py 的
- 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 hook(2 处)HarborForge.Backend/app/main.py— 注册 milestone_actions_router
验证结果:
- 4 个文件 Python AST 语法检查全部通过
- 已 commit:backend
7d8c448
当前阻塞/风险:
- P2 权限骨架尚未落地(
freeze/start/close milestonepermission 需要注册到 permission 表 + 默认角色种子) - milestone 编辑限制(P3.6)只做了部分(freeze 后禁新 feature task),
completed/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.ts(P10.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
- Reject:prompt 填写 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 输入框
- Freeze 按钮:仅
- 所有按钮有 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, parentcc2086e
当前阻塞/风险:
- 后端 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零错误通过- 已 commit:backend
314040c,frontenda4b4ffc,parent6b265ea
当前阻塞/风险:
- 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) - 只读接口,不做任何数据变更
- 当 milestone 为
- 前端 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零错误通过- 已 commit:backend
7a16639,frontendfaf7842
当前阻塞/风险:
- 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 返回 403undergoing → completed:同样校验操作者必须为 assignee
- transition 接口新增
- P5.4 完成 Comment 强制要求:
- transition 接口新增
TransitionBody请求体(含可选comment字段) undergoing → completed时强制要求comment非空,否则返回 400- 后端自动创建 Comment 记录(复用
models.Comment),不再依赖前端单独调用 comment API
- transition 接口新增
- 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零错误通过- 已 commit:backend
ffb0fa6,frontendd6a45c3
当前阻塞/风险:
- 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 字段,否则返回 403open+assignee_id为空 /pending:沿用原有ensure_can_edit_task通用权限
- 前端 TaskDetailPage(P9.3):
canEditTask重构为考虑 status + assignee 的完整守卫undergoing/completed/closed:Edit 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零错误通过- 已 commit:backend
7542f2d,frontend638427d
当前阻塞/风险:
- 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/feature和maintenance/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) - 两个创建表单同步更新
- Story subtypes 移除
改了哪些关键文件:
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— 移除受限 subtypesHarborForge.Frontend/src/pages/CreateTaskPage.tsx— 移除受限 subtypes
验证结果:
- Python AST 语法检查 tasks.py / milestones.py 均通过
npx tsc --noEmit零错误通过- 已 commit:backend
c18b8f3,frontend2897172,parent6441ea5
当前阻塞/风险:
maintenance/releasetask 的受控创建入口尚未明确实现(当前通过 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.7:Propose 详情页编辑功能,仅
open状态可编辑 title 和 description - ProposeDetailPage 新增:
- ✏️ Edit 按钮:仅
open状态显示(与 Accept/Reject 同行) - 编辑弹窗:title 输入框 + description 多行文本框
- 调用
PATCH /projects/{pid}/proposes/{id}提交修改 - title 不能为空时 Save 按钮禁用
- 保存成功后自动刷新详情
- loading 状态和错误提示完整
- ✏️ Edit 按钮:仅
accepted/rejected状态下不显示 Edit 按钮(按钮渲染在open条件分支内),实现主体不可编辑
改了哪些关键文件:
HarborForge.Frontend/src/pages/ProposeDetailPage.tsx— +75 行(编辑状态 + 弹窗 + handler)
验证结果:
npx tsc --noEmit零错误通过- 已 commit:frontend
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.close(category: milestone)task.close/task.reopen_closed/task.reopen_completed(category: task)propose.accept/propose.reject/propose.reopen(category: propose)
- milestone_actions.py:将旧字符串
"freeze milestone"等替换为点分权限名"milestone.freeze"等 - proposes.py:accept/reject/reopen 三个端点从
check_project_role(min_role="mgr")替换为check_permission(..., "propose.accept/reject/reopen"),移除所有 TODO 占位注释 - tasks.py:transition 接口新增:
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_permissionHarborForge.Backend/app/api/routers/tasks.py— 新增 close/reopen 权限检查
验证结果:
- 4 个文件 Python AST 语法检查全部通过
- grep 确认无残留旧权限字符串和 TODO 占位
- 已 commit:backend
3afbbc2,parent054cf43
当前阻塞/风险:
- 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.py(model):列默认值从
"task"改为"issue" - 后端 misc.py:import 默认值从
"task"改为"issue" - 后端 main.py(DB 迁移):
- 新增迁移步骤:
UPDATE tasks SET task_type='issue' WHERE task_type='task' - 新表创建默认值改为
'issue'
- 新增迁移步骤:
- 前端 types/index.ts:Task 类型联合移除
'task' - 前端 CreateTaskModal.tsx:移除 task 类型条目,默认 task_type 改为
'issue' - 前端 CreateTaskPage.tsx:同上
改了哪些关键文件:
HarborForge.Backend/app/schemas/schemas.py— 移除 TASK enumHarborForge.Backend/app/models/task.py— 默认值改为 issueHarborForge.Backend/app/api/routers/tasks.py— 移除 task subtype mapHarborForge.Backend/app/api/routers/misc.py— 默认值改为 issueHarborForge.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'引用 - 已 commit:backend
89e3bcd,frontendd399668
当前阻塞/风险:
- P7.3 历史数据处理:DB 迁移脚本已自动将
task_type='task'转为'issue',但无本地 MySQL 做实际验证 defectsubtype 现在仅属于issue类型(原先task和issue都有 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_tasksJSON 字段,返回结构化DepCheckResult(ok/blockers/reason)- 内部 helper
_parse_json_ids()安全解析 JSON ID 列表,消除重复的 try/except 模式 - 重构
milestone_actions.py:preflight 和 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 语法检查通过
- 已 commit:backend
c6b14ac,parent0bc2379
当前阻塞/风险:
- 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→opentransition 中接入check_task_deps()依赖检查 - 在
dependency_check.py新增check_task_deps()函数,专门处理 task 的depend_on字段(JSON 编码的 task ID 列表) - 在
tasks.pytransition 接口的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 语法检查通过
- 已 commit:
0c75045
当前阻塞/风险:
- 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新增mgr和dev两个默认角色,各带预置权限 - mgr(Manager)权限:
- 项目管理:project.read/write/manage_members
- 全量 task/milestone CRUD
- 所有新增动作权限:milestone.freeze/start/close、task.close/reopen_closed/reopen_completed、propose.accept/reject/reopen
- monitor.read
- dev(Developer)权限:
- project.read(只读项目信息)
- task.create/read/write(日常 task 操作)
- milestone.read(只读 milestone)
- task.close/reopen_closed/reopen_completed(task 状态管理)
- 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零错误(无回归) - 已 commit:backend
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 - 默认
status从open改为pending
- 默认
- 这样 milestone 详情页/相关入口即使未显式传值,也不会再产出已移除的
task_type=task,并且与需求文档“新建 task 默认 pending”保持一致
改了哪些关键文件:
HarborForge.Backend/app/api/routers/milestones.pyHarborForge/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.TASKHarborForge.Backend/app/api/routers/milestones.py— 默认值修复(上轮遗留)HarborForge.Backend/app/api/routers/tasks.py— P3.6 feature story freeze 编辑锁
验证结果:
- 3 个文件 Python AST 语法检查全部通过
- grep 确认后端无残留
TaskType.TASK引用 - 已 commit:
ec91a15(models.py + milestones.py)、586e06f(tasks.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 校验
2026-03-18 00:00 UTC(第 24 轮:P12.1 CLI 更新 — propose 子命令 + task_type 清理 + milestone status 过滤)
本轮做了什么:
- 完整实现 P12.1 CLI 更新
- 新增 5 个 propose 子命令:
proposes --project P— 列出 project 下的 proposespropose-create TITLE --project P— 创建 proposepropose-accept ID --project P --milestone M— accept proposepropose-reject ID --project P [--reason R]— reject proposepropose-reopen ID --project P— reopen propose
- task_type 清理:
tasks --type和create-task --typechoices 中移除task,默认改为issueTYPE_ICON移除task条目
- milestone status 过滤:
milestones --status新增 choices(open/freeze/undergoing/completed/closed) - transition comment 支持:
transition命令新增--comment参数,支持 undergoing→completed 的必填 comment
改了哪些关键文件:
HarborForge.Backend/cli.py— +86 行(propose commands, choices cleanup, comment support)
验证结果:
- Python AST 语法检查通过
- grep 确认 CLI 中无残留
task_type=task引用 - 已 commit:backend
00a1786,parent98c9eb8
当前阻塞/风险:
- CLI propose 命令依赖后端 API 正常运行,无本地环境做集成验证
- P12.2-P12.3 文档(README、状态机总览、权限总览、propose 流程图)尚未编写
- P13 自动化测试未开始
- P11 前端权限展示:RoleEditorPage 已动态加载后端权限列表,新增的 9 个权限会自动按 category 分组展示,P11.1-P11.2 实质已覆盖
下一轮最建议继续做什么:
- P5.4 后端 batch transition 同步 assignee/comment 校验(当前 batch 接口绕过了 P5.3/P5.4 的校验)
- 或 P12.2-P12.3 文档编写(状态机总览 + 权限总览 + propose 流程说明)
- 或 P13.1 开始编写 milestone 后端测试
2026-03-18 02:00 UTC(第 26 轮:P12.2-P12.3 文档编写 — 状态机总览 + 权限总览 + Propose 流程)
本轮做了什么:
- 编写三份核心文档,完成 P12.2-P12.3
docs/state-machine-overview.md(状态机总览):- Milestone 状态枚举、流转图、流转条件、编辑限制矩阵
- Task 状态枚举、流转图、流转条件、编辑限制、与 milestone 联动约束
- Propose 状态枚举、流转图、流转条件、accept 副作用、编辑限制
- 创建限制说明(story/feature 和 maintenance/release 的正确入口)
- 旧枚举 → 新枚举映射表(DB 迁移参考)
docs/permissions-overview.md(权限总览):- 9 个新增权限一览(名称、category、含义)
- 4 个默认角色的权限分配矩阵(admin/mgr/dev/guest)
- 权限设计原则(独立不合并、增量同步、操作者校验)
- 前端可见性现状说明
- 自定义角色指引
docs/propose-flow.md(Propose 流程):- 完整流程图(创建 → 审阅 → accept/reject → reopen)
- 各步骤详细说明(前置条件、系统执行、后续效果)
- Feature task 生命周期与约束
- Milestone 完整生命周期(含 propose 环节)
- Propose 编码规则
- API 端点与 CLI 命令速查
改了哪些关键文件:
HarborForge/docs/state-machine-overview.md— 新增HarborForge/docs/permissions-overview.md— 新增HarborForge/docs/propose-flow.md— 新增
验证结果:
- 已 commit:
90e1b4d - 文档内容与已实现代码逻辑交叉校验一致
当前阻塞/风险:
- P13 自动化测试未开始(milestone/task/propose 后端测试)
- P14 收尾验收未开始(手工走流程 + 数据迁移验证)
- 前端按钮权限可见性仍未根据用户权限做细粒度控制
- 无本地 MySQL/运行环境做集成验证
下一轮最建议继续做什么:
- P13.1 开始编写 milestone 后端测试骨架(freeze/start/close/auto-complete 的核心路径)
- 或 P13.3 propose 后端测试(accept/reject/reopen + feat_task_id 生成)
- 或 P13.2 task 后端测试(状态流转合法性 + assignee 校验 + comment 强制)
2026-03-18 01:00 UTC(第 25 轮:Batch Transition 全量校验同步 P5.2-P5.6)
本轮做了什么:
- 将 batch transition 接口从"几乎无校验"升级为与单条 transition 完全对齐的安全级别
- 新增
current_user依赖注入:batch 接口现在需要认证(之前完全无 auth) - 新增
comment字段:BatchTransitionBody替代旧BatchTransition,支持 completion comment - P5.2 同步:pending→open 时校验 milestone 必须为 undergoing + task depend_on 依赖检查
- P5.3 同步:open→undergoing 时校验 assignee 非空且操作者必须是 assignee
- P5.4 同步:undergoing→completed 时校验 comment 必填 + assignee 身份校验 + 自动创建 Comment 记录
- P5.5 同步:closed 转换需要
task.close权限 - P5.6 同步:reopen 需要
task.reopen_completed/task.reopen_closed权限,并清除 finished_on - P3.5 同步:completed 的 task 触发 milestone auto-complete hook
- Activity log:每个成功转换的 task 写入 activity log
- 所有校验失败的 task 进入
skipped列表而非抛异常(保持 batch 语义:部分成功) - 移除旧
BatchTransition类
改了哪些关键文件:
HarborForge.Backend/app/api/routers/tasks.py— batch transition 重写(+109 行,-18 行)
验证结果:
- Python AST 语法检查通过
- 无残留旧
BatchTransition引用 - 已 commit:backend
7bad57e
当前阻塞/风险:
- 前端如果有使用 batch transition 的地方,请求体需要从旧
BatchTransition格式改为BatchTransitionBody(新增可选comment字段,向后兼容) - P12.2-P12.3 文档(状态机总览、权限总览、propose 流程图)尚未编写
- P13 自动化测试未开始
- 无本地 MySQL/运行环境做集成验证
下一轮最建议继续做什么:
- P12.2-P12.3 文档编写(状态机总览 + 权限总览 + propose 流程说明)
- 或 P13.1 开始编写 milestone/task 后端测试骨架
- 或前端排查是否有调用 batch transition 的地方需要适配新请求体
2026-03-18 03:00 UTC(第 27 轮:P13.1 Milestone 后端测试基础设施 + 17 个测试)
本轮做了什么:
- 搭建后端测试基础设施(P13.1),使用 SQLite 内存数据库 + FastAPI TestClient
- 新建
tests/conftest.py:- SQLite in-memory 引擎 + StaticPool(共享连接)
- 自动建表/销表 fixture(每测试隔离)
- 工厂 fixture:
make_user/make_project/make_milestone/make_task/make_member seed_roles_and_permissions:创建 admin/mgr/dev 角色 + 18 个权限 + 角色-权限映射auth_header:JWT token 生成,用于 TestClient 请求认证
- 新建
tests/test_milestone_actions.py(17 个测试):- TestFreeze(4 个):成功冻结 / 缺 release task 失败 / 多 release task 失败 / 非 open 状态拒绝
- TestStart(3 个):成功启动 + started_at 写入 / 依赖未完成拒绝 / 非 freeze 状态拒绝
- TestClose(5 个):open/freeze/undergoing → closed 成功 / completed/closed 终态拒绝
- TestAutoComplete(3 个):release task 完成自动触发 completed / 非 release task 不触发 / 非 undergoing 不触发
- TestPreflight(2 个):有 release task 时 allowed=true / 无 release task 时 allowed=false
改了哪些关键文件:
HarborForge.Backend/tests/__init__.py— 新增HarborForge.Backend/tests/conftest.py— 新增(~220 行)HarborForge.Backend/tests/test_milestone_actions.py— 新增(~400 行)
验证结果:
python3 -m pytest tests/test_milestone_actions.py -v— 17 passed,0 failed- 已 commit:backend
011a226,parentfaad815
当前阻塞/风险:
- 安装了 pytest/httpx/python-multipart 等测试依赖到系统 Python(非 venv),仅用于本地开发验证
- passlib + bcrypt 5.x 存在兼容性问题,测试中用预计算 hash 绕过
- P13.2 task 测试、P13.3 propose 测试尚未编写
- P14 收尾验收未开始
下一轮最建议继续做什么:
- P13.2 Task 后端测试(状态流转合法性 + assignee 校验 + comment 强制 + 编辑限制)
- 或 P13.3 Propose 后端测试(accept/reject/reopen + feat_task_id 生成 + code 递增)
2026-03-18 04:00 UTC(第 28 轮:P13.2 Task 后端测试 — 34 个测试)
本轮做了什么:
- 编写
tests/test_task_transitions.py,覆盖 task 状态机的完整后端测试(P13.2) - TestPendingToOpen(4 个):成功 / milestone 非 undergoing 拒绝 / depend_on 未完成拒绝 / depend_on 已完成成功
- TestOpenToUndergoing(3 个):assignee 成功启动 / 无 assignee 失败 / 非 assignee 被 403 拒绝
- TestUndergoingToCompleted(4 个):带 comment 成功 / 无 comment 失败 / 空白 comment 失败 / 非 assignee 被 403 拒绝
- TestCloseTask(6 个):pending/open/undergoing 可关闭 / completed/closed 终态拒绝 / 无权限 403
- TestReopen(3 个):completed→open 成功 + finished_on 清除 / closed→open 成功 / 无权限 403
- TestInvalidTransitions(10 个参数化):10 种非法状态流转全部返回 400
- TestEditRestrictions(4 个):undergoing 禁止编辑 / completed 禁止编辑 / open+assignee 仅 assignee 可编辑 / open 无 assignee 任何人可编辑
- 修复 conftest.py 缺少 webhook model import 导致的 "no such table: webhooks" 错误
改了哪些关键文件:
HarborForge.Backend/tests/test_task_transitions.py— 新增(~530 行)HarborForge.Backend/tests/conftest.py— 新增 webhook model import
验证结果:
python3 -m pytest tests/ -v— 51 passed(17 milestone + 34 task),0 failed- 已 commit:backend
c21e4ee
当前阻塞/风险:
- P13.3 propose 后端测试尚未编写
- P14 收尾验收未开始
- 无本地 MySQL/运行环境做集成验证
下一轮最建议继续做什么:
- P13.3 Propose 后端测试(accept/reject/reopen + feat_task_id 生成 + propose_code 递增)
- 或 P14 收尾验收(如果认为核心测试覆盖已足够)
2026-03-18 05:00 UTC(第 29 轮:P13.3 Propose 后端测试 — 19 个测试)
本轮做了什么:
- 编写
tests/test_propose.py,覆盖 Propose 后端的完整功能测试(P13.3) - TestProposeCRUD(4 个):create / list / get / update,验证 propose_code 自动生成、status 默认 open、feat_task_id 默认 None
- TestProposeCode(1 个):两个 project 下分别创建 propose,验证 code 按 project 独立递增且前缀正确
- TestAccept(5 个):
- 成功 accept → 生成 story/feature task(title/description 继承、status=pending、milestone 关联)
- 非 open milestone 拒绝
- 已 accepted 的 propose 再次 accept 拒绝
- feat_task_id 自动填充 + 持久化验证
- dev 角色无 propose.accept 权限被 403 拒绝
- TestReject(3 个):成功 reject / 非 open 拒绝 / dev 无权限 403
- TestReopen(3 个):成功 reopen / 非 rejected 拒绝 / dev 无权限 403
- TestFeatTaskIdProtection(1 个):PATCH 传入 feat_task_id 被服务端忽略
- TestEditRestrictions(2 个):accepted 和 rejected 状态的 propose 编辑被 400 拒绝
改了哪些关键文件:
HarborForge.Backend/tests/test_propose.py— 新增(~560 行)
验证结果:
python3 -m pytest tests/ -v— 70 passed(17 milestone + 34 task + 19 propose),0 failed- 已 commit:backend
e938507
当前阻塞/风险:
- P13.4 前端/E2E 测试尚未编写(需要运行环境)
- P14 收尾验收未开始(手工走流程 + 数据迁移验证)
- 无本地 MySQL/运行环境做集成验证
下一轮最建议继续做什么:
- P14 收尾阶段:核心后端测试已全部通过(70 个),可以开始 P14.3 最终文档整理(更新 ZHI_TASKS.md 勾选已完成项)
- 或回顾所有 P0-P13 任务项,标记完成状态,识别剩余未做项
- 或补充 batch transition 前端适配确认
1. 背景
当前希望把 milestone 的推进过程做成一个更严格的状态机,并把 feature story 的进入方式从“直接创建 task”改为“先提 propose,再 accept 进入 milestone”。
核心目标:
- milestone 有明确生命周期
- feature 进入 milestone 要受控
- release 节点要能约束 freeze / complete
- 依赖关系在开始前做严格检查
2. Milestone 字段调整
Milestone 的 status 使用新的枚举集合,替代当前代码库中的旧枚举。
2.1 目标枚举
openfreezeundergoingcompletedclosed
2.2 替代当前代码中的旧枚举
当前代码里 milestone status 旧枚举为:
openpendingdeferredprogressingclosed
后续应整体替换为新的 milestone 状态集合,不再使用:
pendingdeferredprogressing
另增字段:
started_at- milestone 进入
undergoing时自动记录开始时间
- milestone 进入
默认:
- 新建 milestone 时,
status = open
3. Milestone 状态定义
3.1 open
含义:
- milestone 刚创建,仍可接收 feature 范围内的内容
页面按钮:
freezeclose
约束:
- milestone 下的
task / support / meeting在此阶段都只能处于锁定状态,不允许进入真正开始执行的状态 - 当前可认为它们只能停留在
pending - milestone 基本信息仍可编辑
3.2 freeze
含义:
- milestone 进入冻结,需求范围不再继续扩张,准备开始执行
进入条件:
- 该 milestone 有且仅有一个
maintenance task - 且这个 maintenance task 的
subtype = release - 如果不满足,不能进入
freeze
页面按钮:
startclose
约束:
- 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 各状态按钮
-
openfreezeclose
-
freezestartclose
-
undergoingclose
-
completed- 不显示状态动作按钮
-
closed- 不显示状态动作按钮
4.2 按钮触发条件
freeze
- 仅
open状态显示 - 点击前检查:
- 当前 milestone 下有且仅有一个
maintenance/release task
- 当前 milestone 下有且仅有一个
- 不满足时不可点击,并提示原因
start
- 仅
freeze状态显示 - 点击前检查:
- 当前 milestone 的前置依赖全部完成
- 满足后:
- milestone 进入
undergoing - 自动记录
started_at
- milestone 进入
close
open/freeze/undergoing状态显示- 需要有对应权限
- 如果 milestone 已经是
undergoing,建议弹确认说明:- 已完成的 feature task 需要废弃或移交
- 依赖该 milestone 的对象需要调整依赖
4.3 Milestone 动作权限
将以下三类动作设计为独立权限,由 role 控制:
freeze milestonestart milestoneclose 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 taskrelease maintenance task
设计意图:
feature story task应来自propose -> acceptrelease 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 状态枚举
当前采用以下状态:
openacceptedrejected
明确:
- propose 不需要
closed
6.4 propose 基础字段(当前已明确部分)
至少需要:
project_idpropose_codetitledescriptionstatuscreated_by_idcreated_atupdated_at
6.5 feat_task_id 字段
新增字段:
feat_task_id- 类型:
string - 可选
规则:
- 在 accept 生成
feature story task后自动填写 - 不允许手动修改
- 前端页面应显示该字段
7. Propose 页面草案
7.1 页面按钮
前端页面按钮规则采用当前草案:
-
openacceptreject
-
accepted- 不显示状态动作按钮
- 可显示跳转入口:
View Generated Task
-
rejectedreopen
所有按钮都按权限可见。
7.2 页面显示字段
前端 detail 页面至少应显示:
propose_codetitledescriptionstatusfeat_task_idcreated_by_idcreated_atupdated_at
8. Propose 状态流转与动作规则
8.1 允许的状态流转
open -> acceptedopen -> rejectedrejected -> open
当前不考虑:
accepted -> openaccepted -> 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
字段继承:
titledescription
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 proposereject proposereopen rejected propose
9.2 编辑规则
open- creator 可编辑
title、description - admin 可编辑
- 有特定管理权限的 role 可编辑
- creator 可编辑
accepted- 主体不可编辑
rejected- 主体不可编辑
备注:
- 主体不可编辑不代表不能追加 comment / activity 记录
10. 当前推荐的业务流程
10.1 feature 进入 milestone
推荐流程:
- 用户先在 project 下创建
propose - 负责人在 propose detail 页面审阅
- 若接受,则选择目标 milestone 并
accept - 系统自动生成
feature story task - milestone 处于
open时可继续接纳 feature story - milestone 进入
freeze后,不再接受新的 feature story - milestone 满足条件后
start,进入undergoing - milestone 下唯一
release maintenance task完成后,milestone 自动completed
10.2 废弃 milestone
- 用户点击
close - milestone 进入
closed - 处理已完成 feature task:
- 废弃
- 或移交到其他
openmilestone
- 修正所有依赖该 milestone 的对象依赖配置
11. Task 状态枚举调整
Task 的 status 也采用新的枚举集合。
11.1 目标枚举
openpendingundergoingcompletedclosed
11.2 替代当前代码中的旧枚举
当前代码里 task status 旧枚举为:
openpendingprogressingclosed
后续应整体替换为新的 task 状态集合,不再使用:
progressing
并新增:
undergoingcompleted
11.3 Task 状态语义
pending- 还不能开始,通常是被 milestone 状态或依赖锁住
open- 可以开始,但尚未真正开工
undergoing- 正在处理
completed- 正常完成
closed- 废弃 / 取消,不是正常完成
11.4 当前认可的 Task 基础状态流转
允许的基础流转:
pending -> openopen -> undergoingundergoing -> completedpending -> closedopen -> closedundergoing -> 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 taskreopen closed taskreopen completed task
规则:
- 拥有对应权限的 role 才可以执行对应动作
reopen closed task与reopen completed task分开控制,不合并为一个权限
补充:
undergoing -> completed不走 role 权限控制complete只有当前 assignee 可以执行
11.8 Task 页面按钮可见性
所有按钮都按权限可见。
当前确认的按钮规则:
- 除
closed与completed外,task 页面始终显示close按钮- 也就是:
pending有closeopen有closeundergoing有close
- 也就是:
closed与completed状态显示reopen按钮pending状态显示open按钮open状态显示start按钮undergoing状态显示finish按钮
可理解为:
pending:open+closeopen:start+closeundergoing:finish+closecompleted:reopenclosed:reopen
其中:
finish对应undergoing -> completedstart对应open -> undergoingopen按钮对应pending -> open
11.9 与 Milestone 状态的联动约束
- 当 milestone 为
open/freeze时:- task 原则上只能处于
pending或closed - 不应进入
open / undergoing / completed
- task 原则上只能处于
- 当 milestone 为
undergoing时:- task 才允许从
pending往执行状态推进
- task 才允许从
- 当 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 以及之后的状态
undergoingcompletedclosed
以上状态一律不可编辑。
备注:
- 这里的“不能编辑”指 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.tsxHarborForge.Frontend/src/pages/CreateTaskPage.tsx- 两处都定义了:
task- 其 subtype 只有:
defect
- 当前创建表单默认类型也是
task
后端:
HarborForge.Backend/app/api/routers/tasks.pyTASK_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 完成的关键闸门 - 用“开始前依赖检查”替代大规模自动状态联动
这样业务会更可控,也更容易避免流程混乱。