profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Opetusohjelmat

Lentokenttä-hakemistoDeploymentsBuild & 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

Hands-on-opastus: rakenna sisältövetoisesti ohjattu Stripe-myymälä Profound CMS:ään — luettelo, jota kauppias muokkaa ilman koodia, kaksi parametrireittiä, headless-ostoskori ja Stripen isännöimä kassaprosessi.

Valmis kauppa liikkeessä — selaa kategoriaa, avaa tuote, lisää ostoskoriin, siirry kassalle.

Käytännön opastus, jossa rakennetaan sisältövetoisesti ohjattu kauppa Profound CMS:ään: tuoteluettelo (kategoriat + tuotteet) mallinnettuna CMS:ään, listaus- ja tuotesivut yhdestä reitityskokonaisuudesta sekä Stripen isännöimä kassaprosessi toimitettuna headless-komponenttina.

Runkona toimii käsin kirjoitettu Next.js yhdistettynä Profoundin hallintaan. Claude Code (Profound MCP:n kautta) hoitaa raskaan työn kolmessa tehtävässä — luettelon siementäminen, design-järjestelmän kytkentä ja myymäläkomponenttien kirjoittaminen (mukaan lukien headless-ostoskori). Kolme vaihetta: Setup, Build, Production.

Maksut yhdellä rivillä. Käytämme Stripen isännöimää Checkoutia: ostaja maksaa Stripen sivulla, ei sinun. Sovelluksesi tekee vain kaksi palvelinpuolen asiaa — luo Checkout Sessionin ja vahvista yhden webhookin. Ei korttikenttiä, ei Stripe Elementsia, ei PCI-taakkaa.

Mitä rakennat

  • Pieni julkaistu luettelo CMS:ään — kolme kategoriaa ja kahdeksan tuotetta ("Edison's Inventions" -demo) — jokainen kauppiaan muokattavissa ilman koodia.
  • Kaksi parametristä reittiä (/products/{item_code}, /categories/{category_code}) sekä staattinen /cart, kaikki samasta komponenttijoukosta.
  • Headless-ostoskori (useCart) ja Stripen isännöimä kassa, jossa hinta ratkaistaan aina palvelinpuolella Stripe Price ID:n perusteella.
  • Kauppa julkaistuna Verceliin livenäkyvyyden ja paikan päällä tehtävien muokkausten kanssa tiimille.

Esivaatimukset

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Claude Code ja Profound MCP (osa 1 asentaa sen).
  • Profound CMS -tili.
  • Stripe-tili. Tämä opas pyörii testitilassa, joten rakentamisen aikana ei veloiteta oikeaa rahaa — mutta prosessi on identtinen live-avaimilla, joten voit käyttää oikean tilisi avaimia, jos haluat. (Testitila ei vaadi yritys- tai pankkitietoja.)
  • Stripe CLI (stripe login) paikallisia webhookeja varten.
  • Julkaisua varten: GitHub CLI (gh) ja GitHubiin yhdistetty Vercel-tili.

Miten osat loksahtavat yhteen

Profound erottaa sisällön renderöinnistä:

  • Komponentit määrittelevät sisällön muodon. Custom Component, jossa on Route Slug -kenttä, on reititettävä (category, item); yksi UI Element -tagattu on sijoitettavissa sivulle (nav, product_grid, …).
  • Dokumentit ovat sisältö (tuote, kategoria).
  • UI-elementit ovat sivunosia; jokainen skalaari kenttä ottaa staattisen arvon tai CEL-lausekkeen, joka evaluoidaan renderöinnissä.
  • Parametriset reitit yhdistävät URL-osoitteen dokumenttiin + UI-elementteihin, välittäen reitin parametrit (meta.params.* CEL:ssä, routeParams Reactissa).
  • Next.js-sovelluksesi lukee sen cms-renderer-kirjaston kautta; Stripe lisätään tavallisina API-reitteinä.

