Storefront renderOverview

Storefront render

Public merchant storefronts are served by one shared Next.js app (web), not by a server inside each box. The render app resolves every incoming host to the correct tenant and the correct bank engine backend, then renders the storefront against that backend’s data.

Why centralized render

  • One deployment, every bank. Adding a box does not require standing up a new storefront server.
  • Control-plane host routing. The control plane (via DNS delegation) maps each public host to its box; the render app asks it which backend serves a host.
  • Per-bank isolation. Each request fetches only from its own box’s engine, threaded through request headers — never a shared data pool.

End-to-end flow

  1. Request arrives at the edge for some host.
  2. Middleware resolves the host to a tenant slug and a backend URL — by platform subdomain, by control-plane lookup for non-platform domains, or by custom-domain lookup. See Host & tenant routing.
  3. Headers are injected (x-subdomain-tenant, x-box-backend-url) and the request is rewritten to the [tenant] route.
  4. Route handlers fetch tenant data; the API client reads x-box-backend-url so every consumer talks to the right box with no call-site changes.
  5. Storefront API calls are forwarded through the proxy route with security filters.

Host resolution

For non-platform domains the render app calls the planned control-plane endpoint GET /boxes/resolve?host=… to learn the backend URL and match kind.

⚠️

GET /boxes/resolve is not yet implemented in the control plane. Until it ships, box-resolve.ts in the render app acts as a client stub. Positive lookups are cached 60s, negative lookups 30s (with a 2s timeout), so an unclaimed host cannot stampede the backends.

Sections