profound-logoProfound CMS
⌘K
Admin
Theme
DocsTutorialBlogPhilosophy
DocsTutorialBlogPhilosophy

Tutorials

Build & Ship an Airport DirectoryDeploymentsвитрина на Stripe

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

витрина на Stripe

Практически наръчник: изградете витрина на Stripe, управлявана от съдържание, върху Profound CMS — каталог, който търговецът редактира без код, два параметрични маршрута, headless количка и финализиране на покупката, хоствано от Stripe.

Готовият магазин в действие — разгледайте категория, отворете продукт, добавете в количката, финализирайте покупката.

Практически наръчник, който изгражда магазин, ориентиран към съдържанието, върху Profound CMS: каталог с продукти (категории + артикули), моделирани в CMS, страници за списъци и детайли от един набор маршрути, и финализиране на покупките, хоствано от Stripe, доставено като headless компонент.

Основата е ръчно написан Next.js плюс администраторският панел на Profound. Claude Code (чрез Profound MCP) върши тежката работа по три задачи — пълни каталога, свързва дизайн системата и пише компонентите на витрината (включително headless количката). Три части: Настройка, Изграждане, Продукция.

Плащания в един ред. Използваме финализиране на покупка, хоствано от Stripe: клиентът плаща на страницата на Stripe, не на вашата. Вашето приложение прави само две сървърни действия — създава сесия за финализиране на покупката и проверява един webhook. Няма полета за карта, няма Stripe Elements, няма тежест за PCI.

Какво ще построите

  • Малък публикуван каталог в CMS — три категории и осем продукта (демото „Изобретенията на Едисон“) — всеки може да се редактира от търговец без код.
  • Два параметрични маршрута (/products/{item_code}, /categories/{category_code}) плюс статичен /cart, всички от един набор компоненти.
  • Headless количка (useCart) и финализиране на покупка, хоствано от Stripe, като цената винаги се изчислява на сървъра от Stripe Price ID.
  • Магазинът, разположен на Vercel с жив преглед и редактиране на място за екипа.

Предпоставки

  • Bun ≥ 1.3 — curl -fsSL https://bun.sh/install | bash
  • Claude Code с Profound MCP (част 1 го инсталира).
  • Акаунт в Profound CMS.
  • Акаунт в Stripe. Това ръководство работи в тестов режим, така че нищо няма да начислява реални средства, докато изграждате — но потокът е идентичен с живите ключове, така че използвайте ключовете на реалния си акаунт, ако предпочитате. (Тестовият режим не изисква бизнес или банкови детайли.)
  • Stripe CLI (stripe login) за локални уебхукове.
  • За внедряване: GitHub CLI (gh) и акаунт във Vercel, свързан с GitHub.

Как се вписват частите

Profound разделя съдържанието от рендерирането:

  • Компонентите дефинират формата на съдържанието. Потребителски компонент с поле Route Slug може да се маршрутизира (category, item); такъв, маркиран като UI Element, може да се постави на страница (nav, product_grid, …).
  • Документите са самото съдържание (продукт, категория).
  • UI елементите са секции на страницата; всяко скаларно поле приема статична стойност или CEL израз, оценяван при рендера.
  • Параметричните маршрути свързват URL с документ + UI елементи, предавайки параметрите на маршрута (meta.params.* в CEL, routeParams в React).
  • Вашето Next.js приложение го чете чрез cms-renderer; Stripe се добавя като обикновени API маршрути.

Единственото правило, което оформя изграждането: CEL свързва само string/number полета. Така че скаларният хром (надпис на навигацията, футър, заглавия) се свързва с CEL, докато всичко богато или колекция (мрежа от продукти, галерия от изображения, богато форматиран текст) се зарежда вътре в React компонента по параметър на маршрута. И Stripe е източникът на истина за ценообразуването — price в CMS е само за показване; начислената сума винаги се изчислява на сървъра от Stripe Price ID.

Част 1 — Настройка

Краен резултат: малък публикуван каталог, приложението свързано да го чете, Stripe инсталиран, дизайн поставен — още нищо не се рендерира.

1. Регистрация и създаване на сайта

