OpenSpec-practise

OpenSpec 实战指南

1. 引言

OpenSpec 是一种以规格(Spec)为中心的工程方法与工具链,旨在通过统一的结构化文档与自动化工作流,提升复杂系统在设计到交付全周期的确定性与可验证性。本文结合一个小型电商网站的完整案例,演示从架构设计、系统设计、模块设计、接口设计,到单元测试、集成测试(覆盖接口层验收)、性能测试的全流程,以促进在真实项目中落地。

进阶阅读:关于本案例的 AI 协作全流程复盘(Prompt 设计与交互记录)及 Python 版本的跨语言复刻验证,请参考 OpenSpec 实战指南:AI 辅助软件工程全流程深度复盘

CLI 参考手册:关于 OpenSpec CLI 的完整命令说明(init、validate、archive 等),请参考 OpenSpec 使用手册

培训材料:本项目提供了配套的演示文稿 OpenSpec 使用手册,适合用于团队培训与技术分享。


2. 方法论与 OpenSpec 核心概念

OpenSpec 不仅仅是一套文档格式,更是一种 Spec 驱动开发(Spec-Driven Development) 的工程实践。它主张“以规格为源”,确保代码与测试始终与设计保持一致,解决传统开发中“文档落后于代码”的顽疾。

2.1 核心哲学

术语说明:本文中”规格”与”Spec”同义,均指 OpenSpec 定义的文档结构;”规范”与”规格”可互换使用,不作区分。

OpenSpec 的设计遵循四大原则:

2.2 目录结构与单一事实来源

OpenSpec 将项目状态分为两个核心区域,确保“当前状态”与“变更过程”分离:

当变更开发完成并归档(Archive)后,其 Delta Spec 会合并入主 Spec,形成新的事实来源。

2.3 工作流与 CLI 工具

OpenSpec 提供了两种主要的工作流方式:CLI 和 Slash Commands(AI 协作)。

2.3.1 命令行工具 (CLI)

CLI (openspec) 适合人类开发者进行管理操作:

2.3.2 AI 协作指令 (Slash Commands)

OpenSpec 1.0+ 引入了 OPSX 工作流,实现了动态指令体系——AI 不再接收静态指令,而是主动查询 CLI 了解当前项目状态和文档依赖。

在支持的 AI 编辑器(如 Cursor、Claude Code、Qoder、Windsurf、Junie、Lingma IDE、ForgeCode 等 20+ 工具)中,推荐使用斜杠命令(Slash Commands)驱动开发:

默认 Core 配置

命令 作用
/opsx:propose <description> 一步创建变更并生成所有规划文档(proposal/design/specs/tasks)
/opsx:explore 进入探索模式,思考问题、调查代码库,不写代码
/opsx:apply 按照 tasks.md 实现任务,动态读取当前变更上下文
/opsx:archive 完成并归档当前变更,提示是否同步 Delta Spec 到主规范

扩展工作流命令(通过 openspec config profile 开启)

命令 作用
/opsx:new 仅初始化变更目录结构(不创建文档)
/opsx:continue 按依赖顺序创建下一个文档(逐步模式)
/opsx:ff 快进生成所有规划文档(一步到位)
/opsx:verify 验证实现是否与规范一致
/opsx:sync 将 Delta Spec 合并到主规范(不归档)
/opsx:bulk-archive 批量归档多个已完成的变更
/opsx:onboard 15 分钟全流程引导

OPSX 工作流与旧版的最大区别在于:动作而非阶段。可以在任意时刻编辑任意文档,不存在阶段锁定。

2.4 验证与可观测性


3. 迭代流程总览

OpenSpec 的迭代流程围绕着“规格优先”展开,但并不强制要求繁琐的审批流程。

3.1 目标与范围 (Proposal)

在任何代码开始之前,首先通过 proposal.md 定义WhyWhat

3.2 规格初始化

使用 CLI 快速初始化项目结构(如果你直接使用 examples/ecommerce-mini 源码,此步骤已完成,可跳过):

openspec init --tools none

如果你使用的是配套源码,可运行以下命令确认规范文档完整无误:

openspec validate v1-mvp

openspec/changes/ 下创建一个新的变更集(如 v1-mvp),并包含以下文件:

