Files
DevFlow/docs/05-代码审查/任务模块问题分析-2026-06-16.md

17 KiB
Raw Blame History

任务模块问题分析报告(核对版)

日期: 2026-06-16 范围: 任务模块全栈Rust 后端 + Tauri IPC + Vue 3 前端) 审查文件: task.rs / tasks.ts / Tasks.vue / TaskDetail.vue / crud.rs / models.rs / types.rs / project.ts / state.rs / migrations.rs / router/index.ts 核对方法: Explore 代理并行验源码,逐项 file:line 取证 核对结论: 原清单 18 项中 真 bug 8 项P0×2 P1×6、增强 5 项、假/部分假 3 项、与现有 todo 去重 3 项


〇、核对结论速览

# 原清单结论 核实 处置
1 状态枚举前后端不一致5 vs 7 三方分裂,记 B-260616-12
2 DDL priority 默认(1) vs 代码(2) 潜在非现患,记 B-260616-14
3 delete_task 硬删除无恢复 记 B-260616-13
4 priority 无值域校验 记 B-260616-15
5 id/created_at/project_id 可篡改 记 B-260616-16
6 updateTask 无 try/catch 记 B-260616-17
7 TaskDetail 绕过 store 记 B-260616-18
8 /tasks/:id 路由未注册 🔄 去重 = B-260616-09 已存在
9 无分页全量加载 🔄 去重 = F-260615-03 已立
10 watch 重复 IPC 🔄 去重 = B-260615-29 设计决策
11 列表组件重复 两文件模板结构不同(.task-item vs .task-card排除
12 project_id 无存在性校验 ⚠️ 部分假 db.rs:22 PRAGMA foreign_keys=ON 兜底拦截,降级
13 description 无长度限制 🟡 增强 待产品决策
14 branch_name 无格式校验 🟡 增强 待产品决策
15 TaskDetail 只读无编辑 🟡 增强 待产品决策
16 无批量操作 🟡 增强 待产品决策
17 无排序选项 🟡 增强 待产品决策
18 无搜索能力 🔄 去重 ≈ F-260615-07 思路

一、模块架构概览

┌─────────────────────────────────────────────────────────┐
│                    前端 (Vue 3 + TS)                      │
│  Views          │  Tasks.vue (列表)  →  TaskDetail.vue    │
│  Store          │  stores/project/tasks.ts                │
│  API            │  api/task.ts                            │
│  Types          │  api/types.ts → TaskRecord              │
│  Constants      │  constants/project.ts (状态/优先级映射)  │
├─────────────────────────────────────────────────────────┤
│                   IPC 层 (Tauri)                         │
│  Commands       │  commands/task.rs (5 个命令)            │
│  State          │  state.rs → TaskRepo                    │
├─────────────────────────────────────────────────────────┤
│                   后端 (Rust Crates)                      │
│  df-core        │  types.rs → TaskStatus 枚举             │
│  df-storage     │  models.rs → TaskRecord 结构体          │
│                 │  crud.rs → TaskRepo (CRUD 实现)         │
│                 │  migrations.rs → tasks 表 DDL           │
└─────────────────────────────────────────────────────────┘

IPC 命令5 个)

命令 签名 说明
list_tasks (project_id?) → Vec<TaskRecord> 列出任务,可按项目筛选
get_task_by_id (id) → TaskRecord 按 ID 查单个任务
create_task (input) → TaskRecord 创建任务,默认 status=todo, priority=2
update_task (id, field, value) → bool 更新单字段status 值有枚举校验
delete_task (id) → bool 删除任务(硬删除)

TaskStatus 枚举(后端 7 种)

状态值 说明
todo 待开始
in_progress 进行中
in_review 代码审查中
testing 测试中
done 已完成
blocked 已阻塞
cancelled 已取消

优先级映射

标签 样式
0 P0 critical紧急
1 P1 high
2 P2 medium默认
3 P3 low

二、问题清单(含核对标注)

🔴 P0 — 数据一致性 / 功能断裂

