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

Panduan praktis: bangun etalase Stripe berbasis konten di Profound CMS โ€” katalog yang bisa diedit pedagang tanpa kode, dua rute parametrik, keranjang headless, dan checkout yang di-host Stripe.

Toko yang sudah jadi dalam pergerakan โ€” jelajahi kategori, buka produk, tambah ke keranjang, selesaikan pembayaran.

Panduan praktis yang membangun toko berbasis konten di Profound CMS: sebuah katalog produk (kategori + item) yang dimodelkan di CMS, halaman daftar dan detail dari satu set rute, dan checkout yang di-host Stripe dikirim sebagai komponen headless.

Tulang punggungnya adalah Next.js yang ditulis manual plus admin Profound. Claude Code (melalui Profound MCP) menangani tiga pekerjaan besar โ€” mengisi katalog, menghubungkan sistem desain, dan menulis komponen etalase (termasuk keranjang headless). Tiga bagian: Setup, Build, Production.

Pembayaran dalam satu baris. Kami menggunakan Stripe-hosted Checkout: pembeli membayar di halaman Stripe, bukan milik Anda. Aplikasi Anda hanya melakukan dua hal sisi server โ€” membuat Checkout Session dan memverifikasi satu webhook. Tanpa kolom kartu, tanpa Stripe Elements, tanpa beban PCI.

Apa yang akan Anda bangun

  • Sebuah katalog kecil yang dipublikasikan di CMS โ€” tiga kategori dan delapan produk (demo "Edison's Inventions") โ€” masing-masing dapat diedit pedagang tanpa kode.
  • Dua rute parametrik (/products/{item_code}, /categories/{category_code}) plus satu /cart statis, semuanya dari satu set komponen.
  • Sebuah keranjang headless (useCart) dan checkout yang di-host Stripe, dengan harga selalu diselesaikan sisi server dari Stripe Price ID.
  • Toko yang dideploy ke Vercel dengan pratinjau langsung dan penyuntingan in-place untuk tim.

Prasyarat

  • Bun โ‰ฅ 1.3 โ€” curl -fsSL https://bun.sh/install | bash
  • Claude Code dengan Profound MCP (Bagian 1 memasangnya).
  • Akun Profound CMS.
  • Akun Stripe. Tutorial ini berjalan dalam mode uji sehingga tidak ada uang nyata yang ditarik saat Anda membangun โ€” tetapi alurnya identik dengan kunci live, jadi gunakan kunci akun nyata jika Anda mau. (Mode uji tidak memerlukan detail bisnis atau bank.)
  • Stripe CLI (stripe login) untuk webhook lokal.
  • Untuk deploy: GitHub CLI (gh) dan akun Vercel yang terhubung ke GitHub.

Cara setiap bagian saling terhubung

Profound memisahkan konten dari rendering:

  • Komponen mendefinisikan bentuk konten. Komponen Kustom dengan field Route Slug dapat dirutekan (category, item); satu yang ditandai UI Element dapat ditempatkan di halaman (nav, product_grid, โ€ฆ).
  • Dokumen adalah kontennya (produk, kategori).
  • Elemen UI adalah bagian halaman; setiap field skalar menerima nilai statis atau ekspresi CEL yang dievaluasi saat render.
  • Rute parametrik memetakan URL ke dokumen + elemen UI, meneruskan parameter rute (meta.params.* di CEL, routeParams di React).
  • Aplikasi Next.js Anda membacanya melalui cms-renderer; Stripe ditambahkan sebagai rute API biasa.

Satu aturan yang membentuk pembangunan: CEL hanya mengikat field string/number. Jadi chrome skalar (merek nav, footer, heading) diikat dengan CEL, sementara apa pun yang kaya atau kumpulan (grid produk, galeri gambar, rich text) diambil di dalam komponen React oleh parameter rute. Dan Stripe adalah sumber kebenaran harga โ€” price di CMS hanya untuk tampilan; biaya selalu diselesaikan sisi server dari Stripe Price ID.

Bagian 1 โ€” Setup

Keadaan akhir: katalog kecil yang dipublikasikan, aplikasi terhubung untuk membacanya, Stripe terpasang, desain siap โ€” belum ada yang dirender.

1. Daftar dan buat situs web

Daftar di Profound (WorkOS auth). Buat situs web bernama store, lalu salin website ID-nya (UUID di URL admin) dan sebuah read-tier API key (Deployments โ†’ Create API key). Aplikasi hanya membaca; seed katalog nanti melalui MCP, yang melakukan autentikasi terpisah.

