architecture-decision-record

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Architecture Decision Records

架构决策记录(ADR)

ADR Template

ADR 模板

Every ADR follows this structure:
markdown
undefined
每一份ADR均遵循以下结构:
markdown
undefined

ADR-NNN: Title of the Decision

ADR-NNN: 决策标题

Status

状态

[Proposed | Accepted | Deprecated | Superseded by ADR-NNN]
[提议中 | 已通过 | 已弃用 | 被ADR-NNN取代]

Context

背景

What is the issue that we are seeing that motivates this decision or change? Describe the forces at play (technical, political, social, project-related). Include any constraints, requirements, or assumptions.
当前面临的问题是什么,促使我们做出该决策或变更? 描述相关影响因素(技术、政策、团队、项目相关)。 包含所有约束条件、需求或假设前提。

Decision

决策内容

What is the change that we are proposing and/or doing? State the decision in full sentences using active voice. Be specific about what will be done.
我们提议或即将执行的变更是什么? 使用主动语态的完整句子陈述决策。 明确具体执行方案。

Consequences

决策后果

What becomes easier or more difficult because of this decision? List both positive and negative consequences. Include any follow-up actions required.
undefined
该决策会让哪些事情变得更简单或更复杂? 列出正面和负面后果。 包含所需的后续行动。
undefined

When to Write an ADR

何时编写ADR

Write an ADR for any decision that meets one or more of these criteria:
TriggerExample
Adopting or replacing a technologySwitching from REST to GraphQL
Changing an architectural patternMoving from monolith to microservices
Infrastructure decisionsChoosing a cloud provider or database
API design choicesChoosing pagination strategy
Authentication/authorization strategyAdopting OAuth2 with PKCE
Data model decisionsChoosing between SQL and NoSQL
Cross-cutting concernsStandardizing error handling or logging
Process or convention changesAdopting conventional commits
Build/deployment decisionsChoosing CI/CD platform
Decisions that are hard to reverseAnything with significant migration cost
当决策满足以下任一标准时,需编写ADR:
触发场景示例
采用或替换某项技术从REST切换至GraphQL
变更架构模式从单体架构迁移至微服务架构
基础设施决策选择云服务商或数据库
API设计选择选择分页策略
认证/授权策略采用OAuth2 with PKCE
数据模型决策在SQL与NoSQL之间选择
横切关注点决策统一错误处理或日志规范
流程或约定变更采用规范化提交格式
构建/部署决策选择CI/CD平台
难以回滚的决策任何具有显著迁移成本的决策

Do NOT Write an ADR For

无需编写ADR的场景

  • Routine implementation choices with low impact
  • Temporary decisions that will be revisited within days
  • Individual code-level decisions that are covered by style guides
  • Choices that are trivially reversible
  • 低影响的常规实现选择
  • 数日内会重新评估的临时决策
  • 已被代码风格指南覆盖的单个代码级决策
  • 可轻易回滚的选择

Status Lifecycle

状态生命周期

Proposed  -->  Accepted  -->  Deprecated
                          -->  Superseded by ADR-NNN
StatusMeaning
ProposedUnder discussion, not yet decided
AcceptedDecision has been agreed upon and should be followed
DeprecatedNo longer relevant due to changes in the project or environment
Superseded by ADR-NNNReplaced by a newer decision; link to the replacement
提议中  -->  已通过  -->  已弃用
                          -->  被ADR-NNN取代
状态含义
提议中处于讨论阶段,尚未做出最终决策
已通过决策已达成共识,需遵照执行
已弃用因项目或环境变更,已不再具有相关性
被ADR-NNN取代被较新的决策替代;需链接至替代决策的ADR

Rules

规则

  • An ADR is immutable once accepted; never edit the original text
  • To change a decision, write a new ADR that supersedes the old one
  • Update the old ADR's status to "Superseded by ADR-NNN"
  • Keep deprecated and superseded ADRs in the repository for history
  • ADR一旦通过即不可修改;切勿编辑原始文本
  • 若需变更决策,需编写新的ADR取代旧版本
  • 将旧ADR的状态更新为“被ADR-NNN取代”
  • 已弃用或被取代的ADR需保留在代码库中,以供追溯历史