3.2.1 proposal.md (宏观意图)

这是项目的起点,清晰定义了“我们为什么要做这个”以及“成功的标准是什么”。

# Proposal: Ecommerce Mini MVP

## Why

### Background

本项目起源于社区关于 AI 编程的深度探讨,需要一个完整的实战案例来演示 OpenSpec 规范在 AI 辅助编程中的具体应用。

### Problem Statement

需要一个规范化的方式来确保人与 AI 对需求达成一致,同时保持代码与文档的同步。

### Alternatives Considered

1. **直接编写代码**: 快速但缺乏文档支撑。
2. **传统需求文档**: 与代码分离,容易过时。
3. **OpenSpec 规范驱动**: 先定义规范,再编写代码,保持一致性 ✓ 已选择此方案。

## What Changes

### New Resources Added

- **领域模型**: Product、User、Cart、Order 等核心实体。
- **API 接口**: 商品、购物车、订单、支付等 RESTful 接口。

### New Capabilities

- 商品列表查询与上架。
- 购物车管理(添加、移除)。
- 下单结算与库存扣减。

## Capabilities

### New Capabilities

- `catalog-management`: 商品列表查询、商品上架与库存扣减管理
- `cart-management`: 购物车商品添加、移除与数量限制
- `order-management`: 订单创建、订单查询与总价计算
- `payment`: 订单支付与状态流转
- `domain-model`: 核心业务实体定义
- `error-handling`: 统一错误响应格式与标准错误码体系

### Modified Capabilities

(无,本次为全新 MVP 项目)

## Impact

- **受影响代码**: `ecommerce-mini/src/` (Node.js), `ecommerce-mini-python/src/` (Python)
- **新增 API**: 8 个 REST 端点(GET /api/products, POST /api/products, POST /api/cart/items, DELETE /api/cart/items/:id, POST /api/orders, GET /api/orders/:id, POST /api/payments/:orderId, GET /metrics)
- **依赖**: Node.js 零 npm 依赖;Python 依赖 FastAPI + Pydantic

## Scope

### In Scope

- 商品列表查询与上架。
- 购物车管理(添加、移除)。
- 下单结算与库存扣减。
- 订单支付模拟。
- 内存存储与文件持久化。

### Out of Scope

- 复杂搜索与推荐。
- 真实支付网关集成。
- 后台管理界面。

## Goals (SLO)

- **Latency**: 核心接口 p99 < 100ms。
- **Concurrency**: 支持 50 RPS。
- **Quality**: 核心逻辑测试覆盖率 > 80%。

3.2.2 其他核心文件

3.3 架构与系统设计

基于 Proposal,在 design.md 中确定:

3.4 规范驱动实现

这是 OpenSpec 的核心——代码是对规格的映射

3.5 验证与度量

# 验证变更规范
openspec validate v1-mvp

# 验证成功输出
Change 'v1-mvp' is valid

注意:验证命令会检查 Proposal 章节完整性、目录结构、Delta Header 格式以及 Scenario 覆盖率。详细的验证规则与错误排查请参考 OpenSpec 使用手册 - 6. 验证与常见错误

3.6 归档与沉淀

v1-mvp 开发完成并通过验收后,运行 /opsx:archive(推荐)或 CLI 命令 openspec archive。这会将变更集中的 Spec 合并到主规范目录 (openspec/specs/),成为系统最新的事实来源。


4. 案例背景:小型电商网站

4.1 核心域与上下文

本案例构建一个名为 ecommerce-mini 的微型电商系统,包含五个核心上下文:

4.2 简化假设

为了聚焦 OpenSpec 流程,本项目做了以下工程折衷:

4.3 非功能性目标


5. 架构设计

5.1 分层架构

本项目采用经典的四层架构,确保关注点分离:

层级 目录 (src/) 职责 依赖方向
接口层 http/ 处理 HTTP 请求,参数解析,鉴权,响应格式化 -> Application
应用层 services/ 用例编排(Orchestration),如“下单”涉及扣库存、清购物车 -> Domain, Repo
领域层 domain/ 纯净的业务实体 (types.js) 与逻辑,无外部依赖 None
基础设施 repo/, persist/ 数据持久化实现(Memory/File) Implementation Detail