Ainoa sääntö, joka ohjaa toteutusta: CEL sitoo vain string/number-kentät. Joten skalaari-kromi (navin brändi, footer, otsikot) sidotaan CEL:llä, kun taas kaikki rikas tai kokoelma (tuoteruudukko, kuvagalleria, rich text) haetaan React-komponentin sisällä reittiparametrin avulla. Ja Stripe on hinnoittelun totuuden lähde — CMS:n price on vain näyttöä varten; veloitus ratkaistaan aina palvelinpuolella Stripe Price ID:stä.

Osa 1 — Setup

Lopputila: pieni julkaistu luettelo, sovellus kytketty lukemaan sen, Stripe asennettuna, design paikoillaan — mitään ei vielä renderöidä.

1. Rekisteröidy ja luo sivusto

Rekisteröidy Profoundissa (WorkOS-tunnistus). Luo sivusto nimeltä store, kopioi sen website ID (UUID admin-URL:ssä) ja read-tier API -avain (Deployments → Create API key). Sovellus ainoastaan lukee; luettelon siemennys tapahtuu myöhemmin MCP:n kautta, joka tunnistautuu erikseen.

2. Luo sovellus, yhdistä se ja lisää Stripe

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

Scaffold on Next.js App Router -projekti, joka on valmiiksi kytketty Profoundiin (cms-renderer-SDK, catch-all-reitti, generate-schemas-skripti, <Refresher>). Se ei sisällä tyylitystä. bun add stripe hakee palvelin-SDK:n — ainoa maksuriippuvuus, jonka isännöity kassa tarvitsee.

Lisää arvosi tiedostoon .env.local:

# CMS
PROFOUND_API_KEY=<your read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<your website id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net   # palvelee CMS:n hostaamat kuvat

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # testiavain tähän; vaihda live-avaimeen, kun julkaiset
STRIPE_WEBHOOK_SECRET=whsec_...          # täytetään Build-vaiheen kohdassa 4
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Hae STRIPE_SECRET_KEY Stripe → Developers → API keys -näkymästä. Käytämme testiavain (sk_test_…), jotta rakentaminen ei liikuttele oikeaa rahaa; vaihda live-avaimeen, kun olet valmis ottamaan vastaan maksuja. Aja bun dev ja avaa localhost:3000 — aloitussivu renderöityy.

Isännöity kassa ohjaa selaimen Stripe-URL-osoitteeseen, joten palvelimen salainen avain on kaikki mitä Stripe tarvitsee — ei julkista avainta, ei Stripe-asiakas-SDK:ta.

3. Määritä category-, product_image- ja item-komponentit

Luo kolme Custom Componentia (Components → Create new component) — tietolähteet, joten ei UI Element -tagia. Aseta jokainen Active.

CMS:ssä ei ole "array of image" -kenttää, joten galleria on viitteiden taulukko pieneen product_image-komponenttiin. Luo category ja product_image (ja aseta Active) ennen item-komponenttia — viitekenttä voi osoittaa vain aktiivisiin komponentteihin.

  • 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 (viitteiden taulukko → product_image), price (Number, sentit — vain näyttöön), currency (Select, usd), stripePriceId (Text), category (Reference → category), active (Boolean)

Jätä kaikki kentät valinnaisiksi. Admin muuttaa kenttien nimet pieniksi snake-case -muotoon ("Stripe Price Id" → stripe_price_id) — koodisi käyttää niitä, joten lue oikeat nimet takaisin generate-schemas-skriptillä myöhemmin. Nimeämme reititettävän tunnisteen code: se on sekä Route Slug että avain siistiin documents.getByCode -hakuun myöhemmin.

item-komponentti — code Route Slugina, images viitteinä product_imageen, lisäksi stripePriceId ja category-viite.

4. Hae komponentit paikallisiksi tyypeiksi

bun run generate-schemas

Kirjoittaa Zod-skeemat + tyypit tiedostoon generated/cms-schemas.ts (categorySchema/Category, itemSchema/Item). Toimii myös yhteystarkistuksena — väärät tunnukset kaatuvat tässä.

5. Siemenna luettelo Profound MCP:n kautta

Asenna ja todenna MCP kerran:

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

Aja mcp__Profound__authenticate, suorita WorkOS-kirjautuminen ja ohjeista Claudea:

Luo pieni verkkokaupan luettelo nimeltä Edison's Inventions — kolme kategoriaa ja nämä tuotteet, joille jokaiselle lyhyt ajanmukainen description, price senteissä, currency: "usd" ja 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 $)

