Кейс 1: Многоязычный лендинг + страница платежей
Идея
Подруга продаёт PDF-гид за $29 для экспатов, переезжающих в Корею. Ей нужна была одна страница, которая быстро загружается по всему миру, говорит по-английски, по-корейски и по-китайски и принимает оплату картой без того, чтобы она прикасалась к серверу.
Спецификация
Мы уложили спецификацию в один абзац, прежде чем писать какой-либо код:
Построй одностраничный маркетинговый сайт для цифрового продукта
за $29. Три языка (en/ko/zh), автоопределяемые по браузеру, но
переключаемые тумблером. Одна кнопка «Купить», которая открывает
Stripe Checkout и при успехе перенаправляет на страницу
благодарности. Никакого бэкенд-сервера, который мне придётся
обслуживать. Должен быстро загружаться откуда угодно.
Обратите внимание, чего спецификация не говорит: никакого фреймворка, никакой дизайн-системы, никакой аналитики, никакого сбора email. Каждая из этих вещей была бы разумной фичей, и каждая замедлила бы первый запуск. Дисциплина спецификации в один абзац — это в основном дисциплина того, что оставлено за бортом.
Стек
«Никакого бэкенда, который я обслуживаю» плюс «быстро по всему миру» прямо указывали на статический хостинг на edge-CDN с крошечной serverless-функцией для единственной вещи, которой нужен секрет: создания сессии Stripe. Мы выбрали статический сайт на Cloudflare Pages с единственной Pages Function. Вся архитектура умещается в одно предложение — статическая страница, которая вызывает одну функцию, которая говорит со Stripe, — и именно эта простота сделала её отлаживаемой позже.
Ключевые промпты
Мы начали широко и дали AI предложить структуру:
Набросай статический лендинг (чистый HTML/CSS/JS, без фреймворка)
с переключателем языков для en/ko/zh. Храни тексты в одном
JS-объекте с ключами по языку. Определяй язык по умолчанию из
navigator.language. Уложись в один index.html плюс один main.js.
Затем платёжный путь, где живёт секрет:
Добавь Cloudflare Pages Function по адресу /api/checkout, которая
создаёт сессию Stripe Checkout для одного продукта за $29 и
возвращает URL для редиректа. Читай STRIPE_SECRET_KEY из окружения,
никогда не хардкодь его. Кнопка «Купить» должна делать POST к этой
функции, а затем window.location на возвращённый URL.
Фраза «никогда не хардкодь его» заслуживает своего места. Предоставленный своим умолчаниям, AI с радостью впишет плейсхолдер-ключ прямо в код, чтобы пример «работал», а плейсхолдер имеет свойство превращаться в настоящий ключ, который уходит в прод. Сказать это вслух один раз в промпте дешевле, чем ловить на ревью.
Препятствие
Первый живой тест провалился: кнопка «Купить» ничего не делала, а консоль браузера показывала ошибку CORS. Мы не гадали. Мы вставили точную ошибку обратно:
Клик по «Купить» логирует: "Access to fetch at '/api/checkout'
blocked by CORS policy." Функция и страница на одном домене.
Вот код функции: [вставлено]. Что на самом деле не так?
AI заметил это мгновенно: функция возвращала URL Stripe как JSON, но запрос fetch делался раньше, чем обрабатывался preflight-запрос OPTIONS функции, потому что мы по ошибке задеплоили статическую страницу и функцию в два разных проекта Pages. Настоящим исправлением была топология деплоя, а не код. Мы перенесли функцию в директорию /functions того же проекта, и ошибка исчезла.
На этом уроке стоит задержаться: симптом был в коде (ошибка CORS из fetch), но причина была в инфраструктуре (два проекта вместо одного). Если бы мы дали AI «исправить ошибку CORS», не вставив конфигурацию, он привинтил бы заголовки Access-Control-Allow-Origin — исправление, которое компилируется, замазывает симптом и оставляет настоящий баг живым. Вставляйте дословную ошибку вместе с окружающим контекстом и не принимайте первое правдоподобное объяснение, если оно не соответствует вашей конфигурации.
Запуск
Мы добавили боевые ключи Stripe как зашифрованные переменные окружения в панели Pages (никогда в репозиторий), направили DNS её домена на Pages и провели одну реальную тестовую покупку на $29 картой, а затем сделали возврат. Мы также намеренно прошли по пути ошибки — отклонённой тестовой картой, — чтобы убедиться, что с неё не списали деньги и она увидела вменяемое сообщение, а не пустой экран. Вживую за полдня. Свою первую продажу она совершила тем же вечером.