首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >渐进式AI编程

渐进式AI编程

作者头像
江南一点雨
发布2026-05-07 17:29:54
发布2026-05-07 17:29:54
1650
举报
文章被收录于专栏:AI应用开发实践AI应用开发实践

一、课程缘起与设计

1.1 痛点

  • AI Coding 概念多、工具多,易学难精,单点使用无体系;

1.2 解法

  • 主线任务贯穿:通过完整项目串联工具,三阶段渐进式实战;

二、如何衡量 AI Coding 水平

维度

说明

衡量标准

工作效率

重复性任务交给 AI,专注高价值决策

同样需求,比别人少用多少时间?

工程质量

符合团队规范、有测试覆盖、能过 CR

上线后的 bug 率和返工率

代码准确性

AI 代码一次跑通,不需反复调试

需要人工修改的比例有多高?

可复用性

个人经验沉淀为团队可用的资产

你的经验有没有帮身边人少踩坑?

根据自己业务的实际情况,选择适合自己的工具和方法,不建议盲目追求最新最潮的工具。

三、外卖平台

构建 PC Web 端外卖平台,包含餐厅浏览、购物车下单、订单追踪等功能。

项目

功能

新增工具与技能

阶段 1

餐厅菜单页

CODEBUDDY.md, Plan Mode, Hooks, UI 美化

阶段 2

购物车与下单

ESLint, E2E 测试,MCP, Subagents, Commands

阶段 3

订单状态追踪

Skills, Memory, OpenSpec, Agent Teams

3.1 阶段一:AI 协作基础

目标: 理解 AI 协作基础,掌握规划先行与质量门禁,通过构建餐厅菜单页,掌握 AI 协作的核心工具与工作流程。

3.1.1 怎么选编辑器

CodeBuddy IDE

CodeBuddy Code

方便人工 review 代码或者方案

更加 AI Native,速度快

Plan 功能更丰富

输出的过程信息比较简洁,只关注计划的制定和结果的验收

可视化操作界面

Hooks 只有 CLI 有

CLI 可以开启 think 模式

适合多任务并发执行

3.1.2 核心工具

3.1.2.1 CODEBUDDY.md

每次对话开始时读取的特殊文件,为 CodeBuddy 提供无法从代码本身推断出的持久上下文。

应该写:

  • ✅猜不到的命令
  • ✅非默认代码风格
  • ✅测试说明
  • ✅仓库规范
  • ✅架构决策
  • ✅开发环境的坑

不应该写:

  • ❌读代码能搞清楚的
  • ❌标准语言约定
  • ❌详细 API 文档
  • ❌经常变化的信息
  • ❌逐文件描述
  • ❌废话

配置技巧:

  • 使用 @path/to/file 导入语法引用其他文件;
  • 多位置配置:主目录/项目根/父目录/子目录;
  • 强调词 **IMPORTANT **/ 必须 提高遵守度;
3.1.2.2 Plan Mode

维度

Plan Mode

Craft Mode

工作方式

先规划后执行

直接执行

适用场景

复杂功能、架构设计

局部修改、Bug 修复

输出形式

完整方案

直接代码结果

可控性

高——执行前审阅

边执行边调整

扩展能力

智能编排 MCP/Skill

按需调用

适合使用 Plan Mode 的场景:

  • 新功能从零实现
  • 多文件协同修改
  • UI/UX 设计与实现
  • 存量项目改造
  • 复杂任务拆解
3.1.2.3 Hooks

在 CodeBuddy Code 的会话生命周期内插入自定义脚本或命令。

基于命令的 Hooks:

代码语言:javascript
复制
{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Write/Edit",
      "type": "command",
      "command": "check-style.sh"
    }]
  }
}

基于提示词的 Hooks:

代码语言:javascript
复制
{
  "hooks": {
    "Stop": [{
      "type": "prompt",
      "prompt": "Evaluate if we should stop..."
    }]
  }
}

事件类型:

  • PreToolUse :工具执行前,校验、审批;
  • PostToolUse :工具执行后,格式化,补上下文;
  • Notification :权限或者超市,桌面/IM 提醒;
  • UserPromptSubmit :用户提交时,内容审查;
  • SessionStart - 会话开始,环境初始化;
  • PreCompact - 压缩前,保留关键信息;
  • Stop - 主代理结束,继续执行;
  • SubagentsStop:子代理结束,补充说明;
  • SessionEnd - 会话结束,清理/持久化

3.1.3 工程实践

  1. 创建项目目录,空文件夹
  2. 将基础文件拷贝到项目中
代码语言:javascript
复制
├── .codebuddy
│   ├── hooks
│   │   ├── git-commit-check.sh
│   │   ├── hooks.json
│   │   └── prettier-format.sh
├── CODEBUDDY.md
├── images
│   ├── dishes
│   └── restaurants
├── proposal.md
  • git-commit-check.sh:在 git commit 时自动执行 TypeScript 类型检查,确保只有类型检查通过的代码才能被提交。
  • prettier-format.sh:针对 TS/TSX 文件的自动化格式化脚本,仅在检测到对应文件类型且 prettier 已安装时,通过 prettier 格式化指定文件。
  • hooks.json:通过钩子机制,在特定操作的前后自动执行脚本,实现代码格式化、操作前置校验等自动化管控。

CODEBUDDY.md:

代码语言:javascript
复制
# 外卖平台

## 语言规范

- 所有文档和对话使用中文
- 专业术语保持英文(如 React、TypeScript、API 等)

## 技术栈
- 前端: React 18 + TypeScript + Tailwind CSS + Vite
- 后端: Express + TypeScript
- 数据库: SQLite (better-sqlite3)

## 代码规范

**重要**: 禁止使用any类型,所有变量和函数必须有明确的类型定义。

- 使用TypeScript严格模式(strict: true)
- 使用Functional Components + Hooks(不使用class组件)
- 使用async/await处理异步(不使用.then链式调用)
- 通过services/层封装所有API调用(不在组件中直接fetch)

## API规范

- RESTful风格,资源名用复数形式
- 统一返回格式:
  成功: { success: true, data: { id: 1, name: "麻辣烫" } }
  失败: { success: false, error: "Restaurant not found" }
- 错误统一使用HTTP状态码 + error字段描述

**注意**: 所有API返回必须使用统一格式,禁止直接返回裸数据。

## 前端规范

- 页面级组件放pages/,可复用组件放components/
- 使用Tailwind CSS的utility classes(不写自定义CSS)
- 所有组件props必须定义TypeScript接口
- 使用try-catch统一处理API错误,展示用户友好的错误提示

## 项目结构规范

- 前端源码放 client/src/,后端源码放 server/src/

## 数据库规范

- 表名使用snake_case复数形式(如 restaurants, menu_items)
- 字段名使用snake_case(如 delivery_time, min_order_price)
- 每张表必须有id作为主键,created_at和updated_at时间戳
- 外键命名格式: 关联表单数_id(如 restaurant_id)

## 命名规范

- 组件文件使用PascalCase(如 RestaurantCard.tsx)
- 工具函数和hooks文件使用camelCase(如 useCart.ts)
- TypeScript接口使用PascalCase(如 Restaurant, MenuItemProps)
- CSS类名使用Tailwind utility classes,不自定义class名

## Git规范
- 使用conventional commit格式: feat|fix|refactor|docs(scope): message

proposal.md:

代码语言:javascript
复制
## 为什么

这是构建网页版外卖平台的基础阶段。目前没有任何面向顾客的界面。用户需要能够浏览可用的商家并查看他们的菜单,然后才能下单。这建立了核心的浏览体验,所有未来的功能(购物车、结账、订单)都将建立在此基础之上。

## 变更内容

- **新增**: 商家浏览界面,带搜索功能
- **新增**: 商家详情页,展示商家信息和完整菜单
- **新增**: 菜品详情页,包含规格选择(大小、口味选项)
- **新增**: 后端 REST API,提供商家和菜品数据
- **新增**: SQLite 数据库设计,包含商家、菜品和菜品规格表
- **新增**: 静态图片托管,用于商家 logo 和菜品照片

## 能力范围

### 新增能力

