第六章:文档编写规范
为什么文档质量很重要
OpenSpec 的核心是规范文档。文档质量直接决定 AI 实现的质量。
模糊的规范 → AI 猜测 → 实现偏差 → 反复修改
清晰的规范 → AI 理解 → 精准实现 → 一次到位
proposal.md 编写指南
必须包含
| 字段 | 说明 | 示例 |
|---|---|---|
| 背景 | 为什么要做 | "当前没有用户认证,存在安全风险" |
| 目标 | 要达成什么 | "实现安全的用户登录功能" |
| 范围 | 做什么/不做什么 | "包含手机号登录,不包含邮箱登录" |
| 成功标准 | 怎么算完成 | "用户可以成功登录并访问受保护页面" |
好的 vs 差的
❌ 差的提案:
# 提案:改进登录
需要改进登录功能,让它更好用。
✅ 好的提案:
# 提案:添加手机号验证码登录
## 背景
当前系统使用用户名+密码登录,用户反馈记不住密码,
导致每周有 200+ 次"忘记密码"请求,占客服工作量的 30%。
## 目标
- 添加手机号 + 验证码登录方式
- 减少密码相关的客服请求
## 范围
**包含**:
- 手机号 + 短信验证码登录
- 与现有账号绑定(通过手机号匹配)
**不包含**:
- 替换现有用户名+密码登录(保留)
- 微信登录(下一期)
## 成功标准
- 用户可以用手机号 + 验证码成功登录
- 登录成功率 > 99%
- 验证码发送延迟 < 5 秒
specs/ 编写指南
需求要可测试
每个需求都应该能被测试:
❌ 不可测试:
- 系统要快
- 界面要好看
- 用户体验要好
✅ 可测试:
- API 响应时间 < 200ms(P99)
- 登录页面在 375px 宽度下正常显示
- 验证码输入框自动聚焦
场景要完整
不只写正常流程,还要写异常流程:
## 场景
### 正常场景
1. 用户输入正确验证码
2. 登录成功,跳转首页
### 异常场景 1:验证码错误
1. 用户输入错误验证码
2. 提示"验证码错误,还有 2 次机会"
### 异常场景 2:验证码过期
1. 用户输入已过期验证码
2. 提示"验证码已过期,请重新获取"
### 异常场景 3:网络错误
1. 发送验证码时网络断开
2. 提示"网络错误,请检查网络连接"
3. 按钮恢复可点击状态
### 边界场景:频繁发送
1. 用户 1 分钟内点击 2 次"获取验证码"
2. 第 2 次点击时提示"请 XX 秒后再试"
使用具体数字
❌ 模糊:
- 验证码有一定的有效期
- 支持多次重试
- 密码要足够复杂
✅ 具体:
- 验证码有效期 5 分钟
- 最多重试 3 次,超过后锁定 60 秒
- 密码至少 8 位,包含大小写字母和数字
design.md 编写指南
API 设计要完整
每个接口都要包含:
### POST /api/auth/login
**描述**:用户登录
**请求头**:
Content-Type: application/json
**请求体**:
```json
{
"phone": "13800138000", // 手机号,必填
"code": "123456" // 验证码,必填
}
成功响应 (200):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 604800,
"user": {
"id": 1,
"phone": "138****8000"
}
}
}
错误响应 (400):
{
"success": false,
"error": {
"code": "INVALID_CODE",
"message": "验证码错误"
}
}
错误码:
| 错误码 | 说明 |
|---|---|
| INVALID_CODE | 验证码错误 |
| CODE_EXPIRED | 验证码已过期 |
| TOO_MANY_ATTEMPTS | 尝试次数过多 |
### 数据模型要清晰
```markdown
## 数据模型
### User
```typescript
interface User {
id: number;
phone: string; // 手机号,唯一
wechat_openid?: string; // 微信 OpenID,可选
created_at: Date;
last_login_at: Date;
}
VerificationCode
interface VerificationCode {
id: number;
phone: string;
code: string; // 6 位数字
expires_at: Date; // 5 分钟后过期
used: boolean; // 是否已使用
created_at: Date;
}
---
## tasks.md 编写指南
### 任务要原子化
每个任务应该是**独立可完成**的最小单元:
**❌ 太大**:
```markdown
- [ ] 1.1 实现登录功能
✅ 原子化:
- [ ] 1.1 创建 users 数据库表
- [ ] 1.2 创建 verification_codes 数据库表
- [ ] 1.3 实现 POST /api/auth/send-code 接口
- [ ] 1.4 实现 POST /api/auth/login 接口
- [ ] 1.5 为 send-code 接口添加频率限制
- [ ] 1.6 编写 send-code 接口单元测试
- [ ] 1.7 编写 login 接口单元测试
任务要有顺序
按依赖关系排序:
## 1. 基础设施(先做)
- [ ] 1.1 创建数据库表
- [ ] 1.2 配置 Redis 连接
## 2. 后端 API(依赖 1)
- [ ] 2.1 实现发送验证码接口
- [ ] 2.2 实现登录接口
## 3. 前端页面(依赖 2)
- [ ] 3.1 创建登录页面
- [ ] 3.2 集成 API
## 4. 测试(最后)
- [ ] 4.1 单元测试
- [ ] 4.2 集成测试
包含测试任务
## 4. 测试
- [ ] 4.1 单元测试
- [ ] 4.1.1 测试验证码生成逻辑
- [ ] 4.1.2 测试 Token 生成和验证
- [ ] 4.1.3 测试频率限制逻辑
- [ ] 4.2 集成测试
- [ ] 4.2.1 测试完整登录流程
- [ ] 4.2.2 测试异常场景
- [ ] 4.3 手动测试清单
- [ ] 4.3.1 在 iOS Safari 测试
- [ ] 4.3.2 在 Android Chrome 测试
- [ ] 4.3.3 测试网络断开场景
常见错误
1. 规范太模糊
# ❌
用户可以登录系统
# ✅
用户可以通过手机号 + 6 位数字验证码登录系统,
验证码有效期 5 分钟,错误 3 次后锁定 60 秒
2. 遗漏异常场景
# ❌ 只写了正常流程
用户输入验证码,点击登录,跳转首页
# ✅ 包含异常场景
正常:用户输入正确验证码,登录成功,跳转首页
异常 1:验证码错误,提示剩余次数
异常 2:验证码过期,提示重新获取
异常 3:网络错误,提示检查网络
3. 技术方案不明确
# ❌
使用某种方式存储 Token
# ✅
Token 存储在 localStorage,key 为 "auth_token",
格式为 JWT,有效期 7 天,过期后自动清除并跳转登录页
下一步
→ 第七章:实战案例