profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Tutorials

Build & Ship an Airport DirectoryDeploymentsBuild & Ship a Stripe Storefront

Feature

Documentation Site TemplateFeature Template BuilderTranslation ServiceOrganizations & Website HeirarchyConnect Profound CMS to your AI clientSettings IntegrationsSettings API KeysSettings UsageSettings Websites
All Systems Operational
Powered Byprofound-logo
Theme

Build & Ship a Stripe Storefront

Een praktische walkthrough: bouw een contentgestuurde Stripe-storefront op Profound CMS — een catalogus die een merchant zonder code kan bewerken, twee parametrische routes, een headless winkelwagen en door Stripe gehoste checkout.

De voltooide winkel in beweging — bekijk een categorie, open een product, voeg toe aan de winkelwagen, reken af.

Een praktische walkthrough die een contentgestuurde winkel op Profound CMS opbouwt: een productcatalogus (categorieën + items) gemodelleerd in het CMS, lijst- en detailpagina’s vanuit één set routes, en door Stripe gehoste checkout geleverd als een headless component.

De ruggengraat is met de hand geschreven Next.js plus de Profound-admin. Claude Code (via de Profound MCP) doet het zware werk bij drie taken — het vullen van de catalogus, het aansluiten van het designsysteem en het schrijven van de storefront-componenten (inclusief de headless winkelwagen). Drie delen: Setup, Build, Production.

Betalingen in één regel. We gebruiken door Stripe gehoste Checkout: de klant betaalt op Stripe’s pagina, niet op die van jou. Je app doet slechts twee dingen aan de serverkant — een Checkout Session aanmaken en één webhook verifiëren. Geen kaartvelden, geen Stripe Elements, geen PCI-last.

Wat je gaat bouwen

  • Een kleine gepubliceerde catalogus in de CMS — drie categorieën en acht producten (de "Edison’s Inventions"-demo) — elk bewerkbaar door een merchant zonder code.
  • Twee parametrische routes (/products/{item_code}, /categories/{category_code}) plus een statische /cart, allemaal vanuit één set componenten.
  • Een headless winkelwagen (useCart) en door Stripe gehoste checkout, waarbij de prijs altijd server-side wordt opgelost vanuit een Stripe Price ID.
  • De winkel gedeployed op Vercel met live preview en in-place bewerken voor het team.

Vereisten

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Claude Code met de Profound MCP (deel 1 installeert deze).
  • Een Profound CMS-account.
  • Een Stripe-account. Deze tutorial draait in testmodus, zodat er geen echt geld wordt afgeschreven tijdens het bouwen — maar de flow is identiek met live sleutels, dus gebruik je echte accountgegevens als je dat liever hebt. (Testmodus vereist geen bedrijfs- of bankgegevens.)
  • De Stripe CLI (stripe login) voor lokale webhooks.
  • Voor deployment: de GitHub CLI (gh) en een Vercel-account dat verbonden is met GitHub.

Hoe de onderdelen op elkaar aansluiten

Profound scheidt content van rendering:

  • Componenten definiëren de vorm van content. Een Custom Component met een Route Slug-veld is routeerbaar (category, item); één met het label UI Element is te plaatsen op een pagina (nav, product_grid, …).
  • Documenten zijn de content (een product, een categorie).
  • UI-elementen zijn paginasecties; elk scalair veld krijgt een statische waarde of een CEL- expressie die bij renderen wordt geëvalueerd.
  • Parametrische routes koppelen een URL aan een document + UI-elementen, waarbij route-parameters worden doorgegeven (meta.params.* in CEL, routeParams in React).
  • Je Next.js-app leest dit via cms-renderer; Stripe wordt toegevoegd als gewone API-routes.

De ene regel die de build bepaalt: CEL bindt alleen string/number-velden. Dus scalair chrome (nav-brand, footer, koppen) bind je met CEL, terwijl alles wat rijk is of een collectie (een productraster, een afbeeldingsgalerij, rich text) binnen de React-component wordt opgehaald op basis van de routeparameter. En Stripe is de bron van waarheid voor de prijs — de CMS-price wordt alleen getoond; de afrekening komt altijd server-side uit een Stripe Price ID.

