30 lines
1.1 KiB
Markdown
30 lines
1.1 KiB
Markdown
# 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.
|