Product Requirements Document

Ecommerce Starter Template

A Stripe-powered storefront template for create-profound-next, with checkout as a headless UI component and a catalog modeled entirely in the Profound CMS admin panel.
Product
create-profound-next
Feature
Ecommerce + Stripe template
Author
Daksh (daksh@tryprofound.com)
Date
June 13, 2026
Status
Draft for review
Version
0.1

1. Overview

create-profound-next today scaffolds a generic Next.js + Profound CMS starter. This PRD proposes a second, opinionated ecommerce template that ships a complete, deployable storefront: a Stripe-backed checkout exposed as a headless UI component, plus a product catalog (categories and items) modeled as first-class components inside the Profound CMS admin panel.

The goal is to let a developer run a single command and get a working store where a non-technical merchant can create categories, add products, set prices, and publish — with payments handled by Stripe and the entire visual layer editable in the CMS.

2. Problem & Goals

Problem

Building an ecommerce site on a CMS usually means stitching together a payments provider, a product data model, a checkout UI, and a content-editing experience by hand. There is no turnkey path from "scaffold" to "merchant-editable store with real payments."

Goals

Non-Goals

3. Target Users

PersonaNeedsTouchpoint
DeveloperFast scaffold, typed components, clear Stripe wiring, control over styling.CLI + codebase
Merchant / EditorCreate categories & products, set prices and images, publish — no code.Profound CMS admin panel
ShopperBrowse catalog, add to cart, pay securely.Storefront

4. CMS Components (Admin Panel)

Two new CMS components are registered in the catch-all route's registry (see [...slug]/page.tsx) and exposed in the admin panel for merchant editing.

4.1 Category component

FieldTypeNotes
nametextDisplay name, e.g. "Apparel"
slugtextURL segment, unique
descriptionrich textOptional intro copy
heroImageimageOptional banner
itemsreference[]Ordered list of Item components

4.2 Item (product) component

FieldTypeNotes
nametextProduct title
slugtextURL segment, unique
descriptionrich textProduct detail copy
imagesimage[]Gallery
pricenumberMinor units (cents)
currencyselectISO 4217, default usd
stripePriceIdtextMaps to a Stripe Price; source of truth for charging
categoryreferenceParent Category
activebooleanHide/show without deleting
Pricing integrity: the displayed price is for presentation; the actual charge is always derived server-side from stripePriceId. This prevents client-tampered amounts and keeps Stripe as the pricing source of truth.

5. Headless Stripe Checkout Component

Checkout ships as a headless component: it owns cart state, line-item validation, and the call to create a Stripe Checkout Session, but renders no opinionated markup. The developer supplies the UI via render props / children, so it adapts to any design.

5.1 Shape

// headless: logic + state, zero styling
const {
  items,            // cart line items
  addItem, removeItem, updateQty,
  subtotal,         // derived, display-only
  checkout,         // () => redirects to Stripe Checkout
  status,           // 'idle' | 'loading' | 'redirecting' | 'error'
  error,
} = useCart();

<Checkout>
  {({ checkout, status }) => (
    <button onClick={checkout} disabled={status === 'loading'}>
      Pay
    </button>
  )}
</Checkout>

5.2 Server flow

  1. Client calls a Server Action / route handler with item ids + quantities.
  2. Server resolves each id to its stripePriceId from the CMS, ignoring any client-sent price.
  3. Server creates a Stripe Checkout Session and returns the redirect URL.
  4. Client redirects to Stripe-hosted checkout; Stripe handles card entry (PCI scope stays with Stripe).
  5. A /api/stripe/webhook handler verifies checkout.session.completed and is the trusted fulfillment signal.
Why headless: ecommerce designs vary wildly. By providing state + Stripe wiring but no markup, the template stays reusable across brands while keeping the secure path (price resolution, session creation, webhook verification) fixed and correct.

6. Architecture & File Additions

Built on the existing base template (ParametricRoutePage, Refresher, createCmsProxy). New files added under src/templates/ecommerce/:

src/templates/ecommerce/
  src/
    app/
      [...slug]/page.tsx        # registry += { Category, Item }
      cart/page.tsx             # cart + headless <Checkout>
      api/stripe/
        checkout/route.ts       # create Checkout Session
        webhook/route.ts        # verify + fulfill
    components/
      Category.tsx              # CMS component
      Item.tsx                  # CMS component
      ProductGrid.tsx
    lib/
      stripe.ts                 # server Stripe client
      useCart.ts                # headless cart hook
  next.config.mjs
  _gitignore
  tsconfig.json

The CLI's generatePackageJson() adds stripe and @stripe/stripe-js alongside the existing cms-renderer dependency when the ecommerce template is selected.

7. Environment Variables

VariableScopePurpose
PROFOUND_API_KEYserverExisting — CMS access
NEXT_PUBLIC_PROFOUND_WEBSITE_IDclientExisting — website id
STRIPE_SECRET_KEYserverCreate sessions, verify webhooks
STRIPE_WEBHOOK_SECRETserverVerify webhook signatures
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYclientStripe.js redirect
NEXT_PUBLIC_SITE_URLclientCheckout success/cancel URLs

8. Requirements (MoSCoW)

#RequirementPriority
R1CLI scaffolds the ecommerce template via a flagMust
R2Category & Item registered as editable CMS componentsMust
R3Headless cart hook + Checkout componentMust
R4Server-side price resolution from stripePriceIdMust
R5Signed Stripe webhook handler for fulfillmentMust
R6Category & product listing/detail pages via CMS routingShould
R7Cart persistence across reloads (localStorage)Should
R8Discount/promo code supportCould
R9Inventory count + sold-out stateCould

9. Success Metrics

10. Risks & Open Questions

ItemMitigation / Question
CMS price vs. Stripe price driftTreat Stripe as source of truth; optional sync script to push CMS price → Stripe Price.
Webhook reliability in local devDocument stripe listen / Stripe CLI in template README.
Headless API surface scopeOpen: how much UI (e.g. a default unstyled cart) should ship as an optional example?
Catalog vs. Stripe Product syncOpen: auto-create Stripe Products from CMS Items, or require manual mapping in v1?

11. Milestones

PhaseScope
M1 — Data modelCategory + Item components, registry wiring, listing/detail pages
M2 — PaymentsHeadless cart, checkout session route, webhook handler
M3 — CLI integration--template ecommerce flag, deps in generatePackageJson()
M4 — PolishREADME, env docs, test-mode walkthrough, example styling