Foundaro Spokes Docs

Store

The Store module turns any Front site into a fully functional e-commerce storefront. A single site can host multiple stores (e.g. a consumer shop and a B2B wholesale store). Manage products, categories, and orders in the Hub; customers browse and purchase through your branded Twig theme.

Last updated:

Store

The Store module adds e-commerce functionality to any Front site. You manage products and categories through the Foundaro Hub, and customers experience a fully branded shop on your site.

Multiple Stores per Site

A single Front site can host multiple independent stores. Common use cases include running a consumer retail shop and a B2B wholesale store on the same domain, or separating product lines into distinct storefronts.

Store List

Navigate to Stores in the sidebar to see all stores for your organisation. The list supports card, list, and table views and can be filtered by name or sorted by creation date.

Click New Store to create a store. You will be asked for a name, a slug, and which site to attach it to.

Store Slugs

Each store has a unique slug (URL-friendly identifier, e.g. wholesale). The slug determines the store's public URL:

/site/:siteSlug/shop/:storeSlug/

Slugs must be unique within your organisation and can only contain lowercase letters, numbers, and hyphens.

Store Picker

When a site has more than one store, visiting /site/:siteSlug/shop shows a store picker page where customers can choose which storefront to enter. Each store card displays the store name, description, and type badge.

The store picker is theme-aware and renders using the site's active Twig theme.

Legacy URLs

The legacy /shop/ path (without a store slug) continues to work. Requests to /site/:siteSlug/shop/products resolve to the site's primary store — the first store attached to the site. No links need to be updated.

Store Dashboard

The Store Dashboard is the entry point for all commerce activity within a specific store. It shows:

  • Products — total product count with a link to the product list.
  • Categories — total category count.
  • Orders — total order count (updated in real time when Stripe webhooks are received).
  • Currency — the store's configured currency.

If no store exists yet for the selected site, the dashboard shows a setup prompt. Only Admins can create a store.

Each store inherits the site's Twig theme — no separate design work required.

Products

Products are the items customers can browse and purchase. Navigate to Store › Products to see the full product list.

The list supports three view layouts (cards, list, table) and can be filtered by:

  • Status — Draft, Published, or Archived.
  • Search — by product name or slug.

Each product card shows the featured image (or a placeholder), name, status badge, variant count, and starting price.

Hover over a card to reveal edit and delete action buttons.

Creating a Product

Click New Product in the header. Enter a name and slug in the dialog, then click Create — you will be taken directly to the product editor.

Product Editor

The product editor has three tabs:

Details tab

Field Description
Name Display name shown to customers.
Slug URL-friendly identifier. Used in the storefront URL: /shop/:storeSlug/products/:slug.
Short Description One-line summary shown in listing cards.
Description Full rich description shown on the product detail page.
Product Type Physical, Digital, or Service. Controls shipping requirement logic.
Tags Comma-separated labels for filtering and search.
Taxable Whether the product is subject to tax (used in future tax calculations).
Requires Shipping Disable for digital downloads or services.

Variants tab

Each product must have at least one variant to be purchasable. A variant represents a specific sellable configuration (e.g., "Small / Red").

Variant field Description
Name Describes the variant combination: "Small", "Large / Blue".
Price Price in the smallest currency unit (cents for USD).
Compare At Optional original price shown struck through to indicate a discount.
SKU Optional stock-keeping unit code for fulfilment.

Click Add Variant to create additional variants. Variants can be deleted individually.

SEO tab

Override the default meta title and meta description for the product detail page.

Status

Products have three statuses:

  • Draft — not visible in the storefront.
  • Published — live and browsable by customers.
  • Archived — hidden from the storefront; kept for record-keeping.

Change the status from the dropdown in the editor topbar. The change is saved immediately.

Product Categories

Categories organise your products into navigable groups. Navigate to Store › Categories.

Each category has:

  • Name — displayed in the storefront navigation.
  • Slug — used in the category URL: /shop/:storeSlug/categories/:slug.
  • Description — optional text shown on the category page.
  • Parent — optional parent category for nested hierarchies.
  • Weight — controls display order (lower = first).

Click any row to open the inline edit dialog. Use the delete button to remove a category — products in the deleted category become uncategorised.

Import and Export

Both Products and Categories support JSON import and export for bulk data operations.

Export: Click Import / Export → Export JSON in the list header. A .json file is downloaded containing all records for the current store.

Import: Click Import / Export → Import JSON and select a JSON file. Records are upserted by slug — existing records are updated, new records are created.

Product import supports both JSON and CSV formats.

Customer Cart

The cart is server-side and persists across sessions for 30 days. It is managed via the public REST API:

Endpoint Description
POST /api/public/front/sites/:slug/cart Create a new cart. Returns { cartId }.
GET /api/public/front/sites/:slug/cart/:cartId Get cart contents with computed totals.
POST ...cart/:cartId/items Add item { variantId, quantity }.
PATCH ...cart/:cartId/items/:itemId Update item quantity. Set to 0 to remove.
DELETE ...cart/:cartId/items/:itemId Remove a specific item.
DELETE ...cart/:cartId Clear all items.
POST ...cart/:cartId/checkout Create a Stripe Checkout session.