2. Scaffold aplikasi, sambungkan, dan tambahkan Stripe

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

Scaffoldnya adalah proyek Next.js App Router yang sudah di-wire untuk Profound (cms-renderer SDK, rute catch-all, skrip generate-schemas, <Refresher>). Tidak menyertakan styling. bun add stripe menarik server SDK โ€” satu-satunya dependensi pembayaran yang dibutuhkan hosted checkout.

Tambahkan nilai Anda ke .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   # menyajikan gambar yang di-host CMS

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # kunci uji di sini; ganti ke kunci live saat Anda go live
STRIPE_WEBHOOK_SECRET=whsec_...          # diisi di langkah Build 4
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Ambil STRIPE_SECRET_KEY dari Stripe โ†’ Developers โ†’ API keys. Kami menggunakan kunci uji (sk_test_โ€ฆ) sehingga build tidak memindahkan uang nyata; ganti ke kunci live saat Anda siap menerima pembayaran nyata. Jalankan bun dev dan buka localhost:3000 โ€” starter-nya muncul.

Hosted checkout mengarahkan browser ke URL Stripe, jadi kunci rahasia server adalah satu-satunya yang dibutuhkan Stripe โ€” tanpa publishable key, tanpa client Stripe SDK.

3. Definisikan komponen category, product_image, dan item

Buat tiga Custom Component (Components โ†’ Create new component) โ€” sumber data, jadi tanpa tag UI Element. Setiap komponen dibuat Active.

CMS tidak memiliki field "array of image", jadi galeri adalah array of references ke komponen kecil product_image. Buat category dan product_image (dan set aktif) sebelum item โ€” field referensi hanya bisa menargetkan komponen Active.

  • 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 referensi โ†’ product_image), price (Number, sen โ€” hanya tampilan), currency (Select, usd), stripePriceId (Text), category (Reference โ†’ category), active (Boolean)

Biarkan semua field opsional. Admin akan membuat nama field menjadi lower_snake_case ("Stripe Price Id" โ†’ stripe_price_id) โ€” itulah yang digunakan kode Anda, jadi baca nama sebenarnya kembali dari generate-schemas nanti. Kami menamai handle yang bisa dirutekan sebagai code (bukan slug): itu menjadi Route Slug dan kunci untuk lookup documents.getByCode yang bersih nanti.

Komponen item โ€” code sebagai Route Slug, images sebagai referensi ke product_image, plus stripePriceId dan referensi category.

4. Tarik komponen ke tipe lokal

bun run generate-schemas

Menulis skema + tipe Zod ke generated/cms-schemas.ts (categorySchema/Category, itemSchema/Item). Sekaligus memeriksa koneksi โ€” kredensial yang salah akan gagal di sini.

5. Seed katalog lewat Profound MCP

Instal dan autentikasi MCP sekali:

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

Jalankan mcp__Profound__authenticate, selesaikan alur WorkOS, lalu minta Claude:

Hasilkan katalog ecommerce kecil untuk toko bernama Edison's Inventions โ€” tiga kategori dan produk ini, dengan description singkat yang akurat secara periode, price dalam sen, currency: "usd", dan 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)

Setiap kategori butuh name dan code huruf kecil itu; setiap item butuh name, code huruf kecil tersebut, description, price (dalam sen), currency, dan active. Simpan ke data/catalog.json dan validasi terhadap komponen category dan item kita. Kemudian gunakan Profound MCP untuk membuat masing-masing sebagai dokumen yang dipublikasikan: buat kategori terlebih dahulu, tangkap ID-nya, lalu buat item dengan category diisi referensi โ€” { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }. Biarkan stripePriceId kosong dulu. Kerjakan item paralel.

Claude menulis data/catalog.json, memvalidasinya, dan menjalankan panggilan create_document paralel (status: "published"). Seed kategori sebelum item agar referensi menunjuk ke ID yang sudah ada.

Tiga kategori yang sudah di-seed, published dan Live.

Delapan produk yang di-seed, masing-masing terhubung ke kategori.

6. Buat Stripe Prices dan hubungkan sebagian produk

Katalog sudah di CMS; sekarang berikan beberapa produk harga Stripe nyata โ€” tugas pedagang, selesai di dua panel admin, tanpa kode:

  1. Stripe Dashboard โ†’ Products โ†’ + Add product, tetapkan harga sekali bayar, salin Price ID (price_โ€ฆ).
  2. Lakukan ini untuk ~3 produk hero (mis. Lightbulb, Phonograph, Kinetoscope).
  3. Admin Profound โ†’ item โ†’ Documents โ†’ tempel tiap Price ID ke stripePriceId, simpan.

