Skip to content

Commerce

Chapter 6. Rendering produced a page; a store also needs a cart, a login, and a checkout. This chapter is the pluggable commerce layer that supplies them.

Ratio doesn't own a commerce backend — it's pluggable. There are two seams: a resolver seam (read-side data into pages) and a provider seam (interactive cart / login / checkout). GoKwik is the first backend behind both.

The resolver seam (read — data into pages)

A page template declares dataSources; the renderer resolves them through an injected BindingResolver.

  • packages/builder-core/src/commerce/resolve.ts — the BindingResolver interface + resolvePage(...) (interpolate route params → fan-out fetch → inject into sections → union cache tags) + StubResolver (deterministic sample data for local dev/tests).
  • resolve-shopkit.ts — the real ShopkitResolver over @shopkit/data-layer's custom backend adapter. Dispatches each data-source type to a CommerceClient method; products pass through unmodified (prices in paise — display shaping is deferred to render, never in the fetch layer).
  • DATA_SOURCE_TYPES (page-builder/doc.ts): PRODUCT, PRODUCTS, PRODUCTS_BY_HANDLES, COLLECTION, COLLECTION_BY_HANDLES, COLLECTIONS, MENU, STATIC.
  • Boot factorystorefrontResolver(env) returns the real resolver when the COMMERCE_* URLs are set, else the stub; in production it throws rather than boot on sample data (the "Sample product N went live" guard).

Connecting a store to a backend

Two inputs combine:

  • Per-tenant creds (DB): tenant.commerce = { merchantId, storeId? } — set via the admin commerce route, verified by probing the backend. Shape in packages/data-repo.

  • Platform-global service URLs (env): one backend serves every merchant. The origin/admin task defs inject COMMERCE_{PRODUCT,CART,ORDER,NAV,CUSTOMER,SEARCH}_API_URL. The GoKwik service-prefix map:

    Env varGoKwik URLService
    COMMERCE_PRODUCT_API_URLgkx.gokwik.co/psproduct
    COMMERCE_CART_API_URL / COMMERCE_ORDER_API_URLgkx.gokwik.co/osorder + cart (same /os)
    COMMERCE_NAV_API_URLgkx.gokwik.co/pi/pcnavigation / menus
    COMMERCE_CUSTOMER_API_URLgkx.gokwik.co/cscustomer

    If the URLs aren't set the origin logs gokwik_config_incomplete and (in prod) refuses to serve samples.

The provider seam (interactive — cart / login / checkout)

Storefront interactivity is chosen per store, per capabilitypackages/storefront-integrations. How the active provider is resolved for each capability:

  • Capabilities: cart, login, checkout, account, search. composeStorefront(ctx, integrations) resolves the single active provider per capability (the store's explicit pick if enabled, else the first usable vendor, else a first-party native fallback), and returns head / bodyEnd HTML + a unioned CSP + the activeCart / activeAccount / activeSearch ids the origin dispatches on. — registry.ts, compose.ts, csp.ts
  • GoKwik providers:
    • side-cart/ — the KwikCart hosted drawer (the drawer is the cart; there's no cart page). Bridges the server cart token into the widget via a JS-readable X-Cart-Token cookie.
    • kwikpass/KwikPass phone+OTP login; persists the rt_kp_at cookie (holding the GoKwik access token) so the server can fetch order/account data, then refreshes the account island.
    • checkout/ — the GoKwik checkout SDK; captures order completion via postMessage (origin-pinned to gokwik.co/.io) and redirects to /order-confirmation.
  • Native fallbacks exist for cart / account / search when no vendor is active.

KwikPass ⟂ checkout are independent

Login (KwikPass) and checkout are separate toggles, each gated on its own env/config — a store isn't switched to KwikPass login just because it can sell. Don't consolidate them.

Origin commerce handlers

The interactive endpoints (all no-store) — apps/origin/src/handlers/:

  • cart.tsPOST /cart/add · /cart/update; resolves the variant server-side, sets the cart cookies, returns a re-rendered drawer fragment / JSON / a 303 (no-JS).
  • account.ts — login-gated; fetches profile / order history / addresses using the KwikPass access-token cookie; 3-tier render fallback (templates/account.jsonsections/main-account.liquid → built-in).
  • order.ts — the order-confirmation / thank-you page; clears cart cookies.
  • search.ts — native product search behind the activeSearch seam.
  • POST /checkout (in index.ts) — the server-side GoKwik createCheckout handshake.

Cart-token cookies

Three cookies, easy to conflate: an httpOnly server cart cookie, a JS-readable X-Cart-Token mirror for the GoKwik widget, and a rt_cart_present marker for the native cart. storeCartCookies / readableCartCookie / expireCartPresentCookie are the source of truth.

Note

@shopkit/data-layer (the canonical product/cart/order shapes + the custom-adapter contract) is an external npm dependency, not in-repo. The account-data.ts / search-data.ts fetchers hit /cs and the search service directly, outside the data-layer client.