跳转至

06 技术设计:把需求变成可并行的契约

技术设计阶段是整套流程的“腰”。腰不硬,前后都使不上劲:需求再清楚,前端和后端各写各的;测试再努力,接口语义不一致;Agent 再多,合并时一锅粥。

本章的目标只有一个:在写第一行业务代码之前,把契约冻结。


1. 输入与输出

1.1 输入

  • docs/00-discovery/spec.md
  • docs/00-discovery/user-story.csv
  • docs/00-discovery/user-story-details.md
  • docs/02-ui/ui-spec.md
  • docs/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": "..." }
}

列表:

{
  "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 分页、排序、过滤

GET /api/v1/tasks?project_id=...&status=todo&page=1&page_size=20&sort=-due_date

规则:

  • page 从 1 开始;
  • page_size 默认 20,最大 100;
  • sort=-field 表示降序;
  • 过滤参数显式列出,不要接受任意字段;
  • 大数据量考虑游标分页(cursor)。

4.5 幂等

写操作支持:

Idempotency-Key: <uuid>

服务端行为:

  • 第一次:执行并记录 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 门禁

# 使用 redocly 或 spectral 校验
npx @redocly/cli lint docs/01-design/api/openapi.yaml

要求:

  • 所有 operation 有 operationId;
  • 所有响应有 schema;
  • 所有错误响应有统一结构;
  • 所有字段有类型和约束;
  • 没有未使用的 schema;
  • 示例请求/响应可运行。

5. 数据库设计

5.1 设计步骤

  1. 从用户故事中提取名词 → 候选实体。
  2. 确定实体关系(1:1、1:N、M:N)。
  3. 确定主键、外键、唯一约束。
  4. 确定状态字段和状态转换。
  5. 确定审计、软删除、多租户字段。
  6. 确定高频查询 → 索引。
  7. 确定迁移顺序。

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 状态机

task.status:
  todo ──► in_progress ──► done
    ▲           │
    └───────────┘  (允许回退,需记录审计)

在文档中写清楚:

  • 哪些转换允许;
  • 谁可以转换;
  • 转换失败返回什么错误码;
  • 是否需要并发控制(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 高效、不冲突地实现。