profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Tutorials

Build & Ship an Airport DirectoryImplementacionesBuild & 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

Un recorrido práctico: construye un escaparate de Stripe impulsado por contenido en Profound CMS — un catálogo que un comerciante edita sin código, dos rutas paramétricas, un carrito sin cabeza y un checkout alojado en Stripe.

La tienda terminada en movimiento: explora una categoría, abre un producto, agrégalo al carrito y completa la compra.

Un recorrido práctico que construye una tienda impulsada por contenido en Profound CMS: un catálogo de productos (categorías + artículos) modelado en el CMS, páginas de listado y detalle desde un único conjunto de rutas, y un checkout alojado en Stripe entregado como un componente sin cabeza.

La columna vertebral está escrita a mano en Next.js junto con el panel de administración de Profound. Claude Code (a través del MCP de Profound) hace el trabajo pesado en tres tareas: sembrar el catálogo, conectar el sistema de diseño y escribir los componentes del escaparate (incluido el carrito sin cabeza). Tres partes: Configuración, Construcción, Producción.

Pagos en una sola línea. Usamos Stripe-hosted Checkout: el comprador paga en la página de Stripe, no en la tuya. Tu aplicación hace solo dos cosas del lado del servidor: crear una sesión de Checkout y verificar un webhook. Sin campos de tarjeta, sin Stripe Elements, sin carga PCI.

Qué construirás

  • Un catálogo pequeño publicado en el CMS — tres categorías y ocho productos (la demo de "Edison's Inventions") — cada uno editable por un comerciante sin código.
  • Dos rutas paramétricas (/products/{item_code}, /categories/{category_code}) más un /cart estático, todo desde un único conjunto de componentes.
  • Un carrito sin cabeza (useCart) y checkout alojado en Stripe, con el precio siempre resuelto en el servidor a partir de un Stripe Price ID.
  • La tienda desplegada en Vercel con vista previa en vivo y edición in situ para el equipo.

Requisitos previos

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Claude Code con el Profound MCP (la Parte 1 lo instala).
  • Una cuenta de Profound CMS.
  • Una cuenta de Stripe. Este tutorial se ejecuta en modo de prueba, así que nada cobra dinero real mientras construyes, pero el flujo es idéntico con claves en vivo, así que usa las claves de tu cuenta real si lo prefieres. (El modo de prueba no necesita datos comerciales ni bancarios).
  • La Stripe CLI (stripe login) para webhooks locales.
  • Para desplegar: la GitHub CLI (gh) y una cuenta de Vercel conectada a GitHub.

Cómo encajan las piezas

Profound separa el contenido del renderizado:

  • Los componentes definen la forma del contenido. Un componente personalizado con un campo Route Slug es enrutable (category, item); uno etiquetado como UI Element puede colocarse en una página (nav, product_grid, …).
  • Los documentos son el contenido (un producto, una categoría).
  • Los elementos de interfaz son secciones de página; cada campo escalar toma un valor estático o una expresión CEL, evaluada en el renderizado.
  • Las rutas paramétricas mapean una URL a un documento + elementos de interfaz, pasando parámetros de ruta (meta.params.* en CEL, routeParams en React).
  • Tu aplicación de Next.js lo lee mediante cms-renderer; Stripe se agrega como rutas API ordinarias.

La única regla que guía la construcción: CEL solo enlaza campos de tipo string/number. Así que el cromado escalar (marca de la navegación, pie de página, encabezados) se enlaza con CEL, mientras que cualquier cosa rica o una colección (una cuadrícula de productos, una galería de imágenes, texto enriquecido) se obtiene dentro del componente React por parámetro de ruta. Y Stripe es la fuente de la verdad en la fijación de precios: el price del CMS es solo para mostrar; el cargo siempre se resuelve en el servidor a partir de un Stripe Price ID.

Parte 1 — Configuración

Estado final: un pequeño catálogo publicado, la aplicación conectada para leerlo, Stripe instalado, el diseño en su lugar — nada renderizado todavía.

1. Regístrate y crea el sitio web

Regístrate en Profound (autenticación WorkOS). Crea un sitio web llamado store, luego copia su ID del sitio web (el UUID en la URL del administrador) y una API key de nivel de lectura (Deployments → Create API key). La aplicación solo lee; la siembra del catálogo más adelante pasa a través del MCP, que se autentica por separado.

