跳转到正文

实战案例:从零构建高级 Todo 应用

一个 Superpowers 新手可以构建一个完整的 Todo 应用——从头脑风暴到运行测试——仅在一次工作会话中完成。这是体验完整工作流程的理想入门案例。


背景

你想构建一个 Todo 应用作为 prototype/demo——足够令人印象深刻可以展示,但使用 Superpowers 工作流程从头到尾构建。

需求:

  • CRUD:添加、编辑、删除、标记完成
  • 按状态、优先级、分类进行筛选/搜索
  • 分类(Work / Personal / Study)和优先级(High / Medium / Low)
  • 拖拽排序
  • 每个 todo 设置截止日期
  • 暗色模式(手动切换 + 跟随系统偏好)
  • 数据存储在 localStorage(不需要后端)

技术栈:

  • Vite + React 18 + TypeScript
  • shadcn/ui + Tailwind CSS
  • @dnd-kit(拖拽)
  • date-fns(日期处理)
  • Vitest + React Testing Library

你将学到什么

在本教程中,你将应用 Superpowers 的四个核心技能:

  1. Brainstorming & Design -- 通过问答探索需求,比较方案,用 visual companion 选择布局
  2. Writing Plans -- 拆分为 11 个有明确验证标准的任务
  3. TDD -- 先为 hook 和组件编写测试
  4. Debugging & Verification -- 处理实际兼容性问题并验证一切正常运行

最终目标:一个功能完整的 Todo 应用,12 个测试用例全部通过,production 构建成功,按照有纪律的工作流程构建。


分步实践

步骤 1:头脑风暴 Todo App 设计

你打开与 AI 的对话并说:

"我想用 React + TypeScript 构建一个简单的 Todo 应用。在写代码之前先进行头脑风暴。"

AI 进入头脑风暴模式,启动 visual companion(在浏览器上显示 mockup),然后逐个提问:

问题 1: "这个 Todo 应用的主要目的是什么?"

  • A) 学习项目/作品集
  • B) 个人日常使用的应用
  • C) Prototype/demo 用于展示

你选择:C) Prototype/demo -- 展示时需要令人印象深刻。

问题 2: "应用需要哪些功能?"

  • A) 基础 -- 添加、编辑、删除、标记完成
  • B) 中等 -- 在 A 的基础上加筛选/搜索、分类、优先级
  • C) 高级 -- 在 B 的基础上加拖拽、截止日期、暗色模式、localStorage 持久化

你选择:C) 高级 -- demo 需要功能齐全。

问题 3: "数据存储在哪里?"

  • A) 仅 LocalStorage
  • B) Mock API(json-server 或 MSW)
  • C) 真实后端(Firebase/Supabase)

你选择:A) LocalStorage -- 简单,不需要后端。

问题 4: "UI/样式用什么方案?"

  • A) Tailwind CSS
  • B) shadcn/ui + Tailwind
  • C) CSS Modules / Styled Components
  • D) Ant Design / MUI

你选择:B) shadcn/ui + Tailwind -- 组件美观、专业、易于定制。

问题 5: "工具链/构建用什么?"

  • A) Vite
  • B) Next.js
  • C) Create React App

你选择:A) Vite -- 快速、轻量、最流行。

收集完足够信息后,AI 展示 3 种方案:

## 方案 A:Single Page — All-in-One(推荐)
整个应用在 1 个页面中。侧边栏包含筛选/分类,主区域包含 todo 列表。
- 优点:简单,不需要路由,UX 流畅
- 缺点:所有内容集中在 1 个视图

## 方案 B:Multi-Page 使用 React Router
分成多个页面:Dashboard、Todo List、Settings。
- 优点:结构清晰,易于扩展
- 缺点:对 todo 应用来说过度设计,增加依赖

## 方案 C:Kanban Board 风格
Todo 以列形式显示(To Do / In Progress / Done),在列之间拖拽。
- 优点:演示时视觉效果令人印象深刻
- 缺点:复杂度高很多,难以筛选/排序

你最初选择了 Kanban(C),但在 visual companion 上查看 mockup 后,你改选了 方案 A:Single Page -- 在功能和复杂度之间取得了最佳平衡。

AI 继续询问布局:

  • A) Sidebar + Main Content(类似 Todoist)
  • B) Top Filter Bar + Centered List(极简风格)

你选择:B) Top Filter Bar + Centered List -- 简洁极简。

AI 编写了详细的设计规格,包含 3 个部分:

DESIGN SPEC: Todo App

=== Section 1: Architecture & Data Model ===