Evaluating Alternatives

备选方案评估

Use a structured comparison for every ADR with multiple options.
对于存在多个选项的ADR,需采用结构化方式进行比较。

Pros/Cons Matrix

优缺点矩阵

markdown
undefined
markdown
undefined

Option A: PostgreSQL

选项A: PostgreSQL

Pros:
  • Mature, well-understood RDBMS
  • Strong ACID guarantees
  • Excellent tooling ecosystem
Cons:
  • Horizontal scaling requires additional tooling
  • Schema migrations needed for changes
优点:
  • 成熟、广为人知的关系型数据库管理系统(RDBMS)
  • 强大的ACID保证
  • 完善的工具生态系统
缺点:
  • 水平扩展需要额外工具支持
  • 数据模型变更需执行 schema 迁移
undefined

Option B: MongoDB

加权标准矩阵

Pros:
  • Flexible schema for evolving data models
  • Built-in horizontal scaling (sharding)
Cons:
  • Weaker transaction support (multi-document)
  • Team has limited operational experience
undefined
对于复杂决策,可针对加权标准为每个选项评分:
markdown
| 评估标准              | 权重 | PostgreSQL | MongoDB | DynamoDB |
|-----------------------|--------|------------|---------|----------|
| 团队技术经验        | 5      | 5          | 2       | 2        |
| 扩展性           | 4      | 3          | 4       | 5        |
| 查询灵活性     | 4      | 5          | 3       | 2        |
| 运维成本      | 3      | 3          | 3       | 4        |
| ACID合规性       | 3      | 5          | 3       | 3        |
| **加权总分**    |        | **80**     | **57**  | **60**   |
计算方式:每个选项的(权重 × 评分)之和。

Weighted Criteria Matrix

文件命名与存储

约定规范

For complex decisions, score each option against weighted criteria:
markdown
| Criteria              | Weight | PostgreSQL | MongoDB | DynamoDB |
|-----------------------|--------|------------|---------|----------|
| Team expertise        | 5      | 5          | 2       | 2        |
| Scalability           | 4      | 3          | 4       | 5        |
| Query flexibility     | 4      | 5          | 3       | 2        |
| Operational cost      | 3      | 3          | 3       | 4        |
| ACID compliance       | 3      | 5          | 3       | 3        |
| **Weighted Total**    |        | **80**     | **57**  | **60**   |
Calculation: sum of (weight x score) for each option.
规范类型规则示例
编号规则四位数字前置补零的连续编号
0001
,
0002
,
0015
文件名称
NNNN-title-slug.md
0003-use-postgresql.md
存储位置代码库根目录下的
docs/adr/
文件夹
docs/adr/0003-use-postgresql.md
标题格式ADR-NNN: 祈使句格式ADR-003: 使用PostgreSQL作为存储引擎

File Naming and Storage

目录结构

Conventions

ConventionRuleExample
NumberingZero-padded 4-digit sequential
0001
,
0002
,
0015
File name
NNNN-title-slug.md
0003-use-postgresql.md
Storage location
docs/adr/
at the repository root
docs/adr/0003-use-postgresql.md
Title formatADR-NNN: Imperative sentenceADR-003: Use PostgreSQL for storage
项目根目录/
  docs/
    adr/
      0001-record-architecture-decisions.md
      0002-use-typescript-for-backend.md
      0003-use-postgresql-for-primary-storage.md
      0004-adopt-rest-api-style.md
      0005-use-jwt-for-authentication.md
      README.md   (可选的索引文件)

Directory Structure

将ADR与代码及问题关联