Регистрирайте се в Profound (WorkOS удостоверяване). Създайте сайт с име store, след това копирайте неговото ID на сайта (UUID в URL адреса на администрацията) и API ключ от ниво read (Deployments → Create API key). Приложението само чете; по-късната сеитба на каталога минава през MCP, който се удостоверява отделно.

2. Създаване на скелета на приложението, свързване и добавяне на Stripe

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

Скелетът е проект на Next.js App Router, предварително свързан за Profound (cms-renderer SDK, route catch-all, скрипт generate-schemas, <Refresher>). Не доставя стилове. bun add stripe добавя сървърния SDK — единствената зависимост за плащания, нужна за хостваното финализиране.

Добавете стойностите си в .env.local:

# CMS
PROFOUND_API_KEY=<вашият read ключ>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<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_...          # попълва се в стъпка 4 от Изграждане
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Вземете STRIPE_SECRET_KEY от Stripe → Developers → API keys. Използваме тестов ключ (sk_test_…), така че изграждането да не движи реални средства; сменете с живия, когато сте готови да приемате реални плащания. Стартирайте bun dev и отворете localhost:3000 — стартерът се визуализира.

Хостваното финализиране пренасочва браузъра към URL на Stripe, така че сървърният таен ключ е всичко, което Stripe изисква — няма публикуем ключ, няма клиентски Stripe SDK.

3. Дефинирайте компонентите category, product_image и item

Създайте три Custom Components (Components → Create new component) — източникът на данни, затова без етикет UI Element. Задайте всеки като Active.

CMS няма поле „масив от изображение“, затова галерията е масив от препратки към малък компонент product_image. Създайте category и product_image (и ги задайте като Active) преди item — поле за препратка може да сочи само към 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)

Оставете всички полета незадължителни. Администраторът преобразува имената на полетата в lower-snake-case („Stripe Price Id“ → stripe_price_id) — на това ще разчитате в кода, така че прочетете реалните имена чрез generate-schemas по-долу. Наричаме маршрутизируемия дескриптор code (не slug): това е Route Slug и ключът за чисто извличане чрез documents.getByCode по-късно.

Компонентът item — code като Route Slug, images като препратки към product_image, плюс 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 — три категории и тези продукти, със съкратено описание, точно за периода, 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.

Трите насети категории, публикувани и Live.

Осемте насети продукта, всеки свързан с категория.

6. Създайте Stripe цени и свържете няколко продукта

Каталогът е в CMS; сега дайте реална Stripe цена на няколко продукта — работа на търговеца, изпълнявана в две администраторски панели, без код:

  1. Stripe Dashboard → Products → + Add product, задайте еднократна цена, копирайте Price ID (price_…).
  2. Направете това за около 3 водещи продукта (напр. Lightbulb, Phonograph, Kinetoscope).
  3. Администратор на Profound → item → Documents → поставете всеки Price ID в stripePriceId, запазете.

CMS държи каталога; Stripe държи цената; връзката е един низ, който търговецът поставя. (Предпочитате да автоматизирате? Официалният Stripe MCP може да създаде Products/Prices вместо вас — поставете върнатите ID по същия начин.)

7. Добавете дизайн система и я свържете с AI

Скелетът идва без стил. Поставете DESIGN.md (Tailwind v4 @theme блок + токени) в корена на проекта — собствен или изтеглен от refero.design. После подскажете на Claude, ограничен само до стилизиране:

Прочети дизайна, който току-що добавих. Ако трябва — настрои Tailwind, после свържи темата и шрифтовете, за да проработи стилизирането. Използвай next/font за шрифтове — не ги зареждай от Google в runtime. Само стилизирането — не изграждай страници или компоненти.

Уверете се, че src/app/globals.css съдържа @import "tailwindcss"; + @theme блока и че localhost:3000 показва токените. Дръжте подсказката стегната (отворена — агентът може да изгради цяла начална страница) и зареждайте шрифтовете чрез next/font, никога чрез runtime импортиране от Google.

8. Добавете продуктови изображения (по избор)

По избор — може да достигнете работещо финализиране без изображения. За да ги добавите: създайте по един документ product_image за всяко изображение (качете файла в полето image), после свържете тези документи от масива images на продукта. Донесете свои продуктови снимки или генерирайте координиран набор с модел за изображения (накарайте Claude да изведе прецизни за марката подсказки от DESIGN.md и заключете един Midjourney --sref, за да съответства всяко изображение).