- `merchant-browsing`: 搜索和查看商家列表,包含基本信息(名称、评分、配送时间、起送价)
- `merchant-details`: 查看商家详细信息,包括地址、电话、营业时间,以及按分类组织的完整菜单
- `dish-details`: 查看单个菜品信息,包括照片、描述、价格和可用规格(大小、口味等)
- `merchant-search`: 通过按钮触发按商家名称搜索
- `dish-specifications`: 支持每道菜品的多个规格(如小/中/大杯,辣度等级),每个规格独立定价

### 修改的能力

<!-- 没有现有能力需要修改 - 这是全新项目 -->

## 影响范围

**新增代码**:
- 前端: React 应用,包含路由 (/, /merchant/:id, /dish/:id)
- 后端: Node.js/Express API,包含三个主要端点
- 数据库: SQLite 数据库,包含三个表 (merchants, dishes, dish_specs)

**基础设施**:
- 本地开发环境(第一阶段不部署到生产环境)
- 项目目录中的静态文件服务

**数据**:
- 初始种子数据: 10-15 个商家,每个商家 15-25 道菜品,约 30% 的菜品有多个规格
- 图片资源组织在 `images/` 目录下:
  - `images/merchants/` - 商家 logo 和照片
  - `images/dishes/` - 菜品照片
  - 种子数据根据需要引用这些文件夹中的图片(如 `/images/merchants/mcd.jpg`, `/images/dishes/burger.jpg`)

**不包含的内容**(后续阶段):
- 购物车功能
- 下单和结账
- 用户认证
- 商家管理界面
- 支付处理

进入命令行,开始执行。

开启 thinking 模式,开启 plan 模式:

开始开发:

确认示例:

最终效果:

3.1.4 init 命令

  • /init:初始化项目并生成 CODEBUDDY.md
    • 创建新项目时快速搭建项目骨架
    • 为已有项目添加 CodeBuddy 配置
    • 标准化项目文档和配置管理
    • 功能描述:快速初始化项目结构,并自动生成 CODEBUDDY.md 配置文件。
    • 适用场景:
代码语言:javascript
复制
# CODEBUDDY.md

This file provides guidance to CodeBuddy Code when working with code in this repository.

---

# 外卖平台

## 语言规范

- 所有文档和对话使用中文
- 专业术语保持英文(如 React、TypeScript、API 等)

## 开发命令

### 后端 (`server/`)

npm run migrate   # 建表(幂等,IF NOT EXISTS)
npm run seed      # 写入种子数据(15 商家 / 133 菜品 / 96 规格)
npm run dev       # nodemon + ts-node 热重载,端口 3001
npm run build     # tsc 编译到 dist/

首次启动必须先执行:`npm run migrate && npm run seed`

### 前端 (`client/`)

npm run dev       # Vite 开发服务器,端口 5173
npm run typecheck # tsc --noEmit,仅类型检查
npm run build     # tsc + vite build

### 本地启动

# 终端 1
cd server && npm run dev

# 终端 2
cd client && npm run dev
# 访问 http://localhost:5173

## 技术栈

- **前端**: React 18 + TypeScript + Tailwind CSS + Vite
- **后端**: Express + TypeScript + better-sqlite3 **v12.x**(v9 不兼容 Node 24+)
- **数据库**: SQLite,路径 `server/data/food_delivery.db`(运行时自动创建)

## 项目架构

### 目录结构

food_delivery_website/
├── images/                    # 静态图片(由后端 Express 提供服务)
│   ├── restaurants/           # 商家图片(15 张)
│   └── dishes/                # 菜品图片(60 张)
├── client/src/
│   ├── App.tsx                # React Router 路由配置
│   ├── types/index.ts         # 所有前端 TypeScript 接口(camelCase)
│   ├── services/              # API 封装层,唯一允许调用 fetch 的地方
│   │   ├── api.ts             # apiFetch 基础封装
│   │   ├── merchantService.ts # 商家 API + snake_case→camelCase 转换
│   │   └── dishService.ts     # 菜品 API + snake_case→camelCase 转换
│   ├── pages/                 # 页面级组件
│   └── components/            # 可复用组件
└── server/src/
    ├── index.ts               # Express 入口(端口 3001)
    ├── db.ts                  # SQLite 单例(WAL 模式 + 外键约束)
    ├── types/index.ts         # 后端 TypeScript 接口(snake_case)
    ├── routes/
    │   ├── merchants.ts       # GET /api/merchants, /api/merchants/:id
    │   └── dishes.ts          # GET /api/dishes/:id
    └── scripts/
        ├── migrate.ts         # 建表
        └── seed.ts            # 种子数据

### 前端路由(`client/src/App.tsx`)

| 路径 | 页面 | 功能 |
|------|------|------|
| `/` | MerchantsPage | 商家列表 + 搜索 |
| `/merchant/:id` | MerchantDetailPage | 商家信息 + 分类菜单 |
| `/dish/:id` | DishDetailPage | 菜品详情 + 规格选择 + 实时价格计算 |

### 后端 API(端口 3001)

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/merchants` | 商家列表,支持 `?search=` |
| GET | `/api/merchants/:id` | 商家详情,含按 `category` 分组的菜单 |
| GET | `/api/dishes/:id` | 菜品详情,含按 `spec_name` 分组的规格 |
| GET | `/images/...` | 静态图片(映射到项目根目录 `images/`) |

### 核心设计:snake_case ↔ camelCase 转换层

后端数据库和 API 全部使用 snake_case,前端组件使用 camelCase。**转换统一发生在 `client/src/services/` 层**,组件内不处理原始 API 数据。

DB (snake_case) → Express JSON (snake_case) → services/ 转换 → 组件 (camelCase)

每个 service 文件的模式:
1. 定义 `Raw*` 接口,对应后端返回的 snake_case 结构
2. 定义 `to*()` 转换函数,将 `Raw*` 映射为前端 camelCase 接口
3. 导出的 API 函数内部调用 `apiFetch<Raw*>()` 再经 `to*()` 转换后返回

**新增 API 端点时必须遵循此模式。**

### 数据库表(`server/src/scripts/migrate.ts`)

| 表 | 关键字段 |
|---|---|
| `restaurants` | `id`, `name`, `logo_url`, `rating`, `delivery_time`, `min_order_price` |
| `menu_items` | `id`, `restaurant_id`, `category`, `name`, `price`, `image_url` |
| `dish_specs` | `id`, `dish_id`, `spec_name`, `option_name`, `price_delta` |

`dish_specs.price_delta` 为相对基础价的差价(可正可负可为 0)。`DishDetailPage` 按 `spec_name` 分组展示规格,实时计算 `基础价 + 各选中规格 price_delta 之和`。

### Vite 代理(`client/vite.config.ts`)

开发环境将 `/api` 和 `/images` 代理到 `http://localhost:3001`,前端代码中无需硬编码后端地址。

## 代码规范

**禁止使用 `any` 类型**,所有变量和函数必须有明确的类型定义。

- TypeScript 严格模式(`strict: true`)
- Functional Components + Hooks(不使用 class 组件)
- `async/await` 处理异步(不使用 `.then()` 链式调用)
- **所有 API 调用通过 `services/` 层**,组件内禁止直接 `fetch()`
- 页面级组件放 `pages/`,可复用组件放 `components/`
- 使用 Tailwind CSS utility classes(不写自定义 CSS)
- 所有组件 props 必须定义 TypeScript 接口
- `try-catch` 统一处理 API 错误,展示用户友好的错误提示

## API 规范

- RESTful 风格,资源名用复数形式
- **所有响应必须使用统一格式,禁止返回裸数据**:
  - 成功:`{ success: true, data: ... }`
  - 失败:`{ success: false, error: "..." }`
- 错误统一使用 HTTP 状态码 + `error` 字段描述

## 数据库规范

- 表名 snake_case 复数(`restaurants`, `menu_items`)
- 字段名 snake_case(`delivery_time`, `min_order_price`)
- 每张表必须有 `id` 主键、`created_at`、`updated_at`
- 外键格式:`{关联表单数}_id`(如 `restaurant_id`)

## 命名规范

- 组件文件:PascalCase(`RestaurantCard.tsx`)
- 工具函数/hooks:camelCase(`useCart.ts`)
- TypeScript 接口:PascalCase(`Restaurant`, `MenuItemProps`)
- CSS 类名使用 Tailwind utility classes,不自定义 class 名

## Git 规范

使用 conventional commit 格式:`feat|fix|refactor|docs(scope): message`

3.1.5 UI 美化