project-root/
  docs/
    adr/
      0001-record-architecture-decisions.md
      0002-use-typescript-for-backend.md
      0003-use-postgresql-for-primary-storage.md
      0004-adopt-rest-api-style.md
      0005-use-jwt-for-authentication.md
      README.md   (optional index)
  • 在受影响的代码区域附近的注释中引用ADR:
    typescript
    // 参见ADR-003: 使用PostgreSQL作为主存储
    // docs/adr/0003-use-postgresql.md
    const db = new Pool({ connectionString: DATABASE_URL });
  • 在ADR的页脚链接至相关的问题或PR:
    markdown
    ## 参考资料
    - GitHub Issue: #142
    - Pull Request: #158
    - 相关ADR: ADR-002

Linking ADRs to Code and Issues

示例ADR 1: 选择主数据库

  • Reference the ADR in code comments near the affected area:
    typescript
    // See ADR-003: Use PostgreSQL for primary storage
    // docs/adr/0003-use-postgresql.md
    const db = new Pool({ connectionString: DATABASE_URL });
  • Link to the relevant issue or PR in the ADR footer:
    markdown
    ## References
    - GitHub Issue: #142
    - Pull Request: #158
    - Related: ADR-002
markdown
undefined

Example ADR 1: Choosing a Primary Database

ADR-003: 使用PostgreSQL作为主存储

状态

markdown
undefined
已通过

ADR-003: Use PostgreSQL for Primary Storage

背景

Status

Accepted
我们的应用需要一个主数据存储来管理用户账户、订单及产品库存。我们的需求如下:
  • 金融交易需强一致性
  • 支持跨关联实体的复杂查询(关联查询)
  • 团队拥有总计5年的PostgreSQL使用经验
  • 预期规模:2年内最大表达到1000万行
  • 以读操作为主,偶尔出现写操作峰值
我们评估了三个选项:PostgreSQL、MongoDB和DynamoDB。

Context

决策内容

Our application needs a primary data store for user accounts, orders, and product inventory. We expect the following requirements:
  • Strong consistency for financial transactions
  • Complex queries across related entities (joins)
  • Team has 5 years of collective PostgreSQL experience
  • Expected scale: 10M rows in the largest table within 2 years
  • Read-heavy workload with occasional write bursts
We evaluated three options: PostgreSQL, MongoDB, and DynamoDB.
我们将使用PostgreSQL 16作为主数据库。
我们将使用迁移工具(golang-migrate)管理schema变更,并强制所有schema变更需经过审核的迁移文件。
我们将在生产环境中通过PgBouncer实现连接池。

Decision

决策后果

We will use PostgreSQL 16 as our primary database.
We will manage schema changes with a migration tool (golang-migrate) and enforce that all schema changes go through reviewed migration files.
We will use connection pooling via PgBouncer for production deployments.
正面影响:
  • 团队可凭借现有经验立即开展工作
  • ACID事务简化了订单与支付逻辑
  • 丰富的查询能力减少了应用层的数据处理工作
  • 拥有庞大的监控与备份工具生态
负面影响:
  • 若增长远超预期,水平写扩展将需要分片或只读副本支持
  • Schema迁移增加了数据模型变更的复杂度
  • 需自行管理连接池与性能调优
后续行动:
  • 在基础设施配置中搭建PgBouncer
  • 创建迁移工作流并记录在开发者指南中
  • 建立备份与时间点恢复流程
undefined

Consequences

示例ADR 2: API风格

Positive:
  • Team can be productive immediately with existing expertise
  • ACID transactions simplify order and payment logic
  • Rich query capabilities reduce application-level data manipulation
  • Large ecosystem of monitoring and backup tools
Negative:
  • Horizontal write scaling will require sharding or read replicas if we exceed expected growth significantly
  • Schema migrations add friction to data model changes
  • We need to manage connection pooling and tuning ourselves
Follow-up actions:
  • Set up PgBouncer in the infrastructure configuration
  • Create a migration workflow and document in the developer guide
  • Establish backup and point-in-time recovery procedures
undefined
markdown
undefined

Example ADR 2: API Style

ADR-004: 为公开API采用REST风格

