profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Tutorials

Build & Ship an Airport DirectoryDeploymentsBuild & Ship a Stripe Storefront

CMS機能

Documentation Site TemplateFeature Template BuilderTranslation ServiceOrganizations & Website HeirarchyConnect Profound CMS to your AI clientSettings Integrations設定-APIキーSettings UsageSettings Websites
All Systems Operational
Powered Byprofound-logo
Theme

Build & Ship a Stripe Storefront

実践的なチュートリアル:Profound CMS上にコンテンツ駆動型のStripeストアフロントを構築します。マーチャントがコードなしで編集できるカタログ、2つのパラメトリックルート、ヘッドレスカート、Stripeホスト型チェックアウトを作成します。

完成したストアの動作 — カテゴリを閲覧し、商品を開き、カートに追加してチェックアウトします。

Profound CMS上にコンテンツ駆動型ストアを構築する実践的なチュートリアルです。CMSでモデル化した商品カタログ(カテゴリ+商品)、1組のルートから生成する一覧ページと詳細ページ、そしてヘッドレスコンポーネントとして提供するStripeホスト型チェックアウトを作成します。

中心となるのは手書きのNext.jsとProfound管理画面です。Claude Code(Profound MCP経由)が、カタログのシード、デザインシステムの接続、ストアフロントコンポーネント(ヘッドレスカートを含む)の作成という3つの作業を大きく支援します。全体はセットアップ、構築、本番環境の3部構成です。

決済を一言で。 Stripeホスト型Checkoutを使用します。購入者はあなたのページではなく、Stripeのページで支払います。アプリがサーバー側で行うことは、Checkout Sessionの作成と、1つのWebhookの検証だけです。カード入力欄もStripe ElementsもPCI対応の負担もありません。