Deel 1 — Setup

Eindsituatie: een kleine gepubliceerde catalogus, de app aangesloten om deze te lezen, Stripe geïnstalleerd, design aanwezig — nog niets gerenderd.

1. Meld je aan en maak de website aan

Meld je aan bij Profound (WorkOS-auth). Maak een website met de naam store, kopieer vervolgens het website ID (de UUID in de admin-URL) en een API-sleutel met leesrechten (Deployments → Create API key). De app leest alleen; het vullen van de catalogus gebeurt later via de MCP, die afzonderlijk authenticatie vereist.

2. Scaffold de app, verbind deze en voeg Stripe toe

bunx create-profound-next store
cd store
bun add stripe

De scaffold is een Next.js App Router-project dat vooraf is ingericht voor Profound (de cms-renderer-SDK, een catch-all route, een generate-schemas-script, een <Refresher>). Er worden geen stijlen meegeleverd. bun add stripe haalt de server-SDK op — de enige betalingsafhankelijkheid die gehoste checkout nodig heeft.

Voeg je waarden toe aan .env.local:

# CMS
PROFOUND_API_KEY=<je read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<je website-id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net   # levert CMS-gehoste afbeeldingen

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # test key hier; wissel naar je live key wanneer je live gaat
STRIPE_WEBHOOK_SECRET=whsec_...          # wordt ingevuld in Build stap 4
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Haal STRIPE_SECRET_KEY uit Stripe → Developers → API keys. We gebruiken een testsleutel (sk_test_…) zodat het bouwen nooit echt geld verplaatst; schakel naar je live sleutel zodra je klaar bent om echte betalingen te accepteren. Voer bun dev uit en open localhost:3000 — de starter wordt gerenderd.

Gehoste checkout leidt de browser om naar een Stripe-URL, dus de servergeheime sleutel is alles wat Stripe nodig heeft — geen publishable key, geen client-SDK van Stripe.

3. Definieer de componenten category, product_image en item

Maak drie Custom Components (Components → Create new component) — de datalaag, dus geen UI Element-tag. Stel elk in op Active.

Het CMS heeft geen veld "array of image", dus een galerij is een array van referenties naar een kleine product_image-component. Maak category en product_image (en zet ze op Active) voordat je item maakt — een reference-veld kan alleen Active componenten als doel hebben.

  • category — name (Text), code (Text, Route Slug), description (Rich text), heroImage (Image)
  • product_image — image (Image)
  • item — name (Text), code (Text, Route Slug), description (Rich text), images (array van referenties → product_image), price (Number, cents — alleen weergave), currency (Select, usd), stripePriceId (Text), category (Reference → category), active (Boolean)

Laat alle velden optioneel. De admin zet veldnamen in lagere snake_case ("Stripe Price Id" → stripe_price_id) — daarop baseert je code zich, dus lees de echte namen straks terug uit generate-schemas. We noemen de route-handle code (niet slug): het is de Route Slug en de sleutel voor een nette documents.getByCode-lookup later.

De component item — code als Route Slug, images als referenties naar product_image, plus stripePriceId en een category-referentie.

4. Haal de componenten op naar lokale types

bun run generate-schemas

Schrijft Zod-schema’s + types naar generated/cms-schemas.ts (categorySchema/Category, itemSchema/Item). Dubbele controle van de verbinding — met foutieve inloggegevens faalt dit hier.

5. Vul de catalogus via de Profound MCP

Installeer en authenticatieer de MCP één keer:

claude mcp add --transport http Profound http://107.21.107.99:8081/mcp

Voer mcp__Profound__authenticate uit, rond de WorkOS-flow af en geef Claude vervolgens de prompt:

Genereer een kleine ecommerce-catalogus voor een winkel genaamd Edison’s Inventions — drie categorieën en deze producten, met een korte tijdsgetrouwe description voor elk, een price in cents, currency: "usd", en active: true:

  • Lighting & Power (code: lighting): Incandescent Lightbulb (incandescent-lightbulb, $24), Electric Dynamo (electric-dynamo, $890), Electric Pen (electric-pen, $49)
  • Sound Recording (code: sound): Tinfoil Phonograph (tinfoil-phonograph, $249), Carbon Microphone (carbon-microphone, $59), Dictaphone (dictaphone, $179)
  • Motion Pictures (code: motion): Kinetoscope (kinetoscope, $399), Kinetograph Camera (kinetograph, $549)

