Skip to content

Architecture Decision Record

Purpose

An ADR is the single-decision record for architecture-significant choices. Its unique job is to preserve why a decision was made, what alternatives were considered, what tradeoffs were accepted, and when the decision should be revisited.

ADRs are not architecture documents. Architecture owns the overall structural model. ADRs are not solution designs or technical designs; those apply accepted decisions to narrower scopes. ADRs are not meeting notes; keep only the context that changes how future readers should evaluate the decision.

Example

Show a worked example of this artifact
---
ddx:
  id: example.adr.depositmatch.postgresql-system-of-record
  depends_on:
    - example.architecture.depositmatch
  review:
    self_hash: d068dcadcfb1b7b4cfa6842e63e078f711128e78d5c2dd7e1666506a7c59d9ad
    deps:
      example.architecture.depositmatch: 64b7297158175ff16812e401fe093f7624b5ba70b11265a7a4bdf324e50a6bff
    reviewed_at: "2026-05-15T04:11:24Z"
---

# ADR-001: Use PostgreSQL as the System of Record

| Date | Status | Deciders | Related | Confidence |
|------|--------|----------|---------|------------|
| 2026-05-12 | Accepted | Product and Engineering | FEAT-001, Architecture | High |

## Context

| Aspect | Description |
|--------|-------------|
| Problem | DepositMatch must preserve imports, source rows, match suggestions, reviewer decisions, exceptions, and audit evidence consistently. |
| Current State | v1 starts from CSV imports and does not use external accounting APIs or bank feeds. |
| Requirements | PRD P0-1 import CSV files; P0-3 require reviewer approval; P0-4 preserve match evidence; P0-5 create exceptions for unmatched deposits. |
| Decision Drivers | Auditability, transactional consistency, simple v1 operations, and fast pilot delivery matter more than independent scaling of each data type. |

## Decision

We will use PostgreSQL 16 as the system of record for DepositMatch v1 data,
including clients, import sessions, source rows, invoices, deposits, match
suggestions, reviewer decisions, exceptions, and audit-log records.

**Key Points**: one transactional store | source-row traceability | no separate
search or document store in v1

## Alternatives

| Option | Pros | Cons | Evaluation |
|--------|------|------|------------|
| PostgreSQL 16 | Strong transactions, relational constraints, straightforward audit queries, mature backups, simple v1 operations | Less specialized for full-text search or high-volume event streaming | **Selected**: best fit for consistency and pilot simplicity |
| Document database | Flexible import payload storage, fewer joins for nested evidence | Harder relational integrity for invoices, deposits, matches, and corrections | Rejected: flexibility is less important than audit consistency |
| Separate event store plus read models | Excellent history and replay model | More infrastructure, more operational complexity, slower pilot delivery | Rejected for v1: event sourcing may be revisited if audit replay needs exceed relational history |

## Consequences

| Type | Impact |
|------|--------|
| Positive | Imports, matches, exceptions, and audit records can commit atomically and be queried together. |
| Negative | Future high-volume matching or analytics may need read replicas or separate derived stores. |
| Neutral | Uploaded CSV originals still live in encrypted object storage; PostgreSQL stores metadata and normalized rows. |

## Risks

| Risk | Prob | Impact | Mitigation |
|------|------|--------|------------|
| Import and match tables grow faster than expected | M | M | Partition or archive import sessions after retention policy is defined; add read replica if reporting load grows. |
| Analytics needs pressure the transactional schema | M | L | Keep analytics derived; do not put raw financial fields into analytics events. |

## Validation

| Success Metric | Review Trigger |
|----------------|----------------|
| 100% of accepted rows used in match evidence include source file, row number, identifier, amount, and date | Any accepted match lacks source-row evidence |
| Import confirmation remains atomic under validation and worker failures | Any partial import commit is observed in testing or production |
| Pilot workload stays below PostgreSQL performance targets | Matching backlog exceeds 100 jobs for 5 minutes repeatedly |

## Supersession

- **Supersedes**: None
- **Superseded by**: None

## Concern Impact

- **Concern selection**: Reinforces `reviewer-auditability`,
  `csv-import-integrity`, and `financial-data-security`.
- **Practice override**: None.

## References

- Architecture: `example.architecture.depositmatch`
- Feature Specification: `example.feature-specification.depositmatch.csv-import`
- PRD requirements: P0-1, P0-3, P0-4, P0-5

Reference

ActivityDesign — Decide how to build it. Capture trade-offs, contracts, and architecture decisions.
Default locationdocs/helix/02-design/adr/ADR-{number}-{decision-name}.md
RequiresNone
EnablesNone
InformsSolution Design
Technical Design
HELIX documentsdocs/helix/02-design/adr/ADR-002-tracker-write-safety-model.md
Generation prompt
Show the full generation prompt
# Architecture Decision Record (ADR) Generation Prompt

Write a compact ADR that captures one architecture-significant decision, the
alternatives, and the consequences.

## Storage Location

Store at: `docs/helix/02-design/adr/ADR-NNN-<decision-name>.md` — **one decision
per file**. Naming is canonical and checkable: uppercase `ADR`, a **zero-padded
3-digit** sequential number, then a kebab-case decision name (e.g.
`ADR-001-modular-monolith.md`, `ADR-007-auth-tenant-isolation.md`). Do **not** use
lowercase `adr-` or 4-digit numbers, and do **not** lump multiple decisions into
one record. reconcile-alignment flags non-canonical names and lumped ADRs.

## Purpose

An ADR is the **single-decision record** for architecture-significant choices.
Its unique job is to preserve why a decision was made, what alternatives were
considered, what tradeoffs were accepted, and when the decision should be
revisited.