3.1.5.1 ui-pro-cli
  • 把规范转化为 CSS/LESS/Tailwind 样式文件;
  • 检查代码是否符合规则,自动修复不合规内容;

安装:

代码语言:javascript
复制
npm install -g uipro-cli
uipro init --ai codebuddy
代码语言:javascript
复制
├── .codebuddy
│   └── skills
│       └── ui-ux-pro-max
│           ├── SKILL.md
│           └── scripts
│               ├── __pycache__
│               │   ├── core.cpython-314.pyc
│               │   ├── design_system.cpython-314.pyc
│               │   └── search.cpython-314.pyc
│               ├── core.py
│               ├── design_system.py
│               └── search.py
3.1.5.2 ui-ux-pro-max
  • 输出标准化的配色 / 字体 / 间距规范,定义 UI 合规规则;
  • https://github.com/nextlevelbuilder/ui-ux-pro-max-skill
3.1.5.3 美化
代码语言:javascript
复制
/ui-ux-pro-max 美化一下我的PC版外卖平台页面,为我提供一些优化的风格供我选择
代码语言:javascript
复制
图标统一使用 lucide-react

3.2 阶段二:工程化质量体系

目标: 建立工程化质量体系,掌握 MCP 连接与多 Agent 协作,在已有菜单页基础上,构建购物车与下单系统,引入工程化质量工具。

3.2.1 核心工具

3.2.1.1 MCP (Model Context Protocol)

MCP 解决「连接」,给 Agent 接上手和脚;Skills 解决「执行」,教 Agent 在特定场景下怎么做。

通信方式

stdio

Streamable HTTP

原理

标准输入输出通信

HTTP POST+SSE

通信方式

stdin/stdout

HTTP POST+SSE

典型用途

本地进程、IDE、CLI

远程服务、Web、多客户端

配置示例 - mcp.json:

代码语言:javascript
复制
{
  "mcpServers": {
    "context7": {
      "command": "npx",
      "args": ["-y", "@upstash/context7-mcp"]
    },
    "tapd_copilot": {
      "url": "https://mcp.tapd.woa.com/mcp",
      "transportType": "streamable-http"
    }
  }
}
3.1.2.2 Commands 自定义命令

将常用的 Prompts、脚本和工作流封装成可复用的自定义斜杠命令。

命名规则: 文件路径 → 斜杠命令

示例:commands/backend/deploy/staging.md/backend:deploy:staging

代码语言:javascript
复制
---
description: "运行单元测试并报告结果"
argument-hint: "[test-file] [test-type]"
allowed-tools: Bash (npm run *)
model: gemini-3.0-pro
---

1. 运行 `npm run test-$1-$2`
2. 总结测试结果

修复问题命令示例:

代码语言:javascript
复制
---
description: "修复代码问题"
argument-hint: "[issue-number]"
---

1. 理解问题 → 定位根因 → 实现修复 → 添加测试 → 验证
2. 修复 issue #{{ARGUMENTS}},遵循编码标准
3.1.2.3 Subagents

两种模式:

模式

agentic 模式

manual 模式 (IDE)

调用方式

主 Agent 自动判断调用时机

用户手动选择

上下文

拥有独立上下文窗口

完全替代主 Agent

干预

不能中途干预

可在 Agent 选择框中选中使用

适用场景

专业化分工

深度定制交互

最佳实践:

  • 创建具有单一、明确职责的 Subagents,而不是让一个完成所有任务
  • 执行时不会污染主会话

3.2.2 工程质量保障

3.2.2.1 ESLint 代码规范

集成 ESLint 代码规范检查,确保代码质量一致性。

代码语言:javascript
复制
为项目添加eslint检查
3.2.2.2 自定义 Git 提交命令

新建 commands 目录,目录下新建 git.md 文件,存入 git 技能:

git.md:

代码语言:javascript
复制
---
allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*), Bash(git diff:*), Bash(git log:*)
argument-hint: [message] | --no-verify | --amend
description: 创建格式规范的提交信息,使用常规提交格式和表情符号
---

# 智能 Git 提交

创建格式规范的提交:$ARGUMENTS

## 当前仓库状态

- Git 状态:!`git status --porcelain`
- 当前分支:!`git branch --show-current`
- 暂存的更改:!`git diff --cached --stat`
- 未暂存的更改:!`git diff --stat`
- 最近的提交:!`git log --oneline -5`

## 此命令的作用

1. 除非使用 `--no-verify` 指定,否则自动运行提交前检查:
  - `npm run lint` 确保代码质量
  - `npm run build` 验证构建成功
2. 使用 `git status` 检查哪些文件已暂存
3. 如果有 0 个文件暂存,自动使用 `git add` 添加所有修改的和新文件
4. 执行 `git diff` 以了解正在提交的更改
5. 分析差异以确定是否存在多个不同的逻辑更改
6. 如果检测到多个不同的更改,建议将提交拆分为多个较小的提交
7. 为每个提交(或单个提交(如果不拆分))使用表情符号常规提交格式创建提交信息
8. **必须检查文档更新需求**(见下方"文档更新检查清单"),如符合条件则更新 CODEBUDDY.md 和/或 README.md

## 提交的最佳实践

- **提交前验证**:确保代码已通过 lint 检查、能正确构建、文档已更新
- **原子提交**:每个提交应包含服务于单一目的的相关更改
- **拆分大更改**:如果更改涉及多个关注点,请将其拆分为单独的提交
- **常规提交格式**:使用格式 `<type>: <description>`,其中类型是以下之一:
  - `feat`:新功能
  - `fix`:错误修复
  - `docs`:文档更改
  - `style`:代码样式更改(格式化等)
  - `refactor`:既不修复错误也不添加功能的代码更改
  - `perf`:性能改进
  - `test`:添加或修复测试
  - `chore`:对构建过程、工具等的更改
- **现在时、祈使语气**:将提交信息编写为命令(例如,"add feature" 而不是 "added feature")
- **简洁的第一行**:保持第一行在 72 个字符以下
- **表情符号**:每个提交类型都配有相应的表情符号:
  - ✨ `feat`:新功能
  - 🐛 `fix`:错误修复
  - 📝 `docs`:文档
  - 💄 `style`:格式化/样式
  - ♻️ `refactor`:代码重构
  - ⚡️ `perf`:性能改进
  - `test`:测试
  - 🔧 `chore`:工具、配置
  - 🚀 `ci`:CI/CD 改进
  - 🗑️ `revert`:恢复更改
  - 🧪 `test`:添加失败的测试
  - 🚨 `fix`:修复编译器/linter 警告
  - 🔒️ `fix`:修复安全问题
  - 👥 `chore`:添加或更新贡献者
  - 🚚 `refactor`:移动或重命名资源
  - 🏗️ `refactor`:进行架构更改
  - 🔀 `chore`:合并分支
  - 📦️ `chore`:添加或更新编译文件或包
  - ➕ `chore`:添加依赖项
  - ➖ `chore`:移除依赖项
  - 🌱 `chore`:添加或更新种子文件
  - 🧑💻 `chore`:改善开发者体验
  - 🧵 `feat`:添加或更新与多线程或并发相关的代码
  - 🔍️ `feat`:改善 SEO
  - 🏷️ `feat`:添加或更新类型
  - 💬 `feat`:添加或更新文本和字面量
  - 🌐 `feat`:国际化和本地化
  - 👔 `feat`:添加或更新业务逻辑
  - 📱 `feat`:处理响应式设计
  - 🚸 `feat`:改善用户体验/可用性
  - 🩹 `fix`:非关键问题的简单修复
  - 🥅 `fix`:捕获错误
  - 👽️ `fix`:因外部 API 更新代码
  - 🔥 `fix`:删除代码或文件
  - 🎨 `style`:改进代码的结构/格式
  - 🚑️ `fix`:关键热修复
  - 🎉 `chore`:开始项目
  - 🔖 `chore`:发布/版本标签
  - 🚧 `wip`:进行中的工作
  - 💚 `fix`:修复 CI 构建
  - 📌 `chore`:将依赖项固定到特定版本
  - 👷 `ci`:添加或更新 CI 构建系统
  - 📈 `feat`:添加或更新分析或跟踪代码
  - ✏️ `fix`:修复拼写错误
  - ⏪️ `revert`:恢复更改
  - 📄 `chore`:添加或更新许可证
  - 💥 `feat`:引入重大更改
  - 🍱 `assets`:添加或更新资源
  - ♿️ `feat`:改善可访问性
  - 💡 `docs`:在源代码中添加或更新注释
  - 🗃️ `db`:执行数据库相关更改
  - 🔊 `feat`:添加或更新日志
  - 🔇 `fix`:删除日志
  - 🤡 `test`:模拟事物
  - 🥚 `feat`:添加或更新彩蛋
  - 🙈 `chore`:添加或更新 .gitignore 文件
  - 📸 `test`:添加或更新快照
  - ⚗️ `experiment`:执行实验
  - 🚩 `feat`:添加、更新或删除功能标志
  - 💫 `ui`:添加或更新动画和过渡
  - ⚰️ `refactor`:删除死代码
  - 🦺 `feat`:添加或更新与验证相关的代码
  - ✈️ `feat`:改善离线支持

