profound-logoProfound CMS
⌘K
Admin
Theme
DocsGuidaBlogPhilosophy
DocsGuidaBlogPhilosophy

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

Una guida pratica: costruisci uno storefront Stripe guidato dai contenuti su Profound CMS — un catalogo che un merchant modifica senza codice, due route parametriche, un carrello headless e un checkout ospitato da Stripe.

Il negozio finito in azione — sfoglia una categoria, apri un prodotto, aggiungi al carrello, effettua il checkout.

Una guida pratica che realizza un negozio basato sui contenuti in Profound CMS: un catalogo prodotti (categorie + articoli) modellato nel CMS, pagine di elenco e di dettaglio da un solo set di route e checkout ospitato da Stripe distribuito come componente headless.

La spina dorsale è Next.js scritto a mano più l'admin di Profound. Claude Code (via Profound MCP) svolge il grosso del lavoro in tre attività — caricamento del catalogo, collegamento del design system e scrittura dei componenti dello storefront (incluso il carrello headless). Tre parti: Configurazione, Build, Produzione.

Pagamenti in una sola riga. Usiamo Stripe-hosted Checkout: l'acquirente paga sulla pagina di Stripe, non sulla tua. La tua app fa solo due cose lato server — crea una Checkout Session e verifica un webhook. Niente campi carta, niente Stripe Elements, niente oneri PCI.

Cosa costruirai

  • Un piccolo catalogo pubblicato nel CMS — tre categorie e otto prodotti (la demo "Edison's Inventions") — ognuno modificabile da un merchant senza codice.
  • Due route parametriche (/products/{item_code}, /categories/{category_code}) più una /cart statica, tutte dallo stesso set di componenti.
  • Un carrello headless (useCart) e checkout ospitato da Stripe, con il prezzo sempre risolto lato server da un ID Price di Stripe.
  • Il negozio distribuito su Vercel con anteprima live ed editoria in-page per il team.

Prerequisiti

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Claude Code con Profound MCP (la Parte 1 lo installa).
  • Un account Profound CMS.
  • Un account Stripe. Questo tutorial gira in modalità test così non si addebita denaro reale mentre costruisci — ma il flusso è identico con le chiavi live, quindi usa pure le chiavi del tuo account reale se preferisci. (La modalità test non richiede dati aziendali o bancari.)
  • La Stripe CLI (stripe login) per i webhook locali.
  • Per il deploy: la GitHub CLI (gh) e un account Vercel connesso a GitHub.

Come si incastrano i pezzi

Profound separa contenuti e rendering:

  • I Componenti definiscono la struttura dei contenuti. Un componente personalizzato con un campo Route Slug è routable (category, item); uno contrassegnato come UI Element può essere posizionato su una pagina (nav, product_grid, …).
  • I Documenti sono i contenuti (un prodotto, una categoria).
  • Gli Elementi UI sono sezioni di pagina; ogni campo scalare accetta un valore statico o un'espressione CEL, valutata in fase di rendering.
  • Le Route parametriche mappano un URL a un documento + elementi UI, passando i parametri della route (meta.params.* in CEL, routeParams in React).
  • La tua app Next.js li legge tramite cms-renderer; Stripe viene aggiunto come normali route API.

L'unica regola che dà forma alla build: CEL collega solo campi string/number. Quindi il chrome scalare (brand della nav, footer, intestazioni) è collegato con CEL, mentre tutto ciò che è ricco o una collezione (una griglia prodotti, una galleria immagini, rich text) viene recuperato all'interno del componente React tramite il parametro della route. E Stripe è la fonte della verità per i prezzi — il price nel CMS serve solo per la visualizzazione; l'addebito viene sempre risolto lato server da un ID Price di Stripe.

Parte 1 — Configurazione

Stato finale: un piccolo catalogo pubblicato, l'app collegata per leggerlo, Stripe installato, design in posto — niente ancora in rendering.

1. Registrati e crea il sito web

Registrati su Profound (auth WorkOS). Crea un sito chiamato store, poi copia il suo ID sito web (lo UUID nell'URL dell'admin) e una API key di livello read (Deployments → Create API key). L'app effettua solo letture; il seed del catalogo più avanti passa dal MCP, che si autentica separatamente.

2. Genera l'app, connettila e aggiungi Stripe

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