1. 前后端状态枚举完全不一致 【 真 · 核对确认】

状态值集合 证据
后端枚举 TaskStatus todo, in_progress, in_review, testing, done, blocked, cancelled7 crates/df-core/src/types.rs:131-146
前端类型注释 同后端 7 种 src/api/types.ts:88
前端常量 TASK_STATUS_LABELS todo, in_progress, review_ready, merged, abandoned5 src/constants/project.ts:56-62
前端 taskStatusClass 同常量 5 种,未定义回退 status-todo src/constants/project.ts:76-78
前端 i18n tasks.ts 同常量 5 种 src/i18n/{en,zh-CN}/tasks.ts:47-54

影响链

  • 后端 update_taskTaskStatus::is_valid()task.rs:96)只接受 7 种;前端筛选器的 review_ready/merged/abandoned 后端全部拒绝
  • AI 工具或后端写入 in_review/testing/blocked 时,前端 TASK_STATUS_LABELS 查不到 → 回退显示原始 key用户见 in_review 而非中文)
  • taskStatusClass 查不到 → 回退 status-todo,视觉无法区分
  • Dashboard 统计 activeTasks 仅查 in_progresstesting/blocked 不计入

根因:前端状态集是早期 Git 工作流导向review_ready/merged/abandoned后端枚举后来规范化为通用状态机两者从未对齐。types.ts 注释随了后端,但常量/i18n/样式仍停在旧集。

人定决策点:前端对齐到后端 7 种纯状态机,还是保留 Git 工作流 5 种语义做映射?


2. DDL 默认值与代码默认值矛盾 【 真 · 潜在非现患】

来源 priority 默认值 证据
DDL DEFAULT 1high crates/df-storage/src/migrations.rs:304
Rust default_priority() 2medium src-tauri/src/commands/task.rs:26-28
前端 Tasks.vue 2medium src/views/Tasks.vue:62

当前 create_task 显式传 priority(走代码默认 2DDL 默认值不生效。但未来若有直连 SQL 写入路径或手动改库,priority=1 与应用层 2 不一致。低危,可并入下次 migration 对齐。


3. delete_task 硬删除 — 无恢复机制 【 真 · 核对确认】

// src-tauri/src/commands/task.rs:113
state.tasks.delete(&id).await.map_err(err_str)  // 物理删
// crates/df-storage/src/crud.rs:194 — DELETE FROM tasks WHERE id=?

TaskRecordcrates/df-storage/src/models.rs:53-66)无 deleted_at 字段。对比 ProjectRecord 有完整软删除(deleted_at + list_deleted + restore)。

风险:误删永久丢失;关联 branches.task_id 外键变悬空(无 ON DELETE CASCADE/SET NULL)。

人定决策点:任务是否需要软删除 + 恢复(对标 projects还是物理删除即可任务粒度小、误删可重建


🟠 P1 — 安全 / 竞态 / 架构

4. update_task 缺少 priority 值域校验 【 真 · 核对确认】

// src-tauri/src/commands/task.rs:96-102 — 仅 status 校验
if field == "status" && !TaskStatus::is_valid(&value) { ... }
// priority 直接透传 update_field无范围检查

update_task(id, "priority", "999")"abc" 静默落库。前端 PRIORITY_LABELSconstants/project.ts:82key 0-3查不到 → 回退 P999 + 样式 priority-lowproject.ts:95-97)。

修复field == "priority" 时校验 value.parse::<i32>()0..=3


5. update_task 缺少 id / created_at 等不可变字段保护 【 真 · 核对确认】

// crates/df-storage/src/crud.rs:324-327
"tasks" => &["id", "project_id", "title", "description", "status", "priority",
             "branch_name", "assignee", "workflow_def_id", "base_branch",
             "created_at", "updated_at"],

白名单含 id / created_at / project_id → AI 工具或恶意调用可改主键、篡改创建时间、把任务移到别的项目。前端未暴露,但 IPC 层无防护。

修复tasks 白名单移除 id/created_atproject_id 若允许跨项目移动则保留但加目标项目存在性校验。