5.2 边界与依赖规则

5.3 数据流概览

以“下单”场景为例:

  1. User 发起 POST /api/orders 请求。
  2. HTTP Layer 解析 Token,验证用户身份。
  3. Order Service 接收请求:
    • 调用 Cart Service 获取当前购物车商品。
    • 调用 Catalog Service 扣减库存(事务一致性边界)。
    • 计算总价,生成订单实体。
  4. Order Repo 保存订单数据。
  5. HTTP Layer 返回 201 Created 及订单详情。

6. 系统设计

6.1 接口协议

采用标准的 RESTful JSON 风格。

6.2 数据模型

在 OpenSpec 中,我们首先在 changes/v1-mvp/specs/domain-model/spec.md 中定义模型。规范文件必须使用 Delta Header + Requirement + Scenario 格式:

Spec 定义 (changes/v1-mvp/specs/domain-model/spec.md):

# Domain Model Specification

## Overview

核心业务实体定义,不依赖任何外部框架。

## ADDED Requirements

### Requirement: 商品实体定义

系统 SHALL 定义商品实体,包含唯一标识、名称、价格和库存。

**Priority**: P0 (Critical)

**Rationale**: 商品是电商系统的核心实体,是所有交易的基础。

#### Scenario: 创建有效商品

Given 需要创建新商品
When 提供商品信息 { id, name, priceCents, stock }
Then 商品实体创建成功
And id 格式为 prod_xxxx
And priceCents >= 0
And stock >= 0

---

### Requirement: 库存非负校验

库存扣减后 MUST NOT 为负数。

**Priority**: P0 (Critical)

**Rationale**: 库存为负会导致超卖,影响业务准确性。

#### Scenario: 库存不足时扣减

Given 商品库存为 5
When 尝试扣减 6 个库存
Then 抛出 OUT_OF_STOCK 错误
And 库存保持不变

代码实现 (src/domain/types.js / JSDoc):

由于本项目使用原生 JS,我们通过 JSDoc 实现对 Spec 的映射:

/**
 * @typedef {Object} Product
 * @property {string} id
 * @property {string} name
 * @property {number} priceCents
 * @property {number} stock
 */

6.3 错误处理

统一错误响应结构,便于前端处理:

{
  "code": "OUT_OF_STOCK",
  "message": "商品 [prod_123] 库存不足"
}

7. 模块详细设计

7.1 Catalog (商品域)

7.2 Cart (购物车域)

7.3 Order (订单域)


8. 接口设计

OpenSpec 的核心优势在于使用 Markdown 编写可读性极强的规格文档,同时保持结构化。在 v1.2.0 中,规范按能力(Capability)组织,每个能力一个文件夹。以下是 openspec/changes/v1-mvp/specs/catalog-management/spec.mdopenspec/changes/v1-mvp/specs/order-management/spec.md 的真实片段:

# Catalog Management Specification

## Overview

商品目录管理能力,涵盖商品的查询、上架与库存管理。

## ADDED Requirements

### Requirement: 商品列表查询

系统 SHALL 提供商品列表查询接口,返回所有可用商品。

**Priority**: P0 (Critical)

**Rationale**: 商品浏览是电商系统的核心入口功能,用户必须能够查看可购买的商品。

#### Scenario: 获取所有商品

Given 系统中存在商品数据
When 用户请求 GET /api/products
Then 返回状态码 200
And 返回商品数组 Product[]
# Order Management Specification

## Overview

订单管理能力,涵盖订单的创建、查询与总价计算。

## ADDED Requirements

### Requirement: 订单创建

系统 SHALL 支持从用户购物车结算生成订单,过程中处理库存扣减与购物车清空。

**Priority**: P0 (Critical)

**Rationale**: 订单创建是交易的核心流程,涉及多模块协调(Cart -> Catalog -> Order)。

#### Scenario: 成功创建订单

Given 用户购物车中有商品
And 商品库存充足
When 发送 POST /api/orders 携带 { userId }
Then 返回状态码 201
And 返回新创建的订单 Order
And 订单状态为 PENDING_PAYMENT
And 购物车被清空
And 库存被扣减

#### Scenario: 创建订单时库存不足