構築するもの

  • CMSで公開する小規模なカタログ — 3カテゴリと8商品(「Edison's Inventions」デモ)。各商品は、コードを書かずにマーチャントが編集できます。
  • 1組のコンポーネントから生成する2つのパラメトリックルート(/products/{item_code}、/categories/{category_code})と、静的な/cart。
  • ヘッドレスカート(useCart)とStripeホスト型チェックアウト。価格は常にStripe Price IDからサーバー側で解決します。
  • ライブプレビューとチームによるインプレース編集に対応した、Vercelへのデプロイ。

前提条件

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Profound MCPを設定したClaude Code(Part 1でインストール)。
  • Profound CMSアカウント。
  • Stripeアカウント。 このチュートリアルはテストモードで実行するため、構築中に実際のお金が請求されることはありません。ただしフローは本番キーの場合と同じなので、必要であれば実際のアカウントキーを使用してください。(テストモードでは事業情報や銀行情報は不要です。)
  • ローカルWebhook用のStripe CLI(stripe login)。
  • デプロイ用のGitHub CLI(gh)と、GitHubに接続したVercelアカウント。

各要素の連携方法

Profoundはコンテンツとレンダリングを分離します。

  • コンポーネントはコンテンツの形を定義します。Route Slugフィールドを持つCustom Componentはルーティング可能(category、item)で、UI Elementタグを付けたものはページ上に配置できます(nav、product_gridなど)。
  • ドキュメントはコンテンツです(商品、カテゴリ)。
  • UI要素はページのセクションです。各スカラー値フィールドは静的値またはCEL式を受け取り、レンダリング時に評価されます。
  • パラメトリックルートはURLをドキュメント+UI要素に対応付け、ルートパラメータを渡します(CELではmeta.params.*、ReactではrouteParams)。
  • Next.jsアプリはcms-rendererを通じて読み取り、Stripeは通常のAPIルートとして追加します。

構築全体を決める重要なルール: CELがバインドできるのは**string/numberフィールドだけです。そのため、ナビゲーションのブランド名、フッター、見出しなどのスカラー要素はCELでバインドし、リッチな値やコレクション(商品グリッド、画像ギャラリー、リッチテキストなど)は、ルートパラメータを使ってReactコンポーネント内で取得**します。また、Stripeが価格の唯一の正規ソースです。CMSのpriceは表示専用であり、請求額は常にStripe Price IDからサーバー側で解決します。

Part 1 — セットアップ

完了時には、小規模な公開カタログ、読み取り可能なアプリ、インストール済みのStripe、適用済みのデザインが揃います。まだ何もレンダリングされていません。

1. サインアップしてWebサイトを作成する

Profound(WorkOS認証)でサインアップします。storeという名前のWebサイトを作成し、管理画面URLのUUIDであるWebサイトIDと、読み取り階層のAPIキー(Deployments → Create API key)をコピーします。アプリは読み取りのみ行い、後のカタログのシードは別途認証するMCPを通じて実行します。

2. アプリをひな形から作成し、接続してStripeを追加する

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

ひな形はProfound用に事前接続されたNext.js App Routerプロジェクトです(cms-renderer SDK、キャッチオールルート、generate-schemasスクリプト、<Refresher>を含む)。スタイルは含まれていません。bun add stripeでサーバーSDKを追加します。ホスト型チェックアウトに必要な唯一の決済依存関係です。

.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   # CMSホスト画像を配信

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # ここではテストキー。本番時にライブキーへ変更
STRIPE_WEBHOOK_SECRET=whsec_...          # Build step 4で設定
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Stripe → Developers → API keysからSTRIPE_SECRET_KEYを取得します。構築中に実際のお金が動かないよう、テストキー(sk_test_…)を使用します。実際の決済を受け付ける準備ができたらライブキーに切り替えます。bun devを実行してlocalhost:3000を開くと、スターターが表示されます。

ホスト型チェックアウトではブラウザをStripe URLへリダイレクトするため、Stripeに必要なのはサーバーのシークレットキーだけです。公開可能キーもクライアント用Stripe SDKも必要ありません。

3. category、product_image、itemコンポーネントを定義する

3つのCustom Components(Components → Create new component)を作成します。これらはデータソースなので、UI Elementタグは付けません。それぞれをActiveにします。

CMSには「画像の配列」フィールドがないため、ギャラリーは小さなproduct_imageコンポーネントへの参照の配列にします。参照フィールドはActiveなコンポーネントだけを対象にできるため、itemより先にcategoryとproduct_imageを作成して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(参照の配列 → product_image)、price(Number、セント単位 — 表示専用)、currency(Select、usd)、stripePriceId(Text)、category(Reference → category)、active(Boolean)

すべてのフィールドは任意のままにします。管理画面はフィールド名をスネークケースに変換します(「Stripe Price Id」→stripe_price_id)。コードはこの名前を使うため、次にgenerate-schemasから実際の名前を確認します。ルーティング可能なハンドルにはslugではなくcodeを使用します。これはRoute Slugであり、後で簡潔なdocuments.getByCode検索のキーにもなります。

itemコンポーネント — Route Slugとしてのcode、product_imageへの参照としてのimages、さらにstripePriceIdとcategory参照。

4. コンポーネントをローカル型に取り込む

bun run generate-schemas

Zodスキーマと型をgenerated/cms-schemas.ts(categorySchema/Category、itemSchema/Item)に書き込みます。接続確認も兼ねており、認証情報が間違っていればここで失敗します。

5. Profound MCPでカタログをシードする

MCPを一度インストールして認証します。

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

mcp__Profound__authenticateを実行してWorkOSフローを完了し、Claudeに次のように依頼します。

Edison's Inventionsというストア向けに、小規模なEコマースカタログを生成してください。3カテゴリと次の商品を含め、各商品に当時の時代背景に合う短いdescription、セント単位のprice、currency: "usd"、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)

各カテゴリにはnameと小文字のcodeを、各商品にはname、小文字のcode、description、セント単位のprice、currency、activeを設定してください。data/catalog.jsonに保存し、categoryおよびitemコンポーネントに対して検証してください。その後Profound MCPを使い、各項目を公開済みドキュメントとして作成してください。まずカテゴリを作成してIDを取得し、その後、categoryに参照を設定して商品を作成します — { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }。現時点ではstripePriceIdは空にしてください。商品は並列で作成してください。

Claudeはdata/catalog.jsonを書き、検証し、並列のcreate_document呼び出し(status: "published")を展開します。参照先のIDがすでに存在するよう、カテゴリを商品より先にシードします。

シードされた3カテゴリ。公開済みでLiveです。

シードされた8商品。それぞれカテゴリにリンクされています。

6. Stripe Priceを作成していくつかの商品を接続する

CMSにカタログができたので、いくつかの商品に実際のStripe価格を設定します。これはコード不要で、管理画面を2つ使ってマーチャントが行う作業です。

  1. Stripe Dashboard → Products → + Add productで、1回限りの価格を設定し、Price ID(price_…)をコピーします。
  2. これを代表的な約3商品(Lightbulb、Phonograph、Kinetoscopeなど)に対して行います。
  3. Profound管理画面 → item → Documentsで、各Price IDをstripePriceIdに貼り付けて保存します。

CMSはカタログを、Stripeは正式な価格を保持し、両者の接続はマーチャントが貼り付ける1つの文字列です。(自動化したい場合は、公式のStripe MCPでProducts/Pricesを作成し、返されたIDを同じ方法で貼り付けられます。)

7. デザインシステムを追加してAIで接続する

ひな形にはスタイルがありません。プロジェクトルートにDESIGN.md(Tailwind v4の@themeブロック+トークン)を配置します。自作のものでも、refero.designからダウンロードしたものでも構いません。その後、スタイルだけに範囲を限定してClaudeに依頼します。

追加したデザインファイルを読み込んでください。必要ならTailwindを設定し、テーマとフォントを接続してスタイルが動作するようにしてください。フォントにはnext/fontを使用し、実行時にGoogleから読み込まないでください。スタイルだけを扱い、まだページやコンポーネントは作成しないでください。

src/app/globals.cssに@import "tailwindcss";と@themeブロックがあり、localhost:3000にトークンが表示されることを確認します。依頼を簡潔に保ち、フォントは必ずnext/fontで読み込んでください。

8. 商品画像を追加する(任意)

画像がなくても動作するチェックアウトは構築できます。追加する場合は、画像ごとにproduct_imageドキュメントを作成し(imageフィールドにアップロード)、商品側のimages配列から参照します。商品写真を用意するか、画像モデルで統一感のあるセットを生成します(ClaudeにDESIGN.mdからブランドに合うプロンプトを作らせ、すべての画像で同じMidjourney --srefを固定するとよいでしょう)。

独立したcms-rendererには画像URLヘルパーがないため、buildAssetUrlをsrc/lib/image.tsに移植します(約40行)。NEXT_PUBLIC_BUNNY_CDN_URLを先頭に付け、拡張子を追加します。Build step 3のコンポーネントがこれを使用します。

Part 2 — 構築

レンダリング層とチェックアウトを構築し、テストモードで実際に購入できる状態にします。

1. 5つのUI要素コンポーネントを定義する

5つのコンポーネントをすべてActiveにし、UI Elementタグ(Settings → Tags)を付けます。Route Slugは付けません。

  • nav → brand · product_grid → heading · product_detail → heading · cart_summary → heading · footer → text(すべてText)

UI Elementタグによって、コンポーネントがPage BuilderのAdd UI Element一覧に表示されます。Activeにするだけでは不十分です。各フィールドはCELがバインドできるスカラーです。実際のカタログデータはここでフィールドにせず、ProductGrid/ProductDetailがルートパラメータから取得します(step 3)。

2. 型を再生成する

bun run generate-schemas

3. カタログリーダー、コンポーネント、ヘッドレスカートを生成する

1つのプロンプトで、読み取りヘルパー、5つのコンポーネント、カート、レジストリを作成します。

cms-renderer SDKを使い、src/にストアフロントを構築してください。

src/lib/catalog.ts — サーバー側CMSリーダー。cms-renderer/lib/cms-apiのgetCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! })でクライアントを作成してください。getItemByCode(code)はcms.documents.getByCode.query({ websiteId, schemaName: "item", code })を呼び、**res.document.published_content**を返します。listItems(categoryCode?)はcms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 })を呼び、res.documentsを.published_contentに変換し、active !== falseだけを残します。categoryCodeが指定された場合は、categoryのdocument.idとcategory._refが一致する商品だけを残します。resolveImages(refs)は、各item.images参照をcms.documents.get.query({ websiteId, id: ref._ref })で解決し、その画像フィールドを、Part 1 step 8で移植したbuildAssetUrlでURLに変換します。