Elke categorie heeft een name en die lowercase code; elk item heeft een name, die lowercase code, de description, price (in cents), currency en active. Sla het op in data/catalog.json en valideer het tegen onze componenten category en item. Maak vervolgens met de Profound MCP elk document aan als gepubliceerd: maak eerst de categorieën, leg hun ID’s vast, maak daarna de items met category ingesteld op een referentie — { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }. Laat stripePriceId voorlopig leeg. Doe de items parallel.

Claude schrijft data/catalog.json, valideert deze en voert parallelle create_document-calls uit (status: "published"). Vul categorieën vóór items zodat de referenties naar ID’s wijzen die al bestaan.

De drie gevulde categorieën, gepubliceerd en Live.

De acht gevulde producten, elk gekoppeld aan een categorie.

6. Maak Stripe-prijzen aan en koppel een paar producten

De catalogus staat in het CMS; geef nu een paar producten een echte Stripe-prijs — het werk van de merchant, gedaan in twee adminpanelen, zonder code:

  1. Stripe Dashboard → Products → + Add product, stel een eenmalige prijs in, kopieer de Price ID (price_…).
  2. Doe dit voor ongeveer drie hero-producten (bijv. Lightbulb, Phonograph, Kinetoscope).
  3. Profound-admin → item → Documents → plak elke Price ID in stripePriceId, sla op.

Het CMS bevat de catalogus; Stripe bevat de prijs van record; de link is één string die de merchant plakt. (Lievere automatisering? De officiële Stripe MCP kan de Products/Prices voor je aanmaken — plak de teruggegeven ID’s op dezelfde manier.)

7. Voeg het designsysteem in en sluit het aan met AI

De scaffold wordt ongestyled geleverd. Plaats een DESIGN.md (een Tailwind v4-@theme-blok + tokens) in de projectroot — je eigen bestand, of download er een van refero.design. Vraag vervolgens Claude, beperkt tot styling:

Lees het designbestand dat ik zojuist heb toegevoegd. Richt Tailwind in indien nodig, sluit vervolgens het thema en de fonts aan zodat de styling werkt. Gebruik next/font voor fonts — laad ze niet op runtime van Google. Alleen de styling — bouw nog geen pagina’s of componenten.

Controleer of src/app/globals.css @import "tailwindcss"; + het @theme-blok bevat en dat localhost:3000 de tokens toont. Houd de prompt strak (open prompts laten een agent een hele homepage scaffolden) en laad fonts via next/font, nooit via een runtime-Google-import.

8. Voeg productafbeeldingen toe (optioneel)

Optioneel — je kunt een werkende checkout bereiken zonder afbeeldingen. Voeg je ze toe? Maak dan per afbeelding een product_image-document (upload naar het veld image), en verwijs daar vervolgens naar vanuit de images-array van het product. Gebruik eigen productfoto’s, of genereer een samenhangende set met een imagemodel (laat Claude prompts afleiden die bij DESIGN.md passen en vergrendel één Midjourney --sref zodat elke opname overeenkomt).

De standalone cms-renderer heeft geen helper voor image-URL’s, dus lever buildAssetUrl aan in src/lib/image.ts (~40 regels) — deze voegt NEXT_PUBLIC_BUNNY_CDN_URL als voorvoegsel toe en plakt de extensie eraan. De componenten in Build stap 3 gebruiken dit.

Deel 2 — Build

Bouw de renderlaag en de checkout, met als resultaat een echte aankoop in testmodus.

1. Definieer de vijf UI-elementcomponenten

Vijf componenten, elk Active en gelabeld als UI Element (Settings → Tags), geen Route Slug:

  • nav → brand · product_grid → heading · product_detail → heading · cart_summary → heading · footer → text (allen Text)

