Architecture Decisions
This is the Architecture Decision Record (ADR) log for Portfolixir. Each ADR
captures one decision, the context that forced it, and its consequences.
AGENTS.md
requires that architecture decisions not change silently: when a decision
changes, add a new ADR and mark the old one as superseded rather than editing
history.
The records below were written after the fact to document decisions that were already in force in the codebase.
How to add an ADR
- Copy the template to
docs/decisions/NNNN-short-title.mdwith the next number. - Fill in context, decision, and consequences. Keep it short.
- Set the status to
Acceptedand add it to the list below. - To reverse a decision, add a new ADR and set the old one’s status to
Superseded by ADR-NNNN.
Records
| ADR | Title | Status |
|---|---|---|
| 0001 | Modular Phoenix monolith with bounded contexts | Accepted |
| 0002 | Thin MCP companion over the JSON API only | Accepted |
| 0003 | Decimal for all financial values | Accepted |
| 0004 | Holdings and trades derived from transaction history | Accepted |
| 0005 | Split quote providers: search vs. history | Accepted |
| 0006 | Classifications (taxonomies) with built-in derived trees | Accepted |
| 0007 | Currency conversion with exchange rates | Accepted |
| 0008 | Target weights and target/actual allocation | Accepted |
| 0009 | Cash as balance snapshots, not a mirrored ledger | Accepted |
| 0010 | Daily valuation series and TTWROR | Accepted |
| 0011 | Unified ledger projection (single per-kind reducer) | Accepted |
| 0012 | Asset class inference at read time | Accepted |
| 0013 | Exclude flagged securities from the allocation steering basis | Superseded by 0018 |
| 0014 | Bilingual docs site (EN baseline, DE alongside) without a custom Pages build | Accepted |
| 0015 | Cross-currency transaction settlement with a stored FX rate | Accepted |
| 0016 | Rounding policy — full precision in compute, round only at the human display | Accepted |
| 0017 | Append-only audit journal for financial writes | Accepted |
| 0018 | Buckets — tag-based wealth scoping with view filters | Accepted |
| 0019 | View-scoped performance treats boundary transfers as external flows | Accepted |
| 0020 | target plans belong to a view | Accepted |
| 0021 | In-app broker-PDF transaction intake (sandboxed, text-only) | Accepted |
| 0022 | Task-oriented UI information architecture | Accepted |
| 0023 | Drift sign convention and display-only rebalancing hints | Accepted |
| 0024 | Buckets and views replace portfolios as the user-facing grouping | Accepted |
| 0025 | Automation recipes — docs in the repo, broker scripts outside | Accepted |
| 0026 | Epic-batch workflow — humans review decisions and behavior | Accepted (risk-tier clause amended by 0036; merge-is-signature and owner-tag amendments 2026-09-07) |
| 0027 | Named plan versions and ledger-marker depot snapshots | Accepted (transaction-cost amendment 2026-08-15) |
| 0028 | Corporate actions as ledger events — splits as a first-class kind | Accepted |
| 0029 | Stable identities and re-import survival — identity ladder with ISIN-change aliases | Accepted |
| 0030 | Position-level SOLL targets — positions as source of truth, categories as derived roll-up | Accepted |
| 0031 | Recorded tax-statement snapshots — capture the broker’s tax pots, never derive them | Accepted |
| 0032 | Memoized derived series — cache the daily TTWROR walk in volatile memory | Superseded by 0039 |
| 0033 | Per-position P&L decomposed — price return and currency return over a security-currency cost basis | Accepted |
| 0034 | Money-weighted metrics — net invested capital, wealth multiple, hand-rolled XIRR next to TTWROR | Accepted |
| 0035 | One pricing pass per read — shared preloaded market data instead of six re-derivations | Accepted |
| 0036 | Risk-tier work rides the batch — the dedicated-small-PR exception is withdrawn | Accepted (amends 0026) |
| 0037 | Phoenix 1.8 and LiveView 1.x — taken as a security upgrade, verified in a real browser | Accepted |
| 0038 | Continuous owner feedback loop and a standing design authority | Accepted (amends 0026) |
| 0039 | Durable derived values — one memoization mechanism with a lifetime per analytic | Accepted (gate B3.2; supersedes 0032) |
| 0040 | A target plan states its unallocated remainder | Accepted |
| 0041 | Category result — the positions in a category, rolled up and decomposable | Accepted |
| 0042 | One planning structure — the requirement registry and the work breakdown stop competing | Accepted |
| 0043 | A gate-closing ADR names the asks it answers — and the ones it does not | Accepted (amends 0026) |
| 0044 | Security knowledge as an append-only log — the thesis state is its projection, retractions never vanish | Accepted (gate B4.1 + P0-6) |
| 0045 | Optional built-in authentication for the web UI, and the deployment contract that goes with it — one password by one variable, loopback and Host-validated by default | Accepted (answers OQ-8) |
| 0046 | Benchmark comparison — a fixed rate or a flagged catalog security, replayed “bought once” and as the portfolio’s own savings plan | Accepted (owner sign-off = the merge of PR #780) |