src/components/ — 5つのUI要素コンポーネントを、キャッチオールルートのレジストリにコンポーネント名で登録します。管理画面に合わせてスネークケースを使います:{ nav, product_grid, product_detail, cart_summary, footer }。NavとFooterはcontent prop(cms-renderer/lib/typesのBlockComponentProps<T>型)からスカラー値を読みます。ProductGridとProductDetailはrouteParamsを読み、catalog.tsから取得する非同期サーバーコンポーネントです。routeParams.<param>は{ value, … }なので.valueを読みます。ProductGridはlistItems(routeParams.category_code?.value)を呼び(カードは/products/{code}にリンク)、ProductDetailはgetItemByCode(routeParams.item_code?.value)を呼びます(resolveImagesによるギャラリー、リッチテキストの説明、価格、カート追加)。CartSummaryはuseCartでカートを表示し、Payボタンを配置します。クライアントコンポーネントがサーバー専用のcatalog.tsをインポートしないよう、formatPriceは純粋なsrc/lib/format.tsに置きます。

src/components/AddToCartButton.tsx — { code, name, priceLabel }を受け取り、useCart().addItem({ code, name, priceLabel, quantity: 1 })を呼ぶ"use client"ボタンです。ProductDetail内で使用します。

src/lib/useCart.ts — ヘッドレスカート。状態内の明細は{ code, name, priceLabel, quantity }とし、localStorageに保存します。addItem/removeItem/updateQty/subtotalと、{ lines: [{ code, quantity }] }(コードと数量のみ。価格は絶対に送らない)を/api/stripe/checkoutへPOSTし、返されたurlへリダイレクトするcheckout()を公開します。

