docs+fix: 4份核心文档 + 项目模块版本记录数据全联动

文档:
- architecture.md - 整体架构、心智模型、关键设计原则
- decisions.md - 16条关键决策记录(含为什么)
- workflow.md - 工作流程和协作偏好
- roadmap.md - V1/V2/V3 路线图和已完成清单

修复项目详情版本记录:
1. 状态胶囊数据联动(开发中分支也补传 stageProgress)
2. 日期数据联动:
   - 实际开始 = 取所有阶段最早 actualStartAt/startDate/startedAt
   - 实际截止 = 取所有阶段最晚 completedAt/closedAt
   - 数据完全和版本详情一致

VersionCard 的 versionData useMemo 增加 actualStart/actualEnd 派生字段,
两种状态分支(developing/released)都使用派生值,不再用静态 version.startDate

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Script Generator
2026-06-16 12:40:10 +08:00
parent 4b05e09dab
commit 6d2f6d8b9f
5 changed files with 534 additions and 4 deletions

View File

@@ -77,6 +77,15 @@ function VersionCard({ version, progress, plans, devTasks, testCases, bugs, requ
vTCs.forEach((c) => { if (c.startedAt) startDates.push(c.startedAt); });
const earliestStart = startDates.length > 0 ? startDates.sort()[0] : version.startDate;
const actualStartDisplay = startDates.length > 0 ? startDates.sort()[0].slice(0, 10) : (version.startDate ?? null);
// 实际截止:取所有阶段最晚完成
const endDates: string[] = [];
vPlans.forEach((p) => { if (p.completedAt) endDates.push(p.completedAt); });
vDevTasks.forEach((t) => { if (t.completedAt) endDates.push(t.completedAt); });
vTCs.forEach((c) => { if (c.completedAt) endDates.push(c.completedAt); });
vBugs.forEach((b) => { if (b.closedAt) endDates.push(b.closedAt); });
const actualEndDisplay = endDates.length > 0 ? endDates.sort().reverse()[0].slice(0, 10) : null;
let totalDays = 0;
if (earliestStart) {
@@ -87,7 +96,7 @@ function VersionCard({ version, progress, plans, devTasks, testCases, bugs, requ
totalDays = Math.max(0, Math.floor((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)));
}
return { vPlans, vDevTasks, vTCs, vBugs, totalDays };
return { vPlans, vDevTasks, vTCs, vBugs, totalDays, actualStart: actualStartDisplay, actualEnd: actualEndDisplay };
}, [version, plans, devTasks, testCases, bugs, requirements]);
// 状态胶囊数据 — 与版本详情一致
@@ -185,7 +194,9 @@ function VersionCard({ version, progress, plans, devTasks, testCases, bugs, requ
<span className={`text-[11px] px-2 py-0.5 rounded-full ${displayBg}`}>{displayStatus}</span>
<span className="flex-1 text-[11px] text-[var(--ink-muted)] flex items-center gap-1">
<Calendar className="h-3 w-3" />
{version.startDate ?? '-'} {version.releaseDate ?? '-'}
{versionData.actualStart ?? version.startDate ?? '-'}
<span className="mx-1"></span>
{versionData.actualEnd ?? version.releaseDate ?? '-'}
<span className="ml-1"> {totalDays} </span>
</span>
<ChevronDown className={`h-3.5 w-3.5 text-[var(--ink-muted)] transition-transform ${expanded ? 'rotate-180' : ''}`} />
@@ -212,11 +223,19 @@ function VersionCard({ version, progress, plans, devTasks, testCases, bugs, requ
<span className="text-[11px] tabular-nums text-[var(--ink-muted)]">{progress}%</span>
</div>
</div>
<div className="mb-3"><CapsuleStages /></div>
<div className="mb-3"><CapsuleStages stageProgress={stageProgress} /></div>
<div className="flex items-center justify-between text-[11px] text-[var(--ink-muted)] mb-3 pb-3 border-b border-[var(--line-soft)]">
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{version.startDate ?? '-'} {version.expectedReleaseDate ?? '-'}
{versionData.actualStart ?? version.startDate ?? '-'}
<span className="mx-1"></span>
{version.expectedReleaseDate ?? '-'}
{versionData.actualEnd && (
<>
<span className="mx-1">|</span>
{versionData.actualEnd}
</>
)}
</span>
<span className="flex items-center gap-1">
<Clock className="h-3 w-3" /> {totalDays}

136
docs/architecture.md Normal file
View File

@@ -0,0 +1,136 @@
# FTB 智能项目管理系统 — 架构文档
## 项目定位
FTB 是一个面向中小型研发团队的项目管理平台,集成 AI 能力辅助决策。核心层级:
```
产品Product → 项目Project → 版本Version → 需求/任务/用例/Bug
```
不是给测试团队的工具,也不是 Jira 替代品。**核心目标是让产品/项目经理在一个页面看到:"开发完了吗 → 验收过了吗 → 还有多少 BUG → 能不能发布"**。
## 心智模型(重要)
系统设计遵循**三条维度线**的分离:
```
语义线Why 执行线How 质量线Quality
───────────────── ───────────────── ────────────────
Requirement Version TestCase
解释为什么做 驱动状态流转 └─ Bug
不参与流程 所有状态看版本 质量闭环
```
**Requirement需求= 语义层**,解释功能范围和业务原因,不驱动流程。
**Version版本= 执行主线**,所有任务归属版本,状态由版本派生。
**TestCase + Bug = 质量闭环**,挂在版本上验收。
## 技术栈
| 层 | 技术 | 说明 |
|---|------|------|
| 前端 | Next.js 14 (App Router) | TypeScript + 客户端组件为主 |
| UI | Tailwind CSS + Shadcn/ui | 紧凑信息密度、现代风格 |
| 状态 | Zustand | 每个领域一个 store |
| 持久化 | localStorageV1 | 后端 NestJS + Prisma 已搭好但未启用 |
| 后端 | NestJS + Prisma + PostgreSQLV2 | 暂未启用 |
| AI | Anthropic SDKV3 远景) | 健康度/风险预警/排期建议 |
## 模块结构
```
apps/web/
├── app/
│ ├── products/ # 产品列表 + 详情(点击项目可跳转)
│ ├── projects/[id]/ # 项目详情:版本卡片/状态胶囊
│ ├── versions/ # 版本列表 + 详情
│ ├── requirements/ # 需求池
│ ├── workspace/ # 与我相关(聚合工作台)
│ └── admin/ # 系统管理(任务类型字典等)
├── components/
│ ├── product/ # 产品组件
│ ├── version/ # 版本组件PlanTab, CapsuleStages, MemberChips...
│ ├── dev-task/ # 开发任务组件
│ ├── test-case/ # 测试用例组件
│ ├── bug/ # Bug 组件
│ └── requirement/ # 需求组件
├── lib/
│ ├── derive.ts # 派生数据flattenVersions/flattenProjects
│ ├── linkage-engine.ts # 跨模块联动引擎需求↔DevTask 派生状态)
│ ├── workspace-engine.ts # 工作台聚合引擎统一WorkItem
│ ├── version-status.ts # 版本执行态推导
│ ├── version-plan.ts # 计划任务(调研/产品/UI
│ ├── dev-task.ts # 开发任务
│ ├── test-case.ts # 测试用例
│ ├── bug.ts # Bug
│ └── requirement.ts # 需求
└── stores/ # Zustand stores每个领域独立
```
## 关键架构原则
### 1. 引擎模式(关键)
跨模块的数据派生通过**引擎层**处理,不是各 store 互相调用:
- **linkage-engine.ts**:从 DevTask 状态派生需求"实际进度",新建模块只需在此聚合
- **workspace-engine.ts**:聚合 WorkItem 给"与我相关"页面用
引擎是**纯函数**,输入多个 store 数据,输出统一视图。引擎使应用各模块松耦合,新增模块时不需要改其他模块的代码。
### 2. 派生胜过存储
时间字段、状态、进度都尽量从底层数据派生,而不是手填:
- 实际工时 = `startDate → completedAt` 时间差(精确到 0.5h
- 阶段耗时 = 所有阶段任务的最早开始 → 最晚完成
- 需求开发状态 = 从 DevTask 状态聚合
- 版本执行态 = 从所有 DevTask + TestCase + Bug 聚合
- 阶段进度 = 已完成子任务/总子任务
### 3. 时间戳精确到分钟
所有"实际开始/完成"时间都是 ISO 时间戳(含时分秒),不是日期。展示时统一 `slice(0, 16).replace('T', ' ')`
### 4. 数据联动
修改 A 影响 B 时,**B 通过 filter A 派生**,不要双向写。例:
- 需求关联到版本:需求设 `versionId`,版本详情 `requirements.filter(r => r.versionId === id)`
- 删除版本清理孤儿数据PlanTask/DevTask/TestCase/Bug + 释放 Requirement.versionId
## 状态机概览
| 实体 | 状态流转 |
|------|---------|
| Requirement | pending_review → adopted → planned → developing → testing → released → closedrejected 可回 pending_review|
| VersionPlan | pending → in_progress → completed |
| DevTask | todo → in_progress → testing → submitted终态提测=已完成)|
| TestCase | pending → running → passed/failed/blocked |
| Bug | open → fixing → fixed → verifying → closed/rejected |
DevTask 没有"已完成"状态,"已提测"就是终态——开发交付完成,后续 Bug 单独流转。
## 数据持久化
**V1当前** 全部 localStorage每个 store 独立 key
- `ftb_overview_v1` - 产品/项目/版本树
- `ftb_requirements_v3`
- `ftb_version_plans_v1`
- `ftb_dev_tasks_v1`
- `ftb_test_cases_v1`
- `ftb_bugs_v1`
- `ftb_overtime_v1`
- `ftb_task_categories_v1`
**V2计划** NestJS + Prisma + PostgreSQLSchema 已设计但尚未运行 migration。
## 权限模型(轻量)
V1 仅做前端校验,无后端鉴权:
- 版本 `members` 字段限定参与者
- 版本列表/详情按 `members.contains(currentUser)` 过滤
- 创建版本时自动加入创建者
- 版本 `members` 为空时所有人可见(兼容旧数据)
V2 接入后端后改为基于 `ProjectMember` 表的 RBACOwner/Admin/Member/Viewer

157
docs/decisions.md Normal file
View File

@@ -0,0 +1,157 @@
# 关键设计决策记录
每条决策都包含**为什么这么做**,避免后续模型重新讨论或推翻。
## 1. 进度计算 — 由状态推导,不要手填百分比
**问题**Jira/TAPD 等系统让开发手填进度20%/35%/50%),数据完全主观,不可靠。
**决策**DevTask 进度由 `status` 推导:
- `todo` → 0%
- `in_progress` → 50%
- `testing` → 80%
- `submitted` → 100%
**理由**:客观、不允许造假。需求级/版本级进度 = `Σ(estimateHours × 状态推导%) / Σ(estimateHours)`
## 2. 实际工时 — 由开始/完成时间戳计算
**问题**:让人手填工时太粗糙(一天 8h 真的全部花在这个任务吗?)。
**决策**:精确到 0.5h 的时间差计算
```
实际工时 = (completedAt - startDate) / 3600000精确到 0.5h
```
**理由**:状态流转时自动记录精确时间戳,工时直接派生。
## 3. DevTask "已提测" = 终态
**问题**:原本有 `submitted → done`,但开发提测之后就交付完成了,后续测试结果不应该回过来改 DevTask 状态。
**决策**:去掉 `done``submitted` 是终态。测试通过/失败产生 Bug不影响 DevTask。
**理由**DevTask 的责任是"开发到提测",验收是 TestCase 的职责。
## 4. 调研/产品/UI — 自动开始 + 手动提前开始
**问题**:到了计划开始日期,状态还是 pending 不合理。
**决策**
- 当前时间 ≥ `startTime` 时自动视为 in_progress
- 用户可在计划日期前手动点"开始"
- 自动开始时记录 `actualStartAt`(精确到分钟)
**理由**:减少冗余操作但保留灵活性。
## 5. TestCase 主归属版本,需求是可选标签
**问题**:早期把测试用例挂在需求上,但同一需求跨版本迭代时用例难以管理。
**决策**
- TestCase.versionId 必填(执行归属)
- TestCase.requirementId 可选(语义标签)
- 测试人员从"我的测试用例"看到的就是当前版本的用例
**理由**:测试是按版本执行的,不是按需求;但需求作为思考维度仍然有用。
## 6. Bug 直接挂版本
**问题**:早期通过 `Bug → TestCase → Requirement → Version` 四级反查,太绕。
**决策**Bug 增加 `versionId` 字段,直接挂版本。`testCaseId` 保留作为来源追溯。
**理由**:判断"能不能发布"的唯一维度是版本,必须 O(1) 查询。
## 7. 跨模块通信 — 引擎层,不是事件总线
**问题**模块多了A store 改动影响 B 的派生数据,散落各处难维护。
**决策**:建立**纯函数引擎**
- `linkage-engine.ts`:从 DevTask 状态派生需求"实际进度"
- `workspace-engine.ts`:聚合所有 store 数据为统一 WorkItem
**理由**:事件总线过度设计,纯函数派生更可预测。新增模块只需在引擎中添加聚合逻辑。
## 8. 时间字段统一 ISO 时间戳到分钟
**问题**:日期(`YYYY-MM-DD`) vs 时间戳混用UI 展示不一致。
**决策**:所有"实际开始/完成"用 `new Date().toISOString()`,展示统一 `slice(0, 16).replace('T', ' ')`
**理由**:时间戳到分钟够精确,不像秒/毫秒那么噪。
## 9. 任务类型字典化 + 分组
**问题**:早期 enum 写死类型(前端/后端/大数据/其他),新增类型需改代码。
**决策**:建 TaskCategory 字典表 + groupdevelopment/implementation/other管理员可增删。
**理由**:业务变化快,配置 > 写死。group 方便统计(开发工时 vs 实施工时)。
## 10. 阻塞正交标记,不是状态值
**问题**`status: blocked` 会丢信息——`开发中+阻塞``自测+阻塞`
**决策**
- `status: todo|in_progress|testing|submitted`
- `isBlocked: boolean` + `blockReason: string` + `blockedById: string`
**理由**:阻塞和状态正交。工作台筛选 `isBlocked=true` 一键拉出所有阻塞项,跨状态。
## 11. 加班原因可选,且去掉"其他"
**问题**:可选"其他"会让人逃避思考具体原因。
**决策**:变更原因/加班原因严格定义有限选项,**没有"其他"**。
**理由**:强制具体化,统计才有意义。
## 12. 项目维度 vs 个人维度耗时分开计算
**问题**:多个开发并行做任务,简单加总会重复计算时间。
**决策**
- **个人耗时**:每个任务独立累加(`Σ(end - start)`
- **项目维度阶段耗时**`min(start)``max(end)` 日历跨度(不重复)
**理由**:两个维度回答不同问题——"谁花了多少时间" vs "这个阶段拖了多久"。
## 13. 删除版本时清理孤儿数据
**问题**:删版本只删 version 实体,留下 PlanTask/DevTask/TestCase/Bug 变成孤儿数据。
**决策**:删除版本时级联清理:
1. 释放需求 versionId回需求池
2. 删除 PlanTask
3. 删除 DevTask通过需求 ID
4. 删除 TestCase
5. 删除 Bug
**理由**localStorage 没外键约束,必须手动级联。
## 14. 工作台数据点击 → 侧边详情 + 可操作
**问题**:早期工作台只显示信息,操作要跳转到版本详情。
**决策**:点击卡片打开 Drawer复用版本详情用的同一组件可在 Drawer 内完成状态流转、转交、提 Bug 等。
**理由**减少跳转工作台一站式处理。Drawer 顶部显示"产品/项目/版本"上下文,不会迷失。
## 15. UI 阴影统一 shadow-2xl
**问题**:各 Drawer 阴影不一致(有些 `shadow-lg` 有些 `shadow-2xl`)。
**决策**:全局 Drawer 用 `shadow-2xl`
**理由**:视觉权重明显,且一致。
## 16. 不进入 Brainstorm 模式的判定
**约定**:以下情况直接修复,**不强制走 brainstorming 流程**
1. Bug fix明确 bug方案直接
2. 已批准方案的 in-progress 延续
3. 用户已通过 AskUserQuestion 选择了方案
4. 简单文案/样式调整
**理由**brainstorming 适合新功能设计bug fix 强行套流程浪费时间。

100
docs/roadmap.md Normal file
View File

@@ -0,0 +1,100 @@
# 开发路线图
## 当前阶段V1 — 前端 Mock + 业务流程打磨
所有数据用 localStorage 持久化,重点验证业务模型和交互。
### 已完成(按时间倒序)
**2026-06-16**
- 项目模块顶部卡片(总版本数/已开发/需求数/Bug 总数)
- 项目模块版本记录与版本详情数据联动(耗时 + 状态胶囊)
- 4 份核心文档architecture / decisions / workflow / roadmap
**2026-06-15**
- 与我相关:产品/项目/版本树筛选 + 红色待办徽标
- 与我相关:点击卡片打开 DrawerPlanDetailDrawer 新建DevTask/TestCase/Bug 复用)
- 全局 Drawer 阴影统一 shadow-2xl + 顶部上下文条
- 测试用例提 Bug 流程drawer 内点击 → BugCreateModal
- DevTask + TestCase 转交功能(人员离职场景)
- 需求池:录入人员自动取当前用户 + 状态列改名(业务状态 / 实际进度)
- 产品页面:去掉规划中、项目名/版本胶囊可点击跳转
**2026-06-14**
- 需求变更模块:变更人员/原因/概述/详细 + 概览统计(变更人员排名 + 原因占比饼图)
- 计划任务转交(未开始/进行中可转交,从参与人员选)
- 关联需求增强:描述列 hover 完整内容、需求类型/变更原因/添加日期列
- 计划时间精确到分钟datetime-local+ 到期自动开始
- 阶段耗时 + 个人耗时排名(涵盖调研/产品/UI/开发/测试 5 类工作)
**2026-06-13**
- DevTask 状态简化:去掉 donesubmitted 是终态
- 实际工时改为精确时间戳计算(精确到 0.5h
- TestCase 主归属版本requirement 改为可选标签
- Bug 直接挂版本versionId 字段)
- linkage-engine需求 ↔ DevTask 派生)
- workspace-engine统一 WorkItem 聚合)
**2026-06-12 及更早**
- 完整模块:需求池/版本管理/计划任务(调研/产品/UI/开发任务/测试用例/Bug
- 加班记录 + 排名 + 原因占比饼图
- 健康度计算 + 风险标签
- 版本执行态自动推导
### 进行中
- 项目详情页 VersionCard 状态胶囊数据联动(部分已完成)
## V2 — 后端接入
NestJS + Prisma + PostgreSQL Schema 已设计,等业务流程稳定后开始迁移。
### 关键任务
1. **运行 Prisma migration**:把现有的 lib/*.ts 类型转为 Prisma schema
2. **API 层**:每个 store 对应一组 CRUD endpoint
3. **localStorage → API 切换**:保留 localStorage 作为离线缓存
4. **认证**NextAuth.js + JWT
5. **权限**RBACOwner/Admin/Member/Viewer按项目/版本级别
### 数据迁移策略
提供管理员脚本把当前用户的 localStorage 数据导出为 SQL导入到 PostgreSQL。
## V3 — AI 集成
### 已规划场景
1. **需求智能分解**输入需求描述AI 拆解为子任务(技术分析+UI 调整+联调+测试)
2. **风险预警**:自动识别延期/阻塞集中/工时偏差大的任务,提前预警
3. **排期建议**:基于成员负载和历史耗时,建议下一阶段任务分配
4. **需求转任务**:需求采纳后一键生成 DevTask 草稿
5. **健康度智能解读**:把数据指标转化为自然语言报告
### 落地方式
`apps/server/src/modules/ai/`
- `AiGateway` — 统一 prompt 管理、token 计量、降级
- `AiTaskService.decompose(description)`
- `AiRiskService.analyze(projectId)`
- `AiScheduleService.suggest(projectId)`
- `AiLog` 表存调用记录,便于审计
## 不在路线图(明确不做)
- **Jira/TAPD 替代品**:定位是产品/项目经理视角,不是开发任务管理
- **测试套件/测试计划**:测试用例是版本验收手段,不做完整测试管理
- **Gantt 甘特图**:现有的胶囊状态条 + 阶段耗时已经够用
- **看板视图**DevTask 列表 + 筛选 + 状态流转已够用
- **回归测试**:测试用例不做版本间复用
- **客户/合同管理**:超出研发管理边界
## 关键里程碑
| 节点 | 状态 |
|------|------|
| V1 业务流程打磨 | 进行中 |
| V1 朋友试用反馈 | 持续中 |
| V2 后端接入 | 等 V1 稳定 |
| V3 AI 集成 | 等 V2 数据沉淀 |
| 公开发布 | TBD |

118
docs/workflow.md Normal file
View File

@@ -0,0 +1,118 @@
# 工作流程
记录用户的协作偏好和系统化流程,方便后续模型理解项目运作方式。
## 用户协作风格
- **直接修复明确 bug**,不强制走 brainstorming 流程
- **方案确认后立即执行**,不重复讨论
- **不喜欢自动 push**commit 由模型完成,**push 需要用户明说"推/push"**
- **要求高级开发思维**:考虑数据联动、引擎层抽象,而不是分散写 ad-hoc 逻辑
- **重视一致性**:所有 Drawer 阴影、所有时间格式、所有状态计算都要统一
- **省略多余对话**:能直接做的不要问,只在真有歧义时用 AskUserQuestion 给选项
- **Brainstorming 适用于新功能**bug fix 和已批准方案的延续不走 brainstorming
## 实际工时计算流程
所有"实际开始时间"和"实际完成时间"都是 ISO 时间戳:
```
状态变更时机:
- DevTask: todo → in_progress 时记 startDate
testing → submitted 时记 completedAt
- TestCase: pending → running 时记 startedAt
running → passed/failed/blocked 时记 completedAt
- VersionPlan: pending → in_progress 时记 actualStartAt
in_progress → completed 时记 completedAt
计算:
- 实际工时 = (completedAt - startDate) / 3600000精确到 0.5h
- 阶段日历耗时 = min(start) → max(end) 跨度(项目维度,不重复)
- 个人耗时 = 每个任务独立累加(个人维度)
```
## 数据联动检查清单
新加模块或字段时,检查以下点:
- [ ] 是否需要在 `linkage-engine.ts` 加派生函数?
- [ ] 是否需要在 `workspace-engine.ts` 加聚合?
- [ ] 删除版本时是否需要清理这类数据?
- [ ] 工作台 / 版本详情 / 项目详情三处的统计是否同步?
- [ ] localStorage 旧数据是否需要兼容处理?
## Drawer侧边详情规范
所有侧边详情遵循:
- `fixed inset-0 z-50 flex justify-end`
- 背景 `bg-black/40`
- Drawer 容器 `w-full max-w-md h-full bg-[var(--bg)] border-l shadow-2xl flex flex-col`
- 顶部上下文条(可选):`px-5 py-2 bg-[var(--bg-subtle)] text-[11px]`
- 顶栏:`h-14 border-b bg-[var(--bg-card)]`
- 操作按钮按颜色编码blue=进行/转交、emerald=完成、red=删除/失败、orange=关闭/提BUG
## Modal弹窗规范
- 居中 `flex items-center justify-center bg-black/40`
- `rounded-2xl bg-[var(--bg-card)] border shadow-md`
- 提交 BUG 等图片密集型用 `max-w-2xl`,普通表单 `max-w-md``max-w-lg`
## 字段命名规范
- 实际开始:`startDate` (DevTask) / `startedAt` (TestCase) / `actualStartAt` (VersionPlan)
- 实际完成:`completedAt`(统一)
- 派生进度:在 lib 层提供函数,不存储
历史原因导致命名不完全一致DevTask 用 startDate 是因为最早是日期字段),但行为一致。
## 提交信息规范
- 中文 commit message
- 格式:`类型(模块): 描述`
- feat / fix / refactor / docs / test
- 描述列出关键改动点,特别是跨模块影响
- Co-Authored-By 行带版本号
## 文档维护流程
- **新增/改动核心架构** → 更新 `architecture.md`
- **关键设计决策** → 追加到 `decisions.md`,包含"为什么"
- **新功能/路线图变更** → 更新 `roadmap.md`
- **不影响架构的功能性改动** → 不需要更新文档
## Bug 排查流程
朋友拉新代码出现"显示问题"时,按顺序排查:
1. 旧 localStorage 数据格式不兼容 → 让朋友清缓存
2. 类型定义和实际数据不一致(缺字段)
3. 列宽溢出导致裁切
4. 派生计算错误filter 条件错)
5. 跨模块联动断了store 的 store.getState() 调用时机)
## 测试 / 验证流程
- 改动后必须 `npx tsc --noEmit` 通过
- 涉及 UI 改动:`curl http://localhost:3000/<path>` 检查 200
- 不会自动跑 dev server假定它已经运行
## 与我相关Workspace数据流
```
useProductStore → versions
useRequirementStore → requirements (with versionId)
useDevTaskStore → tasks (with requirementId)
useTestCaseStore → testCases (with versionId)
useBugStore → bugs (with versionId)
useVersionPlanStore → plans (with versionId, owner)
useAuthStore → user (filter by current user)
workspace-engine.aggregateWorkItems(...)
WorkItem[] (统一格式)
Workspace 页面(树筛选 + tab 筛选 + 已完成开关)
```
新增模块时,只需在 `aggregateWorkItems` 中添加聚合逻辑,工作台自动展示。