Data Model:
  interface Todo {
    id: string
    title: string
    completed: boolean
    priority: 'high' | 'medium' | 'low'
    category: 'Work' | 'Personal' | 'Study'
    dueDate: string | null
    order: number
    createdAt: string
  }

State Management:
  - useReducer 管理 todo 状态(add, edit, delete, toggle, reorder)
  - 自定义 hook useTodos() — 处理逻辑 + localStorage 同步
  - 自定义 hook useTheme() — 暗色/亮色模式切换

Component Structure:
  App
  ├── Header(标题、统计、暗色模式切换)
  ├── FilterBar(状态筛选、优先级筛选、分类筛选、搜索)
  ├── TodoInput(添加新 todo 表单 — 点击展开)
  ├── TodoList(DnD 容器)
  │   └── TodoItem[](复选框、标题、优先级徽章、分类、截止日期、操作)
  └── EditTodoDialog(shadcn dialog)

=== Section 2: UI Components & Interactions ===

FilterBar:
  - 水平排列的 Pill 按钮:Status (All|Active|Done) | Priority | Category
  - 使用 AND 组合(Active + High + Work → 只显示满足所有条件的 todo)
  - 搜索输入框在右侧

TodoItem:
  - Checkbox | Title | Priority 徽章(彩色)| Category 标签 | Due date | Menu (⋮)
  - Hover → 左侧显示拖拽手柄
  - Completed → 变淡 + 删除线
  - Overdue → 截止日期显示红色

Drag & Drop:
  - @dnd-kit/sortable 实现拖拽排序
  - 在筛选视图中拖拽时,只更新相对顺序;
    被筛选隐藏的项目保持原始顺序

=== Section 3: Dark Mode & Persistence ===

Dark Mode: Tailwind dark: class + 默认跟随系统偏好
localStorage: 写入时 300ms 防抖,无效数据时回退为空数组
Testing: Vitest + RTL 测试 useTodos hook、TodoInput、TodoItem

AI 分派 spec reviewer 检查规格质量。Reviewer 批准并提出 3 个小建议(已更新到规格中)。

你批准了。进入下一个阶段。

Superpowers 提示: 设计规格保存在 docs/superpowers/specs/ 中,spec reviewer 在转入编写计划之前自动检查。详见 Brainstorming


步骤 2:Superpowers 编写详细计划

基于设计规格,AI 将工作拆分为 11 个任务(比简单应用多很多):

## Plan: Todo App

### Task 1: Project Scaffold
- Vite + React + TS, Tailwind, shadcn/ui, @dnd-kit, date-fns
- Vitest + React Testing Library
- Verification: npm run build 成功

### Task 2: Types & Storage Utilities
- src/types/todo.ts — interface Todo, Filters, constants
- src/lib/storage.ts — localStorage helpers
- Verification: TypeScript compile OK

### Task 3: useTodos Hook (TDD)
- 先写测试: src/hooks/use-todos.test.ts
- 编写代码: src/hooks/use-todos.ts
- Verification: 6/6 tests pass

### Task 4: Filter Logic & useTheme Hook
- src/lib/filters.ts — applyFilters() function
- src/hooks/use-theme.ts — 暗色模式切换

### Task 5: Header & FilterBar Components
- src/components/header.tsx
- src/components/filter-bar.tsx

### Task 6: TodoInput Component (TDD)
- 先写测试: src/components/todo-input.test.tsx
- 编写代码: src/components/todo-input.tsx
- Verification: 3/3 tests pass

### Task 7: TodoItem Component (TDD)
- 先写测试: src/components/todo-item.test.tsx(需要 DndContext wrapper)
- 编写代码: src/components/todo-item.tsx
- Verification: 3/3 tests pass

### Task 8: TodoList + Drag & Drop
- src/components/todo-list.tsx

### Task 9: EditTodoDialog
- src/components/edit-todo-dialog.tsx

### Task 10: Assemble App + Toast
- 将所有组件连接到 App.tsx
- Verification: npm run build 成功

### Task 11: Final Polish & All Tests
- Verification: 12/12 tests pass, tsc --noEmit OK, build OK

AI 分派 plan reviewer 检查。Reviewer 发现 2 个问题:

  1. TodoItem 测试缺少 DndContext wrapper -- useSortable 需要 DndContext provider,测试会失败
  2. Sonner 在 Task 1 中未安装 -- 在 Task 10 会导致报错

AI 在开始实现之前修复了这两个问题。

Superpowers 提示: 计划保存在 docs/superpowers/plans/ 中,在执行前自动审查。详见 Writing Plans

你确认:"OK,开始实现。"