Lo scaffold è un progetto Next.js App Router preconfigurato per Profound (l'SDK cms-renderer, una route catch-all, uno script generate-schemas, un <Refresher>). Non include styling. bun add stripe installa l'SDK server — l'unica dipendenza di pagamenti necessaria per il checkout ospitato.

Aggiungi i tuoi valori a .env.local:

# CMS
PROFOUND_API_KEY=<la tua read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<il tuo website id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net   # serve le immagini ospitate dal CMS

# Stripe
STRIPE_SECRET_KEY=sk_test_...            # chiave di test qui; sostituisci con la chiave live quando vai live
STRIPE_WEBHOOK_SECRET=whsec_...          # da compilare nello step Build 4
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Recupera STRIPE_SECRET_KEY da Stripe → Developers → API keys. Usiamo una chiave di test (sk_test_…) così la build non muove denaro reale; passa alla tua chiave live quando sei pronto a ricevere pagamenti reali. Esegui bun dev e apri localhost:3000 — lo starter si vede.

Il checkout ospitato reindirizza il browser a un URL Stripe, quindi la chiave segreta server è tutto ciò che serve a Stripe — nessuna chiave pubblicabile, nessun SDK client di Stripe.

3. Definisci i componenti category, product_image e item

Crea tre Componenti personalizzati (Components → Create new component) — la fonte dati, quindi niente tag UI Element. Imposta ciascuno come Active.

Il CMS non ha un campo "array of image", quindi una gallery è un'array di riferimenti a un piccolo componente product_image. Crea category e product_image (e impostali come Active) prima di item — un campo reference può puntare solo a componenti 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 di reference → product_image), price (Number, centesimi — solo display), currency (Select, usd), stripePriceId (Text), category (Reference → category), active (Boolean)

Lascia tutti i campi opzionali. L'admin trasforma i nomi campo in lower-snake-case ("Stripe Price Id" → stripe_price_id) — sono quelli che il tuo codice userà, quindi leggi i nomi reali da generate-schemas dopo. Chiamiamo il handle routable code (non slug): è il Route Slug e la chiave per una lookup pulita documents.getByCode più avanti.

Il componente item — code come Route Slug, images come reference a product_image, più stripePriceId e un reference category.

4. Scarica i componenti come tipi locali

bun run generate-schemas

Scrive gli schemi Zod + tipi in generated/cms-schemas.ts (categorySchema/Category, itemSchema/Item). Funziona anche come check di connessione — credenziali errate falliscono qui.

5. Popola il catalogo tramite Profound MCP

Installa e autentica il MCP una volta:

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

Esegui mcp__Profound__authenticate, completa il flusso WorkOS, poi chiedi a Claude:

Genera un piccolo catalogo ecommerce per un negozio chiamato Edison's Inventions — tre categorie e questi prodotti, con una breve description accurata per il periodo, un price in centesimi, currency: "usd" e 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)

Ogni categoria deve avere name e quel code minuscolo; ogni item deve avere name, quel code minuscolo, la description, price (in centesimi), currency e active. Salvalo in data/catalog.json e validalo contro i nostri componenti category e item. Poi usa Profound MCP per creare ciascuno come documento pubblicato: crea prima le categorie, cattura i loro ID, poi crea gli item con category impostato a una reference — { "_type": "reference", "_ref": "<category-id>", "_schema": "category" }. Lascia stripePriceId vuoto per ora. Esegui gli item in parallelo.

Claude scrive data/catalog.json, lo valida e lancia chiamate create_document in parallelo (status: "published"). Popola prima le categorie così i riferimenti puntano a ID già esistenti.

Le tre categorie caricate, pubblicate e Live.

Gli otto prodotti caricati, ciascuno collegato a una categoria.

6. Crea i prezzi Stripe e collega alcuni prodotti

Il catalogo è nel CMS; ora assegna a qualche prodotto un prezzo reale su Stripe — compito del merchant, fatto in due pannelli admin, senza codice:

  1. Stripe Dashboard → Products → + Add product, imposta un prezzo una tantum, copia il Price ID (price_…).
  2. Fallo per ~3 prodotti di punta (es. Lampadina, Fonografo, Kinetoscope).
  3. Admin di Profound → item → Documents → incolla ogni Price ID in stripePriceId, salva.

Il CMS contiene il catalogo; Stripe è la fonte di verità dei prezzi; il collegamento è una stringa che il merchant incolla. (Preferisci automatizzare? L'Stripe MCP ufficiale può creare per te Products/Prices — incolla gli ID restituiti allo stesso modo.)

7. Inserisci il design system e collegalo con l'AI

Lo scaffold arriva senza stile. Inserisci un DESIGN.md (un blocco @theme Tailwind v4 + token) alla radice del progetto — il tuo, oppure scaricane uno da refero.design. Poi chiedi a Claude, limitandoti allo styling:

Leggi il file di design che ho appena aggiunto. Configura Tailwind se serve, poi collega il tema e i font così lo styling funziona. Usa next/font per i font — non caricarli da Google a runtime. Solo lo styling — non costruire pagine o componenti per ora.

Verifica che src/app/globals.css abbia @import "tailwindcss"; + il blocco @theme e che localhost:3000 mostri i token. Mantieni il prompt preciso (se è aperto, un agente ti costruisce un intero homepage), e carica i font via next/font, mai con import Google a runtime.

8. Aggiungi immagini prodotto (opzionale)

Opzionale — puoi arrivare a un checkout funzionante anche senza immagini. Per aggiungerle: crea un documento product_image per immagine (carica nel suo campo image), poi referenziale dal campo images nel prodotto. Porta le tue foto prodotto, o generane un set coerente con un modello di immagini (fai ricavare a Claude prompt in linea con DESIGN.md e fissa un --sref Midjourney così ogni scatto combacia).

Il cms-renderer standalone non ha un helper per gli URL delle immagini, quindi integra buildAssetUrl in src/lib/image.ts (~40 righe) — antepone NEXT_PUBLIC_BUNNY_CDN_URL e aggiunge l'estensione. I componenti dello step 3 della Build lo usano.

Parte 2 — Build

Costruisci il layer di rendering e il checkout, arrivando a un acquisto reale in modalità test.

1. Definisci i cinque componenti UI element

Cinque componenti, ciascuno Active e contrassegnato come UI Element (Settings → Tags), senza Route Slug:

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

Il tag UI Element è ciò che rende un componente visibile nella lista Add UI Element del Page Builder — Active da solo non basta. Ogni campo è uno scalare (quelli che CEL collega); i veri dati di catalogo non sono qui — ProductGrid/ProductDetail li recuperano tramite il parametro della route (step 3).

2. Rigenera i tipi

bun run generate-schemas

3. Genera il lettore del catalogo, i componenti e il carrello headless

Un unico prompt produce l'helper di lettura, i cinque componenti, il carrello e il registry:

Costruisci il nostro storefront in src/, usando l'SDK cms-renderer di Profound.

src/lib/catalog.ts — un lettore CMS lato server. Crea un client con getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) da cms-renderer/lib/cms-api. Esporta getItemByCode(code) → cms.documents.getByCode.query({ websiteId, schemaName: "item", code }) che restituisce res.document.published_content. Esporta listItems(categoryCode?) → cms.documents.list.query({ websiteId, schemaName: "item", status: "published", limit: 100 }), mappa res.documents a .published_content, filtra active !== false, e se categoryCode è fornito tieni gli item il cui category._ref corrisponde all'id della categoria. Esporta resolveImages(refs) che risolve ogni reference item.images tramite cms.documents.get.query({ websiteId, id: ref._ref }) e trasforma il suo campo immagine in un URL con buildAssetUrl integrato (Parte 1 step 8).

src/components/ — cinque componenti UI element registrati nel registry della route catch-all per nome del componente, snake_case per combaciare con l'admin: { nav, product_grid, product_detail, cart_summary, footer }. Nav e Footer leggono il loro campo scalare dalla prop content (tipata BlockComponentProps<T> da cms-renderer/lib/types). ProductGrid e ProductDetail sono server component async che leggono routeParams e recuperano da catalog.ts: routeParams.<param> è { value, … } — leggi .value, quindi ProductGrid chiama listItems(routeParams.category_code?.value) (le card linkano a /products/{code}) e ProductDetail chiama getItemByCode(routeParams.item_code?.value) (gallery via resolveImages, descrizione rich-text, prezzo, Add-to-cart). CartSummary renderizza il carrello da useCart con un pulsante Pay. Mantieni formatPrice in un puro src/lib/format.ts così i componenti client non importano il catalog.ts solo server.

src/components/AddToCartButton.tsx — un pulsante "use client" che accetta { code, name, priceLabel } e chiama useCart().addItem({ code, name, priceLabel, quantity: 1 }). Usalo all'interno di ProductDetail.

src/lib/useCart.ts — un carrello headless: line item { code, name, priceLabel, quantity } in state, persistiti in localStorage, che espone addItem/removeItem/updateQty/subtotal e un checkout() che fa POST di { lines: [{ code, quantity }] } (solo codici e quantità — mai prezzi) verso /api/stripe/checkout, poi reindirizza all'url restituito.

Stila tutto con il nostro design system, come componenti nostri — non copiare il layout del sito sorgente.

Tre cose da sapere dopo l'esecuzione:

  • Il chrome scalare arriva in content ({ content }: BlockComponentProps<T>) — destruttura i campi come prop top-level e il blocco renderizza vuoto. I dati di catalogo arrivano da routeParams + fetch in catalog.ts, perché CEL non può collegare liste o gallery. Il carrello trasporta i codici degli item, mai i prezzi.
  • routeParams.<param> è { value, schemaName, document } — leggi .value. Le letture restituiscono published_content, non .content. Le chiavi del registry sono in snake_case per combaciare con l'admin.
  • Aggiorna @types/react/@types/react-dom alla v19 — lo scaffold arriva con la v18, che rompe i blocchi server component async su React 19.

4. Scrivi il codice server Stripe (la spina dorsale)

Tre file server brevi — l'unico codice pagamenti dell'app. Riutilizzano getItemByCode, così l'addebito si risolve lato 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 — risolve ogni item dal CMS, addebita il prezzo su Stripe:

import { NextResponse } from "next/server";
import { stripe } from "@/lib/stripe";
import { getItemByCode } from "@/lib/catalog"; // lato server, chiave di lettura

export async function POST(req: Request) {
  const { lines } = await req.json();                // [{ code, quantity }] — nessun prezzo dal client
  const line_items = await Promise.all(
    lines.map(async ({ code, quantity }: { code: string; quantity: number }) => {
      const item = await getItemByCode(code);          // il server risolve dal CMS
      return { price: item!.stripe_price_id, quantity }; // prezzo dal CMS, mai dal 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 });     // il client reindirizza qui
}

src/app/api/stripe/webhook/route.ts — il segnale affidabile per il fulfillment:

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

export async function POST(req: Request) {
  const body = await req.text();                      // corpo RAW — necessario per verificare 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 l'ordine / invia una ricevuta.
  }
  return new Response(null, { status: 200 });
}

Fix necessario dello scaffold: src/proxy.ts nello scaffold inoltra ogni /api/* al CMS, quindi le tue route Stripe non girano mai. Lasciale passare per prime:

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();                       // gestisci localmente
  }
  return cmsProxy(request as unknown as Parameters<typeof cmsProxy>[0]);
};
// lascia invariato lo `export const config = { matcher: [...] }` dello scaffold

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

Esegui Stripe CLI per i webhook locali:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# copia il whsec_... in STRIPE_WEBHOOK_SECRET, riavvia bun dev

Il whsec_… è per sessione. Due regole tutelano la sicurezza: il checkout ricalcola il prezzo dal CMS tramite code (un carrello manomesso non può cambiarlo) e il webhook verifica la firma sul corpo raw.

5. Crea le route

Admin → Pages → Create page, tre volte. Mappa ogni parametro al suo componente (campo slug code):

  1. /products/{item_code} → item
  2. /categories/{category_code} → category
  3. /cart — una pagina statica (inserisci letteralmente /cart, non /{cart})

6. Aggiungi gli elementi UI, collega CEL, pubblica

Per ogni route: Page Builder → Add UI Element → Custom → aggiungi i componenti in ordine, compila i campi scalari (valore statico o CEL), Publish.

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

Imposta nav.brand e footer.text come stringhe statiche; le intestazioni come etichette statiche.

Il Page Builder sulla route category — l'elemento product_grid selezionato, il suo heading collegato con CEL.

Il Page Builder sulla route product — l'elemento product_detail su un binding di prodotto.

Gotcha del Page Builder parametrico: sulle due route parametriche, aggiungere elementi UI non persiste (i blocchi restano orfani e la pagina renderizza vuota). Finché non viene risolto, collega i block_ids di quelle pagine direttamente via il Profound MCP update_page, poi pubblica. (La /cart statica si collega normalmente.) Per lo stesso motivo, ProductGrid ricava la sua heading dalla categoria che recupera anziché tramite CEL.

7. Visualizza e compra

  • /categories/lighting → la griglia. Clicca un prodotto → dettaglio + Aggiungi al carrello. /cart → Pay.
  • Il pagamento reindirizza a Stripe-hosted checkout. Usa la carta di test 4242 4242 4242 4242, qualsiasi scadenza/CVC futuro. Torni a /cart?status=success, e stripe listen mostra checkout.session.completed.

Una pagina prodotto renderizzata — gallery, prezzo e Aggiungi al carrello.

Il carrello — line item e un unico pulsante Pay-with-Stripe.

Sono acquistabili solo gli item con prezzo — compra uno dei ~3 che hai prezzato nello step 6.

Opzionale — internazionalizza. Traduci ogni componente (tutte le 35 lingue in una volta), aggiungi un segmento /{language}/… mappato al componente System language integrato, e passa i campi collegati con CEL a documents.translated. Vedi il tutorial dell'aeroporto, Parte 2 step 7.

Parte 3 — Produzione

1. Pubblica: GitHub, poi Vercel

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

Build command: generated/cms-schemas.ts è ignorato da git, quindi blocca la build per rigenerarlo — aggiungi vercel.json:

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

In Vercel: Add New → Project, importa store e aggiungi le variabili d'ambiente — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, NEXT_PUBLIC_BUNNY_CDN_URL, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET (il valore dell'endpoint deployato, sotto), e NEXT_PUBLIC_SITE_URL (il tuo URL di prod). Distribuisci.

Poi collega il webhook in produzione (il secret di stripe listen era solo locale): Stripe → Developers → Webhooks → + Add endpoint → https://<prod>/api/stripe/webhook, evento checkout.session.completed. Copia il whsec_… in Vercel e ridistribuisci.

Variabili d'ambiente mancanti = "funziona in locale, vuoto in prod" — la gotcha #1 del deploy. Distribuiamo con chiavi di test qui; passa STRIPE_SECRET_KEY e il secret del webhook ai valori live quando sei pronto a ricevere pagamenti reali.

2. Anteprima live e editing in-page

Entrambi sono inclusi nello scaffold.

  • Anteprima live: il <Refresher> aggiorna la pagina che stai visualizzando in anteprima quando un editor salva nell'admin — nessuna ridistribuzione. (È un'anteprima per l'editor; i visitatori vedono i contenuti pubblicati sulla normale revalidazione.)
  • Editing in-page: aggiungi ?edit_mode=true a qualsiasi URL per gli overlay di editing. I visitatori pubblici vedono la pagina pulita.

Aggiungi la route di anteprima che lo scaffold omette. L'admin carica il suo iframe di anteprima su /cms-preview_<path>; senza quella route ogni anteprima restituisce 404. Aggiungila:

// src/app/cms-preview_/[...slug]/page.tsx
import { ParametricRoutePreviewPage } from "cms-renderer/lib/renderer";
import { registry } from "../../registry";   // estrai il tuo registry in un modulo condiviso
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
  const PreviewPage = ParametricRoutePreviewPage as any; // async RSC; tipi 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} />;
}

Aggiungi anche src/app/cms-preview_/page.tsx (stesso codice, slug: []) per la root del segmento.

Ecco la build

Uno storefront Stripe guidato dai contenuti: un catalogo nel CMS, pagine di elenco + dettaglio da un unico set di route e un checkout ospitato funzionante. L'AI ha caricato il catalogo, collegato il design e scritto il lettore del catalogo + i componenti + il carrello headless; tu hai gestito i componenti, i collegamenti dei prezzi Stripe, le tre route, il chrome CEL e tre brevi file Stripe. CEL collega il chrome; i componenti recuperano il catalogo. E Stripe è rimasto leggero — una chiamata sessions.create e un webhook firmato, con l'acquirente che paga sulla pagina di Stripe.

Continue Reading
Previous‹Deployments