状态

markdown
undefined
已通过

ADR-004: Adopt REST for Public API

背景

Status

Accepted
我们正在为第三方集成构建公开API。该API将被不同技术水平的合作伙伴使用。我们需要在REST、GraphQL和gRPC之间做出选择。
关键因素:
  • 合作伙伴期望文档完善、稳定的API
  • 大多数使用者为Web应用和移动客户端
  • 希望最小化合作伙伴的接入难度
  • 内部服务间通信为独立需求(将在后续ADR中讨论内部RPC)

Context

决策内容

We are building a public API for third-party integrations. The API will be consumed by partners with varying levels of technical sophistication. We need to choose between REST, GraphQL, and gRPC.
Key factors:
  • Partners expect a well-documented, stable API
  • Most consumers are web applications and mobile clients
  • We want to minimize onboarding friction for partners
  • Internal services also need to communicate, but that is a separate concern (see future ADR for internal RPC)
我们将为面向公众的API采用RESTful API设计。
约定规范:
  • 请求与响应体使用JSON格式
  • URL路径使用复数资源名词(如:/api/v1/orders)
  • 列表接口采用基于游标分页
  • 通过URL路径前缀进行版本控制(/api/v1/, /api/v2/)
  • 遵循api-design skill中的标准HTTP状态码
我们将使用OpenAPI 3.1编写规范,并据此生成文档。

Decision

决策后果

We will adopt RESTful API design for our public-facing API.
Conventions:
  • JSON request and response bodies
  • Plural resource nouns in URL paths (e.g., /api/v1/orders)
  • Cursor-based pagination for list endpoints
  • Versioning via URL path prefix (/api/v1/, /api/v2/)
  • Standard HTTP status codes per our api-design skill
We will use OpenAPI 3.1 for specification and generate documentation from it.
正面影响:
  • 合作伙伴学习成本低(REST被广泛熟知)
  • OpenAPI工具可自动生成SDK
  • 可通过HTTP标准实现缓存(ETags、Cache-Control)
  • 易于使用curl、Postman或任何HTTP客户端进行测试
负面影响:
  • 与GraphQL相比存在过度获取或获取不足的问题
  • 复杂数据需求需多次请求
  • 版本控制需要维护并行实现
后续行动:
  • 创建OpenAPI规范文件
  • 搭建API文档生成流水线
  • 定义错误响应格式(参见api-design skill)
undefined

Consequences

示例ADR 3: 认证策略

Positive:
  • Low learning curve for partners (REST is widely understood)
  • OpenAPI tooling enables auto-generated SDKs
  • Cacheable via HTTP standards (ETags, Cache-Control)
  • Easy to test with curl, Postman, or any HTTP client
Negative:
  • Over-fetching and under-fetching compared to GraphQL
  • Multiple roundtrips for complex data needs
  • Versioning requires maintaining parallel implementations
Follow-up actions:
  • Create the OpenAPI specification file
  • Set up API documentation generation pipeline
  • Define the error response format (see api-design skill)
undefined
markdown
undefined

Example ADR 3: Authentication Strategy

ADR-005: 使用带短期访问令牌的JWT进行认证

状态

markdown
undefined
已通过

ADR-005: Use JWT with Short-Lived Access Tokens for Authentication

背景

Status

Accepted
我们需要对用户进行认证并授权API请求。应用同时拥有Web前端和移动客户端。需求如下:
  • 无状态认证以简化水平扩展
  • 支持无需重新完整认证的令牌刷新
  • 具备泄露令牌的吊销能力
  • 兼容OAuth2以支持未来的第三方集成
评估的选项:
  1. 基于会话的认证,使用服务端存储
  2. 带长期令牌的JWT
  3. 带短期访问令牌与刷新令牌的JWT

Context

决策内容

We need to authenticate users and authorize API requests. The application has both a web frontend and mobile clients. Requirements:
  • Stateless authentication to simplify horizontal scaling
  • Support for token refresh without full re-authentication
  • Revocation capability for compromised tokens
  • Compatibility with OAuth2 for future third-party integrations