Het label UI Element zorgt ervoor dat een component verschijnt in de Add UI Element-lijst van de Page Builder — Active alleen is niet genoeg. Elk veld is een scalair (het type dat CEL bindt); de echte catalogusdata is geen veld hier — ProductGrid/ProductDetail halen die op basis van de routeparameter op (stap 3).

2. Genereer de types opnieuw

bun run generate-schemas

3. Genereer de catalogusreader, componenten en headless winkelwagen

Eén prompt bouwt de leeshulp, de vijf componenten, de cart en de registry:

Bouw onze storefront in src/, met gebruik van de Profound-cms-renderer-SDK.

src/lib/catalog.ts — een server-side CMS-reader. Maak een client met getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) uit cms-renderer/lib/cms-api. Exporteer getItemByCode(code) → cms.documents.getByCode.query({ websiteId, schemaName: "item", code }) en laat res.document.published_content teruggeven. Exporteer listItems(categoryCode?) → cms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 }), map res.documents naar .published_content, filter active !== false, en als categoryCode is meegegeven behoud je items waarvan category._ref gelijk is aan de document.id van de categorie. Exporteer resolveImages(refs) die elke referentie uit item.images ophaalt via cms.documents.get.query({ websiteId, id: ref._ref }) en het beeldveld omzet in een URL met de aangeleverde buildAssetUrl (Deel 1 stap 8).

src/components/ — vijf UI-elementcomponenten geregistreerd in de registry van de catch-all route per componentnaam, snake_case om overeen te komen met de admin: { nav, product_grid, product_detail, cart_summary, footer }. Nav en Footer lezen hun scalair veld van de content-prop (getypt als BlockComponentProps<T> uit cms-renderer/lib/types). ProductGrid en ProductDetail zijn async servercomponenten die routeParams lezen en de data ophalen uit catalog.ts: routeParams.<param> is { value, … } — lees .value, dus ProductGrid roept listItems(routeParams.category_code?.value) aan (kaarten linken naar /products/{code}) en ProductDetail roept getItemByCode(routeParams.item_code?.value) aan (galerij via resolveImages, rich-textbeschrijving, prijs, knop Toevoegen aan winkelwagen). CartSummary rendert de winkelwagen vanuit useCart met een knop Betalen. Plaats formatPrice in een pure src/lib/format.ts zodat clientcomponenten de server-only catalog.ts niet importeren.

src/components/AddToCartButton.tsx — een "use client"-knop met { code, name, priceLabel } die useCart().addItem({ code, name, priceLabel, quantity: 1 }) aanroept. Gebruik deze binnen ProductDetail.

src/lib/useCart.ts — een headless winkelwagen: orderregels { code, name, priceLabel, quantity } in state, opgeslagen in localStorage, met addItem/removeItem/updateQty/subtotal en een checkout() dat { lines: [{ code, quantity }] } (alleen codes en hoeveelheden — nooit prijzen) POST naar /api/stripe/checkout, en daarna doorstuurt naar de geretourneerde url.

Style alles met ons designsysteem, als onze eigen componenten — kopieer de layout van de bron-site niet.

Drie dingen om te weten nadat dit is uitgevoerd:

  • Scalair chrome komt binnen via content ({ content }: BlockComponentProps<T>) — als je velden als top-level props destructureert rendert het block leeg. Catalogusdata komt binnen via routeParams + een fetch in catalog.ts, omdat CEL geen lijsten of galerijen kan binden. De winkelwagen draagt item-codes, nooit prijzen.
  • routeParams.<param> is { value, schemaName, document } — lees .value. Leescalls geven published_content terug, niet .content. Registry-sleutels zijn snake_case om overeen te komen met de admin.
  • Update @types/react/@types/react-dom naar v19 — de scaffold levert v18, wat async servercomponent-blocks breekt tegenover React 19.

4. Schrijf de Stripe-servercode (de ruggengraat)

Drie korte serverbestanden — de enige betalingscode in de app. Ze hergebruiken getItemByCode, zodat de prijs server-side wordt bepaald.

src/lib/stripe.ts:

import Stripe from "stripe";
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

