Snapshotting Tax at Checkout
Snapshotting Tax at Checkout
Congratulations on making it to the final lesson in this path! 🎉 You have come a long way—from building foundational APIs, to managing carts and orders, to applying country-based taxes before checkout. This last step brings everything together in one of the most important moments in an e-commerce backend: turning a live cart into a permanent order snapshot.
In this lesson, we will focus on preserving tax history at checkout time. That means the order should store the exact tax_country, tax_rate_bps, tax_cents, and total_cents that were true at the moment checkout happened. Even if tax rates change later, old orders must not change with them. By the end of this lesson, you will see how the checkout transaction captures those values, why reads must return the stored snapshot instead of recomputing tax, and how the repository keeps order data consistent across both list and get-by-id reads.
Previously, we made carts tax-aware by allowing a cart to store a tax_country and by deriving cart totals from the current tax_rates configuration. That was the right behavior for a cart, because carts are still editable and should reflect current pricing rules. Orders are different: once checkout succeeds, their financial values must become permanent.
Why Checkout Needs a Tax Snapshot
A cart is allowed to change. A user can add items, remove items, switch quantities, or even change the country used for tax calculation. Because of that, cart totals should always reflect the current state of the cart and the current tax configuration.
An order is not like that. Once checkout succeeds, the order becomes a historical record of what the customer actually agreed to pay. If a tax rate for US changes tomorrow, that should affect future carts and future checkouts, but it should never rewrite an existing order from yesterday.
That is why checkout must snapshot tax data. Instead of storing only the final tax_cents, we also persist the tax_country and the exact tax_rate_bps used during checkout. That gives us both the result and the context behind the result, which is useful for receipts, order history, debugging, and accounting.
The Order Row Must Include Tax Snapshot Fields
The first place this lesson touches is src/lib/repositories/ordersRepo.ts. Since orders are supposed to preserve tax details, the repository’s database row type must include those fields explicitly.
This is important because the repository is the layer that converts raw database rows into domain objects. If the row type omits tax_country or tax_rate_bps, those values will never make it into the Order returned by the rest of the application.
-
This row type mirrors the important persisted columns in the
orderstable, including bothtax_countryandtax_rate_bps. That matters because a checkout snapshot is only useful if the repository actually reads those stored values back out of the database. -
Including
tax_countrygives clients the geographic context used for tax resolution at checkout time. Includingtax_rate_bpsgives clients the exact rate that produced the storedtax_cents, which is especially helpful when explaining old orders after tax policies have changed. -
These fields are not optional extras in this workflow. They are part of the order’s financial record, and keeping them in the row type ensures the repository remains aligned with the database schema and the domain model.
