1.1 KiB
ADR-0011: Money as integer minor units
- Status: Accepted
- Date: 2026-08-11
Context
0.1 + 0.2 !== 0.3. Floating-point money produces discrepancies that are invisible in
testing and unfixable once they are in an order history.
Decision
All monetary values are integers in the currency's minor unit, in the database
(priceAmount Int), across the API ({ amount, currency }), and in TypeScript (Money).
VND has a minor-unit scale of 0, so 250000 means ₫250.000. Conversion to a display string
happens in exactly one function, formatMoney, using Intl.NumberFormat.
Consequences
Arithmetic is exact. No conversion happens between layers because every layer holds the same integer. Multi-currency is already representable without a schema change.
Developers must remember that price.amount is not a display value; the single formatter and
the absence of any other division by 100 are what keep that from going wrong.
Alternatives considered
Decimal/numeric columns — correct in the database but arrive in JavaScript as
strings or a Decimal object that must be handled at every boundary. Floats — never.