Jokaisella kategorialla on name ja tuo pieni code; jokaisella tuotteella name, sama pieni code, description, price (senteissä), currency ja active. Tallenna se tiedostoon data/catalog.json ja validoi category- ja item-komponenttejamme vastaan. Käytä sitten Profound MCP:tä luodaksesi jokaisen julkaistuna dokumenttina: luo kategoriat ensin, tallenna niiden ID:t, luo sitten tuotteet category-kentällä, joka on viite — { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }. Jätä stripePriceId tyhjäksi toistaiseksi. Tee tuotteet rinnakkain.

Claude kirjoittaa data/catalog.json -tiedoston, validoi sen ja lähettää rinnakkaiset create_document-kutsut (status: "published"). Siemennä kategoriat ennen tuotteita, jotta viitteet osoittavat jo olemassa oleviin ID:ihin.

Kolme siemennettyä kategoriaa, julkaistuna ja Live-tilassa.

Kahdeksan siemennettyä tuotetta, kukin linkitettynä kategoriaan.

6. Luo Stripen hinnat ja yhdistä muutama tuote

Luettelo on CMS:ssä; anna nyt muutamalle tuotteelle oikea Stripen hinta — kauppiaan työ, tehdään kahdessa hallintapaneelissa ilman koodia:

  1. Stripe Dashboard → Products → + Add product, aseta kertamaksu, kopioi Price ID (price_…).
  2. Tee tämä noin kolmelle hero-tuotteelle (esim. Lightbulb, Phonograph, Kinetoscope).
  3. Profoundin hallinta → item → Documents → liitä jokaisen Price ID stripePriceId -kenttään, tallenna.

CMS säilyttää luettelon; Stripe on hinnan lähde; linkki on yksi merkkijono, jonka kauppias liittää. (Haluatko automatisoida? Virallinen Stripe MCP voi luoda Products/Prices sinulle — liitä palautetut ID:t samalla tavalla.)

7. Lisää design-järjestelmä ja kytke se tekoälyn avulla

Scaffold tulee ilman tyylejä. Aseta DESIGN.md (Tailwind v4 @theme -blokki + tokenit) projektin juureen — oma tai lataa sellainen osoitteesta refero.design. Pyydä sitten Claudea, rajattuna pelkkään tyylitykseen:

Lue juuri lisäämäni design-tiedosto. Asenna Tailwind tarvittaessa, kytke teema ja fontit niin, että tyylitys toimii. Käytä fontteihin next/font -kirjastoa — älä lataa niitä Googlen kautta ajonaikaisesti. Vain tyylitys — älä rakenna sivuja tai komponentteja vielä.

Varmista, että src/app/globals.css sisältää @import "tailwindcss"; + @theme-blokki ja että localhost:3000 näyttää tokenit. Pidä pyyntö tarkkana (avoin tehtävä ja agentti scaffoldaa kokonaisen etusivun), ja lataa fontit next/fontin kautta — ei ajonaikaista Google-tuontia.

8. Lisää tuotekuvat (valinnainen)

Valinnainen — pääset toimivaan kassaan ilman kuvia. Lisätäksesi ne: luo yksi product_image -dokumentti kutakin kuvaa kohden (lataa kuva sen image-kenttään), viittaa sitten niihin tuotteen images-arraysta. Tuo omat tuotekuvasi tai generoi yhtenäinen setti kuvamallilla (pyydä Claudea johtamaan brändin mukaiset promptit DESIGN.md:stä ja lukitse yksi Midjourney --sref, jotta jokainen kuva sopii).

Erillinen cms-renderer ei tarjoa image-URL-helperia, joten ota buildAssetUrl käyttöön tiedostossa src/lib/image.ts (~40 riviä) — se prefiksaa NEXT_PUBLIC_BUNNY_CDN_URL-osoitteen ja lisää tiedostopäätteen. Build-vaiheen kohdan 3 komponentit käyttävät sitä.

Osa 2 — Build

Rakenna renderöinti-kerros ja kassaprosessi, päätyen oikeaan testitilan ostoon.

