Files
iboard/docs/V0.2/任务模块/任务模块功能设计.md
T
jif2.zhang 6c9cd3fd99
Docker Build and Push / build-image (push) Failing after 3m51s
feat(V0.2): 任务模块 —— 项目 / 列表与看板 / 列-状态绑定 / 一级子任务
需求 142 条 (T-*), 设计见 docs/V0.2/任务模块/

数据层:
- 新增 6 张表: Project / ProjectMember / BoardColumn / Task / TaskMember / TaskTag
- 看板列是实体(可增删改排序), Task.columnId 外键 RESTRICT 防误删列丢任务
- Task.status(todo/doing/done) 与 columnId 双落库, 二者正交

领域层 server/task-domain/ (唯一口径, 前后端不重复实现):
- resolveStatus: 列决定状态(只看目标列, 无拖出回退); 状态与列不匹配时按列序取第一个绑定该状态的列自动归位, 无匹配列则不移动; 子任务完全豁免
- retention: 逐列 6 档保留窗口(永不显示/当天/3天/本周/本月/永久显示), 以 doneAt 判定
- copyTask: 跨项目深拷贝, 人员按目标项目成员过滤并回报丢弃名单

接口: /api/projects, /api/columns, /api/tasks (均校验项目成员)

前端:
- 底部 Tab 插入「任务」, 位于「打卡」之后; 默认首页仍为打卡
- 列表视图(子任务缩进+折叠) / 看板视图(长按拖拽换列、拖到卡片降为子任务)
- 列设置(列管理+状态绑定+保留选项) / 任务详情(扩展信息卡片默认收起) / 成员管理
- 视图记忆与上次项目存设备端

已验证: 95 文件语法 0 错误、相对导入 0 缺失、领域逻辑用例全部通过
2026-10-24 11:21:16 +08:00