CMS menyimpan katalog; Stripe menyimpan harga definitif; tautannya adalah satu string yang ditempel pedagang. (Ingin mengotomasi? Stripe MCP resmi bisa membuat Products/Prices untuk Anda โ€” tempelkan ID yang dikembalikan dengan cara yang sama.)

7. Masukkan sistem desain dan hubungkan dengan AI

Scaffold dikirim tanpa gaya. Letakkan DESIGN.md (blok @theme Tailwind v4 + token) di root proyek โ€” milik Anda, atau unduh dari refero.design. Lalu minta Claude, dibatasi hanya styling:

Baca file desain yang baru saya tambahkan. Siapkan Tailwind jika perlu, lalu hubungkan tema dan font agar styling berjalan. Gunakan next/font untuk font โ€” jangan memuat dari Google saat runtime. Hanya styling โ€” jangan membangun halaman atau komponen apa pun dulu.

Pastikan src/app/globals.css memiliki @import "tailwindcss"; + blok @theme dan localhost:3000 menampilkan token. Jaga prompt tetap ketat (prompt terbuka, agen bisa membuat halaman penuh), dan muat font lewat next/font, jangan impor runtime dari Google.

8. Tambahkan gambar produk (opsional)

Opsional โ€” Anda bisa mencapai checkout yang berfungsi tanpa gambar. Untuk menambahkannya: buat dokumen product_image untuk setiap gambar (unggah ke field image), lalu referensikan dari array images produk. Bawa foto produk sendiri, atau hasilkan set yang kohesif dengan model gambar (minta Claude menurunkan prompt sesuai merek dari DESIGN.md dan kunci satu --sref Midjourney agar setiap bidikan selaras).

cms-renderer mandiri tidak memiliki helper URL gambar, jadi masukkan buildAssetUrl ke src/lib/image.ts (~40 baris) โ€” fungsi ini menambahkan awalan NEXT_PUBLIC_BUNNY_CDN_URL dan ekstensi. Komponen di langkah Build 3 menggunakannya.

Bagian 2 โ€” Build

Bangun lapisan rendering dan checkout, berakhir dengan pembelian nyata dalam mode uji.

1. Definisikan lima komponen elemen UI

Lima komponen, masing-masing Active dan ditandai UI Element (Settings โ†’ Tags), tanpa Route Slug:

  • nav โ†’ brand ยท product_grid โ†’ heading ยท product_detail โ†’ heading ยท cart_summary โ†’ heading ยท footer โ†’ text (semuanya Text)

Tag UI Element membuat komponen muncul di daftar Add UI Element Page Builder โ€” Active saja tidak cukup. Setiap field adalah skalar (tipe yang diikat CEL); data katalog bukan field di sini โ€” ProductGrid/ProductDetail mengambilnya melalui parameter rute (langkah 3).

2. Regenerasi tipe

bun run generate-schemas

3. Hasilkan pembaca katalog, komponen, dan keranjang headless

Satu prompt membangun helper pembaca, lima komponen, keranjang, dan registry:

Bangun etalase kita di src/, menggunakan SDK cms-renderer Profound.

src/lib/catalog.ts โ€” pembaca CMS sisi server. Buat klien dengan getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) dari cms-renderer/lib/cms-api. Ekspor getItemByCode(code) โ†’ cms.documents.getByCode.query({ websiteId, schemaName: "item", code }) yang mengembalikan res.document.published_content. Ekspor listItems(categoryCode?) โ†’ cms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 }), mapping res.documents ke .published_content, filter active !== false, dan jika categoryCode diberikan, pertahankan item dengan category._ref sama dengan document.id kategori. Ekspor resolveImages(refs) yang mengurai setiap referensi item.images melalui cms.documents.get.query({ websiteId, id: ref._ref }) dan mengubah field gambarnya menjadi URL dengan buildAssetUrl yang dimasukkan (Bagian 1 langkah 8).