2. Genera la app, conéctala y agrega Stripe

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

El esqueleto es un proyecto de App Router de Next.js preconfigurado para Profound (el SDK cms-renderer, una ruta catch-all, un script generate-schemas, un <Refresher>). No incluye estilos. bun add stripe incorpora el SDK del servidor — la única dependencia de pagos que necesita el checkout alojado.

Añade tus valores a .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   # sirve imágenes alojadas en el CMS

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # clave de prueba aquí; cámbiala por tu clave en vivo cuando publiques
STRIPE_WEBHOOK_SECRET=whsec_...          # se completa en el paso 4 de Construcción
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Obtén STRIPE_SECRET_KEY en Stripe → Developers → API keys. Usamos una clave de prueba (sk_test_…) para que la construcción nunca mueva dinero real; cambia a tu clave en vivo cuando estés listo para aceptar pagos reales. Ejecuta bun dev y abre localhost:3000; el starter se renderiza.

El checkout alojado redirige el navegador a una URL de Stripe, así que la clave secreta del servidor es todo lo que Stripe necesita — sin clave publicable, sin SDK de cliente de Stripe.

3. Define los componentes category, product_image e item

Crea tres Componentes Personalizados (Components → Create new component) — la fuente de datos, por lo que sin etiqueta de UI Element. Activa cada uno.

El CMS no tiene un campo "array de imagen", así que una galería es un array de referencias a un pequeño componente product_image. Crea category y product_image (y actívalos) antes de item; un campo de referencia solo apunta a componentes activos.

  • 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 de referencias → product_image), price (Number, centavos — solo para mostrar), currency (Select, usd), stripePriceId (Text), category (Reference → category), active (Boolean)

Deja todos los campos como opcionales. El administrador convierte los nombres de campo a snake_case en minúsculas ("Stripe Price Id" → stripe_price_id) — eso es lo que tu código usará, así que vuelve a leer los nombres reales con generate-schemas después. Nombramos el identificador enrutable code (no slug): es el Route Slug y la clave para una consulta limpia documents.getByCode más adelante.

El componente item: code como Route Slug, images como referencias a product_image, además de stripePriceId y una referencia category.

4. Extrae los componentes como tipos locales

bun run generate-schemas

Escribe esquemas y tipos de Zod en generated/cms-schemas.ts (categorySchema/Category, itemSchema/Item). También funciona como comprobación de conexión: si las credenciales son incorrectas, falla aquí.

5. Siembra el catálogo mediante el Profound MCP

Instala y autentica el MCP una vez:

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

Ejecuta mcp__Profound__authenticate, completa el flujo WorkOS y luego pide a Claude:

Genera un pequeño catálogo de ecommerce para una tienda llamada Edison's Inventions — tres categorías y estos productos, con una description breve y fiel a la época, un price en centavos, currency: "usd" y 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)

Cada categoría necesita un name y ese code en minúsculas; cada artículo necesita un name, ese code en minúsculas, la description, price (en centavos), currency y active. Guárdalo en data/catalog.json y valídalo contra nuestros componentes category e item. Luego usa el Profound MCP para crear cada uno como documento publicado: crea primero las categorías, captura sus IDs y luego crea los artículos con category configurado como referencia — { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }. Deja stripePriceId vacío por ahora. Haz los artículos en paralelo.

Claude escribe data/catalog.json, lo valida y lanza llamadas create_document en paralelo (status: "published"). Siembra las categorías antes que los artículos para que las referencias apunten a IDs que ya existen.

Las tres categorías sembradas, publicadas y en vivo.

Los ocho productos sembrados, cada uno vinculado a una categoría.

6. Crea precios de Stripe y conecta algunos productos

El catálogo está en el CMS; ahora dales a algunos productos un precio real en Stripe — el trabajo del comerciante, hecho en dos paneles de administración, sin código:

  1. Stripe Dashboard → Products → + Add product, establece un precio de pago único, copia el Price ID (price_…).
  2. Hazlo para unas 3 productos destacados (p. ej., Lightbulb, Phonograph, Kinetoscope).
  3. Administrador de Profound → item → Documents → pega cada Price ID en stripePriceId, guarda.

