一、课程缘起与设计

维度 | 说明 | 衡量标准 |
|---|---|---|
工作效率 | 重复性任务交给 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 |
目标: 理解 AI 协作基础,掌握规划先行与质量门禁,通过构建餐厅菜单页,掌握 AI 协作的核心工具与工作流程。
CodeBuddy IDE | CodeBuddy Code |
|---|---|
方便人工 review 代码或者方案 | 更加 AI Native,速度快 |
Plan 功能更丰富 | 输出的过程信息比较简洁,只关注计划的制定和结果的验收 |
可视化操作界面 | Hooks 只有 CLI 有 |
CLI 可以开启 think 模式 | |
适合多任务并发执行 |
每次对话开始时读取的特殊文件,为 CodeBuddy 提供无法从代码本身推断出的持久上下文。
应该写:
不应该写:
配置技巧:
@path/to/file 导入语法引用其他文件;维度 | Plan Mode | Craft Mode |
|---|---|---|
工作方式 | 先规划后执行 | 直接执行 |
适用场景 | 复杂功能、架构设计 | 局部修改、Bug 修复 |
输出形式 | 完整方案 | 直接代码结果 |
可控性 | 高——执行前审阅 | 边执行边调整 |
扩展能力 | 智能编排 MCP/Skill | 按需调用 |
适合使用 Plan Mode 的场景:
在 CodeBuddy Code 的会话生命周期内插入自定义脚本或命令。
基于命令的 Hooks:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write/Edit",
"type": "command",
"command": "check-style.sh"
}]
}
}
基于提示词的 Hooks:
{
"hooks": {
"Stop": [{
"type": "prompt",
"prompt": "Evaluate if we should stop..."
}]
}
}
事件类型:
PreToolUse :工具执行前,校验、审批;PostToolUse :工具执行后,格式化,补上下文;Notification :权限或者超市,桌面/IM 提醒;UserPromptSubmit :用户提交时,内容审查;SessionStart - 会话开始,环境初始化;PreCompact - 压缩前,保留关键信息;Stop - 主代理结束,继续执行;SubagentsStop:子代理结束,补充说明;SessionEnd - 会话结束,清理/持久化├── .codebuddy
│ ├── hooks
│ │ ├── git-commit-check.sh
│ │ ├── hooks.json
│ │ └── prettier-format.sh
├── CODEBUDDY.md
├── images
│ ├── dishes
│ └── restaurants
├── proposal.md
CODEBUDDY.md:
# 外卖平台
## 语言规范
- 所有文档和对话使用中文
- 专业术语保持英文(如 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:
## 为什么
这是构建网页版外卖平台的基础阶段。目前没有任何面向顾客的界面。用户需要能够浏览可用的商家并查看他们的菜单,然后才能下单。这建立了核心的浏览体验,所有未来的功能(购物车、结账、订单)都将建立在此基础之上。
## 变更内容
- **新增**: 商家浏览界面,带搜索功能
- **新增**: 商家详情页,展示商家信息和完整菜单
- **新增**: 菜品详情页,包含规格选择(大小、口味选项)
- **新增**: 后端 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 模式:

开始开发:

确认示例:






最终效果:



/init:初始化项目并生成 CODEBUDDY.md

# 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`
安装:
npm install -g uipro-cli
uipro init --ai codebuddy

├── .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



/ui-ux-pro-max 美化一下我的PC版外卖平台页面,为我提供一些优化的风格供我选择





图标统一使用 lucide-react
目标: 建立工程化质量体系,掌握 MCP 连接与多 Agent 协作,在已有菜单页基础上,构建购物车与下单系统,引入工程化质量工具。
MCP 解决「连接」,给 Agent 接上手和脚;Skills 解决「执行」,教 Agent 在特定场景下怎么做。
通信方式 | stdio | Streamable HTTP |
|---|---|---|
原理 | 标准输入输出通信 | HTTP POST+SSE |
通信方式 | stdin/stdout | HTTP POST+SSE |
典型用途 | 本地进程、IDE、CLI | 远程服务、Web、多客户端 |
配置示例 - mcp.json:
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"tapd_copilot": {
"url": "https://mcp.tapd.woa.com/mcp",
"transportType": "streamable-http"
}
}
}
将常用的 Prompts、脚本和工作流封装成可复用的自定义斜杠命令。
命名规则: 文件路径 → 斜杠命令
示例:commands/backend/deploy/staging.md → /backend:deploy:staging
---
description: "运行单元测试并报告结果"
argument-hint: "[test-file] [test-type]"
allowed-tools: Bash (npm run *)
model: gemini-3.0-pro
---
1. 运行 `npm run test-$1-$2`
2. 总结测试结果
修复问题命令示例:
---
description: "修复代码问题"
argument-hint: "[issue-number]"
---
1. 理解问题 → 定位根因 → 实现修复 → 添加测试 → 验证
2. 修复 issue #{{ARGUMENTS}},遵循编码标准
两种模式:
模式 | agentic 模式 | manual 模式 (IDE) |
|---|---|---|
调用方式 | 主 Agent 自动判断调用时机 | 用户手动选择 |
上下文 | 拥有独立上下文窗口 | 完全替代主 Agent |
干预 | 不能中途干预 | 可在 Agent 选择框中选中使用 |
适用场景 | 专业化分工 | 深度定制交互 |
最佳实践:
集成 ESLint 代码规范检查,确保代码质量一致性。
为项目添加eslint检查





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

