Один каталог - все каналы продаж: Rozetka, Prom, Epicentr, Google и KeyCRM из одного хаба

Магазин, который продаёт ещё на трёх маркетплейсах и в Google, держит пять копий каталога, и каждое изменение цены должно дойти до всех. Хаб Ezeden хранит один каталог и сам говорит на языке каждого канала - и никогда не удаляет и не пересоздаёт объявление, которое уже продаёт.

Один каталог - все каналы продаж: Rozetka, Prom, Epicentr, Google и KeyCRM из одного хаба
Смотреть проект:
ezeden.com.ua
ezeden.com.ua

Задача

Ezeden продаёт на собственной витрине и ещё на четырёх площадках: на украинских маркетплейсах Rozetka, Prom.ua и Epicentr и в Google Merchant Center, откуда товары бесплатно попадают в поиск и “Покупки” Google. На маркетплейсах уже были тысячи объявлений магазина, созданных вручную за годы, и каждая площадка хочет видеть каталог по-своему. Заказы обрабатываются в KeyCRM.

Вести пять копий каталога вручную - значит отстающие цены, остатки, проданные дважды, и объявления, которые расходятся между собой. Цель - один каталог в хабе, из которого питаются все каналы, причём без удаления и пересоздания чего-либо на маркетплейсах.

Каждому маркетплейсу - его язык

Маркетплейс принимает объявление только в своих идентификаторах. Каждую ночь хаб загружает категории, характеристики и допустимые значения каждой площадки и хранит их по версиям: менеджер видит, что именно площадка добавила, переименовала или убрала.

Сопоставление переводит каталог в эти идентификаторы на трёх уровнях: категория в категорию, характеристика в характеристику, значение в значение.

Категория может делиться: гранитные мойки уходят в одну категорию Rozetka, стальные - в другую, по значению одной характеристики. Единицы и формат тоже задаются правилами: миллиметры становятся сантиметрами, а правило, которое не может перевести единицу, отклоняется ещё при сохранении.

Одна характеристика может заполнять две: Epicentr просит базовый цвет и цвет производителя, и оба берутся из одного цвета в каталоге. Поле, которое площадка требует, а каталог не содержит, - “для кухни” у каждого кухонного смесителя - задаётся один раз на категорию как постоянное значение.

У каждого товара есть статус готовности для каждой площадки: без категории, с пустой обязательной характеристикой или с несопоставленным значением он не уходит. Если площадка убрала запись, сопоставления с ней попадают в очередь “Сломанные сопоставления”.

ИИ-помощник для сопоставления

Первый проход делает помощник. Он отбирает записи площадки, чьи названия похожи на названия в каталоге, на всех языках каталога. Точное совпадение или соответствие, уже подтверждённое в другом месте того же канала, предлагается как уверенное, и менеджер подтверждает все такие одной кнопкой. Когда названия лишь похожи, ИИ-модель выбирает одно - только из отобранного списка - или отвечает, что подходящего нет. На тестовых справочниках она сопоставляла значения на разных языках: русское “круглая” из каталога - с украинским “Кругла” на Rozetka.

Каждое предложение подтверждается один раз; дальше сопоставление применяется ко всем товарам без повторного обращения к модели.

Связка объявлений, которые уже продают

Объявления на маркетплейсах создавались вручную годами и уже продают. Пересоздать их - значит выбросить эту работу, поэтому хаб следует одному правилу: связывать, а не пересоздавать. Он читает, что продаёт каждая площадка - по API или из выгрузки кабинета продавца, - и сопоставляет каждое объявление с товаром:

  • артикул магазина в поле кода продавца, артикул производителя или штрихкод решают дело;
  • артикул в названии объявления или коды модели в названии - только предлагают кандидата.

Всё спорное - два ключа указывают на разные товары, два объявления на один товар - ждёт в очереди “На проверку” с объяснением. Массово связываются только уверенные совпадения, а кому удобнее таблица, может выгрузить список, вписать артикулы и загрузить его обратно через те же проверки.

Единственная запись на площадку здесь - на Prom.ua: по команде менеджера хаб проставляет артикул магазина как внешний идентификатор объявления и затем перечитывает площадку, чтобы убедиться, что это произошло.

Цены и остатки: отправлено, принято, показано

После связки объявление получает цену и остаток из правил цен и журнала остатков хаба.

Каждое обновление передаёт абсолютные цифры, а не разницу: “цена X, остаток Y” вместе с номером версии. Поэтому повторная отправка безвредна, а старая, пришедшая с опозданием, отбрасывается.

Изменение уходит на площадки быстро, примерно через 30 секунд, но пачками, поэтому импорт, поменявший пять тысяч остатков, превращается в одно обновление на канал. Проход раз в пять минут подхватывает то, о чём не сообщает ни одно событие, например акцию, которая начинается в полночь.

То, что площадка приняла цену, ещё не значит, что она её показывает. Поэтому для каждого объявления экран показывает три цифры: что хочет хаб, что площадка приняла и что она на самом деле показывает при обратном чтении. Rozetka, например, задерживает на проверку своим менеджером цену, поднятую больше чем в полтора раза или сниженную больше чем вдвое. Запрос при этом проходит успешно, поэтому хаб помечает такие объявления как ожидающие площадку, пока обратное чтение не прояснит картину.