src/components/ โ€” lima komponen elemen UI yang diregistrasikan di registry rute catch-all dengan nama komponen, snake_case sesuai admin: { nav, product_grid, product_detail, cart_summary, footer }. Nav dan Footer membaca field skalarnya dari prop content (diketik BlockComponentProps<T> dari cms-renderer/lib/types). ProductGrid dan ProductDetail adalah async server component yang membaca routeParams dan fetch dari catalog.ts: routeParams.<param> adalah { value, โ€ฆ } โ€” baca .value, jadi ProductGrid memanggil listItems(routeParams.category_code?.value) (kartu menaut ke /products/{code}) dan ProductDetail memanggil getItemByCode(routeParams.item_code?.value) (galeri lewat resolveImages, deskripsi rich-text, harga, tombol Tambah ke keranjang). CartSummary merender keranjang dari useCart dengan tombol Bayar. Simpan formatPrice dalam src/lib/format.ts murni agar komponen client tidak mengimpor catalog.ts yang hanya sisi server.

src/components/AddToCartButton.tsx โ€” tombol "use client" yang menerima { code, name, priceLabel } dan memanggil useCart().addItem({ code, name, priceLabel, quantity: 1 }). Gunakan di dalam ProductDetail.

src/lib/useCart.ts โ€” keranjang headless: item { code, name, priceLabel, quantity } dalam state, dipersist ke localStorage, mengekspos addItem/removeItem/updateQty/subtotal dan checkout() yang melakukan POST { lines: [{ code, quantity }] } (hanya kode dan kuantitas โ€” jangan pernah harga) ke /api/stripe/checkout, lalu mengarahkan ulang ke url yang dikembalikan.

Gaya semua dengan sistem desain kita, sebagai komponen milik kita sendiri โ€” jangan menyalin layout situs sumber.

Tiga hal yang perlu diketahui setelahnya:

  • Chrome skalar masuk melalui content ({ content }: BlockComponentProps<T>) โ€” destructure field sebagai prop level atas dan block akan kosong. Data katalog berasal dari routeParams + fetch catalog.ts, karena CEL tidak bisa mengikat daftar atau galeri. Keranjang membawa kode item, bukan harga.
  • routeParams.<param> adalah { value, schemaName, document } โ€” bacalah .value. Hasil baca mengembalikan published_content, bukan .content. Kunci registry adalah snake_case sesuai admin.
  • Naikkan @types/react/@types/react-dom ke v19 โ€” scaffold mengirim v18, yang mematahkan block server-component async di React 19.

4. Tulis kode server Stripe (tulang punggung)

Tiga berkas server pendek โ€” satu-satunya kode pembayaran di aplikasi. Mereka memakai ulang getItemByCode, jadi biaya diselesaikan sisi server.

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 โ€” uraikan setiap item dari CMS, tagih harga Stripe:

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // sisi server, kunci baca

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] โ€” tanpa harga dari klien
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // sisi server mengambil dari CMS
      return { price: item!.stripe_price_id, quantity }; // harga dari CMS, bukan dari klien
    })
  );
  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 });     // klien diarahkan ke sini
}

src/app/api/stripe/webhook/route.ts โ€” sinyal pemenuhan tepercaya:

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

export async function POST(req: Request) {
  const body = await req.text();                      // body RAW โ€” wajib untuk verifikasi tanda tangan
  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") {
    // penuhi pesanan: catat order / kirim struk.
  }
  return new Response(null, { status: 200 });
}

