Skip to content

Architecture Decision Log (ADR) – Template

cpx May 30, 2026 5 min read Architecture

A living log of significant architecture decisions. Each decision is captured once, dated, and never edited after acceptance — superseding decisions are added as new entries that reference the old one.

Owner: <name / role> Scope: <system / domain / programme> Last reviewed: <YYYY-MM-DD>


1. Log index

IDTitleStatusDateDecider(s)SupersedesTags
ADR-0001Use PostgreSQL as the primary OLTP storeAccepted2026-01-15A. Architect, B. Leaddata, persistence
ADR-0002Adopt OAuth 2.1 with PKCE for all first-party clientsAccepted2026-02-03Security Guildidentity, security
ADR-0003Deprecate shared SMTP relay in favour of provider-direct sendSuperseded2026-02-20A. Architectmessaging
ADR-0004Route all outbound mail through hardened relay v2Accepted2026-04-10A. Architect, SecurityADR-0003messaging, security
ADR-NNNN<short imperative title>Proposed | Accepted | Rejected | Deprecated | SupersededYYYY-MM-DD<names><ADR-ID or —><tags>

Status definitions

StatusMeaning
ProposedUnder discussion; not yet binding.
AcceptedApproved and in effect.
RejectedConsidered and explicitly declined; kept for the record.
DeprecatedNo longer recommended but not yet replaced.
SupersededReplaced by a newer ADR (link in the Supersedes column of the replacement).

2. ADR record template

Copy the block below for each new decision. Keep it tight — aim for one page. If you need more, the decision is probably two decisions.


ADR-NNNN — <short imperative title>

FieldValue
StatusProposed | Accepted | Rejected | Deprecated | Superseded
DateYYYY-MM-DD
Decider(s)<names / roles>
Consulted<SMEs, security, ops, legal>
Informed<downstream teams, sponsors>
Supersedes<ADR-ID or —>
Superseded by<ADR-ID or —> (fill in only if/when retired)
Tags<comma-separated>

Context

What is the problem, force, or constraint that demands a decision? Include business drivers, technical constraints, and any prior commitments. Keep it factual — no advocacy yet.

Decision

State the decision in one or two sentences, in the active voice: “We will …”. Be specific enough that a new engineer can act on it without asking.

Drivers

#DriverType
1<e.g. RTO ≤ 15 min>Business / NFR
2<e.g. existing PostgreSQL operational expertise>Capability
3<e.g. SOC 2 audit logging requirement>Compliance

Options considered

#OptionSummaryVerdict
A<option name>One-line descriptionChosen / Rejected
B<option name>One-line descriptionRejected — <reason>
C<option name>One-line descriptionRejected — <reason>

Consequences

TypeConsequence
Positive<what gets easier / better / cheaper>
Positive<…>
Negative<what gets harder / riskier / more expensive>
Negative<…>
Neutral<side effects worth recording>

Risks & mitigations

RiskLikelihoodImpactMitigationOwner
<risk>L/M/HL/M/H<action><name>

Compliance & security notes

Call out anything relevant to audit, data classification, regulatory scope (GDPR, SOX, NIS2, etc.), threat model changes, or controls affected. Leave the section in even if empty — write “None identified” — so future readers know it was considered.

Implementation notes

Pointers, not plans: ticket / epic links, target environments, rollout sequencing, feature flags, runbooks, deprecation timeline.

References

  • <link to design doc, RFC, ticket, vendor docs, related ADRs>
  • <link to meeting notes if the decision was made in a forum>

3. Worked example

ADR-0002 — Adopt OAuth 2.1 with PKCE for all first-party clients

FieldValue
StatusAccepted
Date2026-02-03
Decider(s)A. Architect, Security Guild
ConsultedMobile lead, Web platform lead, IAM team
InformedAll product teams
Supersedes
Superseded by
Tagsidentity, security, auth

Context

Our existing first-party clients (web, iOS, Android, desktop) authenticate against the IdP using a mix of OAuth 2.0 implicit flow, authorization code without PKCE, and one legacy resource-owner password grant. The implicit flow is deprecated by the OAuth 2.1 draft, the password grant fails our zero-trust posture review, and the inconsistency makes our SOC 2 control narrative hard to write.

Decision

We will standardise on OAuth 2.1 with PKCE (S256) for all first-party clients — web, native, and desktop — and retire the implicit and password grants by Q3 2026.

Drivers

#DriverType
1Align with OAuth 2.1 best current practiceStandards
2Remove password handling from non-IdP code pathsSecurity
3Single auth pattern simplifies SOC 2 evidenceCompliance
4Reduce per-client auth implementations from 3 to 1Maintainability

Options considered

#OptionSummaryVerdict
AOAuth 2.1 + PKCE everywhereSingle pattern, IdP-hosted loginChosen
BKeep code-flow for web, PKCE for native onlyLess disruptionRejected — preserves two patterns, complicates audit
CMove to SAML for webReuses corporate SSORejected — poor fit for SPA / mobile, increases scope

Consequences

TypeConsequence
PositiveOne auth pattern across all clients; simpler threat model.
PositivePassword handling removed from app code; reduced phishing surface.
PositiveAudit evidence collapses to one flow diagram.
NegativeLegacy desktop client requires a system-browser refactor (≈ 3 sprints).
NegativeShort-lived breakage risk for offline-first mobile features during migration.
NeutralToken lifetime policy must be revisited (separate ADR).

Risks & mitigations

RiskLikelihoodImpactMitigationOwner
Desktop refactor slips past Q3MMPhased rollout; keep legacy grant gated behind feature flag with hard cut-off date.Desktop lead
Mobile users logged out en masse at cutoverLHDual-issue tokens for a 30-day overlap window.IAM team

Compliance & security notes

Removes ROPC grant, closing finding SEC-2025-014. Aligns with NIST SP 800-63B AAL2 for first-party access. No change to data classification handling. Threat model updated to remove “credential interception in client code” branch.

Implementation notes

  • Epic: IAM-1187
  • Cut-off date for legacy grants: 2026-09-30
  • Feature flag: auth.legacy_grants_enabled
  • Runbook: <link>

References

  • OAuth 2.1 draft (IETF)
  • Internal threat model v3.2
  • SOC 2 control CC6.1 mapping

4. House rules

RuleWhy
One decision per ADR.Keeps the log searchable and reversible.
Never edit an Accepted ADR’s Decision or Context.The log is a history, not a wiki page. Add a superseding ADR instead.
Status changes are allowed and dated in the log index.Lifecycle ≠ rewriting history.
Number ADRs sequentially, never reuse an ID.Even rejected ones keep their number.
Link from code / design docs back to the ADR.The log is only useful if people find it.
Review the index quarterly.Catch drift between Accepted and reality.
0 0 votes
Article Rating
guest

0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x