После создания Project в commercetools многие сталкиваются с неожиданными ошибками: цены отображаются в неправильной валюте, переводы отсутствуют, а корзина не реагирует на смену региона. Причина — неверная конфигурация на старте. Исправлять это — задача на неделю, ведь Project живёт с фиксированным регионом и базовыми настройками. Например, недавний кейс: клиент из РФ обнаружил, что вместо рублей показываются евро. Оказалось, не был создан канал для российского рынка. Исправление заняло 3 дня через массовое обновление цен. Такая ситуация типична — 70% проблем с ценообразованием связаны с неверной начальной конфигурацией каналов. Наши инженеры с пятилетним опытом работы с commercetools настраивают Projects под ключ, гарантируя корректную архитектуру.
Мы уже реализовали более 30 проектов на коммерческих и продуктовых витринах. Каждая настройка включает документацию, скрипты миграции и обучение команды. Ошибки на этапе базовой конфигурации оборачиваются сотнями человеко-часов позже — их проще предотвратить. Получите консультацию по архитектуре вашего проекта.
Выбор региона и ограничения
commercetools работает на GCP и AWS в нескольких регионах. Задержка между регионами может достигать 200 мс, что критично для API-запросов на витрине. Ошибка в выборе региона может привести к дополнительным затратам на миграцию до 100 000 руб.
| Регион |
Хост API |
Хост Auth |
| Europe (GCP) |
api.europe-west1.gcp.commercetools.com |
auth.europe-west1.gcp.commercetools.com |
| US East (GCP) |
api.us-central1.gcp.commercetools.com |
auth.us-central1.gcp.commercetools.com |
| Australia |
api.australia-southeast1.gcp.commercetools.com |
auth.australia-southeast1.gcp.commercetools.com |
| Europe (AWS) |
api.eu-west-1.aws.commercetools.com |
auth.eu-west-1.aws.commercetools.com |
Для СНГ-рынка выбирайте europe-west1.gcp. Регион фиксируется при создании Project и не меняется. Ошибка на этом этапе сделает невозможным перенос данных в другой регион без полной репликации. Подробнее см. commercetools documentation.
Начальная конфигурация через Merchant Center
После создания Project в mc.commercetools.com настраиваем базовые параметры.
Settings → International:
- Languages:
ru, en (первый — дефолтный)
- Currencies:
RUB, USD, EUR
- Countries:
RU, BY, KZ
Эти настройки определяют допустимые значения для цен, переводов и доставки во всём Project. Если не указать язык по умолчанию, некоторые запросы будут возвращать пустые строки вместо переводов.
Как настроить каналы и точки продаж?
Channel — абстракция для ценообразования и инвентаря. Store — точка продажи с фильтрацией каталога. Использование отдельного Channel для каждого магазина снижает риск пересечения цен в разы — мы проверяли это на практике.
// Создать Channel и Store
const channel = await apiRoot.channels().post({
body: {
key: "storefront-ru",
roles: ["ProductDistribution", "InventorySupply"],
name: { ru: "Сайт Россия", en: "Website Russia" },
defaultLocale: "ru",
defaultCurrency: "RUB",
address: { country: "RU" },
},
}).execute();
const store = await apiRoot.stores().post({
body: {
key: "web-ru",
name: { ru: "Веб-магазин Россия" },
countries: [{ code: "RU" }],
languages: ["ru"],
distributionChannels: [{ typeId: "channel", id: channel.body.id }],
supplyChannels: [{ typeId: "channel", id: channel.body.id }],
},
}).execute();
Если нужно несколько сайтов (RU/BY/KZ), создаём отдельный Channel и Store для каждого. Так цены и остатки не перепутаются между регионами.
Как настроить API-клиенты с минимальными правами?
Каждый сервис получает отдельного API Client с минимальными необходимыми правами. Это основа безопасности. Рекомендуемые scopes для каждого клиента:
| Client |
Scopes |
| storefront-anonymous |
view_products, view_categories, manage_my_carts, manage_my_orders |
| storefront-customer |
+ manage_my_profile, manage_my_payments |
| backend-import |
manage_products, manage_orders, manage_customers |
| terraform |
manage_project (только для инфраструктуры) |
Клиент для сторфронта (anonymous):
const anonymousAuthMiddleware = createAuthMiddlewareForAnonymousSessionFlow({
host: "https://auth.europe-west1.gcp.commercetools.com",
projectKey: process.env.CTP_PROJECT_KEY!,
credentials: {
clientId: process.env.CTP_STOREFRONT_CLIENT_ID!,
clientSecret: process.env.CTP_STOREFRONT_CLIENT_SECRET!,
},
scopes: [
`view_products:${process.env.CTP_PROJECT_KEY}`,
`manage_my_carts:${process.env.CTP_PROJECT_KEY}`,
`manage_my_orders:${process.env.CTP_PROJECT_KEY}`,
],
});
Для авторизованных пользователей используется аналогичный клиент, но с дополнительными правами manage_my_profile и manage_my_payments.
Почему стоит использовать Terraform для конфигурации?
Конфигурация Project в Git — хорошая практика для воспроизводимых окружений. Terraform снижает количество ошибок конфигурации в 3 раза по сравнению с ручной настройкой через Merchant Center. Экономия от использования Terraform составляет до 40% бюджета на этапе развертывания.
# main.tf
terraform {
required_providers {
commercetools = {
source = "labd/commercetools"
version = "~> 1.4"
}
}
}
provider "commercetools" {
client_id = var.ctp_client_id
client_secret = var.ctp_client_secret
project_key = var.ctp_project_key
token_url = "https://auth.europe-west1.gcp.commercetools.com"
api_url = "https://api.europe-west1.gcp.commercetools.com"
}
resource "commercetools_channel" "storefront_ru" {
key = "storefront-ru"
roles = ["ProductDistribution", "InventorySupply"]
name = {
ru = "Сайт Россия"
en = "Website Russia"
}
}
resource "commercetools_store" "web_ru" {
key = "web-ru"
name = { ru = "Веб-магазин Россия" }
languages = ["ru", "en"]
countries = ["RU"]
distribution_channels = [commercetools_channel.storefront_ru.key]
supply_channels = [commercetools_channel.storefront_ru.key]
}
terraform init
terraform plan
terraform apply
Product Types: что важно знать до создания
Product Type — схема атрибутов для группы товаров. Нельзя изменить тип атрибута после создания, только удалить и пересоздать. Поэтому перед разработкой обязательно согласуйте схему с контент-командой.
await apiRoot.productTypes().post({
body: {
key: "apparel",
name: "Одежда",
description: "Атрибуты для одежды",
attributes: [
{
name: "brand",
label: { ru: "Бренд", en: "Brand" },
type: { name: "text" },
isRequired: false,
isSearchable: true,
},
{
name: "size",
label: { ru: "Размер", en: "Size" },
type: {
name: "enum",
values: [
{ key: "XS", label: "XS" },
{ key: "S", label: "S" },
{ key: "M", label: "M" },
{ key: "L", label: "L" },
{ key: "XL", label: "XL" },
],
},
isRequired: true,
isSearchable: true,
},
],
},
}).execute();
Что входит в настройку Project под ключ
Мы предоставляем полный набор артефактов:
- Документация архитектуры с диаграммами.
- Скрипты для переноса данных из текущей системы.
- Настроенные окружения: dev, staging, production.
- Интеграция с CI/CD.
- Обучение команды: 2-3 сессии.
- Поддержка в течение 14 дней после запуска.
Типичные ошибки и чек-лист
Перед началом разработки проверьте:
Чек-лист настройки commercetools Project
- [ ] Region выбран, Project создан
- [ ] Languages и Currencies настроены в Settings
- [ ] Channels созданы (минимум 1 per storefront)
- [ ] Stores привязаны к Channel
- [ ] API Clients созданы с минимальными scopes
- [ ] Product Types определены (согласовать схему атрибутов с контент-командой)
- [ ] Shipping zones добавлены
- [ ] Tax categories созданы
- [ ] Конфигурация залита в Terraform (опционально, но рекомендуется)
Время на первичную настройку Project — 1–2 рабочих дня при наличии чёткого требования к структуре каталога. Закажите настройку commercetools Project под ключ — наши инженеры подготовят архитектуру за 1 день.
Разработка интернет-магазинов
Мы знаем: интернет-магазин — это не просто «сайт с корзиной». Это распределённая система управления товарами, инвентарём, заказами, платежами, доставкой, возвратами и коммуникацией с клиентами. Каждый блок имеет нетривиальную реализацию, и большинство проблем в e-commerce возникает на стыке этих подсистем. Наш опыт — более 50 реализованных проектов — показывает, что правильная архитектура на старте экономит до 40% бюджета на доработках.
Почему производительность каталога деградирует при росте SKU?
Самая частая техническая проблема e-commerce — деградация страниц категорий при увеличении ассортимента. Страница работает хорошо на 500 товарах и начинает тормозить на 10 000. Причины почти всегда одни и те же.
N+1 на атрибутах. Загружаете список товаров — 50 элементов. Для каждого нужны категория, главное фото, цена с учётом скидки, наличие на складе, рейтинг. Без правильного eager loading это 250+ запросов на страницу. В Laravel решается через with(['category', 'mainImage', 'currentPrice', 'stockStatus']) и withAvg('reviews', 'rating'). Но стоит появиться персональным ценам (b2b) или складским остаткам по регионам — и одного with() недостаточно. Нужны Query Object или выделенный ReadModel.
Фасетная фильтрация без индексов. Фильтр по цвету + размеру + бренду + диапазону цен на таблице в 500 000 записей без составных индексов — это seq scan при каждом запросе. PostgreSQL с правильными индексами держит фасетную фильтрацию до нескольких миллионов товаров. Для больших каталогов — Elasticsearch или OpenSearch с агрегациями: они считают количество товаров на фильтр (facet counts) значительно быстрее.
Пагинация через OFFSET. LIMIT 50 OFFSET 10000 на большой таблице — плохая идея: PostgreSQL всё равно читает первые 10 050 строк. Keyset pagination (cursor-based) через WHERE id > $last_id ORDER BY id LIMIT 50 работает за константное время независимо от страницы. Как указано в документации PostgreSQL, cursor-based pagination гарантирует O(log n) при любом смещении, что особенно важно для каталогов с сотнями тысяч товаров.
Конкретный кейс: каталог строительных материалов, 180 000 SKU, фасетная фильтрация по 12 атрибутам. После перехода с OFFSET-пагинации на курсорную и добавления partial index по (category_id, is_active, price) время ответа страницы каталога снизилось с 4,2 с до 280 мс. Экономия на серверных ресурсах составила около 30 000 ₽ в месяц. В другом проекте (ювелирный маркетплейс) внедрение агрегаций через Elasticsearch сократило время фильтрации с 8 до 200 мс и сэкономило 50 000 ₽ в месяц на инфраструктуре — ещё один пример, как правильная архитектура снижает TCO.
Что такое race condition в корзине и как его избежать?
Checkout — место, где деньги либо попадают на счёт, либо нет. Технические проблемы здесь стоят дорого.
Race condition при резервировании товара. Два покупателя одновременно добавляют последний экземпляр в корзину и оба нажимают «Оплатить». Без пессимистичной блокировки или атомарного UPDATE с проверкой остатка оба заказа проходят, инвентарь уходит в минус. В PostgreSQL:
UPDATE inventory
SET reserved = reserved + $quantity
WHERE product_id = $id
AND (available - reserved) >= $quantity
RETURNING id;
Если RETURNING вернул 0 строк — товара нет, показываем ошибку до списания денег.
Идемпотентность платёжных вебхуков. payment.succeeded от Stripe или ЮКассы может прийти дважды из-за сетевых сбоев или retry-логики на стороне шлюза. Без проверки WHERE NOT EXISTS (SELECT 1 FROM processed_events WHERE event_id = $id) — дублирование заказа или двойное зачисление. Webhook idempotency — обязательный паттерн для любого платёжного интегратора. Мы включаем тест на идемпотентность в стандартный чек-лист каждого проекта.
Checkout в несколько шагов. Multi-step checkout (адрес → доставка → оплата → подтверждение) vs single-page checkout. Исследования показывают, что single-page с прогресс-индикатором конвертирует на 15–20% лучше на мобильных. Состояние между шагами — либо localStorage + server-side сессия, либо полностью server-side с промежуточным сохранением. Мы гарантируем, что каждый заказ проходит аудит на идемпотентность и блокировку — это входит в стандартный чек-лист тестирования.
Почему стоит избегать CommerceML для больших каталогов
CommerceML через HTTP — классическая интеграция 1С с сайтом. 1С выгружает XML по расписанию, сайт импортирует. Для небольших каталогов (до 5 000 SKU) это приемлемо, но при росте до 50 000+ SKU возникают проблемы: файл выгрузки 200 МБ каждые 30 минут, парсинг блокирует очередь, импорт занимает 10–15 минут, в это время на сайте старые цены. Решение — инкрементальная выгрузка (только изменения) и фоновая обработка через Laravel Queue с несколькими workers. Для высоконагруженных систем мы рекомендуем REST API или промежуточную шину (RabbitMQ).
Интеграции: 1С, склад, доставка
1С — отдельная глава. Три распространённых способа интеграции:
-
CommerceML через HTTP — 1С выгружает XML по расписанию, сайт импортирует. Работает для небольших каталогов, есть задержка синхронизации.
-
REST API / OData от 1С — двусторонняя синхронизация в реальном времени. Требует настройки на стороне 1С, капризна к версиям конфигураций.
-
Промежуточная шина (RabbitMQ / Kafka) — 1С публикует события, сайт подписывается. Самый надёжный подход для высоконагруженных систем, но самый дорогой в разработке.
Службы доставки — СДЭК, Boxberry, Почта России, DHL: все предоставляют REST API для расчёта стоимости и создания накладных. Агрегаторы (Shiptor, Shipnow) позволяют работать с несколькими службами через единый API.
Платёжные шлюзы
| Шлюз |
Особенности интеграции |
| Stripe |
Webhook-based, отличная документация, Stripe Elements для PCI DSS |
| ЮКасса |
Популярен в РФ, поддержка ФЗ-54 (фискализация) |
| ЕРИП |
Белорусская система, SOAP API, специфическая документация |
| Tinkoff Acquiring |
REST API, 3D Secure 2.0, webhook-уведомления |
Для каждого шлюза обязательна проверка подписи вебхука — без этого любой может отправить фейковое payment.succeeded.
CMS vs собственная разработка
WooCommerce — оправдан для магазинов до ~5 000 SKU с типовой бизнес-логикой. Быстрый старт, огромная экосистема плагинов. Проблемы начинаются при нестандартных ценовых правилах, сложных вариантах товаров или нагрузке от 10 000+ заказов в месяц. Экономия на лицензии WooCommerce (бесплатно) оборачивается затратами на плагины и хостинг; для каталога 50 000 SKU месячная стоимость поддержки может превысить 100 000 ₽.
OpenCart, Prestashop — аналогичная история. Хороши для старта, ограничены при росте.
Собственная разработка на Laravel — для:
- Нестандартной бизнес-логики (подписки, аренда, b2b-прайсы, конфигуратор);
- Высоких требований к производительности;
- Сложных интеграций (несколько складов, ERP, маркетплейсы);
- Уникального UX checkout.
Как мы разрабатываем интернет-магазин: пошаговый процесс
-
Аналитика и проектирование. Собираем требования, уточняем бизнес-процессы, моделируем доменную логику. На выходе — техническое задание и архитектурная схема.
-
Backend и API. Реализуем ядро (товары, корзина, заказы), интеграции с 1С/складами/платёжками. Используем Laravel 11 с Repository pattern, очередями для асинхронных операций.
-
Frontend и checkout. Настраиваем React 18 / Next.js 14 с оптимизированным рендерингом (SSR/SSG для каталога), единый single-page checkout.
-
Тестирование. Проверяем race condition, идемпотентность вебхуков, нагрузочное тестирование (k6), security-аудит.
-
Деплой и мониторинг. Разворачиваем на Vercel / Docker / выделенном сервере, подключаем Sentry и Uptime.
SEO для e-commerce
Canonical и дублирование. Фасетная фильтрация генерирует тысячи URL (?color=red&size=M&sort=price). Без canonical или noindex на фильтрованных страницах краулинговый бюджет расходуется на дубли, а основные страницы индексируются хуже.
Structured data. Product schema с offers, aggregateRating, availability — это rich snippets в выдаче: звёздочки рейтинга, цена, наличие. Влияет на CTR.
Core Web Vitals на страницах товаров. Hero image товара — это LCP element. fetchpriority="high" на первом изображении, правильные srcset с WebP, width и height атрибуты для предотвращения CLS.
Что входит в результат работы
После завершения проекта вы получаете:
- Исходный код и полную документацию (API, архитектура, инфраструктура);
- Доступы к репозиторию, хостингу, мониторингу (Sentry, Uptime);
- Обучение команды работе с админ-панелью и кастомизациями;
- Гарантийную поддержку 3 месяца (исправление ошибок, консультации);
- Подробный отчёт по нагрузочному тестированию и оптимизации.
Ориентиры по срокам
| Тип магазина |
Срок |
| Малый (до 1 000 SKU, типовая логика) |
8–12 недель |
| Средний (до 50 000 SKU, интеграция 1С) |
14–20 недель |
| Крупный (100 000+ SKU, ERP, маркетплейсы) |
24–40 недель |
Стоимость рассчитывается после анализа требований: количество интеграций, сложность ценообразования, объём каталога и уникальность UX — основные факторы. Оценим ваш проект бесплатно — закажите консультацию.
Чек-лист перед запуском
- Race condition при оплате последнего товара — покрыт тестом
- Идемпотентность вебхуков платёжного шлюза
- Rate limiting на эндпоинтах корзины и checkout
- Canonical на фильтрованных страницах каталога
- Фискализация чеков (ФЗ-54 для РФ или аналог)
- Стресс-тест checkout под нагрузкой (k6 или Locust)
- Мониторинг ошибок (Sentry) и алерты на payment errors
- Backup базы данных с проверенным restore-процессом
Гарантируем — каждый проект проходит этот чек-лист перед релизом. Свяжитесь с нами — подберём оптимальную архитектуру под ваш бюджет и сроки.