Создание интернет-магазина

Почему корзина «теряет» товары: сессия против JWT
Самая частая жалоба новичков — товар пропадает после перехода на другую страницу. Причина не в баге, а в архитектуре хранения данных. В большинстве курсов учат хранить корзину в сессии — это удобно для демо, но в production даёт сбои при параллельных запросах и серверном кешировании. В интернет-магазине каждый запрос может сбросить сессию, если не конфигурирован sticky session или Redis.
Правильное решение — хранить состав корзины на клиенте (localStorage или IndexedDB) и дублировать его в базу через асинхронный API. JWT-токен для аутентификации — единственный надёжный способ сохранить состояние между устройствами. Не используйте session-based auth для корзины: при истечении времени клиент теряет заказ.
- Переводите управление корзиной на клиентскую сторону (single-page application).
- Синхронизируйте корзину с сервером только при оформлении заказа или авторизации.
- Для постоянных пользователей храните корзину в отдельной таблице с внешним ключом на user_id.
Ценообразование: как не потерять деньги из-за округления
Ошибка в одну копейку при большом заказе превращается в десятки тысяч рублей убытка. Проблема — использование float для цен. В 2026 году Python по умолчанию оперирует float64 — при накоплении скидок, налогов и доставки погрешность становится системной. Всегда используйте Decimal (decimal.Decimal) с фиксированной точностью в 2 знака после запятой.
Профессионалы добавляют третий знак для внутренних расчётов — налоги часто считаются до тысячных долей, а округление происходит только на этапе оплаты. Фиксируйте цену каждого товара в момент добавления в корзину: если цена меняется между визитами, клиент видит старую стоимость. Это устраняет юридические споры.
- Используйте Decimal(‘0.01’) для всех арифметических операций с ценой.
- Храните историю изменения цены для каждого товара — это обязательное требование ФНС при возвратах.
- При расчёте корзины применяйте целочисленное представление (копейки) — самые быстрые и точные SQL-запросы.
Как грамотно организовать фильтрацию товаров
Фильтрация через WHERE по каждому параметру (цена, бренд, размер) приводит к «тормозам» при 10 000+ товаров. Проблема не в SQL, а в индексах. Новички создают индекс на price, но запрос с AND по трём полям заставляет базу сканировать миллионы записей. Решение — составной индекс (price, brand, size) строго в том порядке, в каком идут условия фильтра.
Продвинутый приём — материализованные представления для популярных категорий. Раз в 10 минут пересчитываете витрину для категории «Электроника» — запрос к ней выполняется за <10 мс вместо 500 мс. Это особенно критично для сортировки по популярности, где нужен JOIN с таблицей заказов. В 2026 году MySQL 8.4 и PostgreSQL 16 поддерживают instant-пересчёт MV через CREATE MATERIALIZED VIEW.
- Создайте индекс с покрытием для типовых фильтров (цена + размер + цвет).
- Используйте расширенное кеширование Redis для результатов фильтрации с TTL 60 секунд.
- Для атрибутов с малым количеством значений (пол, сезон) применяйте битовые маски в JSON-поле.
Платежные шлюзы: три уязвимости, о которых молчат курсы
Первая — повторная отправка запроса на списание при закрытии браузера. Клиент нажал «Оплатить», страница не перезагрузилась — бэкенд получил два POST-запроса. Без идемпотентности снимется двойная сумма. Решение — UUID транзакции на стороне сервера, который проверяется перед любым списанием.
Вторая — хранение «сырых» ответов от платёжного шлюза прямо в таблице заказов. Злоумышленник, получив доступ к БД, восстанавливает данные карты. Храните только last4 digits и статус — всё остальное удаляется после подтверждения. Третья — отсутствие проверки подписи callback-уведомлений. Хэш вычисляйте из всех полей, включая сумму и ID магазина, а не только из статуса. Не доверяйте IP-адресу отправителя.
- Генерируйте идемпотентный ключ (uuid4) для каждой транзакции до вызова API шлюза.
- При ошибке шлюза делайте не более 3 автоматических повторов с экспоненциальной задержкой.
- В callback-обработчике отключайте тайм-аут запроса — некоторые шлюзы ждут ответа до 30 секунд.
Защита от ботов при заказе: невидимые ловушки
Standalone капча в форме оформления снижает конверсию на 12-15%, а агрессивные боты её обходят сервисами распознавания. Профессиональный подход — «тихие» проверки: время заполнения формы (менее 2 секунд — бот), наличие скрытого поля honeypot, которое не видит человек, но заполняет скрипт. Добавьте check на количество запросов с одного IP за минуту — больше 5 — блокировка на 10 минут без уведомления.
Для интернет-магазина с самовывозом обязательна проверка номера телефона через одноразовый код (SMS/звонок) — это отсекает 80% «левых» заказов. Храните историю IP-адресов для анализа типового поведения: если один аккаунт делает 50 заказов в час — это бот для накрутки рейтинга.
В 2026 году есть готовые решения вроде Turnstile от Cloudflare, но самописная защита даёт больше контроля и не тарифицируется за количество запросов. Интегрируйте минимальную задержку перед отправкой формы (js-setTimeout 3000 ms) — многие боты не ждут.
Обработка заказов без потерь: очереди вместо прямых вызовов
Если при оформлении заказа бэкенд вызывает SMS-шлюз, почтовый сервис и складской API последовательно — время ответа сервера превышает 10 секунд. При возврате клиентом браузера заказ повиснет в статусе «создан», хотя товары уже списаны. Единственно верная схема — асинхронная очередь (Celery, RabbitMQ, или даже простой Beanstalkd).
Ставьте статус «в обработке» мгновенно, а остальные шаги выполняйте в фоне. В случае падения очереди используйте retry policy с backoff (1-5-15 минут). Профессионалы отделяют критичные задачи (списание товара) от необязательных (отправка email), и для последних делают TTL 1 час — если не отправилось, заказ всё равно подтверждён.
- Выносите отправку уведомлений, генерацию PDF-чека и интеграцию со складом в фоновые задачи.
- Каждой задаче присваивайте expiration (soft deadline) — отменяйте её, если заказ уже отменён.
- Мониторьте глубину очереди: если >1000 задач — немедленно увеличивайте количество воркеров.
Добавлено: 23.04.2026