The cart response includes computed subtotal, shippingAmount, discountAmount, and total fields (all in cents).

The Alpine.js storefront JavaScript manages the cart cookie and calls these endpoints automatically.

Checkout and Payments

Checkout uses Stripe Checkout (hosted redirect). When a customer clicks Checkout:

  1. The server creates a Stripe Checkout session with the cart's line items.
  2. The customer is redirected to Stripe's hosted checkout page.
  3. On payment, Stripe sends a webhook to /api/public/front/stripe/webhook.
  4. The server creates an Order record and sends confirmation emails.
  5. The customer is redirected back to the success URL.

Requirements:

  • Set STRIPE_SECRET_KEY in your server environment variables.
  • Configure the Stripe webhook endpoint in your Stripe dashboard pointing to your server's public URL.

Stripe Connect is used so payouts go directly to the organisation's bank account. No platform fee is applied.

Stripe Connect — merchants connect their own Stripe account via OAuth. Payments go directly to the merchant with a 2% platform fee. Connect from Store Settings > Stripe Payments.

Store Settings

Navigate to Store › Settings to configure the store.

General

Setting Description
Store Name Displayed in the storefront header and Stripe checkout.
Slug URL-friendly identifier used in storefront URLs. Unique per organisation.
Description Optional store description (shown on the store picker page).
Currency ISO 4217 currency code (e.g., usd, eur, gbp).
Store Type Consumer (default) or B2B. Switching to B2B unlocks wholesale settings.

Shipping

Setting Description
Enable Shipping Toggle whether shipping costs are applied at checkout.
Flat Rate A fixed shipping cost in cents charged on all orders.
Free Shipping Above Orders over this subtotal (in cents) qualify for free shipping.

B2B Wholesale Settings

Available when Store Type is set to B2B.

Setting Description
Minimum Order Amount Minimum cart subtotal (in cents) required before a customer can proceed to checkout.
Net Payment Terms Display payment terms at checkout — None, Net 15, Net 30, Net 45, or Net 60.
Enable Quote Requests Show a "Request a Quote" button alongside (or instead of) the Checkout button. Submitted quotes are logged as orders with status QUOTE.
Account-Based Pricing Hide public prices and require the customer to be logged in and assigned an account price tier.

Customer Groups — create named pricing tiers (e.g. "Wholesale", "VIP") with discount percentages. Assign customers to groups for automatic price adjustments at checkout.

PO Numbers — B2B customers can enter a purchase order number at checkout. PO numbers appear on order details and exports.

Customer Approval — when "Require approval for new customers" is enabled, new registrations are set to Pending status. Customers can browse but cannot place orders until approved by an admin.

Roles and Permissions

Action Required Role
View products and categories CONTRIBUTOR
Create products CONTRIBUTOR
Edit products / add variants AUTHOR
Delete products / manage variants AUTHOR
Manage categories AUTHOR
Import / Export EDITOR
Manage store settings EDITOR
Create or delete store ADMIN

Orders

Navigate to Store › Orders to manage customer orders.

The order list shows all orders across all statuses with:

  • Order number — sequential number within the store.
  • Customer — name and email from the Stripe checkout.
  • Status — current fulfilment status with colour coding.
  • Total — order total in the store's currency.

Click View on any row to open the order detail page.

Order Detail

The order detail page shows:

  • Line items — product name, variant, price, quantity, and subtotal.
  • Order totals — subtotal, shipping, discounts, and grand total.
  • Customer — name, email, phone, and shipping address captured at checkout.
  • Status transitions — use the dropdown to advance the order through the fulfilment workflow:
From Valid next statuses
PENDING PAID, CANCELLED
PAID PROCESSING, CANCELLED
PROCESSING SHIPPED, CANCELLED
SHIPPED DELIVERED
CANCELLED REFUNDED
  • Tracking number — enter and save a carrier tracking number. Setting status to SHIPPED automatically records a timestamp.
  • Internal notes — private notes not visible to the customer.

Public Storefront

The Store module includes a fully server-rendered storefront. The canonical URL pattern includes the store slug:

Path Description
/site/:siteSlug/shop Store picker (multiple stores) or store home (single store).
/site/:siteSlug/shop/:storeSlug Store home — featured products and categories.
/site/:siteSlug/shop/:storeSlug/products Product catalogue with search and category filter.
/site/:siteSlug/shop/:storeSlug/products/:slug Product detail with variant selection and add-to-cart.
/site/:siteSlug/shop/:storeSlug/categories/:slug Category page with filtered product grid.
/site/:siteSlug/shop/:storeSlug/cart Shopping cart with live totals and checkout button.
/site/:siteSlug/shop/:storeSlug/order-success Confirmation page after successful Stripe payment.

