Storefront Overview
The storefront lives in storefront/ in the rCommerce repository. It is an
Astro site with React islands, designed to serve multiple stores from one
codebase: each store is a separate Cloudflare Pages project, and all
store-specific differences are baked in at build time via PUBLIC_*
environment variables.
Production example: the same codebase serves store-a.example.com
(my-storefront Pages project) and store-b.example.com (store-b-pages
Pages project).
Build-time branding
Section titled “Build-time branding”Brand identity is resolved at build time in src/lib/brand/config.ts and
inlined by Astro — there is no runtime switching.
| Variable | Purpose | Default |
|---|---|---|
PUBLIC_BRAND_SLUG | Store key (store-a, store-b) — selects per-brand page variants | store-a |
PUBLIC_BRAND_NAME | Store name shown in header, footer, emails | My Shop |
PUBLIC_BRAND_LOGO | Logo path under public/ | /images/store-a-logo.png |
PUBLIC_BRAND_PRIMARY | Accent color (Tailwind primary) | #2563EB |
PUBLIC_BRAND_MENU | Header/footer categories: comma-separated slug:Label pairs | gear/apparel/accessories |
PUBLIC_HERO_VIDEO_URL | Cloudflare Stream iframe src for the homepage hero | hero video |
PUBLIC_BRAND_HERO_PRODUCT_SLUG | Product featured in the hero panel | acme-ceramic-mug |
PUBLIC_API_BASE | Backend API base for client-side fetches | https://api.store-a.example.com/api/v1 |
RCOMMERCE_API_URL | Backend origin for the runtime API proxy (no /api/v1 suffix) | — |
PUBLIC_AIRWALLEX_ENV | Fallback Airwallex environment for the checkout Drop-in (demo/prod) | demo |
Values fall back to the example store defaults when unset, so building with no environment produces the demo store.
Brand content system
Section titled “Brand content system”Long-form, user-visible content (taglines, contact pages, footer links and
columns, homepage copy, FAQ) lives in src/lib/brand/:
default.ts— the complete example store content. Every field of theBrandContenttype is present.store-b.ts— Store B overrides. Only fields that differ are set.index.ts— deep-mergesdefaultContentwith the override module selected byPUBLIC_BRAND_SLUG:
export const content: BrandContent = mergeContent(defaultContent, OVERRIDES[brand.slug]);Unknown slugs fall back to the defaults unchanged. To onboard a new store,
add a <slug>.ts override module and register it in the OVERRIDES map —
no other code changes are required. Each store must provide its own logo at
public/images/<store>-logo.png (do not reuse another store’s logo as a
stand-in).
The brand content map also carries wooRedirects — legacy WooCommerce
product slugs mapped to canonical product URLs. See
SEO & Redirects for how these are served.
Runtime API proxy
Section titled “Runtime API proxy”Client-side calls use PUBLIC_API_BASE directly, but cart, coupon, and
checkout mutations go through a same-origin proxy at
/api/v1/* (src/pages/api/v1/[...path].ts, a Pages Function). It forwards
to RCOMMERCE_API_URL at runtime, which keeps credentials and CORS off the
browser’s critical path and lets the storefront talk to its own origin.
Storefront features
Section titled “Storefront features”- Product catalog with category navigation and product detail pages
- Guest cart with drawer, coupon support
- Checkout with shipping selection and Airwallex Drop-in
- Account pages: register, login, password reset, order history
- Per-origin
robots.txt,sitemap.xml, and Google shopping feed - Legacy WooCommerce URL redirects (301) for migrated stores