git.md:
---
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`)将运行以确保代码质量
- 如果这些检查失败,您将被问及是否要继续提交或先修复问题
- 如果已有特定文件暂存,命令将只提交这些文件
- 如果没有文件暂存,它将自动暂存所有修改的和新文件
- 提交信息将根据检测到的更改构建
- 在提交之前,命令将检查差异以确定多个提交是否更合适
- 如果建议多个提交,它将帮助您分别暂存和提交更改
- 始终检查提交差异以确保信息与更改匹配
- **在完成代码提交后,必须使用"文档更新检查清单"逐项检查,如符合条件则创建独立的文档更新提交**
接下来就可以在命令行使用该命令了:



为当前项目添加端到端测试的能力,补全已有功能的测试用例





- 根据项目的测试技术栈,帮我设计一个测试工程师的subagent描述,存到一个新的文件中
- 据项目的技术栈,帮我设计4个工程师的subagent描述,分别存到4个新的文件中,分别是前端工程师、后端工程师、前端代码reviewer工程师、后端代码reviewer工程师

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

异步执行长时间任务,不阻塞主流程。
Ctrl+B - background 运行中的任务Ctrl+K - Kill background agents使用 backend-code-reviewer 子代理评审后端代码 --run_in_background

Git worktree 允许在同一仓库中同时拥有多个工作目录,每个目录可以检出不同的分支。CodeBuddy Code 利用这一特性提供:
Git Worktree:
# 创建新工作树
git worktree add ../project-ui new-ui
# 列出所有工作树
git worktree list
# 移除工作树
git worktree remove ../project-ui
# 清理
git worktree prune


# 生成任务列表
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



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




{
"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 动态查询",
"所有测试在无头模式下通过"
]
}
]
}

/prd 创建需求文档/ralph 转换为任务./scripts/ralph/ralph.sh --tool=codebuddyVibe-Kanban: 任务管理看板,AI 原生体验
npx vibe-kanban
使用示例:
"做一个包含前后端的 todo app,帮我规划出 vibe-kanban 的各个任务,以主任务的方式创建"


目标: 完整的 Spec-Driven 开发流程,迭代修改,Proposal 与经验沉淀。
模块化的、自包含的能力包,通过提供专门的知识、工作流和工具来扩展 AI Agent 的能力。就像"入职指南",将通用 AI Agent 转变为专家。
包含内容:
SKILL 目录结构:
skill-name/
├── SKILL.md (必需) - YAML 元数据 + Markdown 指令
├── bundled-resources/ (可选)
│ ├── scripts/ # 可执行代码
│ ├── references/ # 按需加载的文档
│ └── assets/ # 模板、图标等
渐进式披露:
层级 | 大小 | 加载时机 |
|---|---|---|
元数据 | ~100 词 | 始终加载 |
Skill 主体 | 中等 | 触发时加载 |
打包资源 | 无限 | 按需加载 |
资源:
传统的 AI 编程流程是这样的:
你说一句话 → AI 理解(可能理解错) → AI 写代码 → 你看代码 → 发现不对 → 重新沟通 → 重新写代码
这个循环可能要重复好几次。每一次都是时间浪费。
当你和 AI 聊天时,聊天记录会越来越长。AI 的上下文窗口有限,很容易遗忘之前的决定。比如:
如果是团队开发,问题更严重:
AI 写代码很快,但你不知道它要做什么。没有一个清晰的"任务清单",你无法跟踪进度,也无法知道什么时候才能完成。
OpenSpec 是一个规范驱动开发(Spec-Driven Development, SDD)框架,专门为 AI 编程助手设计。它的核心理念很简单:
在写代码之前,先和 AI 达成共识。用规范(Spec)来约束双方的理解。
OpenSpec 遵循四个原则:
原则 | 含义 |
|---|---|
流动而非僵化 | 没有严格的阶段门控,你可以按需要的顺序工作 |
迭代而非瀑布 | 需求会变化,理解会深化,OpenSpec 拥抱这种现实 |
简单而非复杂 | 轻量级设置,最小化仪式感,需要时再定制 |
棕地优先 | 适合修改现有系统,不只是从零开始的绿地项目 |
OpenSpec 把你的工作分成两个主要区域:
openspec/
├── specs/ # 源代码真理(你的系统现在是什么样的)
│ ├── auth/
│ ├── permissions/
│ └── user/
└── changes/ # 提议的修改(每个改动一个文件夹)
├── add-permission-system/
├── fix-login-bug/
└── archive/ # 已完成的改动
这个分离很关键。你可以同时处理多个改动,不会互相冲突。你可以在合并前审查一个改动。当你完成一个改动时,它的规范会干净地合并到主规范中。
- /opsx:explore 探索订单状态机的设计方案,包括5个状态:待接单 → 已接单 → 配送中 → 已送达 / 已取消。新建一个独立的管理端页面,可以查看订单列表和详情,手动推进订单状态,需要记录每次状态变更的时间。用户在自己的订单详情页可以实时看到状态变更,菜品配送前可以取消订单。
- /opsx:new order-status-machine
- /opsx:continue
- /opsx:apply order-status-machine 使用agent team的形式最大限度地并行开发,代码要经过review,并通过端到端测试。


proposal.md:
## 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:
## 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:
## 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 错误
需求变更:
- @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 | 会话内快速实验和一键回滚 |
消息提醒 | 长任务完成后推送通知,避免空等 |
工具 | 价值 |
|---|---|
CODEBUDDY.md | 持久上下文,让 AI 理解项目规范和架构决策 |
AskUserQuestionTool | 深度访谈消除需求模糊性,生成精确 Spec |
Agent.md 元提示词 | 只做索引不放模板,避免干扰上下文 |
OpenSpec | 规约驱动开发,Spec 作为"单一真理来源" |
CodeWiki | 代码知识库辅助 AI 理解业务逻辑 |
Compound Engineering | 持续改进循环,每次迭代积累复利 |
Context7 | 引入最新文档上下文,减少 API 幻觉 |
对话技巧 | 直接明确的指令比模糊客气的表述准确率更高 |
工具 | 价值 |
|---|---|
ESLint | 团队代码规范自动化检查 |
Hooks (PostToolUse) | 每次文件写入自动触发格式化和质量检查 |
多 Agent 协作 Review | 多维度 Code Review(安全、架构、性能、扩展性) |
Plan Mode | 编码前明确方案,可审阅调整后再执行 |
先做垃圾再重构 | 先完成功能,再人工精调结构 |
Code Simplifier | 自动化代码简化、函数拆分和文件整理 |
工具 | 价值 |
|---|---|
Skills | 模块化能力包,渐进式披露,跨项目复用 |
记忆系统 | 跨会话知识积累 (Claude-Mem/Auto Memory/自建) |
CODEBUDDY.md 分层 | 用户级→项目级→目录级,团队通过 git 共享 |
Commands | 团队共享的标准化工作流命令 |
Subagents | user 级别全局生效,一次配置跨项目复用 |
OpenSpec | 标准化规范流程,变更记录可追溯可归档 |
Skills 市场 | skills.sh/skillsmp.com 社区共享生态 |
一个 Agent 做一个 feature 提一个 PR,瓶颈在于 PR 之间的 conflict。有价值的是从「怎么写代码」转到「怎么做管理」:
描述有多精确、深刻,输出就有多具体。未来的专家是:
每个人都有自己擅长的点,注意力在哪,天赋就在哪。
这不是唯精英论——每个人都能在自己的领域成为专家。
💡 根据自己业务的实际情况,选择适合自己的工具和方法。不建议盲目追求最新最潮的工具,重要的是形成体系化的工作流,让工具之间互相配合、持续积累。