El CMS contiene el catálogo; Stripe contiene el precio oficial; el enlace es una cadena que el comerciante pega. (¿Prefieres automatizarlo? El Stripe MCP oficial puede crear los Products/Prices por ti — pega los IDs devueltos de la misma manera).

7. Agrega el sistema de diseño y conéctalo con IA

El esqueleto se entrega sin estilos. Coloca un DESIGN.md (un bloque @theme de Tailwind v4 + tokens) en la raíz del proyecto — uno propio o descárgalo de refero.design. Luego pídele a Claude, limitado solo al estilo:

Lee el archivo de diseño que acabo de añadir. Configura Tailwind si es necesario, luego integra el tema y las fuentes para que el estilo funcione. Usa next/font para las fuentes — no las cargues desde Google en tiempo de ejecución. Solo el estilo — no construyas páginas ni componentes todavía.

Verifica que src/app/globals.css tenga @import "tailwindcss"; más el bloque @theme y que localhost:3000 muestre los tokens. Mantén el prompt concreto (si es muy abierto, un agente puede crear toda una página de inicio) y carga las fuentes con next/font, nunca con una importación de Google en tiempo de ejecución.

8. Añade imágenes de productos (opcional)

Opcional: puedes llegar a un checkout funcional sin imágenes. Para agregarlas, crea un documento product_image por imagen (sube el archivo en su campo image), luego referencia esas imágenes en el array images del producto. Trae tus propias fotos de producto o genera un conjunto coherente con un modelo de imágenes (haz que Claude derive prompts acordes con marca desde DESIGN.md y bloquea un único --sref en Midjourney para que todas las tomas coincidan).

El cms-renderer independiente no tiene un helper de URLs de imagen, así que incorpora buildAssetUrl en src/lib/image.ts (~40 líneas) — antepone NEXT_PUBLIC_BUNNY_CDN_URL y añade la extensión. Los componentes del paso 3 de Construcción lo usan.

Parte 2 — Construcción

Construye la capa de renderizado y el checkout, terminando con una compra real en modo de prueba.

1. Define los cinco componentes de elementos de interfaz

Cinco componentes, cada uno Activo y etiquetado como UI Element (Settings → Tags), sin Route Slug:

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

La etiqueta UI Element es lo que hace que un componente aparezca en la lista Add UI Element del Page Builder — estar Activo no es suficiente. Cada campo es escalar (el tipo que CEL enlaza); los datos reales del catálogo no son un campo aquí — ProductGrid/ProductDetail los obtienen por parámetro de ruta (paso 3).

2. Regenera los tipos

bun run generate-schemas

3. Genera el lector del catálogo, los componentes y el carrito sin cabeza

Un único prompt genera el helper de lectura, los cinco componentes, el carrito y el registro:

Construye nuestro escaparate en src/, usando el SDK cms-renderer de Profound.

src/lib/catalog.ts — un lector del CMS del lado del servidor. Crea un cliente con getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) de cms-renderer/lib/cms-api. Exporta getItemByCode(code) → cms.documents.getByCode.query({ websiteId, schemaName: "item", code }) que devuelva res.document.published_content. Exporta listItems(categoryCode?) → cms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 }), mapea res.documents a .published_content, filtra active !== false y, si se proporciona categoryCode, conserva los artículos cuyo category._ref coincide con el document.id de la categoría. Exporta resolveImages(refs) que resuelva cada referencia item.images mediante cms.documents.get.query({ websiteId, id: ref._ref }) y convierta su campo de imagen en una URL con el buildAssetUrl incorporado (Parte 1 paso 8).

src/components/ — cinco componentes de elementos de interfaz registrados en el registro de la ruta catch-all por nombre de componente, en snake_case para coincidir con el administrador: { nav, product_grid, product_detail, cart_summary, footer }. Nav y Footer leen su campo escalar del prop content (tipado como BlockComponentProps<T> de cms-renderer/lib/types). ProductGrid y ProductDetail son componentes de servidor asíncronos que leen routeParams y obtienen datos de catalog.ts: routeParams.<param> es { value, … } — lee .value, así que ProductGrid llama listItems(routeParams.category_code?.value) (las tarjetas enlazan a /products/{code}) y ProductDetail llama getItemByCode(routeParams.item_code?.value) (galería mediante resolveImages, descripción de texto enriquecido, precio, Agregar al carrito). CartSummary renderiza el carrito desde useCart con un botón Pagar. Mantén formatPrice en un src/lib/format.ts puro para que los componentes de cliente no importen el catalog.ts solo de servidor.