## 拆分提交的指南

分析差异时,请根据以下标准考虑拆分提交:

1. **不同关注点**:对代码库不相关部分的更改
2. **不同类型的更改**:混合功能、修复、重构等
3. **文件模式**:对不同类型文件的更改(例如,源代码 vs 文档)
4. **逻辑分组**:分开更容易理解或审查的更改
5. **大小**:非常大的更改,如果分解会更清晰

## 文档更新检查清单(强制执行)

**在完成所有代码提交后,必须逐项检查以下每一条,并在回复中输出检查结果表格。不允许跳过或凭直觉判断,必须逐条比对实际变更内容。**

### 检查结果输出格式(必须展示)

完成代码提交后,必须输出如下表格,逐条标注命中/未命中:

| 检查项 | 目标文件 | 是否命中 | 说明 |
|--------|---------|---------|------|
| 新增或修改了 npm scripts | CODEBUDDY.md + README.md | 是/否 | 具体哪些 scripts |
| 修改了开发工具配置 | CODEBUDDY.md | 是/否 | |
| ... | ... | ... | ... |

只要有任意一条命中,就必须创建独立的文档更新提交。

### 必须更新 CODEBUDDY.md 的情况:
1. 新增或修改了 npm scripts(如 `npm run xxx`)
2. 修改了开发工具配置(ESLint、Prettier、TypeScript 等)
3. 修改了代码规范或编码约定
4. 改变了项目架构(目录结构、模块组织方式)
5. 修改了数据库 schema 或数据格式
6. 新增或修改了关键的技术实现细节
7. 修改了构建或部署流程

### 必须更新 README.md 的情况:
1. 新增了用户可见的功能特性
2. 修改了安装或启动步骤
3. 新增或修改了 npm scripts(如 `npm run xxx`)
4. 修改了 API 端点或接口
5. 修改了项目依赖或技术栈
6. 修改了访问地址或端口配置

### 不需要更新文档的情况(仅当以上所有条目均未命中时适用):
- 仅修复 bug 且不改变使用方式
- 纯代码重构且不影响外部接口
- 修复拼写错误或格式问题
- 微小的样式调整

**注意:当不确定某条是否命中时,则判定为不需要更新。**

## 示例

好的提交信息:
- ✨ feat: 添加用户认证系统
- 🐛 fix: 解决渲染过程中的内存泄漏
- 📝 docs: 使用新端点更新 API 文档
- ♻️ refactor: 简化解析器中的错误处理逻辑
- 🚨 fix: 解决组件文件中的 linter 警告
- 🧑💻 chore: 改善开发者工具设置过程
- 👔 feat: 实现交易验证的业务逻辑
- 🩹 fix: 解决头部中轻微的样式不一致
- 🚑️ fix: 修补认证流程中的关键安全漏洞
- 🎨 style: 为更好的可读性重新组织组件结构
- 🔥 fix: 删除已弃用的遗留代码
- 🦺 feat: 为用户注册表单添加输入验证
- 💚 fix: 解决失败的 CI 管道测试
- 📈 feat: 实现用户参与度分析跟踪
- 🔒️ fix: 加强身份验证密码要求
- ♿️ feat: 改善屏幕阅读器的表单可访问性

拆分提交的示例:
- 第一次提交:✨ feat: 添加新的 solc 版本类型定义
- 第二次提交:📝 docs: 为新 solc 版本更新文档
- 第三次提交:🔧 chore: 更新 package.json 依赖项
- 第四次提交:🏷️ feat: 为新 API 端点添加类型定义
- 第五次提交:🧵 feat: 改善工作线程中的并发处理
- 第六次提交:🚨 fix: 解决新代码中的 lint 问题
- 第七次提交:test: 为新 solc 版本功能添加单元测试
- 第八次提交:🔒️ fix: 更新存在安全漏洞的依赖项

## 命令选项

- `--no-verify`:跳过运行提交前检查(lint、build、generate:docs)

## 重要说明

- 默认情况下,提交前检查(`npm run lint`、`npm run build`)将运行以确保代码质量
- 如果这些检查失败,您将被问及是否要继续提交或先修复问题
- 如果已有特定文件暂存,命令将只提交这些文件
- 如果没有文件暂存,它将自动暂存所有修改的和新文件
- 提交信息将根据检测到的更改构建
- 在提交之前,命令将检查差异以确定多个提交是否更合适
- 如果建议多个提交,它将帮助您分别暂存和提交更改
- 始终检查提交差异以确保信息与更改匹配
- **在完成代码提交后,必须使用"文档更新检查清单"逐项检查,如符合条件则创建独立的文档更新提交**

接下来就可以在命令行使用该命令了:

3.2.2.3 E2E 测试
代码语言:javascript
复制
为当前项目添加端到端测试的能力,补全已有功能的测试用例

3.2.3 工作效率提升

3.2.3.1 Sub-agent 模式
  • 任务派生机制,抽象分层分工
  • 派出 sub-agent 探索不同子问题
  • 对主 Agent 屏蔽细节、浓缩 Context 信息量
代码语言:javascript
复制
- 根据项目的测试技术栈,帮我设计一个测试工程师的subagent描述,存到一个新的文件中
- 据项目的技术栈,帮我设计4个工程师的subagent描述,分别存到4个新的文件中,分别是前端工程师、后端工程师、前端代码reviewer工程师、后端代码reviewer工程师

也可以通过 /agents 命令来创建 subagent。

3.2.3.2 Background Agent

异步执行长时间任务,不阻塞主流程。

  • 快捷键 Ctrl+B - background 运行中的任务
  • 快捷键 Ctrl+K - Kill background agents
  • 适用场景:轮询 issue 的评论、持续监控构建状态
代码语言:javascript
复制
使用 backend-code-reviewer 子代理评审后端代码 --run_in_background
3.2.3.3 Worktree

Git worktree 允许在同一仓库中同时拥有多个工作目录,每个目录可以检出不同的分支。CodeBuddy Code 利用这一特性提供:

  • 并行开发:在不影响主工作区的情况下进行实验性开发
  • 安全隔离:AI 的所有更改都在独立目录中进行
  • 零存储开销:worktree 共享 Git 对象,不会复制整个仓库
  • 子代理隔离:支持多个 AI 子代理在独立 worktree 中并行工作
  • tmux 集成:可选在独立的 tmux 会话中运行
  • 非 Git 支持:通过 WorktreeCreate/WorktreeRemove hooks,SVN、Perforce 等项目也能使用 worktree 隔离

Git Worktree:

代码语言:javascript
复制
# 创建新工作树
git worktree add ../project-ui new-ui

# 列出所有工作树
git worktree list

# 移除工作树
git worktree remove ../project-ui

# 清理
git worktree prune
3.2.3.4 多实例并行
代码语言:javascript
复制
# 生成任务列表
codebuddy -p "列出需要迁移的 React 类组件" --output-format json > tasks.json

# 并行处理 (4 个并发任务)
jq '.files[]' tasks.json | xargs -P4 -I {} bash -c '
  codebuddy -p "将 {} 转换为 hooks" --allow-tools Edit --timeout 300
'

# 批量任务派发 - 并行分析→汇总报告
codebuddy -p "可维护性分析" --output-format json > maint.json &
codebuddy -p "性能分析" --output-format json > perf.json &
codebuddy -p "安全扫描" --output-format json > sec.json &
wait

codebuddy -p "基于分析生成综合报告" --input-files maint.json,perf.json,sec.json --output-format html > report.html
3.2.3.5 Ralph