331 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iBoard V0.2 任务模块 功能设计
| 项 | 内容 |
| --- | --- |
| 版本 | V0.2(对应分支 `dev-0.2`,应用版本 `0.2.0`) |
| 文档状态 | **设计基线**(待评审) |
| 上游文档 | `任务模块需求文档.md`(**142 条需求点**,编号 `T-*`) |
| 配套文档 | `任务模块设计文档-框架设计.md`、`任务模块数据库设计文档.md`、`任务模块界面设计.html` |
| 对应关系 | **本文与需求点一一对应**:每条需求点均给出「设计落点(功能/组件/接口/表字段)」与「实现要点」 |
> **阅读方式**
> 1. 本文按需求文档的模块码组织(`VW` / `COL` / `BD` / `FL` / `TK` / `AS` / `ST` / `PJ` / `PM` / `CP` / `UI` / `DT` / `NF` / `EX`)。
> 2. 每条需求点一行:**编号 → 设计落点 → 实现要点**。设计落点中的组件名、接口路径、表字段均与《任务模块数据库设计文档》《任务模块界面设计》一致。
> 3. 文末 §15 给出**覆盖自检表**,确保 142 条无遗漏。
---
## 0. 通用约定
### 0.1 契约命名
| 类别 | 约定 | 示例 |
| --- | --- | --- |
| 状态枚举 | `todo` / `doing` / `done` | 未开始 / 执行中 / 完成 |
| 列 | `BoardColumn` 实体,按 `sortOrder` 升序 | 默认 `Plan/Doing/Action/Done` |
| 保留选项 | `never` / `today` / `3d` / `week` / `month` / `forever` | 永不显示 / 当天 / 3 天 / 本周 / 本月 / 永久显示 |
| 视图 | `list` / `board` | 设备端记忆 |
| 设备端键 | `iboard_task_prefs` | `{ lastProjectId, viewMode: { [projectId]: 'list'\|'board' } }` |
### 0.2 接口总览
| 方法 | 路径 | 用途 |
| --- | --- | --- |
| GET | `/api/projects` | 我参与的项目(含个人默认项目、归档标记) |
| POST | `/api/projects` | 新建普通项目(同时初始化 4 个默认列) |
| GET | `/api/projects/:id` | 项目详情(含成员、列配置) |
| PUT | `/api/projects/:id` | 改名 / 归档 |
| DELETE | `/api/projects/:id` | 删除项目(个人项目 400) |
| POST | `/api/projects/:id/members` | 加成员(个人项目 400) |
| DELETE | `/api/projects/:id/members/:uid` | 移成员 / 自己退出 |
| GET/POST | `/api/projects/:id/columns` | 列列表 / 新增列 |
| PUT | `/api/columns/:id` | 改名 / 改绑定 / 改保留选项 |
| DELETE | `/api/columns/:id` | 删列(需 `moveToColumnId`,最后列 400) |
| PUT | `/api/projects/:id/columns/order` | 列排序 |
| GET | `/api/projects/:id/tasks` | 任务列表(含子任务与列信息) |
| POST | `/api/projects/:id/tasks` | 新建任务 / 子任务 |
| GET | `/api/tasks/:id` | 任务详情 |
| PUT | `/api/tasks/:id` | 改状态 / 换列 / 改字段(触发裁决) |
| DELETE | `/api/tasks/:id` | 删除任务(级联子任务) |
| POST | `/api/tasks/:id/copy` | 跨项目拷贝 |
---
## 1. 视图体系(T-VW)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-VW-01 | `ProjectView.jsx` 内 `viewMode` 分支渲染 `ListView` / `BoardView` | 两视图共用 `TaskStore` 的同一份任务数据,仅渲染方式不同 |
| T-VW-02 | `SwipeTabs`/分段控件切换 `viewMode` | 纯本地状态切换,不触发路由跳转、不重新拉取数据(满足"无整页刷新") |
| T-VW-03 | `prefs.js` → `viewMode[projectId]` | 按项目 id 分键存储,A/B 项目互不影响 |
| T-VW-04 | `ProjectView` 挂载时读 `prefs.getViewMode(projectId)` | 有值用之;无值走 T-VW-05 默认 |
| T-VW-05 | 默认值 `'list'` | 新项目首次进入为列表 |
| T-VW-06 | `localStorage.iboard_task_prefs` | **不落库、不同步**;换设备不继承(与 T-FL-15 的项目级配置区分) |
| T-VW-07 | `prefs.getLastProjectId()` / `setLastProjectId()` | 进入 `/task` 时读取;无记录或记录的项目已不可见 ⇒ 回落个人默认项目 |
> **实现细节**:`lastProjectId` 指向的项目若已被退出/删除,视为"无记录",静默回落到个人默认项目,不弹错。
---
## 2. 看板列管理(T-COL)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-COL-01 | `POST /api/projects` 内部初始化 4 列 | 事务内创建 `Plan(todo, sort 0)`、`Doing(doing,1)`、`Action(null,2)`、`Done(done,3)` |
| T-COL-02 | `ColumnSettings` → `POST /api/projects/:id/columns` | `sortOrder = max+1` 追加末尾;`boundStatus=null`、`retention='forever'`(B-18) |
| T-COL-03 | `PUT /api/columns/:id` | 改 `name`;前端 `TaskStore` 整体替换列列表后重渲染 |
| T-COL-04 | `DELETE /api/columns/:id?moveToColumnId=` | 二次确认弹窗;见 T-EX-16 |
| T-COL-05 | `PUT /api/projects/:id/columns/order` | 传完整 `[columnId…]` 数组,服务端按索引重写 `sortOrder` |
| T-COL-06 | 服务端校验总量 | `1 <= count <= 10`;达上限拒绝新增(T-EX-19)、仅剩 1 列拒绝删除(T-EX-17) |
| T-COL-07 | `BoardColumn.name` 校验 | trim 后非空、长度 ≤ 12;`@@unique([projectId,name])` 兜底重名 409 |
| T-COL-08 | 列删除即绑定消失 | 绑定存在列记录上,列删则解除,无需额外清理 |
| T-COL-09 | `requireProjectMember` | 项目级配置,任一成员可改;不影响其他项目 |
| T-COL-10 | `ListView` 不分组但仍显示列信息 | 任务行内以小标签显示所属列名(可关闭),归属始终正确 |
---
## 3. 看板与列-状态绑定(T-BD)
> 联动的**唯一实现**在 `server/task-domain/resolveStatus.js`,前端只做乐观更新。判定矩阵见《框架设计》§2.3。
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-BD-01 | `BoardView` 按 `columns` 数组渲染列 | 列来自项目配置,可增删改排序 |
| T-BD-02 | `ColumnSettings` 每列一组「绑定开关 + 状态下拉」 | 写入 `BoardColumn.boundStatus`(`null`/`todo`/`doing`/`done`) |
| T-BD-03 | 无唯一约束限制多列绑定同状态 | 允许 `done` 与 `action` 同为 `done` |
| T-BD-04 | `onColumnChange()` | 目标列 `boundStatus != null` ⇒ `status = boundStatus` |
| T-BD-05 | `onStatusChange()` | 状态变更后若当前列已匹配则不动作,否则走归位 |
| T-BD-06 | 归位取列序首个匹配 | `columns` 按 `sortOrder` 排序后 `find()` 首个 |
| T-BD-07 | **只看目标列** | 目标列不绑定 ⇒ 保留原状态;**无"拖出回退"规则** |
| T-BD-08 | 不绑定列完全正交 | 拖入/拖出、改状态均不改该列以外语义 |
| T-BD-14 | `resolveColumn(task, newStatus)` | 当前列 `boundStatus !== newStatus` ⇒ 触发归位 |
| T-BD-15 | 按当前 `sortOrder` 取首个 | 用户调序后归位目标随之改变 |
| T-BD-16 | 无匹配返回 `null` | `null` ⇒ 不改 `columnId`,状态照常写库 |
| T-BD-09 | 初始化默认值 | `Plan=todo`、`Doing=doing`、`Done=done`、`Action=null` |
| T-BD-10 | 项目级配置 | 任一成员可改;不同项目独立 |
| T-BD-11 | 配置变更不回溯 | 保存配置时**不触发**任何任务更新语句 |
| T-BD-12 | 保存后返回最新列列表 | 前端整体替换 + 重算可见集合,无需刷新 |
| T-BD-13 | `resolveStatus()` 首行判 `parentId` | 子任务直接跳过全部联动 |
---
## 4. 已完成任务显示控制(T-FL)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-FL-01 | `BoardColumn.retention` | 每列独立字段 |
| T-FL-02 | `ColumnSettings` 下拉 6 项 | 固定枚举,无自由输入 |
| T-FL-03 | `retention='forever'` | 判定恒为可见 |
| T-FL-04 | `retention='never'` | 已完成任务恒不可见 |
| T-FL-05 | `retention='today'` | `doneAt >= 今天 00:00` |
| T-FL-06 | `retention='3d'` | `doneAt >= 今天-2天 00:00` |
| T-FL-07 | `retention='week'` | `doneAt >= 本周一 00:00` |
| T-FL-08 | `retention='month'` | `doneAt >= 本月1日 00:00` |
| T-FL-09 | `task-domain/retention.js` + 前端定时重算 | 超出窗口自动隐藏,无需操作 |
| T-FL-10 | 判定字段 `Task.doneAt` | 与当前列无关;取消完成时 `doneAt=null` |
| T-FL-11 | 前端可见性统一走同一函数 | 列表与看板共用 `isTaskVisible(task, column)`;列表不分组但归属不变 |
| T-FL-12 | 判定前置 `status !== 'done'` | 未完成任务恒可见 |
| T-FL-13 | 纯展示层过滤 | 不修改任何字段;接口返回全量,前端过滤(或服务端按需过滤但不改数据) |
| T-FL-14 | 列计数取过滤后集合长度 | 列头计数与卡片数同源,杜绝不一致 |
| T-FL-15 | 存在 `BoardColumn` 上 | 项目级共享,非个人偏好(对比 T-VW-06 设备端) |
> **实现细节**:保留判定在前后端各有一份实现(服务端用于分页/统计,前端用于即时过滤),但**必须共用同一口径常量**,跨度边界由 `date.js` 单测覆盖。
---
## 5. 任务字段体系(T-TK)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-TK-01 | `Task` 表 | 字段:`title`/`description`/`projectId`/`columnId`/`status`/`assigneeId`/`creatorId`/`doneAt`/`sortOrder` + 关联成员/标签/扩展 |
| T-TK-02 | `title` 非空校验 | 其余字段允许空;trim 后为空 ⇒ 400 |
| T-TK-03 | `status` 枚举三值 | DB 层用 `VARCHAR(8)` + 应用层校验(避免 ENUM 改值困难) |
| T-TK-04 | `TaskDetail` → `ExtrasCard` 组件 | 任意条目增删改,无字段上限(建议 ≤ 20 条) |
| T-TK-05 | `Task.extras` JSON | 结构 `[{label, value, url?}]`;`value` 支持纯文本或 URL |
| T-TK-06 | `ExtrasCard` 默认 `collapsed=true` | 首次打开详情为收起态 |
| T-TK-07 | 无必填校验 | 全空可保存 |
| T-TK-08 | `Task.assigneeId` 单值 | 重复设置以最后一次为准 |
| T-TK-09 | 新建时服务端默认赋值 | 未显式传 `assigneeId` ⇒ 取 `req.user.id`(B-10) |
| T-TK-10 | `assigneeId` 允许 `null` | 显式传 `null` 即清空,UI 显示「未指派」 |
| T-TK-11 | `TaskMember` 关联表 | 多对多,`@@unique([taskId,userId])` 去重 |
| T-TK-12 | `TaskTag` 表 + 卡片标签渲染 | 多标签,展示于卡片/条目 |
| T-TK-13 | 服务端维护 | `creatorId`/`createdAt` 不可改;`updatedAt` 自动刷新 |
---
## 6. 负责人 & 成员(T-AS)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-AS-01 | `TaskCard` 负责人区 | 字号 13px/600 + 头像,位于标题下方主信息位 |
| T-AS-02 | `TaskCard` 成员区 | 字号 11px/400、色 `#999`,位于卡片底部 |
| T-AS-03 | `UserPicker` 数据源 = 项目成员 | 只列 `ProjectMember` 中的用户 |
| T-AS-04 | 同上(多选模式) | 不可选项目外用户 |
| T-AS-05 | `assigneeId === null` 时渲染「未指派」 | 占位样式弱化,可点击再次指派 |
| T-AS-06 | 渲染时 `LEFT JOIN ProjectMember` 判定 | 非成员 ⇒ 显示「已退出」灰标;见 T-EX-06 |
| T-AS-07 | 权限模型 | 无"负责人可编辑"概念,所有成员全读写(T-PM-02) |
---
## 7. 子任务体系(T-ST)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-ST-01 | `Task.parentId` 自关联 | 创建子任务时校验:父任务 `parentId IS NULL`,否则 400 |
| T-ST-02 | 一致性校验 | 子任务 `projectId` 必须等于父任务 `projectId`,否则 400(T-EX-12) |
| T-ST-03 | 状态独立 | 父/子状态字段各自独立,无级联更新 |
| T-ST-04 | `SubtaskRow` 缩进 | 左侧 28px 缩进 + 层级线 |
| T-ST-05 | 折叠/展开按钮 | 组件内存状态,折叠时不渲染子项 |
| T-ST-06 | `TaskCard` 内嵌 `SubtaskRow` 列表 | 简洁单行:复选框 + 标题,最多显示 3 条 + 「查看全部」 |
| T-ST-07 | 卡片内直接勾选 | 勾选调 `PUT /api/tasks/:id {status}`;完整编辑走 `TaskDetail` 弹窗 |
| T-ST-08 | 子任务跳过绑定 | 见 T-BD-13;父任务完成时子任务状态不变 |
| T-ST-09 | `SubtaskRow` 带 `StatusDot` | 三色小圆点:灰=未开始 / 蓝=执行中 / 绿=完成 |
| T-ST-10 | 看板只渲染顶层任务 | 看板查询 `WHERE parentId IS NULL` |
| T-ST-11 | `Task.parentId` 级联删除 | `onDelete: Cascade`(T-EX-07) |
| T-ST-12 | `useLongPressDrag` 落点为目标顶层任务 | 设置 `parentId` |
| T-ST-13 | 目标为子任务 ⇒ 拒绝 | Toast「仅支持一级子任务」 |
| T-ST-14 | 被拖任务有子任务 ⇒ 拒绝 | 避免二级嵌套 |
| T-ST-15 | 保持原列与状态 | 仅更新 `parentId`,不触发状态裁决 |
---
## 8. 项目体系(T-PJ)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-PJ-01 | 用户首次访问自动创建 | 按 `isPersonal=true` 且 `ownerId=userId` 幂等创建 |
| T-PJ-02 | `DELETE /api/projects/:id` 校验 `isPersonal` | 为真 ⇒ 400(T-EX-09) |
| T-PJ-03 | `POST .../members` 校验 `isPersonal` | 为真 ⇒ 400 |
| T-PJ-04 | `name` 初始 `${user.name}的任务` | 允许 `PUT` 改名,`isPersonal` 不变 |
| T-PJ-05 | `POST /api/projects` | 创建者自动写入 `ProjectMember` |
| T-PJ-06 | 成员接口 | 增/删成员,即时影响可见性 |
| T-PJ-07 | `DELETE .../members/:uid` 允许 `uid == ownerId` | 创建人退出后不再是成员 ⇒ 不可见 |
| T-PJ-08 | 删除最后成员不删项目 | 仅删 `ProjectMember`(B-11);见 T-EX-11 |
| T-PJ-09 | `Project.archived` | 列表分「进行中 / 已归档」 |
| T-PJ-10 | 列表查询按成员关系过滤 | `WHERE EXISTS ProjectMember(userId)` |
---
## 9. 项目权限与入口(T-PM)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-PM-01 | `requireProjectMember` 中间件 | 非成员 403;列表查询天然过滤 |
| T-PM-02 | 无角色区分 | 所有成员对任务/列/成员均有全读写 |
| T-PM-03 | `ProjectMember.permission` 字段 | 本期恒为 `member`,预留分级扩展位 |
| T-PM-04 | 归档接口无权限限制 | 任意成员可归档(`PUT /api/projects/:id {archived}`) |
| T-PM-05 | 复用 `authRequired` | 未登录 401 |
| T-PM-06 | `BottomNav.TABS` 插入 `{ key:'/task', label:'任务' }` | 位于 `打卡` 之后;`HomePath` 仍为 `/checkin` |
| T-PM-07 | `prefs.lastProjectId` | 设备端;无记录 ⇒ 个人默认项目 |
---
## 10. 跨项目拷贝(T-CP)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-CP-01 | `POST /api/tasks/:id/copy` | 复制而非移动,源任务零改动 |
| T-CP-02 | `copyTask()` 字段映射 | 标题/描述/状态/列/扩展/标签/成员 全量复制 |
| T-CP-03 | 递归复制子任务 | 只复制一层(子任务无更深层级) |
| T-CP-04 | `creatorId = req.user.id` | 覆盖源创建人 |
| T-CP-05 | 无任何关联字段 | 拷贝后两条独立记录 |
| T-CP-06 | 校验目标项目成员身份 | 非成员 403 |
| T-CP-07 | 人员交集过滤 | 保留属于目标项目成员者,返回 `dropped` 名单(T-EX-08) |
| T-CP-08 | 子任务 `projectId` 同步改写 | 与父任务一致 |
| T-CP-09 | 状态与列沿用不纠正 | 见 T-EX-14 |
---
## 11. UI 交互规范(T-UI)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-UI-01 | 列表条目结构 / 快速新增 / 子任务折叠 | 参考 Todoist:底部输入框回车即建 |
| T-UI-02 | `TaskCard` 精简版 | 仅标题、状态点、负责人、子任务摘要;无边框装饰 |
| T-UI-03 | 单 `TaskStore` | 任一视图修改写入 store,另一视图读取同一数据 |
| T-UI-04 | 视图切换纯本地 | 不重新请求,不重载页面 |
| T-UI-05 | 复用 `.card` 与安全区变量 | 375~430px 无横向滚动;底部预留 TabBar 高度 |
| T-UI-06 | 勾选即时变色 | 乐观更新,先改 UI 再发请求 |
| T-UI-07 | `useLongPressDrag` | 长按 300ms 拖拽 + 「⋯」菜单「移动到」兜底 |
| T-UI-08 | `EmptyState` 组件 | 无项目 / 无任务 / 无子任务三档空态 + CTA |
| T-UI-09 | `LoadingState` 骨架屏 | 首屏与切换视图 |
| T-UI-10 | `ErrorState` 组件 | 展示错误 + 重试按钮 |
---
## 12. 数据需求(T-DT)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-DT-01 | `Project` / `ProjectMember` | 见《数据库设计文档》 |
| T-DT-02 | `BoardColumn.boundStatus` | 每列独立字段,允许多列同值 |
| T-DT-03 | `BoardColumn.retention` | 六档枚举字符串 |
| T-DT-04 | `Task` | 含 `parentId` 自关联、`assigneeId`、`status`、`columnId`、`extras` |
| T-DT-05 | `TaskMember` / `TaskTag` | 关联表;`extras` 为 JSON |
| T-DT-06 | 设备端 | 不落库 |
| T-DT-07 | 索引 | `(projectId, columnId)`、`(projectId, status)`、`(parentId)` |
| T-DT-08 | 迁移文件 | `prisma migrate deploy` 流程 |
| T-DT-09 | `Project.archived` / 任务无物理删 | 归档保留历史 |
---
## 13. 非功能需求(T-NF)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-NF-01 | 单请求聚合 + 乐观更新 | 见《框架设计》§4.2 |
| T-NF-02 | 不依赖桌面专有 API | 触控事件统一 `touch` / `pointer` 兼容 |
| T-NF-03 | `src/pages/task/*` + `server/routes/*.js` | 与既有模块结构一致 |
| T-NF-04 | 路由挂载于 `server/index.js` | 沿用既有组织方式 |
| T-NF-05 | 千级任务可用 | 索引 + 分页/虚拟滚动 |
---
## 14. 异常与边界(T-EX)
| 编号 | 设计落点 | 实现要点 |
| --- | --- | --- |
| T-EX-01 | 前端 500ms 防抖 + 服务端幂等判定 | 相同终态请求直接返回当前任务 |
| T-EX-02 | 乐观更新快照回滚 | 失败恢复快照 + Toast + 重试按钮 |
| T-EX-03 | 列配置改为不绑定 | 已有任务保持不动 |
| T-EX-04 | 状态与列不匹配 | 走 T-BD-14~16 归位 |
| T-EX-05 | 拖到不绑定列 | 状态保留,不回退 |
| T-EX-06 | 非成员渲染「已退出」 | 见 T-AS-06 |
| T-EX-07 | 级联删除子任务 | 确认弹窗提示条数 |
| T-EX-08 | 拷贝丢弃人员 | 返回 `dropped` 并提示 |
| T-EX-09 | 个人项目两个保护接口 | 400 + 明确文案 |
| T-EX-10 | 列空态 | 展示该列空态,不报错 |
| T-EX-11 | 无成员项目 | 静默不可见,无特判报错 |
| T-EX-12 | 子任务跨项目 | 服务端 400 |
| T-EX-13 | 拖拽降级 | 保持原列与状态 |
| T-EX-14 | 拷贝状态/列无法对应 | 沿用源值,不纠正 |
| T-EX-15 | 拖到自身或后代 | 拒绝 + Toast |
| T-EX-16 | 删除有任务的列 | 二次确认 + 迁移到指定列(默认相邻)+ 重新裁决 |
| T-EX-17 | 删除最后一列 | 400「至少保留一列」 |
| T-EX-18 | 跨周期当场消失 | 定时重算 + 退场动画 + 重排 |
| T-EX-19 | 达到列数上限 | 拒绝新增 + 提示 |
---
## 15. 覆盖自检表
| 模块 | 编号范围 | 条数 | 本文对应章节 |
| --- | --- | --- | --- |
| 视图体系 | T-VW-01 ~ 07 | 7 | §1 |
| 看板列管理 | T-COL-01 ~ 10 | 10 | §2 |
| 列-状态绑定 | T-BD-01 ~ 16 | 16 | §3 |
| 已完成显示控制 | T-FL-01 ~ 15 | 15 | §4 |
| 任务字段体系 | T-TK-01 ~ 13 | 13 | §5 |
| 负责人 & 成员 | T-AS-01 ~ 07 | 7 | §6 |
| 子任务体系 | T-ST-01 ~ 15 | 15 | §7 |
| 项目体系 | T-PJ-01 ~ 10 | 10 | §8 |
| 项目权限与入口 | T-PM-01 ~ 07 | 7 | §9 |
| 跨项目拷贝 | T-CP-01 ~ 09 | 9 | §10 |
| UI 交互规范 | T-UI-01 ~ 10 | 10 | §11 |
| 数据需求 | T-DT-01 ~ 09 | 9 | §12 |
| 非功能需求 | T-NF-01 ~ 05 | 5 | §13 |
| 异常与边界 | T-EX-01 ~ 19 | 19 | §14 |
| **合计** | — | **142** | — |
> 需求文档共 **142 条**需求点,本文逐条给出设计落点,覆盖率 **142/142**。(其中 `T-BD-14~16`、`T-COL-*`、`T-EX-18~19` 为评审后新增,编号不连续,非笔误。)