En esta guía (17 elementos)
Architectural Decision Records
Architectural Decision Records (ADR)
BINDING RULES FOR ALL AI AGENTS: Every architecturally significant decision MUST be captured as an ADR before merging. Default template = MADR. Default location =
docs/adr/. ADRs are append-only: anacceptedADR is never edited — supersede it instead. Source: https://adr.github.io/.
This guide is the source of truth for ADR practice in this project. Skills and commands reference it; do not duplicate content elsewhere.
1. Definitions
- Architectural Decision (AD): justified design choice addressing a functionally or non-functionally significant requirement.
- Architecturally Significant Requirement (ASR): requirement with measurable effect on system architecture or quality attributes.
- Architectural Decision Record (ADR): persistent document capturing one AD plus its context, alternatives, rationale, and consequences.
- Decision Log: the ordered set of all ADRs in the repo.
2. When to Write an ADR
Write an ADR when the decision affects any of:
- Layer boundaries or dependency direction (hexagonal violations).
- Port shape or contract (inbound/outbound interfaces).
- Adapter technology choice (JDBC vs JPA, Kafka vs RabbitMQ, REST vs gRPC).
- Aggregate boundary or bounded context split.
- Transaction strategy (Transaction port impl, outbox vs sync, saga vs 2PC).
- Persistence engine, message broker, cache provider.
- Security model (auth, authorization, multi-tenancy).
- Cross-cutting concerns implemented as decorators (CoR ordering).
- Public API contracts and versioning policy.
- Build / deployment topology (modules, packaging, runtime).
Do NOT ADR trivial choices: variable names, internal helper signatures, formatting, single-file refactors with no API change.
3. Template Selection
| Template | Use when |
|---|---|
| MADR | Default. Most decisions. Need tradeoff analysis with options + rationale. |
| Nygard | Quick capture of an obvious choice with simple consequences. |
| Y-Statement | One-line decision summary embedded in code comments or PR descriptions. |
| ISO 42010 | Formal enterprise / regulated contexts only. |
Default to MADR unless a project rule says otherwise.
4. MADR Template (default)
Filename: docs/adr/NNNN-title-with-dashes.md (e.g. 0007-use-kafka-outbox.md). NNNN is consecutive, zero-padded to 4 digits. Lowercase title with dashes.
---status: proposed # proposed | accepted | rejected | deprecated | supersededdate: 2026-05-05 # YYYY-MM-DD, last updatedecision-makers: [andres, jane]consulted: [security-team] # two-way communicationinformed: [product] # one-way communication---
# NNNN. Short Decision Title
## Context and Problem Statement
Two or three sentences (or a short narrative) describing the forces and theproblem. State the ASR being addressed and any quality attributes at stake.
## Decision Drivers
- Driver 1 (e.g., must support exactly-once delivery)- Driver 2 (e.g., team has Kafka operational experience)- Driver 3 (e.g., budget caps managed-broker spend)
## Considered Options
- Option A — Kafka with transactional outbox- Option B — RabbitMQ with publisher confirms- Option C — Direct JDBC + Debezium CDC
## Decision Outcome
Chosen option: **Option A — Kafka with transactional outbox**, because itsatisfies the exactly-once driver while reusing existing operationalexpertise.
### Consequences
- **Good** — exactly-once via outbox pattern + idempotent consumers.- **Good** — reuse of existing Kafka cluster, no new infra cost.- **Bad** — additional complexity in outbox table maintenance and relay process.- **Neutral** — schema registry adoption deferred to ADR-NNNN.
### Confirmation
Compliance verified by:- ArchUnit rule forbidding direct `KafkaTemplate` use outside outbox-relay module.- Integration test `OutboxRelayIT` asserting at-least-once delivery with dedup.- Runtime metric `outbox.lag.seconds` < 5s SLO.
## Pros and Cons of the Options
### Option A — Kafka with transactional outbox- Good — leverages existing infra.- Good — fits hexagonal port `DomainEventPublisher`.- Bad — operational burden of the relay process.
### Option B — RabbitMQ with publisher confirms- Good — simpler at-least-once model out of the box.- Bad — introduces a second broker, higher TCO.
### Option C — Direct JDBC + Debezium CDC- Good — zero application-level publishing code.- Bad — couples consumers to internal schema; brittle on migrations.
## More Information
- Spike: `docs/spikes/2026-04-kafka-vs-rabbit.md`- Related: ADR-0003 (use hexagonal architecture), ADR-0005 (transaction port).Required vs Optional Sections
| Section | Required | Notes |
|---|---|---|
| Title | yes | NNNN. Short title, problem-solution focused. |
| Context and Problem Statement | yes | 2–3 sentences or short narrative. |
| Considered Options | yes | Bulleted list. At least 2. |
| Decision Outcome | yes | Chosen option + one-sentence justification. |
| Decision Drivers | optional | Recommended for MADR-full. |
| Consequences | optional | Strongly recommended. |
| Confirmation | optional | How compliance is enforced (ArchUnit, IT, SLO). |
| Pros and Cons of Options | optional | Required when ≥3 options or stakeholders ask. |
| More Information | optional | Links to spikes, prior ADRs, RFCs. |
Frontmatter
| Key | Required | Values / Format |
|---|---|---|
status |
yes | proposed | accepted | rejected | deprecated | superseded |
date |
yes | YYYY-MM-DD, last update |
decision-makers |
recommended | YAML list of names or roles |
consulted |
optional | YAML list — two-way communication |
informed |
optional | YAML list — one-way communication |
5. Status Lifecycle
proposed ──► accepted ──► deprecated │ │ ▼ ▼rejected superseded ──► points to NNNN of replacementRules:
proposedis the initial state when scaffolded.- Move to
acceptedonce decision-makers agree and the PR is approved. rejectedis final; keep the file for the historical record.deprecatedmeans the decision is no longer in force but no replacement exists.supersededrequires a new ADR; old ADR’s frontmatter gainssuperseded-by: NNNNand the new ADR’s frontmatter gainssupersedes: NNNN.
Immutability: an accepted ADR is append-only. Never edit its content. Fix typos before acceptance only. After acceptance, write a new ADR that supersedes it.
6. Nygard Template (quick capture)
# NNNN. Short Title
## StatusAccepted
## ContextWhat is the issue we're seeing that motivates this decision.
## DecisionWhat we are going to do.
## ConsequencesWhat becomes easier or harder.Use when the decision is obvious and tradeoffs are minimal. Promote to MADR if a reviewer asks “why not X?”.
7. Y-Statement (one-liner)
In the context of
<use case>, facing<concern>, we decided for<option>and against<alternatives>to achieve<quality>, accepting<downside>.
Extended form adds because <rationale> and rejected: <list>.
Drop a Y-Statement into a PR description, code comment, or commit message when an ADR is overkill but the reasoning is non-obvious.
8. ISO/IEC/IEEE 42010 (formal)
Nine information items: identifier, summary, decision, status, rationale, alternatives, related decisions, related concerns, related artifacts. Use only in regulated / certification contexts. Out of scope for typical project work.
9. Repo Layout
docs/└── adr/ ├── README.md # decision log index, auto- or hand-curated ├── 0001-record-architectural-decisions.md ├── 0002-use-hexagonal-architecture.md ├── 0003-transaction-port.md └── ...docs/adr/README.md lists all ADRs with status and one-line summary. Regenerate or hand-edit on every accepted/superseded change.
10. Workflow
- Detect significance — does the change match any trigger in §2?
- Run
/add-adr "short title"(or scaffold manually). - Fill MADR sections. Set
status: proposed. - Open PR. Reviewers comment on the ADR alongside code.
- On approval, flip status to
acceptedin the same PR or a follow-up. - Update
docs/adr/README.mdindex. - Reference the ADR in code via
// see ADR-NNNNonly when context is non-obvious.
11. Hexagonal Architecture Tie-Ins
ADRs that this project expects, indicative list:
0001— Use hexagonal architecture (ports & adapters).0002— Transaction port over@Transactionalon use cases.0003— Outbox pattern for domain event publishing.0004— Chain of Responsibility for cross-cutting decorators.0005— ArchUnit as the layer boundary enforcement gate.0006— JsonMapper over ObjectMapper (Jackson 3.x).
When introducing a new bounded context, port, or adapter technology, write an ADR before merging.
12. Review Checklist
Before accepting an ADR:
- Title is problem-solution oriented, not solution-only.
- At least 2 options considered.
- Decision Drivers are measurable (no “better” without a metric).
- Consequences include at least one negative item.
- Confirmation lists how compliance is enforced (ArchUnit / IT / SLO / lint).
- No conflict with existing accepted ADRs (or this one supersedes them explicitly).
- Filename matches
NNNN-title-with-dashes.mdand is consecutive. - Frontmatter
statusisproposedat PR open,acceptedonly after approval.
13. Anti-Patterns
- ADR for a code-style nit. Use
clean-code.mdor a lint rule instead. - “We picked X because the team likes it” with no driver. Restate the driver.
- Editing an
acceptedADR. Supersede. - Single-option ADR. If only one option exists, capture it as a Nygard or skip.
- ADRs in a wiki separate from the repo. Decisions co-locate with code.
- Oversize ADRs (>2 pages). Split or link out to a spike.
14. Tooling (optional)
- adr-tools — bash CLI for scaffolding ADRs. Not required.
/add-adrslash command in this repo (seecommands/add-adr.md) — preferred for AI-driven flows.- Render
docs/adr/README.mdas the decision log; many static-site generators support it natively.
15. References
- ADR organization: https://adr.github.io/
- MADR: https://adr.github.io/madr/
- Templates comparison: https://adr.github.io/adr-templates/
- Nygard’s original post: “Documenting Architecture Decisions” (2011).
- Y-Statement: “Sustainable Architectural Decisions” (Zimmermann et al.).