Ralph: 自主 AI Agent 循环,反复运行直到 PRD 全部完成

  • https://github.com/snarktank/ralph
代码语言:javascript
复制
{
  "projectName": "外卖平台 - 购物车功能",
"branchName": "ralph/cart",
"description": "为外卖平台添加购物车功能。当前项目已完成浏览阶段(商家列表、商家详情、菜品详情+规格选择)。本 PRD 专注于购物车阶段:顾客可以将菜品(含规格)加入购物车,修改数量,查看汇总,并清空购物车。购物车状态仅在前端维护(localStorage 持久化),无需后端改动。",
"techStack": {
    "frontend": "React 18 + TypeScript + Tailwind CSS + Vite",
    "backend": "Express + TypeScript + better-sqlite3",
    "stateManagement": "React Context + localStorage 持久化",
    "testing": "Playwright E2E"
  },
"constraints": [
    "购物车状态在前端维护,使用 React Context,无需后端 API 改动",
    "购物车数据通过 localStorage 持久化,刷新页面不丢失",
    "购物车仅允许同一家商家的菜品,切换商家时需提示并清空",
    "所有新代码必须通过 typecheck 和 lint",
    "遵循现有代码规范:services/ 层、camelCase、禁止 any 类型",
    "E2E 测试必须使用 Page Object Pattern,禁止硬编码数据库 ID"
  ],
"stories": [
    {
      "id": "CART-01",
      "title": "购物车 Context 与 localStorage 持久化",
      "priority": 1,
      "passes": false,
      "description": "创建购物车的核心数据层。实现 CartContext,提供购物车状态和操作方法,并通过 localStorage 持久化。",
      "acceptanceCriteria": [
        "创建 client/src/types/cart.ts,定义 CartItem(dishId, dishName, restaurantId, restaurantName, price, quantity, selectedSpecs)和 CartState 接口",
        "创建 client/src/context/CartContext.tsx,提供以下方法:addItem(item)、removeItem(dishId, specKey)、updateQuantity(dishId, specKey, quantity)、clearCart()、getItemCount()、getTotalPrice()",
        "购物车数据存储在 localStorage key='cart',应用加载时自动恢复",
        "当加入不同商家的菜品时,Context 需暴露 restaurantId 和 restaurantName 供上层判断",
        "在 client/src/App.tsx 中用 CartProvider 包裹整个应用",
        "通过 typecheck 和 lint 检查"
      ]
    },
    {
      "id": "CART-02",
      "title": "菜品详情页「加入购物车」按钮",
      "priority": 2,
      "passes": false,
      "description": "在 DishDetailPage 底部添加「加入购物车」按钮,点击后将当前菜品(含已选规格)加入购物车,同商家累加数量,切换商家时弹出确认对话框。",
      "acceptanceCriteria": [
        "DishDetailPage 底部固定显示「加入购物车」按钮,显示当前计算价格",
        "点击按钮调用 CartContext.addItem,将菜品+当前选中规格+计算后总价加入购物车",
        "specKey 为各维度选中选项的组合字符串,用于区分不同规格组合(如 '大杯-全糖-少冰')",
        "若购物车已有同商家同菜品同规格,则数量 +1",
        "若购物车已有其他商家的菜品,弹出确认框:'购物车中有其他商家的菜品,是否清空并添加?',确认后清空并添加,取消则不操作",
        "按钮点击后显示简短的成功提示(toast 或页面内提示,1.5s 后消失)",
        "通过 typecheck 和 lint 检查"
      ]
    },
    {
      "id": "CART-03",
      "title": "购物车浮窗组件(底部固定栏)",
      "priority": 3,
      "passes": false,
      "description": "在 Layout 底部添加购物车浮窗,显示商品数量角标和总价,点击展开购物车详情抽屉。",
      "acceptanceCriteria": [
        "创建 client/src/components/CartBar.tsx:固定在页面底部,购物车为空时隐藏",
        "CartBar 显示:购物车图标 + 红色数量角标(商品总件数)+ 总价",
        "点击 CartBar 展开 CartDrawer(底部抽屉或弹层)",
        "CartDrawer 展示购物车内所有商品列表:菜品名、规格描述、单价、数量(±按钮)、小计",
        "CartDrawer 底部显示总价 + 「清空购物车」按钮,清空前需二次确认",
        "CartDrawer 中可通过 ± 按钮修改数量,数量减为 0 时自动移除该条目",
        "Layout.tsx 中引入 CartBar,使其在所有页面底部显示",
        "通过 typecheck 和 lint 检查"
      ]
    },
    {
      "id": "CART-04",
      "title": "商家详情页菜品卡片添加「+」快捷按钮",
      "priority": 4,
      "passes": false,
      "description": "在 DishCard 组件右下角添加「+」按钮,有规格的菜品点击跳转到菜品详情页(让用户选规格后再加购),无规格的菜品直接加入购物车。",
      "acceptanceCriteria": [
        "DishCard 右下角显示橙色圆形「+」按钮",
        "若菜品有规格(需通过 API 判断,或由父组件传入 hasSpecs 标志),点击「+」跳转到 /dish/:id",
        "若菜品无规格,点击「+」直接调用 CartContext.addItem 将菜品以基础价加入购物车,同商家累加,跨商家弹确认框",
        "加购成功后 DishCard 上显示当前数量 badge(来自 CartContext),数量 > 0 时显示数量和「-」按钮",
        "菜品卡片上的数量 badge 和 ± 操作与 CartDrawer 保持同步(同一 Context)",
        "通过 typecheck 和 lint 检查"
      ]
    },
    {
      "id": "CART-05",
      "title": "购物车 E2E 测试",
      "priority": 5,
      "passes": false,
      "description": "为购物车功能编写完整的 Playwright E2E 测试,覆盖核心用户流程。",
      "acceptanceCriteria": [
        "创建 e2e/pages/CartPage.ts(Page Object,封装购物车相关操作)",
        "创建 e2e/tests/cart.spec.ts,包含以下测试场景:",
        "  - 初始状态:购物车为空,CartBar 不可见",
        "  - 从菜品详情页加购无规格菜品,CartBar 出现,数量和价格正确",
        "  - 从菜品详情页加购有规格菜品,规格信息正确显示在 CartDrawer 中",
        "  - 同菜品同规格重复加购,数量累加",
        "  - 在 CartDrawer 中修改数量(+/-),总价实时更新",
        "  - 在 CartDrawer 中将数量减为 0,条目自动移除",
        "  - 清空购物车,CartBar 消失",
        "  - 跨商家加购,确认框出现,确认后购物车替换",
        "  - 跨商家加购,取消后购物车不变",
        "  - 刷新页面,购物车数据从 localStorage 恢复",
        "禁止硬编码数据库 ID,使用 e2e/helpers/api.ts 动态查询",
        "所有测试在无头模式下通过"
      ]
    }
  ]
}
  • 记忆持久化:git history + progress.txt + prd.json
  • 使用流程:
    • /prd 创建需求文档
    • /ralph 转换为任务
    • ./scripts/ralph/ralph.sh --tool=codebuddy
3.2.3.6 Vibe-Kanban

Vibe-Kanban: 任务管理看板,AI 原生体验

  • https://github.com/BloopAI/vibe-kanban
代码语言:javascript
复制
npx vibe-kanban

使用示例:

"做一个包含前后端的 todo app,帮我规划出 vibe-kanban 的各个任务,以主任务的方式创建"

3.3 阶段三:Spec-Driven 开发

目标: 完整的 Spec-Driven 开发流程,迭代修改,Proposal 与经验沉淀。

3.3.1 Skills

模块化的、自包含的能力包,通过提供专门的知识、工作流和工具来扩展 AI Agent 的能力。就像"入职指南",将通用 AI Agent 转变为专家。

包含内容:

  • 专业工作流 - 针对特定领域的自动多步骤程序
  • 工具集成 - 处理特定文件格式或 API 的指令
  • 领域专业知识 - 公司特定的知识、架构和业务逻辑
  • 打包资源 - 脚本、参考资料和资产

SKILL 目录结构:

代码语言:javascript
复制
skill-name/
├── SKILL.md (必需) - YAML 元数据 + Markdown 指令
├── bundled-resources/ (可选)
│   ├── scripts/        # 可执行代码
│   ├── references/     # 按需加载的文档
│   └── assets/         # 模板、图标等