すべてをデザインシステムでスタイルし、独自コンポーネントとして作成してください。元サイトのレイアウトをコピーしないでください。

実行後に知っておくべきことは3つです。

  • スカラー要素はcontent({ content }: BlockComponentProps<T>)から渡されます。フィールドをトップレベルのpropsとして分割代入しないと、ブロックは空になります。カタログデータはCELでリストやギャラリーをバインドできないため、routeParams+catalog.tsの取得で読み込みます。カートが保持するのは商品コードであり、価格ではありません。
  • routeParams.<param>は{ value, schemaName, document }です。.valueを読みます。読み取り結果は.contentではなくpublished_contentです。レジストリキーは管理画面に合わせてスネークケースにします。
  • @types/react/@types/react-domをv19に上げます。ひな形はv18を含むため、React 19の非同期サーバーコンポーネントブロックで問題が起きます。

4. Stripeサーバーコードを書く(中心部分)

短いサーバーファイルを3つ作ります。アプリ内の決済コードはこれだけです。getItemByCodeを再利用するため、請求額はサーバー側で解決されます。

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 — 各商品をCMSから解決し、Stripeの価格を請求します。

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // サーバー側、読み取り階層キー

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] — クライアントから価格を受け取らない
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // サーバーがCMSから解決
      return { price: item!.stripe_price_id, quantity }; // CMS由来の価格。クライアント値は使用しない
    })
  );
  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 });     // クライアントはここへリダイレクト
}

src/app/api/stripe/webhook/route.ts —信頼できるフルフィルメント通知です。

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

export async function POST(req: Request) {
  const body = await req.text();                      // RAWボディ — 署名検証に必須
  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") {
    // フルフィルメント: 注文を記録する / 領収書を送信する。
  }
  return new Response(null, { status: 200 });
}