Perbaikan scaffold wajib: src/proxy.ts di scaffold meneruskan setiap /api/* ke CMS, sehingga rute Stripe Anda tidak pernah jalan. Biarkan mereka lolos dulu:

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();                       // tangani secara lokal
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// biarkan `export const config = { matcher: [...] }` scaffold tetap

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

Jalankan Stripe CLI untuk webhook lokal:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# salin whsec_... ke STRIPE_WEBHOOK_SECRET, restart bun dev

whsec_โ€ฆ bersifat per sesi. Dua aturan menjaga keamanan: checkout menurunkan ulang harga dari CMS lewat code (keranjang yang diubah tidak bisa mengganti harga), dan webhook memverifikasi tanda tangan terhadap body mentah.

5. Buat rute

Admin โ†’ Pages โ†’ Create page, tiga kali. Petakan setiap parameter ke komponennya (field slug code):

  1. /products/{item_code} โ†’ item
  2. /categories/{category_code} โ†’ category
  3. /cart โ€” halaman static (masukkan literal /cart, bukan /{cart})

6. Tambahkan elemen UI, hubungkan CEL, publikasikan

Untuk setiap rute: Page Builder โ†’ Add UI Element โ†’ Custom โ†’ tambahkan komponen berurutan, isi field skalar (nilai statis atau CEL), Publish.

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

Set nav.brand dan footer.text ke string statis; heading ke label statis.

Page Builder di rute kategori โ€” elemen product_grid dipilih, heading-nya diikat oleh CEL.

Page Builder di rute produk โ€” elemen product_detail pada binding produk.

Gotcha Page Builder parametrik: pada dua rute parametrik, menambahkan elemen UI tidak tersimpan (block jadi yatim dan halaman kosong). Sampai diperbaiki, hubungkan block_ids rute tersebut langsung lewat Profound MCP update_page, lalu publish. (/cart statis terhubung normal.) Untuk alasan yang sama, ProductGrid mengambil heading dari kategori yang di-fetch ketimbang via CEL.

7. Render dan beli

  • /categories/lighting โ†’ grid. Klik produk โ†’ detail + Tambah ke keranjang. /cart โ†’ Bayar.
  • Pembayaran mengarahkan ke Stripe-hosted checkout. Gunakan kartu uji 4242 4242 4242 4242, masa berlaku/CVC apa pun di masa depan. Anda kembali ke /cart?status=success, dan stripe listen menampilkan checkout.session.completed.

Halaman produk yang dirender โ€” galeri, harga, dan tombol Tambah ke keranjang.

Keranjang โ€” item baris dan satu tombol Bayar dengan Stripe.

Hanya item yang punya harga yang bisa dibeli โ€” belilah salah satu dari ~3 yang sudah Anda beri harga di langkah 6.

Opsional โ€” internasionalisasi. Terjemahkan tiap komponen (semua 35 bahasa sekaligus), tambahkan segmen /{language}/โ€ฆ yang dipetakan ke komponen Sistem language bawaan, dan ubah field yang diikat CEL ke documents.translated. Lihat tutorial direktori bandara, Bagian 2 langkah 7.

Bagian 3 โ€” Production

1. Kirim: GitHub, lalu Vercel

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

Perintah build: generated/cms-schemas.ts diabaikan git, jadi pin build untuk menghasilkannya lagi โ€” tambahkan vercel.json:

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

Di Vercel: Add New โ†’ Project, impor store, dan tambahkan variabel env โ€” PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, NEXT_PUBLIC_BUNNY_CDN_URL, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (nilai endpoint ter-deploy, di bawah), dan NEXT_PUBLIC_SITE_URL (URL produksi Anda). Deploy.

Lalu hubungkan webhook produksi (rahasia stripe listen lokal hanya untuk lokal): Stripe โ†’ Developers โ†’ Webhooks โ†’ + Add endpoint โ†’ https://<prod>/api/stripe/webhook, event checkout.session.completed. Salin whsec_โ€ฆ-nya ke Vercel dan deploy ulang.

Env vars yang hilang = "berfungsi lokal, kosong di produksi" โ€” jebakan deploy nomor satu. Kami deploy dengan kunci uji di sini; ganti STRIPE_SECRET_KEY dan rahasia webhook ke nilai live saat siap menerima pembayaran nyata.

2. Pratinjau live dan penyuntingan in-place

Keduanya dikirim bersama scaffold.

  • Live preview: <Refresher> memperbarui halaman yang sedang Anda pratinjau ketika editor menyimpan di admin โ€” tanpa redeploy. (Ini pratinjau untuk editor; pengunjung melihat konten published pada revalidasi normal.)
  • Penyuntingan in-place: tambahkan ?edit_mode=true ke URL apa pun untuk overlay edit. Pengunjung umum melihat halaman bersih.

Tambahkan rute preview yang tidak disertakan scaffold. Admin memuat iframe pratinjau di /cms-preview_<path>; tanpa rute itu setiap pratinjau 404. Tambahkan:

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

Tambahkan juga src/app/cms-preview_/page.tsx (sama, slug: []) untuk root segmennya.

Itulah build-nya

Etalase Stripe berbasis konten: katalog CMS, halaman daftar + detail dari satu set rute, dan checkout hosted yang berfungsi. AI men-seed katalog, menghubungkan desain, dan menulis pembaca katalog + komponen + keranjang headless; Anda membuat komponen, tautan harga Stripe, tiga rute, chrome CEL, dan tiga berkas Stripe singkat. CEL mengikat chrome; komponen mengambil katalog. Dan Stripe tetap sederhana โ€” satu panggilan sessions.create dan satu webhook bertanda tangan, dengan pembeli membayar di halaman Stripe sendiri.

Continue Reading
Previousโ€นDeployments