步骤 3:按计划实现(TDD:RED → GREEN → REFACTOR)

AI 按计划逐个执行任务。有测试的任务都遵循 TDD 循环。

Task 1: Project Scaffold

搭建 Vite + React + TS,安装所有依赖。遇到实际问题:

  • Vite 8 不兼容 @tailwindcss/vite → 使用 --legacy-peer-deps
  • shadcn/ui init 失败 因为缺少 import alias → 在 tsconfig + vite.config 中配置 @/ alias
  • Vite 8 与 shadcn 冲突 → 降级到 Vite 7

实际经验: 脚手架搭建并不总是一帆风顺。库之间的兼容性问题很常见。重要的是知道如何调试和找到变通方案。

Task 2: Types & Storage Utilities

文件描述
src/types/todo.tsInterface Todo, Filters, type aliases, constants (PRIORITIES, CATEGORIES)
src/lib/storage.tsloadTodos(), saveTodos(), loadTheme(), saveTheme() 带错误处理

Task 3: useTodos Hook (TDD)

文件描述
测试src/hooks/use-todos.test.ts6 个测试用例:starts empty, add todo, toggle todo, delete todo, edit todo, reorder todos
代码src/hooks/use-todos.tsuseReducer + localStorage 同步,暴露:addTodo, toggleTodo, deleteTodo, editTodo, reorderTodos

RED → npx vitest run → FAIL(文件不存在)→ GREEN → 实现 hook → 6/6 PASS

Task 4: Filter Logic & useTheme

文件描述
src/lib/filters.tsapplyFilters() -- 对 status、priority、category、search 进行 AND 组合筛选
src/hooks/use-theme.ts暗色/亮色切换,同步 localStorage + 系统偏好

Task 5: Header & FilterBar

文件描述
src/components/header.tsx应用名称、统计计数器、暗色模式切换(Sun/Moon 图标)
src/components/filter-bar.tsx状态/优先级/分类的 Pill 按钮 + 搜索输入框

Task 6: TodoInput (TDD)

文件描述
测试src/components/todo-input.test.tsx3 个测试用例:render placeholder, call onAdd on submit, clear input after submit
代码src/components/todo-input.tsx输入框展开为表单:title, priority dropdown, category dropdown, date picker

RED → FAIL → GREEN → 3/3 PASS

Task 7: TodoItem (TDD)

文件描述
测试src/components/todo-item.test.tsx3 个测试用例:render title + priority, toggle checkbox, line-through when completed。注意: 测试需要 DndContext + SortableContext wrapper
代码src/components/todo-item.tsx带拖拽手柄的 Sortable 项目,checkbox, priority 徽章, category 标签, due date, dropdown menu

RED → FAIL → GREEN → 3/3 PASS

Task 8-9: TodoList + EditTodoDialog

文件描述
src/components/todo-list.tsx使用 @dnd-kit/core + @dnd-kit/sortable 的 DnD 容器,空状态
src/components/edit-todo-dialog.tsxshadcn Dialog 带编辑表单:title, priority, category, date picker

Task 10: Assemble App

将所有内容连接到 App.tsxuseTodos + useTheme + applyFilters + Toaster。Production 构建成功。

Task 11: Final Polish

运行 tsc --noEmit 通过,但 npm run build 发现 TypeScript 错误 asChild prop -- shadcn v2 使用 base-ui 替代 radix,需要改用 render prop。修复后 → 构建成功,12/12 测试通过。

每个任务的 TDD 流程: AI 先写测试 → 运行测试确认 FAIL → 实现最小代码 → 运行测试确认 PASS → 需要时重构 → 提交。详见 TDD


步骤 4:Verification -- 全面验证

所有 11 个任务已完成。运行最终验证。

运行完整测试套件

npx vitest run
✓ src/hooks/use-todos.test.ts (6 tests)
  ✓ useTodos > starts with empty todos
  ✓ useTodos > adds a todo
  ✓ useTodos > toggles a todo
  ✓ useTodos > deletes a todo
  ✓ useTodos > edits a todo
  ✓ useTodos > reorders todos

✓ src/components/todo-input.test.tsx (3 tests)
  ✓ TodoInput > renders placeholder input
  ✓ TodoInput > calls onAdd with todo data on submit
  ✓ TodoInput > clears input after submit

✓ src/components/todo-item.test.tsx (3 tests)
  ✓ TodoItem > renders todo title and priority
  ✓ TodoItem > calls onToggle when checkbox clicked
  ✓ TodoItem > shows line-through when completed

Test Files  3 passed (3)
     Tests  12 passed (12)