src/components/AddToCartButton.tsx — un botón "use client" que recibe { code, name, priceLabel } y llama useCart().addItem({ code, name, priceLabel, quantity: 1 }). Úsalo dentro de ProductDetail.

src/lib/useCart.ts — un carrito sin cabeza: líneas { code, name, priceLabel, quantity } en estado, persistidas en localStorage, exponiendo addItem/removeItem/updateQty/subtotal y un checkout() que hace POST de { lines: [{ code, quantity }] } (solo códigos y cantidades — nunca precios) a /api/stripe/checkout, y luego redirige a la url devuelta.

Estiliza todo con nuestro sistema de diseño, como componentes propios — no copies el layout del sitio de origen.

Tres cosas clave tras ejecutarlo:

  • El cromado escalar llega en content ({ content }: BlockComponentProps<T>); si desestructuras los campos como props de primer nivel, el bloque se renderiza en blanco. Los datos del catálogo provienen de routeParams + una obtención en catalog.ts, porque CEL no puede enlazar listas ni galerías. El carrito lleva los códigos de los artículos, nunca los precios.
  • routeParams.<param> es { value, schemaName, document } — lee .value. Las lecturas devuelven published_content, no .content. Las claves del registro están en snake_case para coincidir con el administrador.
  • Actualiza @types/react/@types/react-dom a v19 — el esqueleto se entrega con v18, que rompe los bloques de componentes de servidor asíncronos en React 19.

4. Escribe el código de servidor de Stripe (la columna vertebral)

Tres archivos breves del lado del servidor — el único código de pagos en la app. Reutilizan getItemByCode, así que el cargo se resuelve del lado del servidor.

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 — resuelve cada artículo desde el CMS, cobra el precio de Stripe:

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // del lado del servidor, clave de solo lectura

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] — sin precios desde el cliente
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // el servidor lo resuelve desde el CMS
      return { price: item!.stripe_price_id, quantity }; // precio desde el CMS, nunca del cliente
    })
  );
  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 });     // el cliente redirige aquí
}

src/app/api/stripe/webhook/route.ts — la señal de cumplimiento confiable:

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

export async function POST(req: Request) {
  const body = await req.text();                      // cuerpo RAW — requerido para verificar la firma
  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") {
    // fulfillment: registra el pedido / envía un recibo.
  }
  return new Response(null, { status: 200 });
}