6. 前端 updateTask store 无错误处理 【 真 · 核对确认】

// src/stores/project/tasks.ts:29-35 — 无 try/catch
async function updateTask(id, field, value) {
  await taskApi.update(id, field, value)
  const idx = state.tasks.findIndex(t => t.id === id)
  if (idx >= 0) (state.tasks[idx] as any)[field] = value
}

对比同文件 loadTasks(10-16) / createTask(18-27) / deleteTask(37-44) 都有 try/catch。IPC 失败(如非法 status 被后端拒)→ Promise reject 冒泡,错误不写 state.error,用户无提示。

修复:补 try/catch失败写 state.error + toast。


7. TaskDetail.vue 绕过 store 直接调 API 【 真 · 核对确认】

// src/views/TaskDetail.vue:101  import { taskApi, projectApi } from '@/api'
// src/views/TaskDetail.vue:137-141  直接 taskApi.get() / projectApi.list()

其他视图走 useProjectStore()TaskDetail 直调 API

  • 不享受 AR-11 df-data-changed 联动刷新(其他窗口改任务,本页不自动刷新)
  • projectApi.list() 全量拉项目列表仅为解析 project_id → name

修复:改走 store.loadTasks/store.projects或单独监听 df-data-changed 重载当前 task。


8. /tasks/:id 路由未注册 【 真 · 导航断裂 · 🔄 去重 = B-260616-09 已存在】

// src/router/index.ts:45-49 — 只有 /tasks
{ path: '/tasks', name: 'Tasks', component: () => import('../views/Tasks.vue') }
// src/views/Tasks.vue:57 — 任务卡点击跳转
router.push('/tasks/${task.id}')   // 路由表无此路径 → 落空

对比 /ideas/:id/projects/:id 均已注册,唯独 /tasks/:id 遗漏。点击任务卡片匹配不到路由(落入 catch-all 或空白页。1 行改动速赢。


🟡 P2 — 性能 / 体验 / 代码质量

9. 无分页 — 全量加载所有任务 【🔄 去重 = F-260615-03】

// src-tauri/src/commands/task.rs:32-41
None => state.tasks.list_all().await,  // 无 limit/offsetORDER BY created_at DESC

已有任务 F-260615-03 覆盖,不重复立项。


10. Tasks.vue 筛选切换导致重复全量请求 【🔄 去重 = B-260615-29】

// src/views/Tasks.vue:229-233
watch(activeProject, (key) => { store.loadTasks(key === 'all' ? undefined : key) })
// src/views/Tasks.vue:165-192  filteredGroups computed 已做纯前端 filter

这是 B-260615-29 的设计决策(避免跨项目视图不同步),代价是每次切换 IPC 往返。不重复立项。


11. Tasks.vueProjectDetail.vue 任务列表样式/逻辑重复 假 · 排除】

核对:Tasks.vue:57-73.task-item 布局,ProjectDetail.vue:137-151.task-card 布局,模板结构不同。两者引用相同常量函数(状态/优先级映射),但模板本身非重复。排除


12. create_taskproject_id 存在性校验 【⚠️ 部分假 · 降级】

// src-tauri/src/commands/task.rs:59-84 — create_task 不校验 project_id
project_id: input.project_id,  // 直接使用

crates/df-storage/src/db.rs:22 已开 PRAGMA foreign_keys=ONDB 层外键约束会拦截指向不存在 project 的 insert。代码层无显式校验但风险被 DB 兜住。降级为非漏洞,仅留注释说明依赖外键。


13. description 字段无长度限制 【🟡 增强】

TaskRecord.descriptionStringDDL 为 TEXT NOT NULL DEFAULT ''。无前后端长度校验,超大文本影响 Markdown 渲染性能。待产品决策加上限。


14. branch_name / base_branch 无 Git 分支名格式校验 【🟡 增强】

允许任意字符串(空格/特殊字符/中文),可能与实际 Git 分支不兼容。待产品决策加格式校验。


🔵 P3 — 增强建议(均待产品决策)

# 说明
15 TaskDetail 纯只读 无编辑/改状态/改优先级 UI列表页也无内联编辑 → 当前无任何 UI 改任务状态,只能靠 AI 工具/API
16 无批量操作 无法批量改状态/删除/分配
17 无排序选项 固定 ORDER BY created_at DESC,无法按优先级/状态/更新时间排
18 无搜索能力 ≈ F-260615-07 思路

三、问题汇总矩阵(含核对标注)

# 严重度 类型 问题 影响 核实
1 P0 数据一致性 前后端状态枚举不一致5 vs 7 种) 全局
2 P0 数据一致性 DDL priority 默认值(1) vs 代码(2) 数据层 真(潜在)
3 P0 数据安全 delete_task 硬删除无恢复 数据丢失
4 P1 安全校验 priority 无值域校验 数据质量
5 P1 安全校验 id/created_at/project_id 可被篡改 数据完整性
6 P1 健壮性 updateTask store 无 try/catch 用户体验
7 P1 架构 TaskDetail 绕过 store 数据同步
8 P1 功能缺陷 /tasks/:id 路由未注册 导航断裂
9 P2 性能 无分页全量加载 扩展性 🔄 F-260615-03
10 P2 性能 筛选切换重复 IPC 响应速度 🔄 B-260615-29
11 P2 代码质量 任务列表组件重复 可维护性
12 P2 安全校验 project_id 无存在性校验 数据完整性 ⚠️ 部分假(外键兜底)
13 P2 安全校验 description 无长度限制 性能 🟡 增强
14 P2 安全校验 branch_name 无格式校验 数据质量 🟡 增强
15 P3 功能缺失 TaskDetail 无编辑能力 用户体验 🟡 增强
16 P3 功能缺失 无批量操作 效率 🟡 增强
17 P3 功能缺失 无排序选项 用户体验 🟡 增强
18 P3 功能缺失 无搜索能力 用户体验 🔄 ≈F-260615-07