Самостоятелният cms-renderer няма помощник за URL на изображение, затова добавете buildAssetUrl в src/lib/image.ts (~40 реда) — той добавя префикс NEXT_PUBLIC_BUNNY_CDN_URL и разширението. Компонентите в стъпка 3 от Изграждане го използват.

Част 2 — Изграждане

Изградете слоя за рендериране и финализирането на покупката, завършвайки с реална покупка в тестов режим.

1. Дефинирайте петте компонента UI element

Пет компонента, всеки Active и маркиран с UI Element (Settings → Tags), без Route Slug:

  • nav → brand · product_grid → heading · product_detail → heading · cart_summary → heading · footer → text (всички Text)

Етикетът UI Element прави компонента видим в списъка Add UI Element в Page Builder — Active само по себе си не е достатъчно. Всяко поле е скаларно (тип, който CEL свързва); реалните данни за каталога не са поле тук — ProductGrid/ProductDetail ги извличат по параметър на маршрута (стъпка 3).

2. Генерирайте типовете отново

bun run generate-schemas

3. Генерирайте четеца на каталога, компонентите и headless количката

Един prompt изгражда помощника за четене, петте компонента, количката и регистъра:

Построй нашата витрина в src/, използвайки SDK cms-renderer на Profound.

src/lib/catalog.ts — сървърен четец на CMS. Създай клиент с getCmsClient({ cmsUrl: process.env.NEXT_PUBLIC_CMS_API_URL!, apiKey: process.env.PROFOUND_API_KEY, websiteId: process.env.NEXT_PUBLIC_PROFOUND_WEBSITE_ID! }) от cms-renderer/lib/cms-api. Експортирай 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._ref съвпада с document.id на категорията. Експортирай resolveImages(refs), който разрешава всяка препратка от item.images чрез cms.documents.get.query({ websiteId, id: ref._ref }) и превръща полето image в URL с въведената buildAssetUrl (част 1, стъпка 8).

src/components/ — пет UI елемент компонента, регистрирани в регистъра на catch-all маршрута по име на компонента, snake_case, за да съвпада с администратора: { nav, product_grid, product_detail, cart_summary, footer }. Nav и Footer четат своето скаларно поле от пропса content (тип BlockComponentProps<T> от cms-renderer/lib/types). ProductGrid и ProductDetail са асинхронни сървърни компоненти, които четат routeParams и извличат данни от catalog.ts: routeParams.<param> е { value, … } — чети .value, така че ProductGrid извиква listItems(routeParams.category_code?.value) (картичките водят към /products/{code}), а ProductDetail извиква getItemByCode(routeParams.item_code?.value) (галерия чрез resolveImages, богат текст за описанието, цена, бутон Add-to-cart). CartSummary визуализира количката от useCart с бутон „Плати“. Дръж formatPrice в чист файл src/lib/format.ts, за да не импортират клиентските компоненти сървърния catalog.ts.

src/components/AddToCartButton.tsx — "use client" бутон, приемащ { code, name, priceLabel } и извикващ useCart().addItem({ code, name, priceLabel, quantity: 1 }). Използвай го в ProductDetail.

src/lib/useCart.ts — headless количка: редове { code, name, priceLabel, quantity } в състояние, запазвани в localStorage, предоставя addItem/removeItem/updateQty/subtotal и checkout(), който изпраща POST { lines: [{ code, quantity }] } (само кодове и количества — никога цени) към /api/stripe/checkout, след което пренасочва към върнатия url.

Стилизирай всичко с нашата дизайн система, като наши собствени компоненти — не копирай оформлението на изходния сайт.

Три неща, които трябва да знаете след изпълнението:

  • Скаларният хром идва чрез content ({ content }: BlockComponentProps<T>) — деструктурирайте полетата като пропсове на най-горно ниво и блокът ще остане празен. Данните за каталога идват от routeParams + извличане в catalog.ts, защото CEL не може да свързва списъци или галерии. Количката носи кодове на артикули, никога цени.
  • routeParams.<param> е { value, schemaName, document } — чете се .value. Четенето връща published_content, не .content. Ключовете в регистъра са snake_case, за да съвпадат с администратора.
  • Повишете @types/react/@types/react-dom до v19 — скелетът идва с v18, което чупи асинхронни сървърни компоненти срещу React 19.