Безопасность заложена в само устройство: нулевая цена не отправляется никогда, каждый остаток проходит через буфер канала, а товару, который нужно снять с продажи, отправляется нулевой остаток. Ничто не удаляет и не скрывает объявление.

Отказы попадают в очередь ошибок со словами самой площадки.

Новые объявления по правилам

Какие товары должна нести площадка, решают правила публикации по бренду, категории или поставщику с условиями: полное сопоставление, наличие, фото. Условия влияют только на создание нового объявления, а правило может ждать менеджера в обе стороны, так что сужение правила никогда тихо не снимает объявления с продажи. Карточки уходят по API, фидом или файлом для загрузки - как поддерживает площадка.

Google Merchant Center

Бесплатные товарные объявления Google показывают товары в поиске и в “Покупках”, каждое со ссылкой на страницу магазина. Хаб собирает фид из витрины: название, описание, фото, цену и наличие самой витрины (Google отклоняет предложение, если цена расходится со страницей), категорию из таксономии Google, бренд, штрихкод или артикул, группу цветов и все характеристики. Товар считается опубликованным, когда Google забрал файл.

Заказы и KeyCRM

Хаб опрашивает каждую площадку на предмет заказов и записывает их так же, как заказы витрины, по ценам площадки: заказ с маркетплейса - это факт, а не запрос. Строка без найденного товара сохраняется, а не отбрасывается, а нехватка остатка уходит в очередь менеджера, не теряя заказ.

Каждый заказ сразу после оформления уходит в KeyCRM; если CRM недоступна, он ждёт в очереди и отправляется повторно сам. Обратно приходят статусы, номера накладных, фискальные чеки и отметки об оплате. Таблица статусов в админке определяет, какой статус CRM означает какой статус хаба, а настройка решает, чей статус главнее. Клиенты тоже синхронизируются, с очередью конфликтов для неоднозначных совпадений.

Здоровье интеграций и осторожный запуск

Экран состояния площадок показывает для каждой, принимает ли она токен, когда каждый обмен последний раз прошёл и сломался и что ждёт своей очереди. Токены проверяются каждые шесть часов, и эта же проверка поддерживает токен Rozetka, которая отключает токен, не использовавшийся 24 часа. “Ключ отклонён” и “площадка не ответила” сообщаются раздельно: только первое требует человека.

Для спокойного запуска каждую запись на площадку можно поставить на подтверждение менеджером, при этом чтение продолжает работать.

Технологии

- Хаб: Laravel 13 + Inertia + React 19 + Ant Design
- Коннекторы: Rozetka, Prom.ua, Epicentr, Google Merchant Center, KeyCRM
- ИИ-сопоставление: Anthropic Claude, выбор только из списка кандидатов по названию
- Фоновые задачи: Laravel Horizon на Redis 7, с ограничением частоты для каждой площадки
- Данные: MySQL 8.4; фиды отдаёт сам хаб

Результат

У магазина один каталог. Из него цены, остатки, карточки и заказы попадают на Rozetka, Prom.ua, Epicentr, в Google и KeyCRM, каждая цифра проверяется после отправки, а объявления, которые уже продавали, сохраняют свою историю.

Похожие кейсы

Каталог, который наполняется сам: парсеры, прайсы поставщиков и импорт, который можно откатить

Каталог, который наполняется сам: парсеры, прайсы поставщиков и импорт, который можно откатить

Тысячи товаров из нескольких источников - это бесконечное копирование: новые модели, изменённые характеристики, новые фото, прайсы в разных форматах. Хаб за магазином Ezeden берёт эту работу на себя: сам читает источники, показывает, что изменится, и не даёт импорту испортить каталог.

Ezeden: интернет-магазин на 3 500 товаров поверх собственного мастер-каталога

Ezeden: интернет-магазин на 3 500 товаров поверх собственного мастер-каталога

Тысячи товаров от множества поставщиков - это грязные данные: разные единицы, дубли, недостающие переводы, цены в трёх валютах. Ezeden - быстрый магазин на трёх языках поверх мастер-каталога, который превращает эти данные в один чистый и контролируемый источник.

Магазин в Telegram: ИИ-продавец, мини-приложение и оплата прямо в чате

Магазин в Telegram: ИИ-продавец, мини-приложение и оплата прямо в чате

Многим покупателям проще написать магазину в Telegram, чем заполнять форму на сайте, а держать человека, который отвечает ночью, магазину не по карману. Эта платформа переносит в чат ИИ-продавца, витрину и оплату, а менеджеры видят всё в реальном времени и подключаются в один клик.

ИИ-наполнение каталога: переводы, описания и SEO-тексты только из фактов карточки

ИИ-наполнение каталога: переводы, описания и SEO-тексты только из фактов карточки

Каталог из тысяч технических товаров приходит на одном языке, с неровными описаниями и без SEO-текстов. Хаб за магазином Ezeden заполняет пробелы с помощью ИИ - но только из фактов, которые уже есть в каталоге, по цене, которую менеджер видел заранее, и с проверкой человеком там, где это важно.