1. Määritä viisi UI-elementtikomponenttia

Viisi komponenttia, kukin Active ja tagattu UI Element -tagilla (Settings → Tags), ei Route Slugia:

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

UI Element -tagi tekee komponentista näkyvän Page Builderin Add UI Element -listalla — pelkkä Active ei riitä. Jokainen kenttä on skalaari (sellainen, jonka CEL sitoo); varsinainen luettelodata ei ole kenttä täällä — ProductGrid/ProductDetail hakee sen reittiparametrin perusteella (kohta 3).

2. Generoi tyypit uudelleen

bun run generate-schemas

3. Generoi luettelolukija, komponentit ja headless-ostoskori

Yksi pyyntö rakentaa lukuhelperin, viisi komponenttia, ostoskorin ja rekisterin:

Rakenna myymälämme hakemistoon src/ käyttäen Profoundin cms-renderer-SDK:ta.

src/lib/catalog.ts — palvelinpuolen CMS-lukija. Luo asiakas funktiolla getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) moduulista cms-renderer/lib/cms-api. Vie getItemByCode(code) → cms.documents.getByCode.query({ websiteId, schemaName: "item", code }), joka palauttaa res.document.published_content. Vie listItems(categoryCode?) → cms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 }), map res.documents → .published_content, suodata active !== false, ja jos categoryCode annetaan, pidä tuotteet, joiden category._ref vastaa kategorian document.id:tä. Vie resolveImages(refs), joka hakee jokaisen item.images -viitteen cms.documents.get.query({ websiteId, id: ref._ref }) -kutsulla ja muuntaa sen kuvan URL:ksi vendoroidun buildAssetUrl-funktion avulla (osa 1, kohta 8).

src/components/ — viisi UI-elementtikomponenttia rekisteröitynä catch-all-reitin rekisteriin komponenttien nimillä, snake_case adminin mukaisesti: { nav, product_grid, product_detail, cart_summary, footer }. Nav ja Footer lukevat skalaarikenttänsä content-propista (tyyppi BlockComponentProps<T> moduulista cms-renderer/lib/types). ProductGrid ja ProductDetail ovat async-palvelinkomponentteja, jotka lukevat routeParams-arvoja ja hakevat catalog.ts-tiedostosta: routeParams.<param> on { value, … } — lue .value, joten ProductGrid kutsuu listItems(routeParams.category_code?.value) (kortit linkittävät /products/{code}-reitille) ja ProductDetail kutsuu getItemByCode(routeParams.item_code?.value) (galleria resolveImages-funktion kautta, rich text -kuvaus, hinta, Lisää ostoskoriin). CartSummary renderöi ostoskorin useCart:sta Pay-painikkeen kanssa. Säilytä formatPrice puhtaana moduulissa src/lib/format.ts, jotta asiakaskomponentit eivät tuo palvelinpuolen catalog.ts:ää.

src/components/AddToCartButton.tsx — "use client" -painike, joka ottaa propsit { code, name, priceLabel } ja kutsuu useCart().addItem({ code, name, priceLabel, quantity: 1 }). Käytä sitä ProductDetail-komponentissa.

src/lib/useCart.ts — headless-ostoskori: rivit { code, name, priceLabel, quantity } tilassa, tallennettuna localStorageen, tarjoaa addItem-, removeItem-, updateQty- ja subtotal-funktiot sekä checkout()-metodin, joka tekee POST-pyynnön { lines: [{ code, quantity }] } (vain koodit ja määrät — ei koskaan hintoja) reitille /api/stripe/checkout ja ohjaa sitten palautettuun url-osoitteeseen.

Tyylitä kaikki design-järjestelmällämme omilla komponenteillamme — älä kopioi esimerkkisivuston layoutia.

Kolme asiaa tiedettäväksi, kun se on valmis:

  • Skalaari-kromi tulee content-propista ({ content }: BlockComponentProps<T> ) — purkamalla kentät ylätason propseiksi blokki renderöityy tyhjänä. Luettelodata tulee routeParamsista + catalog.ts -hausta, koska CEL ei sido listoja tai gallerioita. Ostoskori kantaa tuotteiden koodeja, ei hintoja.
  • routeParams.<param> on { value, schemaName, document } — lue .value. Haut palauttavat published_content, eivät .content. Rekisterin avaimet ovat snake_case adminin mukaisesti.
  • Päivitä @types/react/@types/react-dom versioon 19 — scaffold toimitetaan versiolla 18, joka rikkoo async-palvelinkomponenttiblokit React 19:n kanssa.