必須のひな形修正: ひな形のsrc/proxy.tsはすべての/api/*をCMSへ転送するため、Stripeのルートが実行されません。まずローカルのルートを通過させます。

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();                       // ローカルで処理
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// ひな形の`export const config = { matcher: [...] }`は変更しない

curl -X POST localhost:3000/api/stripe/webhook -d xを実行し、Bad signatureが返ることを確認します。

ローカルWebhook用にStripe CLIを実行します。

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# whsec_...をSTRIPE_WEBHOOK_SECRETにコピーして、bun devを再起動

whsec_…はセッションごとに異なります。セキュリティ上の重要なルールは2つです。チェックアウトではcodeを使ってCMSから価格を再取得するため、改ざんされたカートで価格を変更できません。またWebhookはRAWボディに対して署名を検証します。

5. ルートを作成する

Admin → Pages → Create pageを3回実行します。各パラメータをコンポーネント(slugフィールドはcode)に対応付けます。

  1. /products/{item_code} → item
  2. /categories/{category_code} → category
  3. /cart — 静的ページ(リテラルの/cartを入力し、/{cart}にはしない)

6. UI要素を追加し、CELを接続して公開する

各ルートでPage Builder → Add UI Element → Customを選び、コンポーネントを順番に追加します。スカラー値フィールドに静的値またはCELを入力し、Publishします。

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

nav.brandとfooter.textには静的文字列を設定し、見出しにも静的なラベルを設定します。

カテゴリルートのPage Builder — product_grid要素を選択し、見出しをCELでバインドしています。

商品ルートのPage Builder — 商品バインディング上にproduct_detail要素があります。

パラメトリックPage Builderの注意点: 2つのパラメトリックルートでは、UI要素の追加が保存されません(ブロックが孤立し、ページが空になります)。修正されるまでは、Profound MCPのupdate_pageでそれらのページのblock_idsを直接設定してから公開してください。(静的な/cartは通常どおり接続されます。)同じ理由で、ProductGridはCELではなく取得したカテゴリから見出しを導出します。

7. 表示して購入する

  • /categories/lighting → グリッド。商品をクリックすると詳細+カート追加が表示されます。/cart → Pay。
  • PayでStripeホスト型チェックアウトへリダイレクトされます。テストカード4242 4242 4242 4242と、任意の将来の有効期限/CVCを使用します。/cart?status=successに戻り、stripe listenにはcheckout.session.completedが表示されます。

レンダリングされた商品ページ — ギャラリー、価格、カート追加。

カート — 明細と1つのStripe決済ボタン。

購入できるのは価格が設定された商品だけです。step 6で価格を設定した約3商品のいずれかを購入してください。

任意 — 国際化。 各コンポーネントを翻訳し(35言語すべてを一度に対応可能)、組み込みのlanguage System componentに対応付けた/{language}/…セグメントを追加し、CELでバインドしたフィールドをdocuments.translatedに切り替えます。airport directoryチュートリアルのPart 2 step 7を参照してください。

Part 3 — 本番環境

1. GitHub、そしてVercelへ出荷する

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

ビルドコマンド: generated/cms-schemas.tsはgitignoreされているため、ビルド時に再生成するよう固定します。vercel.jsonを追加してください。

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

VercelでAdd New → Projectを選び、storeをインポートして環境変数を追加します。PROFOUND_API_KEY、NEXT_PUBLIC_PROFOUND_WEBSITE_ID、NEXT_PUBLIC_CMS_API_URL、NEXT_PUBLIC_BUNNY_CDN_URL、STRIPE_SECRET_KEY、STRIPE_WEBHOOK_SECRET(下記のデプロイ済みエンドポイント用の値)、NEXT_PUBLIC_SITE_URL(本番URL)を設定してデプロイします。

次にデプロイ済みWebhookを接続します(ローカルのstripe listen用シークレットはローカル専用です)。Stripe → Developers → Webhooks → + Add endpoint → https://<prod>/api/stripe/webhookを開き、イベントとしてcheckout.session.completedを指定します。そのwhsec_…をVercelにコピーして再デプロイします。

環境変数の不足は「ローカルでは動くのに本番では空白になる」という、最も多いデプロイ上の落とし穴です。ここではテストキーでデプロイします。実際の決済を受け付ける準備ができたら、STRIPE_SECRET_KEYとWebhookシークレットをライブの値に切り替えます。

2. ライブプレビューとインプレース編集

どちらもひな形に含まれています。

  • ライブプレビュー: <Refresher>により、管理画面で編集者が保存するとプレビュー中のページが更新されます。再デプロイは不要です。(これは編集者向けのプレビューです。通常の再検証では、訪問者には公開済みコンテンツが表示されます。)
  • インプレース編集: 任意のURLに?edit_mode=trueを追加すると編集オーバーレイが表示されます。一般の訪問者には通常のページが表示されます。

ひな形にないプレビュールートを追加してください。 管理画面は/cms-preview_<path>でプレビュー用iframeを読み込みます。このルートがないと、すべてのプレビューが404になります。追加してください。

// src/app/cms-preview_/[...slug]/page.tsx
import { ParametricRoutePreviewPage } from "cms-renderer/lib/renderer";
import { registry } from "../../registry";   // レジストリを共有モジュールへ切り出す
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
  const PreviewPage = ParametricRoutePreviewPage as any; // 非同期RSC。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} />;
}

セグメントのルート用にsrc/app/cms-preview_/page.tsxも追加します(同じ内容でslug: [])。

これで構築完了です

コンテンツ駆動型のStripeストアフロントです。CMSカタログ、1組のルートから生成する一覧+詳細ページ、そして動作するホスト型チェックアウトが揃いました。AIがカタログをシードし、デザインを接続し、カタログリーダー+コンポーネント+ヘッドレスカートを書きました。あなたが行ったのは、コンポーネント、Stripe価格とのリンク、3つのルート、CELによるUI要素、そして3つの短いStripeファイルです。CELはUI要素をバインドし、コンポーネントはカタログを取得します。 Stripeの実装も小さく、sessions.createの呼び出し1つと署名付きWebhook 1つだけです。購入者はStripe自身のページで支払います。

Continue Reading
Previous‹Deployments