渐进式披露:

层级

大小

加载时机

元数据

~100 词

始终加载

Skill 主体

中等

触发时加载

打包资源

无限

按需加载

资源:

  • https://skills.sh/
  • https://skillsmp.com/

3.3.2 OpenSpec

3.3.2.1 为什么 AI 编程流程这么低效?
需求模糊导致返工

传统的 AI 编程流程是这样的:

代码语言:javascript
复制
你说一句话 → AI 理解(可能理解错) → AI 写代码 → 你看代码 → 发现不对 → 重新沟通 → 重新写代码

这个循环可能要重复好几次。每一次都是时间浪费。

上下文丢失导致不一致

当你和 AI 聊天时,聊天记录会越来越长。AI 的上下文窗口有限,很容易遗忘之前的决定。比如:

  • 之前说过"权限数据存在 MySQL 数据库",后来 AI 又用了 Redis
  • 之前说过"不要改动现有的 User 表结构",后来 AI 又添加了一堆新字段
  • 之前说过"这个功能要兼容现有的 Spring Security 配置",后来 AI 用了完全不同的认证方式
多人协作时更混乱

如果是团队开发,问题更严重:

  • 不同的人和 AI 沟通,AI 可能给出不同的实现方式
  • 没有统一的"规范",每个人都在按自己的理解做
  • 代码审查时发现问题,又得重新讨论
没有清晰的实现路线图

AI 写代码很快,但你不知道它要做什么。没有一个清晰的"任务清单",你无法跟踪进度,也无法知道什么时候才能完成。

3.3.2.2 OpenSpec 简介

OpenSpec 是一个规范驱动开发(Spec-Driven Development, SDD)框架,专门为 AI 编程助手设计。它的核心理念很简单:

在写代码之前,先和 AI 达成共识。用规范(Spec)来约束双方的理解。

OpenSpec 的核心哲学

OpenSpec 遵循四个原则:

原则

含义

流动而非僵化

没有严格的阶段门控,你可以按需要的顺序工作

迭代而非瀑布

需求会变化,理解会深化,OpenSpec 拥抱这种现实

简单而非复杂

轻量级设置,最小化仪式感,需要时再定制

棕地优先

适合修改现有系统,不只是从零开始的绿地项目

OpenSpec 的核心概念

OpenSpec 把你的工作分成两个主要区域:

代码语言:javascript
复制
openspec/
├── specs/              # 源代码真理(你的系统现在是什么样的)
│   ├── auth/
│   ├── permissions/
│   └── user/
└── changes/            # 提议的修改(每个改动一个文件夹)
    ├── add-permission-system/
    ├── fix-login-bug/
    └── archive/        # 已完成的改动
  • specs/ 是你系统的"源代码真理"——它描述你的系统现在是什么样的。
  • changes/ 是"提议的修改"——每个改动都有自己的文件夹,包含所有相关的文档和规范。

这个分离很关键。你可以同时处理多个改动,不会互相冲突。你可以在合并前审查一个改动。当你完成一个改动时,它的规范会干净地合并到主规范中。

3.3.2.3 OpenSpec 的工作流程
代码语言:javascript
复制
- /opsx:explore 探索订单状态机的设计方案,包括5个状态:待接单 → 已接单 → 配送中 → 已送达 / 已取消。新建一个独立的管理端页面,可以查看订单列表和详情,手动推进订单状态,需要记录每次状态变更的时间。用户在自己的订单详情页可以实时看到状态变更,菜品配送前可以取消订单。
- /opsx:new order-status-machine
- /opsx:continue
- /opsx:apply order-status-machine 使用agent team的形式最大限度地并行开发,代码要经过review,并通过端到端测试。

proposal.md:

代码语言:javascript
复制
## Why

当前平台仅支持浏览阶段,顾客无法下单,商家无法处理订单。引入订单状态机,打通从下单到送达的完整流程,并为运营提供管理端工具手动推进订单状态。

## What Changes

- 新增订单下单 API,顾客提交购物车内容及联系方式后生成订单,返回唯一 token
- 新增订单状态机,支持 5 个状态:待接单 → 已接单 → 配送中 → 已送达 / 已取消
- 顾客凭 token 查询订单详情及实时状态,`PENDING` 和 `ACCEPTED` 状态下可主动取消
- 每次状态变更自动记录时间戳和前后状态,形成状态变更历史
- 新增管理端页面(无需认证的内部工具),可查看全部订单列表、订单详情、手动推进状态
- 顾客端新增"我的订单"入口,从 localStorage 读取本设备的历史订单并展示状态

## Capabilities

### New Capabilities

- `order-placement`: 顾客下单流程——提交购物车 items、收货地址、联系电话,服务端生成订单及 order_token,写入 localStorage
- `order-status-machine`: 订单状态定义(PENDING / ACCEPTED / DELIVERING / DELIVERED / CANCELLED)、合法状态转换规则、取消权限规则
- `order-status-history`: 每次状态变更记录 from_status、to_status、changed_at,作为时间线展示给顾客和管理端
- `customer-order-tracking`: 顾客端订单追踪——凭 token 查询订单状态、10 秒轮询实时刷新、配送前取消按钮
- `admin-order-management`: 管理端页面——订单列表(支持按状态筛选)、订单详情、手动推进状态按钮

### Modified Capabilities

(无现有 spec 需要修改)

## Impact

**数据库**(`server/src/scripts/migrate.ts`、`seed.ts`)
- 新增表:`orders`、`order_items`、`order_status_logs`
- `orders` 表含 `token` 字段(UUID v4,UNIQUE)、`contact_phone` 字段

**后端路由**(`server/src/routes/`)
- 新增 `orders.ts`:POST `/api/orders`、GET `/api/orders/:id`(token 验证)、PATCH `/api/orders/:id/status`(管理端推进)、POST `/api/orders/:id/cancel`(顾客取消)

**前端路由**(`client/src/App.tsx`)
- 新增页面:`/order/:id`(顾客订单详情 + 轮询)、`/orders`(我的订单列表)、`/admin`(管理端订单列表)、`/admin/order/:id`(管理端订单详情)

**前端服务层**(`client/src/services/`)
- 新增 `orderService.ts`,遵循 snake_case → camelCase 转换规范

**依赖**
- 后端引入 `uuid` 包生成 order_token(或使用 `crypto.randomUUID()`,Node 14.17+ 原生支持,无需新增依赖)

design.md:

代码语言:javascript
复制
## Context

当前平台为纯浏览阶段:顾客可查看商家、菜单、菜品规格,购物车状态由 `CartContext` 管理,但无法下单。本次变更在现有 Express + SQLite + React 架构上叠加订单系统,不引入新的运行时依赖。

已有约定:
- 后端 snake_case,前端 camelCase,转换发生在 `services/` 层
- 统一响应格式 `{ success, data }` / `{ success, error }`
- 禁止 `any`,strict TypeScript

## Goals / Non-Goals

**Goals:**
- 顾客可下单、凭 token 追踪订单状态、配送前可取消
- 状态变更全程有历史记录(时间戳 + 前后状态)
- 管理端可查看所有订单并手动推进状态
- 不引入新的后端运行时依赖

**Non-Goals:**
- 用户注册 / 登录 / 权限系统
- 管理端访问控制(内部工具,不做认证)
- 支付流程
- 推送通知(短信 / 邮件)
- 多设备订单同步(换设备后订单不可见,接受此限制)

## Decisions

### D1:顾客身份——order_token 方案

**决策**:下单时服务端生成 `crypto.randomUUID()` 作为 `order_token`,存入 `orders.token`(UNIQUE)。客户端将 `{ orderId, token }` 存入 `localStorage["my_orders"]`。查询/取消时通过 `Authorization: Bearer <token>` 传递,服务端用 `WHERE id = ? AND token = ?` 验证。

**放弃的方案**:
- 手机号/邮箱登录:引入认证系统,超出当前阶段范围
- URL 传 token(`?token=xxx`):token 会出现在服务器 access log 和浏览器历史

**权衡**:换设备后订单不可见,但对 demo 阶段可接受;`crypto.randomUUID()` 为 Node 14.17+ 原生 API,无需额外依赖。

---

### D2:状态机转换规则

**合法转换**(仅管理端可推进,顾客只能触发取消):

