Quotes, sales, invoices, credit notes and payments.
orders is the system of record for every commercial document, and the one table both storefront backends and the field app converge on.
| Table | Holds |
|---|---|
orders | The header: customer, totals, addresses, dates, an external id, a status, a type. |
order_lines | One per product: quantity, unit price, the frozen tax split, the chosen variant's option codes. |
order_payments | Financial movements; a refund points at the payment it reverses. |
One table models the whole document chain. A quote becomes a sale becomes an invoice, chained by parent pointer and discriminated by type; a credit note or a return points at the order it reverses. Money is integer minor units and the VAT split is frozen per line on write, at the rate in force on the order date.
Every money-affecting write is a privileged database function, never client DML, because a public buyer has no session and a webhook carries no token.
| Path | Who | Born |
|---|---|---|
| Checkout | A public buyer, via the gateway webhook | paid |
| Field capture | A signed-in rep, on behalf of a store | draft, then confirmed |
| Shopify mirror | Shopify's paid-order webhook | paid |
Checkout is idempotent on the gateway's own reference, so a retried webhook returns the existing order. Field capture writes the draft as the rep and elevates only the confirmation, which re-prices every line, re-splits tax, checks stock and checks the store's credit limit, landing confirmed, flagged or on_hold.
/orders is the order list and detail with its lines, payments and deliveries. The customer's own history is the storefront's /account/orders.
orders.
orders.read and orders.manage. Row-level security is owner-or-admin: a rep sees the orders they created.
The order list leaves the sidebar and the route, the dashboard drops its revenue, order and average-order tiles, and nothing writes an order. The catalog and the marketing site stay.