Inkress ADRsarchitecture decisions
Overview / Fulfillment
ADR 0045

Delivery is a merchant-authored rate matrix; the checkout shipping total is client-supplied

AcceptedFulfillment

Context

Merchants shipping physical goods need to charge for delivery. There were choices for both the rate model (carrier live-rate APIs, a merchant-defined matrix, or a flat fee) and for who is authoritative over the shipping charge at checkout. Tax is a related question.

Decision

Let merchants author a shipping rate matrix, but take the shipping charge at checkout as a client-supplied fulfillment_total that the server validates as money but does not recompute; run no tax engine.

  • Merchant rate matrix. Delivery is modeled as shipping methods × areas × rates × day-windows: ShippingMethodArea carries the price/ETA/exclusions per area, ShippingArea adds hierarchy and time windows, ShippingMethodDay gives day availability, and ShippingStatus tracks per-order fulfillment (distinct from order status, ADR 0013).
  • Client-supplied shipping total. At order time the checkout takes fulfillment_total from the request, validates it as a well-formed money value, and uses it — it does not re-derive the figure from the rate matrix server-side.
  • No tax computation. fetch_tax returns zero; tax is either baked into merchant prices or out of scope.

Consequences

  • Positive: merchants express arbitrary delivery rules (per-area prices, ETAs, exclusions, day availability); checkout stays simple by consuming a single computed shipping figure.
  • Neutral / to revisit — a real tension with server-authoritative pricing (ADR 0012). Shipping is the one checkout component the server trusts from the client: fulfillment_total is not recomputed from the matrix at order time, so a tampered client could understate shipping. It is an accepted gap today (shipping is merchant-configured and small relative to the item total, which is server-authoritative), and the clear remediation is to recompute shipping server-side from the matrix.
  • Neutral / to revisit — no tax engine. With fetch_tax stubbed to zero, tax-inclusive pricing is the merchant's responsibility; a tax subsystem is unbuilt.

Alternatives considered

  • Carrier live-rate APIs (real-time rates): not adopted — heavier integration than the markets served need; the merchant-authored matrix covers them.
  • Recompute the shipping charge server-side from the matrix at order time: not currently done — the client-supplied fulfillment_total is trusted; this is the gap noted above and the natural next step.
  • A single flat shipping fee: rejected — too coarse; the matrix gives per-area, per-method control.
← 0044 Bookings are a thin vertical over the commerce catalog, not a standalone scheduler 0046 Notifications are medium-tagged records fanned to per-channel adapters via a polling outbox →