Corrección necesaria del esqueleto: src/proxy.ts reenvía cada /api/* al CMS, así que tus rutas de Stripe nunca se ejecutan. Deja que pasen primero:

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();                       // manejar localmente
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// deja sin cambios el `export const config = { matcher: [...] }` del esqueleto

Verificación: curl -X POST localhost:3000/api/stripe/webhook -d x devuelve Bad signature.

Ejecuta la Stripe CLI para webhooks locales:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# copia el whsec_... en STRIPE_WEBHOOK_SECRET, reinicia bun dev

El whsec_… es por sesión. Dos reglas sostienen la seguridad: el checkout vuelve a derivar el precio desde el CMS por code (un carrito manipulado no puede cambiarlo) y el webhook verifica la firma contra el cuerpo sin procesar.

5. Crea las rutas

Administrador → Pages → Create page, tres veces. Mapea cada parámetro a su componente (campo slug code):

  1. /products/{item_code} → item
  2. /categories/{category_code} → category
  3. /cart — una página estática (introduce literal /cart, no /{cart})

6. Añade elementos de interfaz, conecta CEL y publica

Para cada ruta: Page Builder → Add UI Element → Custom → añade los componentes en orden, completa los campos escalares (valor estático o CEL), Publica.

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

Configura nav.brand y footer.text con cadenas estáticas; encabezados con etiquetas estáticas.

El Page Builder en la ruta de categoría: product_grid seleccionado, su heading enlazado con CEL.

El Page Builder en la ruta de producto: el elemento product_detail en el enlace de un producto.

Advertencia del Page Builder paramétrico: en las dos rutas paramétricas, añadir elementos de interfaz no persiste (los bloques quedan huérfanos y la página se renderiza en blanco). Hasta que se corrija, conecta los block_ids de esas páginas directamente mediante el MCP de Profound update_page, luego publica. (El /cart estático se adjunta con normalidad). Por la misma razón, ProductGrid deriva su heading de la categoría que obtiene en lugar de usar CEL.

7. Renderiza y compra

  • /categories/lighting → la cuadrícula. Haz clic en un producto → detalle + Añadir al carrito. /cart → Pagar.
  • El pago redirige al checkout alojado de Stripe. Usa la tarjeta de prueba 4242 4242 4242 4242, cualquier fecha de caducidad futura/CVC. Regresas a /cart?status=success y stripe listen muestra checkout.session.completed.

Una página de producto renderizada — galería, precio y Añadir al carrito.

El carrito — líneas de artículos y un único botón Pagar con Stripe.

Solo los artículos con precio son comprables — compra uno de los ~3 que conectaste en el paso 6.

Opcional — internacionaliza. Traduce cada componente (los 35 idiomas a la vez), añade un segmento /{language}/… mapeado al componente de sistema language integrado y cambia los campos enlazados por CEL a documents.translated. Consulta el tutorial del directorio del aeropuerto, Parte 2 paso 7.

Parte 3 — Producción

1. Súbelo: GitHub y luego Vercel

git init && git add -A && git commit -m "Stripe storefront"
gh repo create store --private --source=. --push   # --public también es válido

Comando de build: generated/cms-schemas.ts está en .gitignore, así que fija el build para regenerarlo — añade vercel.json:

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

En Vercel: Add New → Project, importa store y añade las variables de entorno — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, NEXT_PUBLIC_BUNNY_CDN_URL, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (el valor del endpoint desplegado, más abajo) y NEXT_PUBLIC_SITE_URL (tu URL de producción). Despliega.

Luego conecta el webhook desplegado (el secreto stripe listen local era solo local): Stripe → Developers → Webhooks → + Add endpoint → https://<prod>/api/stripe/webhook, evento checkout.session.completed. Copia su whsec_… en Vercel y vuelve a desplegar.

Variables de entorno faltantes = "funciona localmente, en blanco en producción" — el problema de despliegue #1. Aquí desplegamos con claves de prueba; cambia STRIPE_SECRET_KEY y el secreto del webhook a tus valores en vivo cuando estés listo para aceptar pagos reales.

2. Vista previa en vivo y edición in situ

Ambas funciones vienen con el esqueleto.

  • Vista previa en vivo: <Refresher> actualiza la página que estás previsualizando cuando un editor guarda en el panel — sin redeploy. (Es una vista previa para el editor; los visitantes ven contenido publicado con la revalidación normal).
  • Edición in situ: añade ?edit_mode=true a cualquier URL para superposiciones de edición. Los visitantes públicos ven la página limpia.

Añade la ruta de vista previa que falta en el esqueleto. El administrador carga su iframe de vista previa en /cms-preview_<path>; sin esa ruta, cada vista previa devuelve 404. Añádela:

// src/app/cms-preview_/[...slug]/page.tsx
import { ParametricRoutePreviewPage } from "cms-renderer/lib/renderer";
import { registry } from "../../registry";   // extrae tu registro a un módulo compartido
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
 ; const PreviewPage = ParametricRoutePreviewPage as any; // componente de servidor async; tipos de 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} />;
}

Añade también src/app/cms-preview_/page.tsx (igual, slug: []) para la raíz del segmento.

Ese es el proyecto

Un escaparate de Stripe impulsado por contenido: un catálogo en el CMS, páginas de listado y detalle desde un mismo conjunto de rutas, y un checkout alojado funcional. La IA sembró el catálogo, conectó el diseño y escribió el lector del catálogo + componentes + carrito sin cabeza; tú hiciste los componentes, los enlaces de precio de Stripe, las tres rutas, el cromado con CEL y tres archivos breves de Stripe. CEL enlaza el cromado; los componentes obtienen el catálogo. Y Stripe se mantuvo pequeño: una llamada sessions.create y un webhook firmado, con el comprador pagando en la propia página de Stripe.

Continue Reading
Previous‹Implementaciones