Проект: магазин с оплатой
Главное отличие сильного портфолио — «взрослость»: не статичный лендинг, а продукт с реальными деньгами. Принимаем платежи через Stripe/ЮKassa и понимаем, откуда приходит подтверждение.
Как устроены платежи
Ваш сервер не видит и не хранит карту. Клиент её вводит на странице провайдера; провайдер возвращает код успеха/платёж другой стороне, а ваш бэкенд получает результат по webhook — сервер считает заказ оплаченным.
// Сервер: создать платёж и вернуть клиенту ссылку/сессию
const session = await stripe.checkout.sessions.create({
mode: "payment",
line_items: [{ price: product.priceId, quantity: 1 }],
success_url: "https://myshop.ru/success"
});
res.json({ url: session.url });
Webhook: статусы платежа
app.post("/webhooks/stripe", express.raw({ type: "application/json" }), async (req) => {
const sig = req.headers["stripe-signature"];
const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
if (event.type === "checkout.session.completed") {
await db.query("UPDATE orders SET paid=TRUE WHERE sid=$1", [event.data.object.id]);
}
res.json({ received: true });
});
💡
Обрабатывайте webhook идемпотентно: уведомления могут дублироваться. «paid=TRUE» повторно — просто строка не изменится, но для переданных сумм считайте «уже было» флагом.
Какие карты для тестов
Провайдер даёт тестовые карты: Stripe — 4242 4242 4242 4242 (любая будущая дата, CVV любые). Реальные деньги не списываются — только «среда sandbox».
ℹ️
Безопасность из урока 61 здесь в прямом смысле: никогда не пишите карту в код, держите ключи в env (урок 62), проверяйте подпись webhook. Это продукт, который (не) ломают — и это видно в резюме.
💡
Уроки пройдены: от тегов HTML до оплат и оркестрации. Теперь портфолио из уроков 10, 18, 19, 34, 36, 71 и 72 — это убедительное «могу под ключ». Вы справились!
Следующая ступень — уроки с 73 по 90: веб-компоненты, системный дизайн, кроссплатформа и новые проекты.