Options evaluated:
  1. Session-based authentication with server-side storage
  2. JWT with long-lived tokens
  3. JWT with short-lived access tokens and refresh tokens
我们将使用基于JWT的认证方案,具体如下:
  • 访问令牌: 15分钟有效期,使用RS256签名
  • 刷新令牌: 7天有效期,存储在数据库中,每次使用时轮换(刷新令牌轮换)
  • 令牌存储: 访问令牌存储在前端内存中,刷新令牌存储在httpOnly安全Cookie中
  • 吊销机制: 刷新令牌可通过从数据库删除实现吊销;访问令牌有效期较短,大多数场景下无需显式吊销
  • 密钥轮换: RSA密钥对每季度轮换一次,通过JWKS端点对外提供

Decision

决策后果

We will use JWT-based authentication with:
  • Access tokens: 15-minute expiry, signed with RS256
  • Refresh tokens: 7-day expiry, stored in the database, rotated on each use (refresh token rotation)
  • Token storage: Access token in memory (frontend), refresh token in httpOnly secure cookie
  • Revocation: Refresh tokens can be revoked by deleting from the database; access tokens are short-lived enough to not require explicit revocation in most cases
  • Key rotation: RSA key pairs rotated quarterly with JWKS endpoint
正面影响:
  • 访问令牌验证无状态(无需每次请求查询数据库)
  • 刷新令牌轮换限制了被盗令牌的有效窗口
  • RS256允许无需共享签名密钥即可验证令牌
  • JWKS端点支持密钥轮换且无需停机
负面影响:
  • 无法立即吊销访问令牌(15分钟窗口)
    • 缓解方案:对于关键操作(密码修改、检测到泄露),维护一个短期的拒绝列表,由中间件检查
  • 刷新令牌存储增加了数据库依赖
  • 客户端的令牌处理逻辑复杂
  • 密钥轮换流程需要谨慎实现
后续行动:
  • 实现JWKS端点
  • 创建令牌验证中间件
  • 为前端和移动团队编写令牌刷新流程文档
  • 搭建认证失败尝试的监控
undefined

Consequences

ADR审核 Checklist

Positive:
  • Stateless verification of access tokens (no database lookup per request)
  • Refresh token rotation limits the window for stolen tokens
  • RS256 allows verification without sharing the signing key
  • JWKS endpoint enables key rotation without downtime
Negative:
  • Cannot instantly revoke access tokens (15-minute window)
    • Mitigation: for critical actions (password change, detected breach), maintain a short-lived deny list checked by middleware
  • Refresh token storage adds database dependency
  • Token handling complexity on the client side
  • Key rotation process needs careful implementation
Follow-up actions:
  • Implement the JWKS endpoint
  • Create middleware for token verification
  • Document the token refresh flow for frontend and mobile teams
  • Set up monitoring for failed authentication attempts
undefined
在通过ADR之前,需验证以下内容:
  • 背景部分清晰解释了问题,新成员也能理解
  • 列出并评估了所有可行的备选方案
  • 决策内容明确、无歧义
  • 已承认正面和负面后果
  • 已识别后续行动
  • ADR已链接至相关问题或PR
  • 文件遵循命名规范(NNNN-title-slug.md)
  • 状态在审核时设为“提议中”,批准后设为“已通过”
  • 至少两名团队成员已审核该ADR

ADR Review Checklist

Before accepting an ADR, verify:
  • Context explains the problem clearly enough that someone new can understand it
  • All viable alternatives are listed and evaluated
  • The decision is stated explicitly and unambiguously
  • Both positive and negative consequences are acknowledged
  • Follow-up actions are identified
  • The ADR is linked to relevant issues or PRs
  • The file follows naming conventions (NNNN-title-slug.md)
  • Status is set to "Proposed" for review, "Accepted" after approval
  • At least two team members have reviewed the ADR