4. Kirjoita Stripen palvelinkoodi (ranka)

Kolme lyhyttä palvelintiedostoa — ainoa maksukoodi sovelluksessa. Ne käyttävät getItemByCode-funktiota, joten veloitus ratkaistaan palvelimella.

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 — ratkaise jokainen tuote CMS:stä, veloita Stripen hinnalla:

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // palvelinpuoli, read-tier-avain

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] — ei hintoja asiakkaalta
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // palvelin ratkaisee CMS:stä
      return { price: item!.stripe_price_id, quantity }; // hinta CMS:stä, ei asiakkaalta
    })
  );
  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 });     // asiakas uudelleenohjaa tänne
}

src/app/api/stripe/webhook/route.ts — luotettava täyttösignaali:

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

export async function POST(req: Request) {
  const body = await req.text();                      // RAaka runko — vaaditaan allekirjoituksen tarkistukseen
  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") {
    // täytä: kirjaa tilaus / lähetä kuitti.
  }
  return new Response(null, { status: 200 });
}

Pakollinen scaffold-korjaus: scaffoldin src/proxy.ts ohjaa jokaisen /api/*-pyynnön CMS:ään, joten Stripe-reittisi eivät koskaan toimi. Päästä nämä ensin läpi:

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();                       // käsittele paikallisesti
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// pidä scaffoldin `export const config = { matcher: [...] }` muuttumattomana

Varmista: curl -X POST localhost:3000/api/stripe/webhook -d x palauttaa Bad signature.

Aja Stripe CLI paikallisia webhookeja varten:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# kopioi whsec_... STRIPE_WEBHOOK_SECRET -kenttään, käynnistä bun dev uudelleen

whsec_… on sessiokohtainen. Kaksi sääntöä pitää turvallisuuden: checkout johtaa hinnan CMS:stä code-kentän avulla (manipuloitu ostoskori ei voi muuttaa sitä), ja webhook vahvistaa allekirjoituksen raakaan runkoon.

5. Luo reitit

Admin → Pages → Create page, kolme kertaa. Kartoit reitit parametreineen komponentteihin (slug-kenttä code):

  1. /products/{item_code} → item
  2. /categories/{category_code} → category
  3. /cart — staattinen sivu (syötä kirjaimellisesti /cart, ei /{cart})

6. Lisää UI-elementit, kytke CEL ja julkaise

Jokaiselle reitille: Page Builder → Add UI Element → Custom → lisää komponentit järjestyksessä, anna skalaari-kentille arvot (staattinen arvo tai CEL), Publish.

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

Aseta nav.brand ja footer.text staattisiksi merkkijonoiksi; otsikot staattisiksi nimilapuiksi.

Page Builder kategoriasivulla — product_grid-elementti valittuna, sen heading sidottu CEL:llä.

Page Builder tuotesivulla — product_detail-elementti tuotteen sidonnalla.

Parametrisen Page Builderin sudenkuoppa: kahdella parametrisella reitillä UI-elementtien lisääminen ei pysy (blokit orpoutuvat ja sivu renderöityy tyhjänä). Kunnes se korjataan, kytke noiden sivujen block_ids suoraan Profound MCP:n update_page -kutsun kautta, ja julkaise. (Staattinen /cart kiinnittyy normaalisti.) Samasta syystä ProductGrid johtaa otsikkonsa hakemastaan kategoriasta CEL:n sijaan.

7. Renderöi ja osta

  • /categories/lighting → ruudukko. Klikkaa tuotetta → tuotesivu + Lisää ostoskoriin. /cart → Pay.
  • Pay ohjaa Stripen isännöimään kassaan. Käytä testikorttia 4242 4242 4242 4242, mikä tahansa tuleva voimassaoloaika/CVC. Palaat /cart?status=success -sivulle, ja stripe listen näyttää checkout.session.completed -tapahtuman.

Renderöity tuotesivu — galleria, hinta ja Lisää ostoskoriin.

Ostoskori — rivit ja yksi Pay-with-Stripe -painike.

Vain hinnalla varustetut tuotteet ovat ostettavissa — osta jokin niistä ~3 tuotteesta, joille annoit hinnan kohdassa 6.

Valinnainen — kansainvälistä. Käännä jokainen komponentti (kaikki 35 kieltä kerralla), lisää /{language}/… -segmentti, joka on yhdistetty sisäänrakennettuun language-System-komponenttiin, ja vaihda CEL-sidotut kentät documents.translated -muotoon. Katso lentokenttähakemiston opas, osa 2, kohta 7.

Osa 3 — Production

1. Julkaise: GitHub, sitten Vercel

git init && git add -A && git commit -m "Stripe storefront"
gh repo create store --private --source=. --push   # --public käy myös

Build-komento: generated/cms-schemas.ts on gitignorattu, joten naulaa build generoimaan se uudelleen — lisää vercel.json:

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

Vercelissä: Add New → Project, tuo store, ja lisää ympäristömuuttujat — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, NEXT_PUBLIC_BUNNY_CDN_URL, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (julkaistun päätepisteen arvo, alla) ja NEXT_PUBLIC_SITE_URL (tuotantourlisi). Julkaise.

Kytke sitten julkaistu webhook (paikallisen stripe listen -komennon salaisuus oli vain paikallinen): Stripe → Developers → Webhooks → + Add endpoint → https://<prod>/api/stripe/webhook, tapahtuma checkout.session.completed. Kopioi sen whsec_… Verceliin ja julkaise uudelleen.

Puuttuvat ympäristömuuttujat = "toimii lokaalisti, tyhjä tuotannossa" — suurin deploy-sudenkuoppa. Julkaisemme täällä testiavainilla; vaihda STRIPE_SECRET_KEY ja webhook-salaisuus live-arvoihisi, kun olet valmis vastaanottamaan oikeita maksuja.

2. Live-esikatselu ja paikan päällä muokkaus

Molemmat toimitetaan scaffoldin mukana.

  • Live preview: <Refresher> päivittää esikatseltavan sivun, kun toimittaja tallentaa muutoksen hallinnassa — ei uudelleenjulkaisua. (Se on esikatselu toimittajalle; vierailijat näkevät julkaistun sisällön normaalilla revalidoinnilla.)
  • Paikan päällä muokkaaminen: lisää ?edit_mode=true mihin tahansa URL-osoitteeseen editaatioverlayn saamiseksi. Julkiset vierailijat näkevät puhtaan sivun.

Lisää esikatselureitti, jonka scaffold jättää pois. Hallinta lataa esikatselun iframeen osoitteessa /cms-preview_<path>; ilman tuota reittiä jokainen esikatselu päätyy 404:ään. Lisää se:

// src/app/cms-preview_/[...slug]/page.tsx
import { ParametricRoutePreviewPage } from "cms-renderer/lib/renderer";
import { registry } from "../../registry";   // vie rekisterisi yhteiseen moduuliin
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
  const PreviewPage = ParametricRoutePreviewPage as any; // async RSC; React 19 -tyypit
  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} />;
}

Lisää myös src/app/cms-preview_/page.tsx (sama, slug: []) segmenttijuurelle.

Siinä koko rakennus

Sisältövetoisesti ohjattu Stripe-myymälä: CMS-luettelo, listaus + tuotesivut yhdestä reittijoukosta ja toimiva isännöity checkout. Tekoäly siemensi luettelon, kytki designin ja kirjoitti luettelolukijan + komponentit + headless-ostoskoriin; sinä teit komponentit, Stripen hintalinkit, kolme reittiä, CEL-kromin ja kolme lyhyttä Stripe-tiedostoa. CEL sitoo kromin; komponentit hakevat luettelon. Ja Stripe pysyi pienenä — yksi sessions.create -kutsu ja yksi allekirjoitettu webhook, ostajan maksaessa Stripen omalla sivulla.

Continue Reading
Previous‹Deployments