src/app/api/stripe/checkout/route.ts — haal elk item op uit het CMS, reken af tegen de Stripe-prijs:

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // server-side, sleutel met leesrechten

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] — geen prijzen van de client
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // server haalt op uit het CMS
      return { price: item!.stripe_price_id, quantity }; // prijs uit het CMS, nooit van de client
    })
  );
  const session = await stripe.checkout.sessions.create({
    mode: "payment",
    line_items,
    success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/cart?status=success`,
    cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/cart?status=cancelled`,
  });
  return NextResponse.json({ url: session.url });     // client leidt hierheen om
}

src/app/api/stripe/webhook/route.ts — het vertrouwde fulfillment-signaal:

import { stripe } from "@/lib/stripe";

export async function POST(req: Request) {
  const body = await req.text();                      // RAUWE body — vereist voor handtekeningcontrole
  const sig = req.headers.get("stripe-signature")!;
  let event;
  try {
    event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch {
    return new Response("Bad signature", { status: 400 });
  }
  if (event.type === "checkout.session.completed") {
    // fulfill: order registreren / ontvangstbewijs versturen.
  }
  return new Response(null, { status: 200 });
}

Benodigde scaffoldfix: de scaffold stuurt src/proxy.ts elke /api/* door naar de CMS, waardoor je Stripe-routes nooit draaien. Laat deze eerst passeren:

import { createCmsProxy } from "cms-renderer/lib/proxy";
import { NextResponse, type NextRequest } from "next/server";
import { cmsConfig } from "@/lib/cms-config";

const cmsProxy = createCmsProxy({ upstream: cmsConfig.cmsUrl });
const LOCAL_API_PREFIXES = ["/api/stripe"];

export const proxy = async (request: NextRequest) => {
  if (LOCAL_API_PREFIXES.some((p) => request.nextUrl.pathname.startsWith(p))) {
    return NextResponse.next();                       // lokaal afhandelen
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// laat de `export const config = { matcher: [...] }` van de scaffold ongewijzigd

Controle: curl -X POST localhost:3000/api/stripe/webhook -d x geeft Bad signature terug.

Laat de Stripe CLI draaien voor lokale webhooks:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# kopieer de whsec_... naar STRIPE_WEBHOOK_SECRET, start bun dev opnieuw

De whsec_… is per sessie. Twee regels dragen de beveiliging: checkout leidt de prijs opnieuw af uit het CMS via code (een gemanipuleerde winkelwagen kan deze niet veranderen), en de webhook verifieert de handtekening tegen de rauwe body.

5. Maak de routes aan

Admin → Pages → Create page, drie keer. Koppel elke parameter aan de bijbehorende component (slug-veld code):

  1. /products/{item_code} → item
  2. /categories/{category_code} → category
  3. /cart — een statische pagina (voer letterlijk /cart in, niet /{cart})

6. Voeg UI-elementen toe, sluit CEL aan, publiceer

Voor elke route: Page Builder → Add UI Element → Custom → voeg componenten in de juiste volgorde toe, vul de scalair velden (statische waarde of CEL), Publish.

  • /products/{item_code}: nav, product_detail, footer
  • /categories/{category_code}: nav, product_grid, footer
  • /cart: nav, cart_summary, footer

Stel nav.brand en footer.text in op statische strings; koppen op statische labels.

De Page Builder op de categorie-route — het element product_grid geselecteerd, de heading gebonden via CEL.

De Page Builder op de productroute — het element product_detail op een productbinding.

Parametrische Page Builder-valkuil: op de twee parametrische routes blijven UI-elementen niet bewaard (blocks raken verweesd en de pagina rendert leeg). Totdat dit is opgelost, koppel je die pagina’s block_ids rechtstreeks via de Profound MCP update_page, en publiceer je daarna. (De statische /cart koppelt zich normaal.) Om dezelfde reden haalt ProductGrid zijn heading af van de categorie die hij ophaalt, in plaats van via CEL.

7. Render en koop

  • /categories/lighting → het raster. Klik op een product → detail + Voeg toe aan winkelwagen. /cart → Betalen.
  • Betalen leidt naar door Stripe gehoste checkout. Gebruik testkaart 4242 4242 4242 4242, elke toekomstige vervaldatum/CVC. Je komt terug op /cart?status=success, en stripe listen toont checkout.session.completed.

Een gerenderde productpagina — galerij, prijs en Voeg toe aan winkelwagen.

De winkelwagen — orderregels en één Pay-with-Stripe-knop.

Alleen geprijsde items zijn te kopen — koop één van de ~3 die je in stap 6 hebt geprijsd.

Optioneel — internationaliseren. Vertaal elke component (alle 35 talen tegelijk), voeg een /{language}/…-segment toe dat is gekoppeld aan de ingebouwde System-component language, en schakel CEL-gebonden velden over op documents.translated. Zie de vliegveld-directory-tutorial, Deel 2 stap 7.

Deel 3 — Production

1. Deploy: GitHub, daarna Vercel

git init && git add -A && git commit -m "Stripe storefront"
gh repo create store --private --source=. --push   # --public is ook prima

Build-opdracht: generated/cms-schemas.ts staat in .gitignore, dus pin de build zodat deze opnieuw genereert — voeg vercel.json toe:

{ "$schema": "https://openapi.vercel.sh/vercel.json", "buildCommand": "bun run generate-schemas && next build" }

In Vercel: Add New → Project, importeer store, en voeg de omgevingsvariabelen toe — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, NEXT_PUBLIC_BUNNY_CDN_URL, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (de waarde voor het gedeployde endpoint, hieronder), en NEXT_PUBLIC_SITE_URL (je productie-URL). Deploy.

Koppel vervolgens de gedeployde webhook (de lokale stripe listen-sleutel was alleen lokaal): Stripe → Developers → Webhooks → + Add endpoint → https://<prod>/api/stripe/webhook, event checkout.session.completed. Kopieer de whsec_… naar Vercel en deploy opnieuw.

Ontbrekende omgevingsvariabelen = "lokaal werkt het, in productie blanco" — dé deploy-valkuil nummer 1. We deployen hier met testsleutels; wissel STRIPE_SECRET_KEY en de webhook-sleutel naar je live waarden zodra je echte betalingen wilt accepteren.

2. Live preview en in-place bewerken

Beide worden meegeleverd met de scaffold.

  • Live preview: de <Refresher> werkt de pagina bij die je aan het previewen bent zodra een editor in de admin opslaat — geen redeploy nodig. (Het is een preview voor de editor; bezoekers zien gepubliceerde content bij normale revalidatie.)
  • In-place bewerken: voeg ?edit_mode=true toe aan elke URL voor edit-overlays. Publieke bezoekers zien de schone pagina.

Voeg de preview-route toe die de scaffold weglaat. De admin laadt zijn preview-iframe op /cms-preview_<path>; zonder die route krijgt elke preview een 404. Voeg deze toe:

// src/app/cms-preview_/[...slug]/page.tsx
import { ParametricRoutePreviewPage } from "cms-renderer/lib/renderer";
import { registry } from "../../registry";   // haal je registry naar een gedeelde module
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
  const PreviewPage = ParametricRoutePreviewPage as any; // async RSC; React 19-types
  return <PreviewPage registry={registry} apiKey={process.env.PROFOUND_API_KEY ?? ""}
    websiteId={process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID ?? ""}
    cmsUrl={process.env.NEXT_PUBLIC_CMS_API_URL ?? "https://cms.dev.tryprofound.com"}
    params={Promise.resolve({ slug })} searchParams={searchParams} />;
}

Voeg ook src/app/cms-preview_/page.tsx toe (zelfde, slug: []) voor de segmentroot.

Dat is de build

Een contentgestuurde Stripe-storefront: een CMS-catalogus, lijst + detailpagina’s vanuit één set routes en een werkende gehoste checkout. AI vulde de catalogus, sloot het design aan en schreef de catalogusreader + componenten + headless winkelwagen; jij deed de componenten, de Stripe-prijskoppelingen, de drie routes, de CEL-chrome en drie korte Stripe-bestanden. CEL bindt de chrome; componenten halen de catalogus op. En Stripe bleef klein — één sessions.create-call en één ondertekende webhook, met de shopper die betaalt op Stripe’s eigen pagina.

Continue Reading
Previous‹Deployments