Given 用户购物车中有商品
And 商品库存不足
When 发送 POST /api/orders 携带 { userId }
Then 返回状态码 409
And 返回错误码 OUT_OF_STOCK

注意

9. 规范驱动实现

这是 OpenSpec 的核心——代码是对规格的映射。在编写代码时,开发者(或 AI)应始终打开 Spec 文件作为参考。

9.1 追踪矩阵

建立 Spec ↔ 代码 ↔ 测试 的映射关系,确保每一条 Spec 都有代码落地:

Spec 定义 (Requirements) 代码实现 (Implementation) 验证方式 (Verification)
POST /api/orders src/http/server.js (Route Handler) Integration Test
Response 409: Stock insufficient catch (e) { if (e.message === 'OUT_OF_STOCK') ... } Unit Test (Error Case)
Order.totalCents (Model) src/domain/types.js (Interface) JSDoc / Code Review
p99 < 100ms (SLO) performance.spec.js (Performance Test) CI Pipeline

实践建议:在代码注释中引用对应的 Spec 章节,如 // 对应 Spec: POST /api/orders

9.2 目录结构映射

OpenSpec-practise/
├── docs/                            <-- 文档目录
│   ├── openspec-user-manual.md          <-- OpenSpec 使用手册
│   ├── openspec-practical-guide.md  <-- 实战指南(本文档)
│   └── openspec-ai-workflow-analysis.md  <-- AI 协作流程分析
├── examples/
│   ├── openspec/                    <-- OpenSpec 规范目录
│   │   ├── config.yaml              <-- 项目配置(技术栈、规则等)
│   │   ├── specs/                   <-- 主规范(归档后的事实来源)
│   │   │   ├── catalog-management/spec.md
│   │   │   ├── cart-management/spec.md
│   │   │   ├── order-management/spec.md
│   │   │   ├── payment/spec.md
│   │   │   ├── domain-model/spec.md
│   │   │   └── error-handling/spec.md
│   │   └── changes/v1-mvp/          <-- MVP 变更规范
│   │       ├── .openspec.yaml       <-- 变更元数据
│   │       ├── proposal.md          <-- 对应提案文档
│   │       ├── design.md            <-- 对应设计文档
│   │       ├── tasks.md             <-- 对应任务清单
│   │       └── specs/               <-- Delta 规范(按能力组织)
│   │           ├── catalog-management/spec.md  <-- 商品管理规范
│   │           ├── cart-management/spec.md     <-- 购物车管理规范
│   │           ├── order-management/spec.md    <-- 订单管理规范
│   │           ├── payment/spec.md             <-- 支付规范
│   │           ├── domain-model/spec.md        <-- 领域模型规范
│   │           └── error-handling/spec.md      <-- 错误处理规范
│   ├── ecommerce-mini/              <-- Node.js Implementation
│   │   └── src/
│   │       ├── domain/types.js      <-- 对应 Spec 中的 Data Models
│   │       ├── services/            <-- 对应 Spec 中的 Business Rules
│   │       ├── http/server.js       <-- 对应 Spec 中的 API Definitions
│   │       └── persist/             <-- 对应 Design 中的 Storage Strategy
│   └── ecommerce-mini-python/       <-- Python Implementation

9.3 代码实现示例

Controller 层 (src/http/server.js):

// 对应 Spec: POST /api/orders
if (pathname === "/api/orders" && req.method === "POST") {
  const body = await readJson(req);
  try {
    // 编排业务逻辑 (Orchestration)
    // 1. 检查购物车 (Rule: Cart Not Empty)
    // 2. 检查库存 (Rule: Stock Check)
    // 3. 创建订单
    const order = orderService.createOrder(body.userId);
    return sendJson(res, 201, order);
  } catch (e) {
    if (e.message === "CART_EMPTY")
      return sendError(res, "CART_EMPTY", "购物车为空", 400);
    if (e.message === "OUT_OF_STOCK")
      return sendError(res, "OUT_OF_STOCK", "库存不足", 409);
    throw e;
  }
}

10. 验证与评估:确保实现符合规格

编写代码后,如何有效评估实现与 Spec 之间的一致性?本节介绍 OpenSpec 推荐的验证方法与工具。

10.1 追踪矩阵(Traceability Matrix)