类型检查和构建

npx tsc --noEmit    # No errors
npm run build       # 构建成功

声明

Todo App 完成。12/12 测试通过。Production 构建 OK。无 TypeScript 错误。10 个干净的按功能划分的提交。


结果

完成整个流程后,你拥有:

完整功能:

  • CRUD todos(添加、编辑、删除、切换完成状态)
  • AND 组合筛选(status、priority、category + search)
  • 拖拽排序
  • 截止日期带逾期警告(红色)
  • 暗色模式(手动切换 + 跟随系统偏好)
  • localStorage 持久化(300ms 防抖)
  • 响应式、极简 UI,使用 shadcn/ui
  • 显示统计信息(总任务、活跃、已完成)

12 个测试用例 100% 通过 覆盖:

  • 自定义 hook useTodos:add, toggle, delete, edit, reorder, empty state
  • 组件 TodoInput:render, submit, clear
  • 组件 TodoItem:render, toggle, completed style

文件结构:

src/
  App.tsx
  index.css
  test-setup.ts
  types/
    todo.ts
  lib/
    storage.ts
    filters.ts
    utils.ts
  hooks/
    use-todos.ts
    use-todos.test.ts
    use-theme.ts
  components/
    header.tsx
    filter-bar.tsx
    todo-input.tsx
    todo-input.test.tsx
    todo-item.tsx
    todo-item.test.tsx
    todo-list.tsx
    edit-todo-dialog.tsx
    ui/  (shadcn components)

实际遇到的问题

与理想化的教程不同,实际工作会话遇到了许多需要处理的问题:

1. Vite 8 与 Tailwind 插件不兼容

@tailwindcss/vite 尚未支持 Vite 8 → 使用 --legacy-peer-deps 安装,之后当 shadcn 也冲突时降级到 Vite 7。

2. shadcn/ui init 因缺少 import alias 失败

shadcn 要求 @/ import alias → 必须在 tsconfig 中配置 baseUrl + paths,在 vite.config 中配置 resolve.alias

3. shadcn v2 使用 base-ui 替代 radix

asChild prop 不再有效 → 必须改用 render prop 用于 PopoverTrigger 和 DropdownMenuTrigger。这个错误仅在运行 npm run build 时出现(vite build 有自己的类型检查),tsc --noEmit 反而通过了,dev 模式也不报错。

4. TodoItem 测试需要 DnD wrapper

useSortable hook 要求 DndContext + SortableContext provider。不 wrap 的话测试会崩溃。Plan reviewer 在实现之前就发现并修复了这个问题。

经验: 这就是验证环节至关重要的原因。许多错误只在 production 构建或严格类型检查时才会出现,在 dev 模式下看不到。


关键要点

1. 头脑风暴帮你在正确的时机改变想法

你最初选择了 Kanban Board,但在 visual companion 上查看 mockup 后,你意识到 Single Page 更合适。在头脑风暴阶段改变想法花费 0 行代码。在实现之后改变则需要数小时的重构。

2. Plan reviewer 在写代码之前就捕获了 bug

Reviewer 在计划中发现了 2 个问题(测试中缺少 DndContext wrapper、缺少 sonner 依赖)。如果不进行审查,这些 bug 会在实现过程中出现,浪费调试时间。

3. 兼容性问题是常态

11 个任务中有 3 个遇到了兼容性问题(Vite 8、shadcn alias、asChild prop)。这不是你的 bug -- 这是 JavaScript 生态系统的现实。工作流程帮你快速发现和修复,而不是手忙脚乱。

4. useReducer + Custom Hook + TDD 是强大的组合

useTodos hook 封装了全部逻辑(CRUD、reorder、localStorage sync)并有 6 个测试用例保护。当 UI 变得复杂(拖拽、筛选、编辑对话框)时,逻辑依然稳定,因为已经独立测试过了。

5. 11 个任务但每个都小而清晰

"构建高级 Todo 应用"听起来很吓人。但当拆分成 11 个任务时,每个任务只创建 1-2 个文件并有自己的验证标准。你永远不需要在脑中记住整个应用 -- 只需专注于当前任务。

6. 这是实际项目的跳板

这个"高级"Todo 应用已经包含了:自定义 hooks、拖拽、暗色模式、shadcn/ui、localStorage 持久化、TDD、自动审查。这些都是你在所有 React 项目中都会复用的模式。


现实不像教程那样完美。 你会遇到兼容性问题、库的变更和意外错误。Superpowers 工作流程不会消除这些问题 -- 它帮你尽早发现并系统性地处理,而不是不知从何下手地手忙脚乱。