PENDING    → ACCEPTED   (管理端)
PENDING    → CANCELLED  (顾客 或 管理端)
ACCEPTED   → DELIVERING (管理端)
ACCEPTED   → CANCELLED  (顾客 或 管理端)
DELIVERING → DELIVERED  (管理端)
DELIVERING → CANCELLED  (仅管理端,顾客不可取消)

**服务端强制校验**:PATCH `/api/orders/:id/status` 和 POST `/api/orders/:id/cancel` 均在路由层校验当前状态是否允许此转换,非法转换返回 `400 { success: false, error: "..." }`。

---

### D3:实时更新——轮询方案

**决策**:顾客订单详情页每 10 秒调用 `GET /api/orders/:id` 一次,用 `useEffect` + `setInterval` 实现,组件卸载时 `clearInterval`。

**放弃的方案**:
- SSE(Server-Sent Events):需要服务端维护长连接,实现更复杂,对订单状态追踪场景收益有限
- WebSocket:双向通信,过度设计

**权衡**:最多 10 秒延迟,对外卖配送场景完全可接受;实现简单,无额外依赖。

---

### D4:数据库表结构

orders
  id INTEGER PRIMARY KEY AUTOINCREMENT
  token TEXT NOT NULL UNIQUE          -- crypto.randomUUID()
  restaurant_id INTEGER NOT NULL REFERENCES restaurants(id)
  status TEXT NOT NULL DEFAULT 'PENDING'
    -- CHECK(status IN ('PENDING','ACCEPTED','DELIVERING','DELIVERED','CANCELLED'))
  contact_name TEXT NOT NULL
  contact_phone TEXT NOT NULL
  delivery_address TEXT NOT NULL
  total_price REAL NOT NULL
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))

order_items
  id INTEGER PRIMARY KEY AUTOINCREMENT
  order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE
  menu_item_id INTEGER NOT NULL REFERENCES menu_items(id)
  item_name TEXT NOT NULL              -- 快照,防止菜品改名后历史订单显示错误
  unit_price REAL NOT NULL             -- 下单时的实际单价快照(含规格差价)
  quantity INTEGER NOT NULL DEFAULT 1
  spec_summary TEXT                    -- 规格文字快照,如"大份 / 微辣",可为空
  created_at TEXT NOT NULL DEFAULT (datetime('now'))

order_status_logs
  id INTEGER PRIMARY KEY AUTOINCREMENT
  order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE
  from_status TEXT                     -- NULL 表示初始创建
  to_status TEXT NOT NULL
  changed_at TEXT NOT NULL DEFAULT (datetime('now'))
  note TEXT                            -- 可选备注,如"顾客主动取消"

**索引**:
- `idx_orders_token` ON `orders(token)`
- `idx_orders_restaurant_id` ON `orders(restaurant_id)`
- `idx_orders_status` ON `orders(status)`
- `idx_order_items_order_id` ON `order_items(order_id)`
- `idx_order_status_logs_order_id` ON `order_status_logs(order_id)`

---

### D5:spec_summary 快照而非关联规格表

**决策**:`order_items` 不外键关联 `dish_specs`,而是在下单时将选中规格序列化为纯文本快照(如 `"大份 / 微辣"`)存入 `spec_summary`,`unit_price` 存储含差价的最终单价。

**理由**:菜品规格可能后续变更,历史订单应展示下单时的状态;文本快照比 JSON 更易读,查询更简单。

---

### D6:管理端路由与权限

**决策**:管理端作为同一前端应用的新路由 `/admin` 和 `/admin/order/:id`,无认证保护。

**理由**:当前阶段为内部工具 demo,引入认证超出范围;路由隔离已足够区分顾客端与管理端。未来可在路由层加 `AdminRoute` 组件做简单密码保护。

---

### D7:下单入口位置

**决策**:在 `MerchantDetailPage` 购物车浮层上新增"去结算"按钮,点击后弹出结算表单(联系人姓名、电话、收货地址),确认后调用 `POST /api/orders`,成功后跳转 `/order/:id`。

**理由**:购物车已绑定特定商家,在商家页完成下单逻辑最自然;不新增独立 checkout 页面,减少页面数量。

## Risks / Trade-offs

- **localStorage 丢失** → 顾客换设备或清浏览器后无法找回订单。无缓解措施,属已知限制,接受。
- **并发状态推进** → 管理端同时操作同一订单时可能产生竞态。SQLite 单写特性天然串行,风险极低;路由层状态校验作为第二道防线。
- **total_price 计算** → 服务端根据 `order_items` 的 `unit_price × quantity` 求和写入 `orders.total_price`,不信任客户端传来的金额,防止篡改。
- **轮询频率** → 10 秒一次,多标签页同时打开会叠加请求。可接受,demo 阶段流量极低。
- **管理端无权限** → 任何人访问 `/admin` 均可操作所有订单。已知风险,内部工具 demo 阶段接受。

tasks.md:

代码语言:javascript
复制
## 1. 数据库迁移

- [x] 1.1 在 `server/src/scripts/migrate.ts` 中新增 `orders` 表(含 `token UNIQUE`、`status CHECK` 约束、`contact_name`、`contact_phone`、`delivery_address`、`total_price`)
- [x] 1.2 在 `server/src/scripts/migrate.ts` 中新增 `order_items` 表(含 `item_name`、`unit_price`、`quantity`、`spec_summary` 快照字段,外键 `ON DELETE CASCADE`)
- [x] 1.3 在 `server/src/scripts/migrate.ts` 中新增 `order_status_logs` 表(含 `from_status`、`to_status`、`changed_at`、`note`,外键 `ON DELETE CASCADE`)
- [x] 1.4 为五张新表添加索引:`idx_orders_token`、`idx_orders_restaurant_id`、`idx_orders_status`、`idx_order_items_order_id`、`idx_order_status_logs_order_id`
- [x] 1.5 运行 `npm run migrate` 验证建表成功,无报错

## 2. 后端类型定义

- [x] 2.1 在 `server/src/types/index.ts` 中新增 `Order`、`OrderItem`、`OrderStatusLog` 接口(snake_case)
- [x] 2.2 定义 `OrderStatus` 联合类型:`'PENDING' | 'ACCEPTED' | 'DELIVERING' | 'DELIVERED' | 'CANCELLED'`
- [x] 2.3 定义合法状态转换规则常量(用于路由层校验)

## 3. 后端订单路由(顾客端)

- [ ] 3.1 新建 `server/src/routes/orders.ts`,实现 `POST /api/orders`:接收 `restaurant_id`、`items[]`、`contact_name`、`contact_phone`、`delivery_address`;服务端用 `crypto.randomUUID()` 生成 token,计算 `total_price`,事务内写入 `orders`、`order_items`、`order_status_logs`(初始 `PENDING` 日志);返回 `{ orderId, token }`
- [ ] 3.2 实现 `GET /api/orders/:id`:从 `Authorization: Bearer <token>` 提取 token,`WHERE id = ? AND token = ?` 验证,返回订单详情 + `order_items` + `order_status_logs`(按 `changed_at` 升序);验证失败返回 `404`
- [ ] 3.3 实现 `POST /api/orders/:id/cancel`:token 验证,校验当前状态为 `PENDING` 或 `ACCEPTED`,事务内更新状态并写入日志(note: "顾客主动取消");`DELIVERING` 时返回 `400`

## 4. 后端管理端路由

- [ ] 4.1 新建 `server/src/routes/adminOrders.ts`,实现 `GET /api/admin/orders`:返回所有订单列表(含商家名),支持 `?status=` 筛选,按 `created_at` 降序
- [ ] 4.2 实现 `GET /api/admin/orders/:id`:无 token 验证,返回完整订单详情 + items + statusLogs
- [ ] 4.3 实现 `PATCH /api/admin/orders/:id/status`:接收 `{ status }`,校验合法状态转换,事务内更新状态并写入日志;非法转换返回 `400`

## 5. 注册路由与集成

- [ ] 5.1 在 `server/src/index.ts` 中注册 `orders` 路由(`/api/orders`)和 `adminOrders` 路由(`/api/admin/orders`)
- [ ] 5.2 启动后端,用 curl 或 Postman 手动验证 `POST /api/orders` 和 `GET /api/orders/:id` 正常工作

## 6. 前端类型定义与服务层