追踪矩阵已在 9.1 追踪矩阵 中给出,建议在编写代码阶段同步维护,确保每一条 Spec 都有对应的代码实现与测试验证。

10.2 从 Scenario 到测试用例

OpenSpec 的 Gherkin 格式场景天然适合转化为测试用例:

Spec 中的场景specs/order-management/spec.md):

#### Scenario: 成功创建订单

Given 用户购物车中有商品
And 商品库存充足
When 发送 POST /api/orders 携带 { userId }
Then 返回状态码 201
And 返回新创建的订单 Order
And 购物车被清空
And 库存被扣减

对应的集成测试__tests__/integration.spec.js):

以下示例假设测试环境服务运行在 http://localhost:3000base 变量指向该地址)。

it('完整购物流程', async () => {
  // 1. 上架商品 → Given 商品库存充足
  const res1 = await fetch(`${base}/api/products`, {...})
  assert.strictEqual(res1.status, 201)

  // 2. 加购 → Given 用户购物车中有商品
  const res2 = await fetch(`${base}/api/cart/items`, {...})
  assert.strictEqual(res2.status, 200)

  // 3. 下单 → When 发送 POST /api/orders
  const res3 = await fetch(`${base}/api/orders`, {...})
  assert.strictEqual(res3.status, 201)  // Then 返回状态码 201
  const order = await res3.json()
  assert.strictEqual(order.totalCents, 1000)  // Then 返回新创建的订单
  assert.strictEqual(order.status, 'PENDING_PAYMENT')
})

10.3 与 TDD 的关系

OpenSpec 不是替代 TDD,而是与 TDD 协同

传统 TDD: 需求 → 写测试 → 写代码 → 重构
OpenSpec + TDD: 需求 → 写 Spec → 验证 Spec → 写测试(基于 Scenario)→ 写代码 → 重构

关键区别

遇到格式报错?请参考 OpenSpec 使用手册 - 6. 验证与常见错误 排查问题。

10.4 代码审查清单

在 PR 审查时,检查实现与 Spec 的一致性:


11. 测试设计:验证规格

测试不是事后补充,而是规格的可执行版本。

11.1 单元测试 (src/domain/logic.spec.js)

针对纯函数逻辑,如金额计算、状态机流转。

import { test } from "node:test";
import assert from "node:assert";
import { calculateTotal } from "./logic.js";

test("calculateTotal sums up item prices", () => {
  const items = [
    { priceCents: 100, quantity: 2 },
    { priceCents: 50, quantity: 1 },
  ];
  const total = calculateTotal(items);
  assert.strictEqual(total, 250);
});

11.2 集成测试 (__tests__/integration.spec.js)

模拟真实用户路径,验证模块间协作。

11.3 性能基线 (performance.spec.js)

定义并验证 SLO。


12. 示例代码操作手册

12.1 准备环境

本项目无 package.json 依赖(除开发工具外),不仅展示了原生能力,也降低了试运行门槛。

12.2 运行开发版服务

开发版使用内存存储,重启后数据重置。

# 启动服务
node examples/ecommerce-mini/src/http/server.js

# 在另一个终端运行测试套件
node --test examples/ecommerce-mini/__tests__/

12.3 运行生产版服务

生产版开启了文件持久化、鉴权与幂等性检查。

# 启动生产服务 (Port 3002)
node examples/ecommerce-mini/src/http/server.prod.js

13. 生产级扩展实践

为了演示 OpenSpec 如何应对复杂性,我们在 server.prod.js 中引入了三个高级特性。

13.1 持久化存储 (src/persist/fileStore.js)

Spec 变更: 系统需要即使在重启后也能保留用户数据。

实现:

13.2 鉴权与安全

Spec 变更: 所有非公开接口必须携带 Bearer Token。

实现:

13.3 幂等性 (Idempotency)

Spec 变更: 对同一订单的重复支付请求,系统应返回相同结果且不重复扣款。

实现:

13.4 可观测性

Spec 变更: 系统需暴露 /metrics 端点供监控采集。

实现:


14. 结语

通过 ecommerce-mini 案例,我们展示了 OpenSpec 如何贯穿从 “Proposal” 到 “Production” 的全生命周期。

希望本实战指南能帮助你在实际项目中更好地应用 OpenSpec 方法论。