06 技术设计:把需求变成可并行的契约¶
技术设计阶段是整套流程的“腰”。腰不硬,前后都使不上劲:需求再清楚,前端和后端各写各的;测试再努力,接口语义不一致;Agent 再多,合并时一锅粥。
本章的目标只有一个:在写第一行业务代码之前,把契约冻结。
1. 输入与输出¶
1.1 输入¶
docs/00-discovery/spec.mddocs/00-discovery/user-story.csvdocs/00-discovery/user-story-details.mddocs/02-ui/ui-spec.mddocs/02-ui/design-tokens.json- 技术选型 ADR(见 04 后端技术选型)
- 环境约束(AWS、域名、证书、CI/CD、合规)
1.2 输出¶
| 产物 | 路径 | 作用 |
|---|---|---|
| 技术设计总文档 | docs/01-design/tech-design.md |
架构、组件、数据流、技术决策 |
| API 契约 | docs/01-design/api/openapi.yaml |
前后端唯一接口事实 |
| 数据库模型 | docs/01-design/db/schema.sql |
表、索引、约束、迁移策略 |
| 架构决策记录 | docs/01-design/adr/ADR-xxx.md |
关键选择的背景与后果 |
| 功能实现细节 | docs/01-design/feature-implementation.md |
每个故事怎么实现、怎么测 |
| 文件所有权清单 | docs/01-design/file-ownership.md |
多 Agent 并行时谁改哪些文件 |
| 测试策略 | docs/01-design/test-strategy.md |
单测/集成/E2E 的范围与门禁 |
| 项目 AI 约定 | CLAUDE.md |
每次会话自动加载的“项目宪法” |
| 发布拓扑 | docs/01-design/deployment.md |
环境、网络、域名、证书、回滚 |
注意:user-story.csv 和 user-story-details.md 是需求阶段的产物,但技术设计阶段要 回填 API 引用、表名、实现报告路径等字段。CSV 是贯穿全流程的索引。
2. 技术设计的六个原则¶
原则一:契约优先(Contract First)¶
先写 OpenAPI 和 schema,再写实现。不要让后端“先写着,回头再补文档”。
原则二:单一事实源(Single Source of Truth)¶
- 接口字段只以 OpenAPI 为准;
- 数据库结构只以
schema.sql为准; - 状态枚举只在一处定义;
- 错误码只在一处定义;
- 用户在
spec.md,实现细节在feature-implementation.md。
原则三:可并行(Parallelizable)¶
每个模块有清晰的边界、文件所有权和依赖顺序。两个 Agent 不应该改同一个文件。
原则四:请求隔离(Request Isolation)¶
见 04 后端技术选型。技术设计里要明确:
- 哪些状态是全局的(尽量少);
- 哪些是每请求的;
- 哪些是每租户的;
- 事务边界在哪里;
- 幂等策略是什么。
原则五:可测试(Testable)¶
每个业务规则都要能映射到一个测试。设计文档里写清楚“怎么测”,而不是只写“怎么实现”。
原则六:可回滚(Rollbackable)¶
数据库迁移、部署、功能开关都要有回滚方案。AI 很擅长“往前冲”,你要提前设计“怎么退”。
3. tech-design.md 结构¶
# 技术设计:<产品名>
## 1. 背景与目标
## 2. 非目标
## 3. 架构总览
## 4. 组件与职责
## 5. 关键数据流
## 6. API 设计规范
## 7. 数据库设计
## 8. 鉴权与权限
## 9. 错误处理
## 10. 并发与请求隔离
## 11. 性能与容量
## 12. 安全与隐私
## 13. 可观测性
## 14. 部署拓扑
## 15. 测试策略
## 16. 风险与缓解
## 17. 里程碑与并行计划
## 18. 未决问题
3.1 架构总览示例¶
┌────────────────────────────────────────────────────────────┐
│ Browser (Vue SPA) │
│ Vue Router / Pinia / API Client / UI Components │
└───────────────────────────┬────────────────────────────────┘
│ HTTPS / JSON
▼
┌────────────────────────────────────────────────────────────┐
│ CDN + Static Hosting │
│ S3 + CloudFront / Nginx │
└───────────────────────────┬────────────────────────────────┘
│ /api/v1/*
▼
┌────────────────────────────────────────────────────────────┐
│ API Gateway / ALB │
│ TLS / 路由 / 限流 / 访问日志 │
└───────────────────────────┬────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ Go API Service │
│ Router → Middleware → Handler → Usecase → Repository │
│ RequestID / Auth / Recover / Timeout / RateLimit │
└───────────────┬────────────────────────────┬───────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ PostgreSQL (RDS) │ │ Redis (可选) │
│ 业务数据 / 审计日志 │ │ 会话 / 幂等 / 限流 │
└──────────────────────────┘ └──────────────────────────┘
│
▼
┌──────────────────────────┐
│ S3 (附件) / SES (邮件) │
└──────────────────────────┘
3.2 组件职责¶
| 组件 | 职责 | 不负责 |
|---|---|---|
| 前端 SPA | 页面、交互、状态、前端校验 | 权限最终判断、敏感数据 |
| API 服务 | 业务逻辑、鉴权、校验、审计 | 静态资源托管、邮件实际发送 |
| PostgreSQL | 持久化、约束、事务 | 业务规则(尽量用约束兜底) |
| Redis | 会话、幂等、限流、缓存 | 作为唯一数据源 |
| S3 | 附件、导出文件 | 公开可写 |
| 邮件服务 | 发送通知 | 业务状态 |
| 监控 | 日志、指标、告警 | 业务逻辑 |
3.3 关键数据流:创建一个任务¶
1. 用户在 Vue 页面点击“创建任务”
2. 前端校验标题/负责人/日期
3. POST /api/v1/tasks + Idempotency-Key
4. Gateway 转发到 API
5. Middleware:RequestID → Auth → RateLimit
6. Handler:解析 JSON、校验 DTO
7. Usecase:
a. 查项目是否存在、是否归档
b. 查用户是否是项目成员
c. 校验负责人是否是项目成员
d. 开启事务
e. 插入 tasks
f. 写入 audit_logs
g. 提交事务
h. 异步发送通知(写 outbox / 队列)
8. 返回 201 + TaskResponse
9. 前端乐观更新看板;失败回滚
把这个流程写进文档,前端、后端、测试 Agent 就有了同一张地图。
4. API 设计规范¶
4.1 URL 与版本¶
/api/v1/projects
/api/v1/projects/{project_id}
/api/v1/projects/{project_id}/members
/api/v1/tasks/{task_id}
规则:
- 资源用复数名词;
- 层级不超过 2-3 层;
- 动作用子资源或 PATCH,不要
/doSomething; - 版本放在路径中(
/v1); - 破坏性变更升版本,不悄悄改字段语义。
4.2 HTTP 方法与状态码¶
| 方法 | 用途 | 成功码 |
|---|---|---|
| GET | 查询 | 200 |
| POST | 创建 | 201 |
| PUT | 全量替换 | 200 |
| PATCH | 部分更新 | 200 |
| DELETE | 删除 | 204 |
错误码:
| 状态码 | 场景 |
|---|---|
| 400 | 参数校验失败 |
| 401 | 未认证 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 409 | 冲突(重复、状态不允许) |
| 422 | 语义校验失败(可选,统一用 400 也行) |
| 429 | 限流 |
| 500 | 服务内部错误 |
| 503 | 依赖不可用 |
4.3 统一响应格式¶
成功:
列表:
{
"data": [
{ "id": "...", "title": "..." }
],
"pagination": {
"page": 1,
"page_size": 20,
"total": 137,
"total_pages": 7
}
}
错误:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "标题不能为空",
"request_id": "01J...",
"details": { "field": "title" }
}
}
统一格式非常重要:前端可以写一个拦截器处理所有错误,测试可以断言统一结构。
4.4 分页、排序、过滤¶
规则:
page从 1 开始;page_size默认 20,最大 100;sort=-field表示降序;- 过滤参数显式列出,不要接受任意字段;
- 大数据量考虑游标分页(
cursor)。
4.5 幂等¶
写操作支持:
服务端行为:
- 第一次:执行并记录 key → response;
- 重复:直接返回第一次的 response;
- key 过期时间:24 小时;
- key 作用域:用户 + 路由。
4.6 时间与时区¶
- API 中所有时间用 ISO 8601 UTC:
2026-10-25T12:00:00Z。 - 纯日期用
YYYY-MM-DD(如截止日期)。 - 前端负责按用户时区展示。
- 数据库用
TIMESTAMPTZ。
4.7 鉴权¶
推荐:
- 短期 access token(15 分钟)+ 长期 refresh token(7 天,可撤销);
- 或者 httpOnly cookie + CSRF token;
- 不要在前端 localStorage 存长期令牌(XSS 风险);
- 所有对象级权限在后端校验。
在 OpenAPI 中声明:
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: []
4.8 OpenAPI 示例¶
openapi: 3.1.0
info:
title: TeamTask API
version: 1.0.0
servers:
- url: http://localhost:8080/api/v1
description: local
- url: https://staging-api.example.com/api/v1
description: staging
- url: https://api.example.com/api/v1
description: production
paths:
/tasks:
post:
summary: 创建任务
operationId: createTask
security:
- bearerAuth: []
parameters:
- in: header
name: Idempotency-Key
schema:
type: string
format: uuid
required: false
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'400':
$ref: '#/components/responses/ValidationError'
'403':
$ref: '#/components/responses/Forbidden'
'409':
$ref: '#/components/responses/Conflict'
components:
schemas:
CreateTaskRequest:
type: object
required: [project_id, title, assignee_id, priority]
properties:
project_id:
type: string
format: uuid
title:
type: string
minLength: 1
maxLength: 100
description:
type: string
maxLength: 2000
assignee_id:
type: string
format: uuid
due_date:
type: string
format: date
priority:
type: string
enum: [low, medium, high]
TaskResponse:
type: object
required: [id, project_id, title, status, priority, created_at]
properties:
id:
type: string
format: uuid
project_id:
type: string
format: uuid
title:
type: string
description:
type: string
nullable: true
assignee_id:
type: string
format: uuid
nullable: true
due_date:
type: string
format: date
nullable: true
priority:
type: string
enum: [low, medium, high]
status:
type: string
enum: [todo, in_progress, done]
version:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
Error:
type: object
required: [error]
properties:
error:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
request_id:
type: string
details:
type: object
additionalProperties: true
responses:
ValidationError:
description: 参数校验失败
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Forbidden:
description: 无权限
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Conflict:
description: 冲突
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
4.9 OpenAPI 门禁¶
要求:
- 所有 operation 有
operationId; - 所有响应有 schema;
- 所有错误响应有统一结构;
- 所有字段有类型和约束;
- 没有未使用的 schema;
- 示例请求/响应可运行。
5. 数据库设计¶
5.1 设计步骤¶
- 从用户故事中提取名词 → 候选实体。
- 确定实体关系(1:1、1:N、M:N)。
- 确定主键、外键、唯一约束。
- 确定状态字段和状态转换。
- 确定审计、软删除、多租户字段。
- 确定高频查询 → 索引。
- 确定迁移顺序。
5.2 实体清单示例¶
| 实体 | 说明 | 关键字段 |
|---|---|---|
users |
用户 | email, password_hash, display_name, status |
projects |
项目 | tenant_id, name, short_code, status |
project_members |
项目成员 | project_id, user_id, role |
tasks |
任务 | project_id, title, assignee_id, due_date, priority, status, version |
comments |
评论 | task_id, author_id, body |
audit_logs |
审计日志 | tenant_id, actor_id, action, resource, request_id |
outbox |
异步事件 | aggregate_type, aggregate_id, event_type, payload, status |
5.3 状态机¶
在文档中写清楚:
- 哪些转换允许;
- 谁可以转换;
- 转换失败返回什么错误码;
- 是否需要并发控制(
version)。
5.4 索引原则¶
- 外键列加索引(PostgreSQL 不自动加)。
- 高频过滤/排序组合加复合索引。
- 软删除表用部分索引:
WHERE deleted_at IS NULL。 - 不要给每个列都加索引;写入也会变慢。
- 用
EXPLAIN ANALYZE验证关键查询。
5.5 迁移策略¶
migrations/
├── 00001_init.sql
├── 00002_add_projects.sql
├── 00003_add_tasks.sql
└── 00004_add_audit_logs.sql
规则:
- 已上线迁移不可修改;
- 每次迁移可重复执行或由版本表控制;
- 生产迁移先备份;
- 大表变更用
CONCURRENTLY/ 分批; - 破坏性变更走 expand-contract;
- 回滚脚本单独准备。
6. feature-implementation.md:每个故事怎么落地¶
这份文档是给开发 Agent 的“施工图”。它比 tech-design.md 更细,比 user-story-details.md 更技术。
6.1 结构¶
每个故事使用显式锚点
<a id="us-004"></a>,保证feature-implementation.md#us-004可跳转。完整模板见 模板/feature-implementation.md。
## US-004 创建任务
### 1. 涉及模块
- backend/internal/usecase/task
- backend/internal/adapter/http/task_handler.go
- backend/internal/adapter/postgres/repo/task_repo.go
- frontend/src/views/ProjectBoardView.vue
- frontend/src/components/task/CreateTaskModal.vue
### 2. 数据表
- 读:projects, project_members, users
- 写:tasks, audit_logs
### 3. API
- POST /api/v1/tasks
- 请求/响应见 OpenAPI `createTask`
### 4. 业务逻辑
1. 校验 project_id 存在且未归档。
2. 校验当前用户是项目成员。
3. 校验 assignee_id 是项目成员。
4. 校验 due_date 不早于今天(按用户时区)。
5. 生成任务编号。
6. 插入 tasks。
7. 写 audit_logs。
8. 写 outbox(任务创建事件)。
9. 返回 TaskResponse。
### 5. 事务边界
- 从步骤 6 到步骤 8 在一个事务内。
- 通知发送在事务外,由 worker 消费 outbox。
### 6. 错误码
| 场景 | 状态码 | 错误码 |
|---|---|---|
| 标题为空 | 400 | VALIDATION_ERROR |
| 项目不存在 | 404 | PROJECT_NOT_FOUND |
| 非项目成员 | 403 | FORBIDDEN |
| 项目已归档 | 409 | PROJECT_ARCHIVED |
| 负责人不在项目 | 400 | ASSIGNEE_NOT_IN_PROJECT |
### 7. 并发与幂等
- 同一 Idempotency-Key 24 小时内只创建一次。
- 任务编号生成使用数据库序列,避免并发重复。
- 乐观锁 version 用于更新,不用于创建。
### 8. 前端
- 弹窗表单,字段见 ui-spec。
- 提交时禁用按钮。
- 成功后关闭弹窗、乐观插入卡片、toast。
- 失败时保留输入、显示字段错误。
### 9. 测试
- 单元测试:校验、权限、状态转换。
- 集成测试:插入、审计、幂等、唯一约束。
- E2E:正常创建、空标题、无权限、日期非法。
### 10. 可观测性
- 日志:request_id, user_id, project_id, task_id, duration_ms。
- 指标:task_created_total。
- 审计:task.created。
### 11. 依赖与顺序
- 依赖 US-002、US-003。
- 可与 US-005 并行,但 US-005 依赖本故事的 `TaskResponse`。
### 12. 文件所有权
- 后端:`internal/usecase/task/**`, `internal/adapter/http/task_handler.go`, `internal/adapter/postgres/repo/task_repo.go`
- 前端:`src/components/task/CreateTaskModal.vue`, `src/views/ProjectBoardView.vue`
- 测试:`**/task*_test.go`, `frontend/src/components/task/__tests__/**`
- 禁止修改:`internal/adapter/http/router.go`(由架构 Agent 统一维护)
6.2 写作检查¶
- 每个业务规则都有对应实现位置。
- 每个错误码都有触发条件。
- 事务边界明确。
- 幂等/并发策略明确。
- 前端状态明确。
- 测试用例明确。
- 文件所有权明确。
- 依赖顺序明确。
7. 文件所有权:多 Agent 并行的“交通规则”¶
7.1 为什么需要¶
两个 Agent 同时改 router.go,必然冲突。冲突本身不可怕,可怕的是 Agent 在冲突后自行“修复”,把别人的路由删了。
7.2 所有权清单示例¶
# 文件所有权
## 架构 Agent(串行,先完成)
- backend/cmd/api/main.go
- backend/internal/adapter/http/router.go
- backend/internal/config/**
- backend/api/openapi.yaml
- backend/migrations/**(迁移由架构 Agent 统一编号)
- frontend/src/router/index.ts
- frontend/src/api/client.ts
## 后端 Agent 1(US-001 认证)
- backend/internal/usecase/auth/**
- backend/internal/adapter/http/auth_handler.go
- backend/internal/adapter/postgres/repo/user_repo.go
- backend/internal/adapter/http/middleware/auth.go
- 测试:对应 `_test.go`
## 后端 Agent 2(US-002/US-003 项目与成员)
- backend/internal/usecase/project/**
- backend/internal/usecase/member/**
- backend/internal/adapter/http/project_handler.go
- backend/internal/adapter/http/member_handler.go
- backend/internal/adapter/postgres/repo/project_repo.go
- backend/internal/adapter/postgres/repo/member_repo.go
## 后端 Agent 3(US-004/US-005 任务)
- backend/internal/usecase/task/**
- backend/internal/adapter/http/task_handler.go
- backend/internal/adapter/postgres/repo/task_repo.go
## 前端 Agent 1
- frontend/src/views/**
- frontend/src/components/task/**
- frontend/src/components/project/**
## 前端 Agent 2
- frontend/src/components/ui/**
- frontend/src/styles/**
## 测试 Agent
- docs/04-qa/**
- scripts/e2e/**
- 不修改业务代码;发现 bug 写 issue 给对应 Agent
7.3 共享文件的修改流程¶
共享文件(router、main、openapi、schema、package.json)由 架构 Agent 串行修改,其他 Agent 只能提交“变更请求”:
Agent 发现需要新增路由
→ 不直接改 router.go
→ 在 docs/01-design/change-requests/CR-001.md 写:
需要新增 POST /tasks
对应 handler: task_handler.Create
对应 OpenAPI operationId: createTask
→ 架构 Agent 审核后统一修改 router.go + openapi.yaml
→ 通知相关 Agent 重新拉取
如果觉得这个流程太重,至少要做到:共享文件只允许一个 Agent 改,改完立刻提交并通知其他人。
8. CLAUDE.md:项目宪法¶
CLAUDE.md 每次会话都会加载,必须短而关键。详细内容链接到 docs/。
8.1 推荐结构¶
# 项目:TeamTask
## 一句话
一个面向 20-50 人咨询团队的任务协作系统。
## 技术栈
- 前端:Vue 3 + TypeScript + Vite + Pinia
- 后端:Go 1.23 + chi + pgx + sqlc
- 数据库:PostgreSQL 16
- 测试:go test / Vitest / Chrome MCP
- 部署:Docker + AWS ECS + S3/CloudFront
## 目录
- `backend/` Go API
- `frontend/` Vue SPA
- `docs/00-discovery/` 需求
- `docs/01-design/` 技术设计
- `docs/02-ui/` UI 规格
- `docs/03-dev/reports/` 功能报告
- `docs/04-qa/` E2E 与 Word 报告
## 常用命令
- `make dev` 启动数据库和应用
- `make test` 跑全部单元/集成测试
- `make lint` 格式 + 静态检查
- `make e2e` 跑 Chrome MCP E2E
- `make report` 生成 Word 报告
- `make migrate-up` 执行迁移
## 约定
- 先读契约:`docs/01-design/api/openapi.yaml`、`docs/01-design/db/schema.sql`
- 不修改未授权的共享文件(见 `docs/01-design/file-ownership.md`)
- 所有新代码必须有测试
- 所有错误使用统一错误码
- 所有时间用 UTC
- 所有权限在后端校验
- 不把密钥写入代码或日志
- 完成后按 `模板/feature-report.md` 生成报告
- 用 `scripts/update_story_status.py` 更新 CSV
## 禁止
- 不要改 `migrations/` 中已上线的文件
- 不要在生产环境执行写操作
- 不要绕过类型检查(`any`、`@ts-ignore`)
- 不要在日志中输出令牌/密码
- 不要删除测试来让 CI 变绿
## 完成定义
见 `docs/01-design/definition-of-done.md`
8.2 不要写什么¶
- 不要粘贴整个 API 文档(放链接)。
- 不要写长篇业务背景(放
spec.md)。 - 不要写会频繁变化的临时状态(放 CSV)。
- 不要写“请努力”“要仔细”这种无法执行的指令。
9. 测试策略¶
9.1 测试金字塔¶
┌─────────────┐
│ E2E (10%) │ Chrome MCP / Playwright
├─────────────┤
│ 集成 (20%) │ 真实 DB / API / 契约
├─────────────┤
│ 单元 (70%) │ domain / usecase / components
└─────────────┘
9.2 每个故事的测试要求¶
| 类型 | 必须覆盖 |
|---|---|
| 单元测试 | 正常路径、边界、错误码、权限判断 |
| 集成测试 | 数据库约束、事务、幂等、审计 |
| API 测试 | 状态码、响应结构、鉴权、错误格式 |
| E2E | 用户主流程 + 至少 2 个异常分支 |
9.3 测试数据¶
- 使用种子脚本创建固定测试数据;
- 测试数据带唯一前缀(如
e2e-<run_id>-),避免污染; - 测试账号权限最小化;
- 生产环境只用测试租户,不碰真实数据;
- 测试结束清理(或保留一段时间供排查)。
9.4 覆盖率与质量¶
- 覆盖率是下限,不是目标;
- 关键模块 ≥ 80%;
- 关键 bug 修复必须加回归测试;
- 定期做变异测试(可选),检查测试是否真的能发现问题。
10. 部署拓扑与环境¶
10.1 环境¶
| 环境 | 用途 | 数据 | 访问 |
|---|---|---|---|
| local | 开发 | 本地 Docker | 开发者 |
| dev | 联调 | 测试数据 | 团队 |
| staging | 预发验收 | 脱敏/合成数据 | 团队 + 产品 |
| prod | 生产 | 真实数据 | 受限 |
10.2 拓扑要点¶
- 前端静态资源走 CDN;
- API 走负载均衡/网关;
- 数据库不暴露公网;
- 密钥放 Secrets Manager;
- 日志/指标集中收集;
- 每个环境独立数据库;
- 生产变更需审批。
10.3 回滚¶
- 镜像版本可追溯;
- 数据库迁移可回滚;
- 功能开关可关闭;
- 回滚步骤写在
deployment.md; - 回滚后跑冒烟测试。
11. 风险与缓解¶
在 tech-design.md 里列一个风险表:
| 风险 | 概率 | 影响 | 缓解 |
|---|---|---|---|
| AWS 权限不足 | 中 | 高 | 提前申请,准备备用账号 |
| Figma MCP 不可写 | 中 | 中 | 用 HTML 原型或插件 |
| E2E 登录需要 2FA | 高 | 中 | 使用测试账号 + 持久 profile |
| 并发写入冲突 | 中 | 高 | 乐观锁 + 幂等 |
| 迁移锁表 | 中 | 高 | CONCURRENTLY + 分批 |
| AI 生成测试造假 | 中 | 高 | 审查测试 + 变异测试 |
| 生产测试数据污染 | 中 | 高 | 测试租户 + 前缀 + 清理 |
12. 架构评审清单(G4 契约门禁)¶
在冻结契约前,逐项检查:
12.1 API¶
- 所有 P0/P1 故事都有对应 endpoint
- OpenAPI lint 通过
- 请求/响应有 schema 和示例
- 错误格式统一
- 分页/排序/过滤规则统一
- 鉴权方式明确
- 幂等策略明确
- 时间/时区规则明确
12.2 数据库¶
- 所有实体有表
- 主键/外键/唯一约束合理
- 高频查询有索引
- 软删除/审计/多租户字段齐全
- 迁移顺序和回滚方案明确
- 大表变更方案明确
12.3 架构¶
- 组件职责清晰
- 依赖方向正确
- 请求隔离规则明确
- 事务边界明确
- 异步/队列策略明确
- 缓存 key 规则明确
12.4 测试¶
- 每个故事有测试计划
- 集成测试环境可运行
- E2E 测试账号/数据就绪
- CI 门禁命令明确
12.5 并行¶
- 文件所有权清单完成
- 依赖顺序图完成
- 共享文件修改流程明确
- 迁移编号规则明确
12.6 AI 约定¶
-
CLAUDE.md更新 - 构建/测试/运行命令可直接复制执行
- 禁止事项明确
- 完成定义明确
13. 架构 Agent 提示词¶
13.1 生成技术设计¶
你是资深架构师。请基于以下输入生成技术设计:
输入:
- 需求:@docs/00-discovery/spec.md
- 用户故事:@docs/00-discovery/user-story.csv
- 故事细节:@docs/00-discovery/user-story-details.md
- UI 规格:@docs/02-ui/ui-spec.md
- 技术选型:@docs/01-design/adr/ADR-001-backend-stack.md
- 约束:3 周上线、AWS、1 人 + AI 团队
请输出:
1. `docs/01-design/tech-design.md`,严格按模板结构。
2. `docs/01-design/api/openapi.yaml`,覆盖所有 P0/P1 故事。
3. `docs/01-design/db/schema.sql`,包含表、索引、约束、注释。
4. `docs/01-design/feature-implementation.md`,每个故事一节。
5. `docs/01-design/file-ownership.md`,模块与文件归属。
6. `docs/01-design/test-strategy.md`。
7. `docs/01-design/deployment.md`。
8. 更新 `CLAUDE.md`。
约束:
- 不要发明需求;不确定的列入“未决问题”。
- API 必须使用统一错误格式和分页格式。
- 数据库必须考虑多租户、审计、软删除。
- 请求隔离规则必须具体。
- 每个设计决策说明理由和替代方案。
- 输出前自查:有没有字段在 OpenAPI 中不存在?有没有故事没有 API?有没有表没有索引?
13.2 架构批判¶
你是苛刻的架构评审专家。请审查以下文件:
- @docs/01-design/tech-design.md
- @docs/01-design/api/openapi.yaml
- @docs/01-design/db/schema.sql
- @docs/01-design/feature-implementation.md
请找出:
1. 无法支撑需求的设计缺口
2. 前后端契约不一致
3. 数据库约束/索引/迁移风险
4. 权限模型漏洞
5. 并发/事务/幂等风险
6. 单点故障和扩展性问题
7. 测试无法覆盖的地方
8. 过度设计
9. 文件所有权冲突
10. 缺失的回滚方案
输出表格:编号、位置、问题、影响、建议、严重度。
不要改文件。
13.3 契约冻结检查¶
请做一次契约冻结前的最终检查:
1. 遍历 user-story.csv 中所有 P0/P1 故事。
2. 对每个故事,确认:
- 是否有对应 API operationId
- 是否有对应数据表
- 是否有 feature-implementation 章节
- 是否有文件所有权
- 是否有测试计划
3. 输出缺失矩阵。
4. 如果存在缺失,不要冻结;列出需要补的内容。
5. 如果全部齐全,输出“契约可冻结”,并列出冻结版本号。
14. 契约变更管理¶
契约冻结不是“永远不能改”,而是“改要有流程”。
14.1 变更请求(CR)¶
# CR-001 任务增加“标签”字段
## 提出人
前端 Agent 1
## 原因
设计稿中有标签筛选,但 OpenAPI 缺少标签字段。
## 影响
- OpenAPI: CreateTaskRequest/TaskResponse 增加 `tags: string[]`
- DB: 新增 `task_tags` 表
- 前端: 任务卡片显示标签
- 测试: 新增标签相关用例
## 兼容性
向后兼容(新增可选字段)。
## 决策
待架构 Agent + 人确认。
14.2 变更规则¶
- 新增可选字段:向后兼容,可直接加。
- 修改字段语义/类型:破坏性,需升版本或双写过渡。
- 删除字段:先标记 deprecated,观察一个发布周期后再删。
- 所有变更记录在
docs/01-design/change-log.md。 - 变更后重新生成前端类型、更新测试、通知所有 Agent。
15. 本章交付清单¶
-
tech-design.md完成并通过架构批判 -
openapi.yaml通过 lint,覆盖所有 P0/P1 故事 -
schema.sql完成,索引/约束/迁移策略明确 -
feature-implementation.md每个故事一节 -
file-ownership.md完成 -
test-strategy.md完成 -
deployment.md完成 -
CLAUDE.md更新 - ADR 记录关键决策
- CSV 回填了 API/表/报告路径
- G4 契约门禁由人确认
下一章:07 AI 编码与多 Agent 并行开发 —— 契约冻结后,如何让多个 Agent 高效、不冲突地实现。