- [ ] 6.1 在 `client/src/types/index.ts` 中新增 `Order`、`OrderItem`、`OrderStatusLog`、`OrderDetail` 接口(camelCase)及 `OrderStatus` 联合类型
- [ ] 6.2 新建 `client/src/services/orderService.ts`,实现:`placeOrder()`、`getOrder(id, token)`、`cancelOrder(id, token)`、`getAdminOrders(status?)`、`getAdminOrder(id)`、`advanceOrderStatus(id, status)`;遵循 `Raw*` → camelCase 转换规范

## 7. 结算表单组件与下单流程

- [ ] 7.1 新建 `client/src/components/CheckoutModal.tsx`:弹窗表单,含联系人姓名、电话、收货地址必填字段;校验通过后调用 `placeOrder()`,成功后将 `{ orderId, token }` 写入 `localStorage["my_orders"]`,跳转至 `/order/:id`
- [ ] 7.2 在 `MerchantDetailPage` 的购物车浮层上新增"去结算"按钮(购物车为空时禁用),点击打开 `CheckoutModal`

## 8. 顾客订单详情页

- [ ] 8.1 新建 `client/src/pages/OrderDetailPage.tsx`(路由 `/order/:id`):从 `localStorage` 读取对应 token,调用 `getOrder()`,展示订单基本信息、商品列表、状态变更时间线
- [ ] 8.2 在 `OrderDetailPage` 实现 10 秒轮询:`useEffect` + `setInterval`,组件卸载时 `clearInterval`
- [ ] 8.3 在 `OrderDetailPage` 实现取消按钮:`PENDING`/`ACCEPTED` 时显示,点击后调用 `cancelOrder()`,成功后刷新状态

## 9. 顾客我的订单列表页

- [ ] 9.1 新建 `client/src/pages/MyOrdersPage.tsx`(路由 `/orders`):从 `localStorage["my_orders"]` 读取订单列表,并行请求各订单当前状态,展示摘要列表(订单号、商家名、状态、下单时间);空状态时展示提示
- [ ] 9.2 列表每项可点击跳转至 `/order/:id`

## 10. 管理端页面

- [ ] 10.1 新建 `client/src/pages/AdminOrdersPage.tsx`(路由 `/admin`):调用 `getAdminOrders()`,展示订单列表,支持按状态筛选 Tab;空状态时展示提示
- [ ] 10.2 新建 `client/src/pages/AdminOrderDetailPage.tsx`(路由 `/admin/order/:id`):调用 `getAdminOrder()`,展示完整订单信息和状态历史时间线
- [ ] 10.3 在 `AdminOrderDetailPage` 实现状态推进按钮:根据当前状态渲染对应按钮(接单 / 开始配送 / 确认送达 / 取消订单),点击后调用 `advanceOrderStatus()`,成功后刷新页面状态
- [ ] 10.4 终止状态(`DELIVERED` / `CANCELLED`)不显示任何操作按钮

## 11. 路由注册

- [ ] 11.1 在 `client/src/App.tsx` 中注册四条新路由:`/order/:id`、`/orders`、`/admin`、`/admin/order/:id`

## 12. 类型检查与 Lint

- [ ] 12.1 在 `client/` 运行 `npm run typecheck`,修复所有类型错误
- [ ] 12.2 在 `server/` 运行 `npm run typecheck`(若有),修复所有类型错误
- [ ] 12.3 运行 `client/` 和 `server/` 的 `npm run lint`,修复所有 lint 错误

需求变更:

代码语言:javascript
复制
- @openspec/changes/order-status-machine/proposal.md 文档中增加以下需求:用户端的首页添加“订单”入口,可以查看订单列表和详情。用户端的详情页可以看到订单状态变更的时间线。订单不需要区分不同用户
- /opsx:continue 根据proposal新增的内容更新工件 
- /opsx:apply 
- 怎么没有代码改动
- /opsx:verify
- /opsx:archive

- /opsx:new 已送达订单可在详情页打1-5星评价,已评价显示星级,未评价(已送达)显示评价入口。评价后实时更新餐厅的平均评分,餐厅列表页展示平均评分。
- /opsx:ff
- /opsx:apply

四、小结

工具

价值

Plan Mode

先规划后执行,复杂任务避免返工

Hooks

自动化校验和环境初始化,减少人工操作

Commands

封装常用提示词和脚本为斜杠命令

Subagents

专业化分工,独立上下文并行处理

Worktree+ 多实例

多分支并行开发,多 AI 实例互不冲突

Background Agent

后台运行长耗时任务,不阻塞主工作流

Ralph

自主 AI 循环,持续迭代直到 PRD 完成

vibe-kanban

可视化任务管理与自动拆分

Agent Team

多 Agent 并行协作,模拟团队分工

Happy CLI + Termius

移动端随时随地进行 AI 编程

Checkpoint/Rewind

会话内快速实验和一键回滚

消息提醒

长任务完成后推送通知,避免空等

4.1 代码准确性工具

工具

价值

CODEBUDDY.md

持久上下文,让 AI 理解项目规范和架构决策

AskUserQuestionTool

深度访谈消除需求模糊性,生成精确 Spec

Agent.md 元提示词

只做索引不放模板,避免干扰上下文

OpenSpec

规约驱动开发,Spec 作为"单一真理来源"

CodeWiki

代码知识库辅助 AI 理解业务逻辑

Compound Engineering

持续改进循环,每次迭代积累复利

Context7

引入最新文档上下文,减少 API 幻觉

对话技巧

直接明确的指令比模糊客气的表述准确率更高

4.2 工程质量工具

工具

价值

ESLint

团队代码规范自动化检查

Hooks (PostToolUse)

每次文件写入自动触发格式化和质量检查

多 Agent 协作 Review

多维度 Code Review(安全、架构、性能、扩展性)

Plan Mode

编码前明确方案,可审阅调整后再执行

先做垃圾再重构

先完成功能,再人工精调结构

Code Simplifier

自动化代码简化、函数拆分和文件整理

4.3 可复用性工具

工具

价值

Skills

模块化能力包,渐进式披露,跨项目复用

记忆系统

跨会话知识积累 (Claude-Mem/Auto Memory/自建)

CODEBUDDY.md 分层

用户级→项目级→目录级,团队通过 git 共享

Commands

团队共享的标准化工作流命令

Subagents

user 级别全局生效,一次配置跨项目复用

OpenSpec

标准化规范流程,变更记录可追溯可归档

Skills 市场

skills.sh/skillsmp.com 社区共享生态

4.4 松哥观点

1️⃣ 组织能力 > 代码能力

一个 Agent 做一个 feature 提一个 PR,瓶颈在于 PR 之间的 conflict。有价值的是从「怎么写代码」转到「怎么做管理」:

  • 先当 PM + 技术 leader
  • 变成 PM + 技术总监
  • 搭 SOP 管需求闭环迭代

2️⃣ 模型输出上限 = 用户认知边界

描述有多精确、深刻,输出就有多具体。未来的专家是:

  • 品味好
  • 逻辑严密
  • 能提出正确问题
  • 会审阅结果的人

3️⃣ Attention is All You Need

每个人都有自己擅长的点,注意力在哪,天赋就在哪。

这不是唯精英论——每个人都能在自己的领域成为专家。

4.5 关键建议

💡 根据自己业务的实际情况,选择适合自己的工具和方法。不建议盲目追求最新最潮的工具,重要的是形成体系化的工作流,让工具之间互相配合、持续积累。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江南一点雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 痛点
  • 1.2 解法
  • 二、如何衡量 AI Coding 水平
  • 三、外卖平台
    • 3.1 阶段一:AI 协作基础
      • 3.1.1 怎么选编辑器
      • 3.1.2 核心工具
      • 3.1.3 工程实践
      • 3.1.4 init 命令
      • 3.1.5 UI 美化
    • 3.2 阶段二:工程化质量体系
      • 3.2.1 核心工具
      • 3.2.2 工程质量保障
      • 3.2.3 工作效率提升
    • 3.3 阶段三:Spec-Driven 开发
      • 3.3.1 Skills
      • 3.3.2 OpenSpec
  • 四、小结
    • 4.1 代码准确性工具
    • 4.2 工程质量工具
    • 4.3 可复用性工具
    • 4.4 松哥观点
      • 1️⃣ 组织能力 > 代码能力
      • 2️⃣ 模型输出上限 = 用户认知边界
      • 3️⃣ Attention is All You Need
    • 4.5 关键建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档