ADRs are not architecture documents. Architecture owns the overall structural
model. ADRs are not solution designs or technical designs; those apply accepted
decisions to narrower scopes. ADRs are not meeting notes; keep only the context
that changes how future readers should evaluate the decision.

## Reference Anchors

Use these local resource summaries as grounding:

- `docs/resources/adr-github-organization.md` grounds ADRs as
  single-decision records with rationale, tradeoffs, and consequences.
- `docs/resources/google-cloud-architecture-decision-records.md` grounds ADR
  traceability to architecture evolution, code, and infrastructure context.

## Focus
- State the context and decision plainly.
- Keep alternatives and tradeoffs honest but brief.
- Note validation and references only if they affect the decision.
- Use one ADR per decision. If the decision has independent parts, split it.
- Treat accepted ADRs as history. New decisions supersede old records instead
  of rewriting them.
- **Do not accept a decision whose design-defining facts are assumed.** A
  decision's design-defining facts (API shape, data model, pricing/cost
  semantics, security/permissions, operational guarantees, or work decomposition)
  must be **evidenced** — by an operator statement, a governing artifact, an
  existing implementation, a docs/API proof, or a completed spike — not by model
  familiarity, and not because a mechanism was picked or a provider named.
  Choosing a provider and deferring its live integration does **not** evidence the
  decision. If a design-defining fact is assumed, the ADR must cite **spike
  evidence**, record a **blocked-spike rationale**, or carry an explicit
  **provisional-risk** note (what is assumed, what could invalidate it, and that
  the assumption is reversible/non-blocking). See the anti-reframe check in
  `workflows/references/concern-resolution.md` (step 3a). An operator-marked
  "spike/unknown" may not be accepted as a settled ADR without **spike evidence, a
  blocked-spike rationale, or an explicit provisional-risk note**. A
  **business/product** unknown a technical spike can't answer (e.g. a pricing
  model) → record **guidance-needed** or a blocked spike rather than forcing a
  technical spike or accepting an assumed decision.

## Boundary Test

| If you are writing... | Put it in... |
|---|---|
| Overall system structure or deployment topology | Architecture |
| One architecture-significant decision and rationale | ADR |
| Feature-specific design applying accepted architecture | Solution Design |
| Story-level component or code plan | Technical Design |
| API schema, event payload, or file format | Contract |
| Work steps or sequencing | Implementation Plan |

## Completion Criteria
- The decision is unambiguous.
- Alternatives are compared clearly.
- Consequences are explicit.
- Status and supersession state are clear.
- Reconsideration triggers are concrete when the decision has uncertainty.
Template
Show the template structure
---
ddx:
  id: ADR-XXX
---

# ADR-NNN: [Title]
<!-- Filename: ADR-NNN-<decision-name>.md — uppercase ADR, zero-padded 3-digit, one decision per file. -->


| Date | Status | Deciders | Related | Confidence |
|------|--------|----------|---------|------------|
| [YYYY-MM-DD] | [Proposed/Accepted/Deprecated/Superseded] | [Names] | [FEAT-XXX] | [High/Med/Low] |

## Context

| Aspect | Description |
|--------|-------------|
| Problem | [Specific problem] |
| Current State | [Existing situation] |
| Requirements | [Key requirements driving this] |
| Decision Drivers | [Forces that make this architecture-significant] |

## Decision

We will [decision statement].

**Key Points**: [Point 1] | [Point 2] | [Point 3]

## Alternatives

| Option | Pros | Cons | Evaluation |
|--------|------|------|------------|
| [Option 1] | [Advantages] | [Disadvantages] | [Rejected: reason] |
| [Option 2] | [Advantages] | [Disadvantages] | [Rejected: reason] |
| **[Selected]** | [Advantages] | [Disadvantages + mitigations] | **Selected: reason** |

## Consequences

| Type | Impact |
|------|--------|
| Positive | [Good outcomes] |
| Negative | [Trade-offs, technical debt] |
| Neutral | [Side effects] |

## Risks

| Risk | Prob | Impact | Mitigation |
|------|------|--------|------------|
| [Risk 1] | H/M/L | H/M/L | [Strategy] |

## Validation

| Success Metric | Review Trigger |
|----------------|----------------|
| [Metric 1] | [Condition for reconsideration] |

## Supersession

- **Supersedes**: [ADR-XXX or None]
- **Superseded by**: [ADR-YYY or None]

## Concern Impact

If this decision affects the project's active concerns or overrides a
library practice, note the impact here:

- **Concern selection**: [Does this ADR select, change, or constrain a concern?]
- **Practice override**: [Does this ADR override a library concern practice? If so,
  update `docs/helix/01-frame/concerns.md` Project Overrides with this ADR ref.]
- **No concern impact**: [Delete this section if the ADR has no concern relevance.]

## References

- [PRD section link]
- [Related ADRs]

## Review Checklist

Use this checklist when reviewing an ADR:

- [ ] Context names a specific problem — not "we need to decide about X"
- [ ] Decision statement is actionable — "we will" not "we should consider"
- [ ] At least two alternatives were evaluated
- [ ] Each alternative has concrete pros and cons, not vague assessments
- [ ] Selected option's rationale explains why it wins over the best alternative
- [ ] Consequences include both positive and negative impacts
- [ ] Negative consequences have documented mitigations
- [ ] Risks are specific with probability and impact assessments
- [ ] Validation section defines how we'll know if the decision was right
- [ ] Review triggers define conditions for reconsidering the decision
- [ ] Concern impact section is complete (or explicitly marked as no impact)
- [ ] ADR is consistent with governing feature spec and PRD requirements