Skip to main content
Restates decision 2 of 0036: the money keys stay in Postgres with the ledger entry. The category is commerce (ADR 0127).

Context

Money is wrong in a payment system when it is stored as a float, rounded differently in two places, or changed in place. The owner’s money answers PP3, PP8, MN1 and P2 (mem L517, L797, L872, 2026-10-20) fix the representation, the rounding and the ledger shape.

Decision

  1. Packages. @stackra/money (commerce category) represents money in minor units with ISO 4217 currency codes and an @Money field. A ledger package records every movement. FX is snapshotted at the transaction time. Each tenant has a base currency.
  2. Exponent (MN1). The ISO 4217 exponent is used, so KWD and BHD have three digits and JPY has none.
  3. Rounding (MN1). Half-even rounding by default. Half-up where a tax rule requires it. Allocation of a ratio is exact, with deterministic remainders. FX stores the rate and its source.
  4. Ledger (P2). A double-entry, immutable ledger: accounts per party and purpose, balances derived from entries, and reversals instead of edits.
  5. Idempotency. Money idempotency keys stay in Postgres, in the same entry as the movement (restated from 0036).

Consequences

  • A balance is always the sum of entries, so a mistake is corrected by a reversal that remains visible.
  • Rounding is decided once, so two services cannot disagree on a cent.

Enforcement

planned — property tests on the allocation and the rounding modes; the ledger rejects an update to a posted entry.

Supersedes and sources

Supersedes: none. Restates: decision 2 of 0036. Sources: owner money answers PP3, PP8, MN1, P2 (stackra-decisions-2026-10-19.md L517, L797, L872, 2026-10-20).