四、todo 编号映射

记入 docs/todo.mdB-260615-58 起,沿用 6.15 编号保连续):

todo 号 原清单 # 等级 摘要
B-260616-12 1 P0 状态枚举前后端分裂7 vs 5需人定Git 工作流 vs 纯状态机
B-260616-13 3 P0 delete_task 硬删除无恢复,需人定:是否要任务软删除
B-260616-14 2 P1 DDL priority DEFAULT 1 vs 代码 2migration 对齐
B-260616-15 4 P1 update_task priority 无值域校验0..=3
B-260616-16 5 P1 allowed_columns 含 id/created_at/project_id 可篡改
B-260616-17 6 P1 updateTask store 无 try/catch
B-260616-18 7 P1 TaskDetail 绕 store不享受联动刷新
B-260616-09 8 P1 /tasks/:id 路由未注册 — 已存在去重todo 排查会话区块)

编号沿用 B-260616 批次(与 B-260616-08~11 同批,今日 06-16 发现)。 增强 #13-17 归 F- 类,待产品决策后立项。


五、建议修复顺序

  1. #8 路由注册 /tasks/:id1 行速赢)
  2. #6 updateTask store 加 try/catch
  3. #4 priority 值域校验0..=3
  4. #5 不可变字段保护id/created_at 移出白名单)
  5. #1 状态枚举对齐(需人定决策
  6. #3 软删除支持(需人定决策
  7. #2 DDL 默认值修正
  8. #7 TaskDetail 接入 store
  9. 其余 P2/P3 按需排期

六、人定决策点(需用户拍板,非大模型推断)

  1. 状态枚举方向#1前端对齐到后端 7 种纯状态机,还是保留 Git 工作流 5 种语义review_ready/merged/abandoned做映射影响筛选器/i18n/统计全链。
  2. 任务软删除#3任务是否需要软删除 + 恢复(对标 projects还是物理删除即可任务粒度小、误删可重建

这两项是产品/架构取舍,与模型能力无关,决策后记入功能决策记录。