EN DE

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

  1. Copy the template to docs/decisions/NNNN-short-title.md with the next number.
  2. Fill in context, decision, and consequences. Keep it short.
  3. Set the status to Accepted and add it to the list below.
  4. 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 (pipeline summary corrected to the code by the note of 2026-10-03)
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 (amended 2026-10-07: a cross-currency booking’s fees and taxes are in its cash account’s currency; amended 2026-10-09: a closed trade is in one currency, whatever booked its lots, a third currency is refused, and the history backfill derives missing legs)
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; two-PR amendment 2026-10-08: a sprint is a planning PR and one sprint PR)
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 (amended by 0050: the Context sentence on account renames, hash-first ordering with retired hashes, the scoped in-run key, the former-name tier, §3’s repair via the security merge; noted by 0053: a CSV row’s hash reads the file’s Betrag)
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)
0047 Derived metrics — a metric names the series it describes, and carries no verdict Accepted (design gate for FR-39/FR-40, ladder level (a); owner sign-off = the merge of the Sprint 13 planning PR)
0048 Security events as first-class objects — calendar facts about the whole catalog, entered by hand or by an agent, fetched by nobody Accepted (gate B3.4, FR-44; owner sign-off = the merge of the Sprint 13 planning PR)
0049 Policy rules as first-class objects — a rule is a standard in force over a period, evaluated at read into findings that carry no action Accepted (gate B3.6, FR-43; owner sign-off = the merge of the Sprint 15 planning PR; amended by the Sprint 16 planning PR: renamable name, §8 remedy corrected)
0050 Lifecycle merges — rename, merge and delete for cash accounts and depots, and merge for duplicate securities, under a post-merge re-import contract Accepted (design gate for #328 and #608, risk-tier; owner sign-off = the merge of the Sprint 16 planning PR; amends 0029; amended 2026-10-07: the first limit’s fail-closed probe, names compared as exact strings; amended 2026-10-09: the probe reads the dry run)
0051 Contribution analysis — which position made how much of a period’s result, summing exactly to the period’s money result Accepted (design gate for FR-41, ladder level (b); owner sign-off = the merge of the Sprint 17 planning PR; amended 2026-10-09: a security-linked interest booking is its position’s income)
0052 Bond master data in dedicated columns, read with display-only metrics Accepted (a story-level decision recorded by #330’s story, Sprint 18 PR γ U7; adopted by the merge of Sprint 18’s PR γ, #1054)
0053 A Portfolio Performance CSV books its Gesamtpreis — read as PP writes it, hashed as before, corrected by a separate confirm Accepted (design gate for #1076, risk-tier; owner sign-off = the merge of the Sprint 19 planning PR; notes 0029; amended 2026-10-07: the JSON path’s negative tax and a credit row that nets to nothing; amended 2026-10-09: what the parsers refuse, and what the correction lists)
0054 The agent’s surface — one authority for every token, the journal names the credential, and the companion spells what the operator cannot see Accepted (the architecture’s FU-6, #967; supersedes the architecture’s D4 and closes OD-4; adopted by the merge of the Sprint 20 sprint PR)