Legacy routes (without :storeSlug) continue to work and resolve to the site's primary store.

Cart JavaScript

The storefront uses a self-contained vanilla JS module (/public/js/shop-cart.js) for cart interactivity. Cart state is persisted in localStorage and synced to the server-side cart API — no page reload is required to add or remove items.

The global window._shopCart object exposes helper methods used by the Twig templates. Cart interactions are wired via data-action attributes and delegated event listeners; no inline event handlers are needed.

Digital Downloads

Set productType to DIGITAL to sell downloadable files. For each variant, configure:

  • Download URL — The direct URL to the file (e.g., an R2/S3 pre-signed URL).
  • Download Limit — Optional cap on how many times a link can be used. Leave blank for unlimited.

After a successful Stripe checkout, the system automatically generates a secure download token (64-character hex, valid for 30 days) for each digital variant. Customers are redirected to /site/:siteSlug/shop/order-success which displays their download links.

Download tokens are accessible in the Hub under Store → Orders → [order] → Download Links.

Download API

Route Description
GET /api/public/front/sites/:siteSlug/downloads/:token Validates token and redirects to file URL. Returns 410 Gone if expired, 403 Forbidden if limit reached.
GET /api/front-downloads/order/:orderId List tokens for an order (authenticated, CONTRIBUTOR+).
POST /api/front-downloads/tokens/:tokenId/regenerate Regenerate an expired/exhausted token (EDITOR+).

Recurring Subscriptions

Set productType to SUBSCRIPTION to sell recurring billing plans. Once set, a Plans tab appears on the product edit page where you can create multiple billing tiers.

Subscription Plans

Each plan has:

Field Description
Name Display name (e.g. "Monthly", "Pro Annual").
Interval MONTHLY, QUARTERLY (3-month), or ANNUAL.
Price Amount in the store's currency (cents).
Trial Days Optional free trial period before billing begins.

Plans are lazily synced to Stripe: the first time a checkout is attempted for a given plan, a Stripe Price object is created and the stripePriceId is stored to avoid future duplication.

Subscriber Management

Navigate to Store → Subscriptions to see all subscribers with their status, plan, period dates, and trial end date. From this view you can cancel any active subscription (which also calls stripe.subscriptions.cancel() immediately).

Subscription lifecycle is kept in sync via Stripe webhooks (customer.subscription.created/updated/deleted), all routed through the existing /api/public/front/stripe/webhook endpoint.

Coupon Codes

Navigate to Store → Coupons to create and manage discount codes for your customers.

Coupon Types

Type Description
Percentage Deducts a percentage of the subtotal (e.g., 10% off). Value is stored in basis points — 1000 = 10%.
Fixed Amount Deducts a fixed amount in cents (e.g., 500 = $5.00 off). Capped at the order subtotal.
Free Shipping Zeroes the shipping cost.

Coupon Fields

Field Description
Code Uppercase alphanumeric code shown to customers. Unique per store.
Min Order Amount Minimum subtotal (in cents) required to use the coupon.
Max Uses Total number of times this coupon can be used. Leave blank for unlimited.
Expires At Date after which the coupon is no longer valid.
Active Toggle to enable or disable the coupon without deleting it.

Customers enter coupon codes on the cart page before checkout. The discount is reflected in the order summary before payment. Coupon usage counts are incremented when an order is fulfilled.

Tax Rules

Configure tax settings in Store → Settings → Tax.

Setting Description
Tax Rate (%) Percentage applied to taxable products at checkout (e.g., 8.5 for 8.5%). Set to 0 to disable.
Prices Include Tax When enabled, prices are treated as tax-inclusive and no tax is added at checkout.

Tax is computed as: taxableSubtotal × taxRate ÷ 100, where taxableSubtotal is the total of all items where product.taxable = true, minus any coupon discount. The tax amount is shown as a separate line item on the cart summary.

For Stripe Checkout, tax is passed as an additional line item. For PayPal, it is included in the order breakdown.tax_total.

PayPal Checkout

Enable PayPal as an additional payment method in Store → Settings → PayPal.

  1. Create a PayPal Developer account at developer.paypal.com
  2. Create a REST API app to obtain a Client ID and Client Secret
  3. Enter these credentials in Store Settings
  4. Toggle Enable PayPal checkout — a "Pay with PayPal" button will appear on the cart page alongside the Stripe card button

Sandbox mode: Set PAYPAL_BASE_URL=https://api-m.sandbox.paypal.com in your server environment variables to use PayPal's sandbox. Remove this variable (or set it to https://api-m.paypal.com) for live payments.

PayPal orders are captured via the PayPal Orders API v2. On capture, an Order record is created with paymentMethod: PAYPAL. No Stripe involvement.

Upcoming Features

The following features are planned for future phases:

  • Multi-currency display and automatic currency conversion
  • Account-based pricing tiers for B2B customers (assignable price lists)
  • Service and booking products with calendar integration