4. Напишете сървърния код на Stripe (гръбнака)

Три кратки сървърни файла — единственият платежен код в приложението. Те използват 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"; // сървърно, read-tier ключ

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();                      // Сурово тяло — необходимо за проверка на подписа
  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.

Стартирайте Stripe CLI за локални уебхукове:

stripe login
stripe listen --forward-to localhost:3000/api/stripe/webhook
# копирайте whsec_... в STRIPE_WEBHOOK_SECRET, рестартирайте bun dev

whsec_… е за всяка сесия. Две правила осигуряват сигурността: финализирането преразчита цената от CMS чрез code (манипулирана количка не може да я промени) и webhook-ът проверява подписа срещу суровото тяло.

5. Създайте маршрутите

Администратор → Pages → Create page, три пъти. Свържете всеки параметър с неговия компонент (поле за слъг 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: на двата параметрични маршрута добавянето на UI елементи не се запазва (блоковете остават без връзка и страницата се рендерира празна). Докато това се поправи, свържете block_ids на тези страници директно чрез Profound MCP update_page, после публикувайте. (Статичният /cart се присъединява нормално.) По същата причина ProductGrid извлича заглавието си от категорията, която зарежда, вместо чрез CEL.

7. Визуализирайте и купете

  • /categories/lighting → мрежата. Щракнете върху продукт → детайли + Add to cart. /cart → Плати.
  • Плащането пренасочва към финализиране на покупка, хоствано от Stripe. Използвайте тестовата карта 4242 4242 4242 4242, всяка бъдеща дата на валидност/код. Връщате се към /cart?status=success, а stripe listen показва checkout.session.completed.

Визуализирана продуктова страница — галерия, цена и бутон Add to cart.

Количката — редове и един бутон „Плати със Stripe“.

Само продукти с цена могат да се купуват — купете един от ~3-те, които сте оценили в стъпка 6.

По избор — интернационализирайте. Преведете всеки компонент (всички 35 езика наведнъж), добавете сегмент /{language}/…, картографиран към вградения системен компонент language, и превключете CEL-свързаните полета към documents.translated. Вижте урока за директорията на летището, част 2, стъпка 7.

Част 3 — Продукция

1. Изпратете го: GitHub, после Vercel

git init && git add -A && git commit -m "Stripe storefront"
gh repo create store --private --source=. --push   # --public също е възможно

Команда за build: generated/cms-schemas.ts е игнориран от git, така че фиксирайте build-а да го регенерира — добавете 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 и внедрете отново.

Липсващи променливи на средата = „работи локално, празно в прод“ — номер 1 сред проблемите при внедряване. Тук внедряваме с тестови ключове; сменете STRIPE_SECRET_KEY и тайния ключ за webhook с живи стойности, когато сте готови да приемате реални плащания.

2. Жив преглед и редактиране на място

И двете идват със скелета.

  • Жив преглед: <Refresher> обновява страницата, която редакторът преглежда, когато запази в администратора — без повторно внедряване. (Това е преглед за редактора; посетителите виждат публикуваното съдържание при нормална ревалидация.)
  • Редактиране на място: добавете ?edit_mode=true към всеки URL за редакторски наслагвания. Обикновените посетители виждат чистата страница.

Добавете маршрута за преглед, който скелетът пропуска. Администраторът зарежда iframe за преглед на /cms-preview_<path>; без този маршрут всеки преглед ще е 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; // async 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 каталог, страници за списъци + детайли от един набор маршрути и работещо хоствано финализиране на покупката. AI насее каталога, свърже дизайна и напише четеца на каталога + компонентите + headless количката; вие изграждате компонентите, връзките към цените в Stripe, трите маршрута, CEL хромирането и трите кратки Stripe файла. CEL свързва хрома; компонентите извличат каталога. И Stripe остана малък — едно извикване sessions.create и един подписан webhook, като клиентът плаща на страницата на Stripe.

Continue Reading
Previous‹Deployments