⚡️ LEGENDARY TOXIC CODE ONLY // AI DEEP TUNING // GAMEDEV NEURAL CORES // NO CHAT JUST DEV // bobbyjones HIGH PERFORMANCE // ⚡️ ⚡️ LEGENDARY TOXIC CODE ONLY // AI DEEP TUNING // GAMEDEV NEURAL CORES // NO CHAT JUST DEV // bobbyjones HIGH PERFORMANCE // ⚡️

Основы работы в моем понимании

1. Выбор шлюза и подход Шлюзы условно делятся на: Агрегаторы: Stripe, ЮKassa, CloudPayments, Paddle — берут на себя PCI DSS, дают SDK, вебхуки, рефанды. Прямые эквайринги (Тинькофф, Сбер, Альфа) — больше контроля, но больше ручной работы. Правило простое: не трогай карточные данные руками. Пусть шлюз держит форму оплаты или хостед-страницу, а ты держи только токены/идентификаторы. Иначе ты в PCI DSS, а это не про джуна. 2. SDK vs сырой HTTP SDK — быстро, но тянет за собой зависимости и часто ломает совместимость между мажорами. Сырой HTTP — контроль, но больше кода. Если SDK нормальный (Stripe, ЮKassa) — бери его. Если это «SDK на 40 зависимостей ради одного POST» — бей fetch руками: js const res = await fetch('https://api.provider.com/v1/payments', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.PROVIDER_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': orderId, }, body: JSON.stringify({ amount, currency: 'RUB', order_id: orderId }), }); if (!res.ok) throw new Error(`Payment failed: ${res.status}`); const payment = await res.json(); Ключи — только из process.env, никогда в коде и не в git. Ротация ключей — часть прода. 3. Идемпотентность — святой грааль Самая частая боль: клиент дважды нажал «Оплатить» или сеть дёрнулась на ретрае — и списание двойное. Правила: Генеришь idempotency_key на клиенте или на бэке, привязанный к order_id. Шлёшь его в шлюз, шлюз сам отсекает дубли. На своей стороне — уникальный индекс в БД по order_id + provider_payment_id. js // простая защита: одна попытка оплаты на заказ const existing = await db.payments.findByOrderId(orderId); if (existing) return res.json(existing); Без идемпотентности ты не в проде, ты в аду. 4. Создание платежа: нормальный флоу Типичный сценарий: Бэк создаёт заказ (status: 'pending'). Бэк дёргает шлюз → получает payment_url или client_secret. Отдаёт клиенту URL, клиент платит на стороне шлюза. Шлюз дёргает твой вебхук. Бэк проверяет подпись, обновляет статус заказа. Если нужен редирект — отдельный эндпоинт успеха/ошибки, но статус — только по вебхуку. Никогда не доверяй «success_url» — это просто редирект, а не подтверждение оплаты. 5. Вебхуки: сердце интеграции Вебхук — единственный надёжный источник правды об оплате. Обрабатывай его аккуратно. js app.post('/webhooks/payment', express.raw({ type: 'application/json' }), async (req, res) => { const signature = req.headers['x-signature']; const isValid = verifySignature(req.body, signature, process.env.WEBHOOK_SECRET); if (!isValid) return res.status(400).end(); const event = JSON.parse(req.body); // идемпотентность по event.id if (await db.events.exists(event.id)) return res.status(200).end(); await db.events.insert({ id: event.id }); switch (event.type) { case 'payment.succeeded': await db.orders.update(event.data.order_id, { status: 'paid' }); break; case 'payment.canceled': await db.orders.update(event.data.order_id, { status: 'canceled' }); break; } res.status(200).end(); }); Важные моменты: Сырое тело (raw) — подпись считается по байтам, а не по распарсенному JSON. Проверка подписи — иначе тебе могут прислать фейковый «оплачено». Идемпотентность по event.id — шлюз может слать повторно. Отвечай 200 быстро — иначе шлюз будет ретраить. Тяжёлую логику — в очередь. 6. Подпись вебхука: как не словить уязвимость Простой HMAC: js const crypto = require('crypto'); function verifySignature(rawBody, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); } timingSafeEqual — обязательно. Обычное === сравнивает за разное время и утекает байты. Звучит параноидально, но так и есть. 7. Возвраты, рефанды и частичные Все рефанды делай через API шлюза, не «просто поменяй статус в БД». Храни provider_payment_id — без него рефанд не сделать. Частичный рефанд — проверяй, что не превысил сумму и количество. Веди отдельную таблицу refunds, а не флаг в orders. 8. Логи и мониторинг Платёжка — это место, где логи спасают жизни. Но: Не логируй карточные данные, CVV, полные токены — никогда. Логируй order_id, payment_id, event_type, статусы — этого хватит. Алерты на: рост failed payments, зависшие pending дольше N минут, ошибки вебхука. 9. Окружения и тесты Sandbox-режим у шлюза — обязателен. Тестовые карты — в открытом доступе. Тесты: успешный платёж; отказ шлюза; повторный вебхук; неверная подпись; таймаут шлюза. Не в проде с реальными картами — никогда. Даже «просто проверить». 10. Безопасность: чек-лист Секреты — в env / Vault / Secret Manager, не в git. HTTPS только. HTTP-вебхук — мусор. Проверка подписи вебхуков — всегда. Идемпотентность по order_id и event.id. Рейт-лимит на эндпоинт создания платежа (защита от брута). Whitelist IP шлюза для вебхука — если шлюз даёт список, добавь. Логи без PII и без карточных данных. Ротация ключей — по расписанию, а не «когда скомпрометировали».