Тимур ТурдыевНаписать

кейс · 2025

Mercurio: своя платформа для интернет-магазинов

С 2025 года строю Mercurio: платформу, где сырьё поставщиков неизменяемо, человек правит только решения, а каталог собирается детерминированно. Два клиента, обе витрины пока на демо-стендах.

LaravelPHPPostgreSQLInertiaReactTypeScriptManticoreimgproxy1С

Зачем ​

Четыре года я веду магазин офисной мебели prvoffice.ru, и за это время админка выросла в тысячу коммитов. Она работает, но в ней есть то, что я больше не хочу повторять: правки каталога руками поверх загруженных прайсов, свой класс на каждого поставщика, поиск, который три раза менял движок. Когда появился второй магазин, упаковка из Петербурга на OpenCart 2.3, стало ясно, что копировать prvoffice ещё раз не вариант. Нужна платформа.

Платформу я начал в 2025 году и прошёл через несколько подходов: админка в стиле OpenCart, потом платформа сразу под несколько вертикалей. От обоих отказался, оставил только имя. Нынешняя версия с августа 2026 написана с чистого листа, а модель каталога спроектирована от предметной области, а не от таблиц старой админки: сначала разобрал боевую базу prvoffice запросами, потом рисовал схему.

Как устроено ​

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

Из закона выросли модули админки.

Приём прайсов. Прайс или YML поставщика принимается потоком и хранится как есть. Разбор задаётся профилем, короткой настройкой: где артикул, где цена, какие колонки - оси исполнений, какие - характеристики. В старой админке на пять поставщиков было пять классов, здесь новый поставщик - это новый профиль на экране, а не новая программа. Забор по ссылке и ночной обход идут в фоне.

Решения и словарь. Контентщик открывал домен «Цвет ЛДСП» и видел 1090 значений, половина из них - составные вроде «Дуб Аттик/Белый бриллиант». Разбор по разделителю даёт 428 атомов. Сведение дублей, разбор композитов и подсказки живут отдельным слоем решений, сырьё при этом не трогается.

Сборка каталога. Детерминированная и идемпотентная, единственное место, которое пишет в каталог. Проверял на индексе Manticore: документы до и после рефакторинга сборки совпадают побайтно, 299 тысяч у мебели и 7,9 тысячи у упаковки.

Обмен с 1С сделан как фича платформы со своим протоколом: 1С сама шлёт цены и наличие пакетом JSON, сама забирает заказы, в интернет её выставлять не нужно. Сторож обмена ловит молчание и незабранные заказы.

Конверторы чужих баз - legacy:import для каталога prvoffice и opencart:import для магазина на OpenCart, 22 этапа от справочников до переезда адресов. Разовый инструмент: гоняется у меня, на сервер уезжает готовая база. Фиды, sitemap, письма о заказах, чистку корзин тоже гоняет админка, витрина - только веб.

Стек: Laravel 13, PostgreSQL, Inertia с React и TypeScript, Manticore для поиска, imgproxy для картинок. Livewire не взял сознательно: он гоняет снапшот состояния на каждый клик, и у контентщика с большими формами это тормозит. Деньги в копейках: лента стоит 89,90, пакет с замком - 20 копеек, и округление до рубля обнуляло его цену.

Общая часть вынесена в composer-пакет mercurio/kit: модели, чтение каталога, поиск, заказы, SEO, миграции. Пакет не знает приложения, это держит тест на границы. Ставится по тегу, и каждый клиент называет свою версию сам - клиенты не ходят строем.

У каждого клиента своя машина, своя база, свой домен и своё приложение витрины. Админка одна по коду, разворачивается каждому отдельно. Витрина рисуется темой, и запасного шаблона нет намеренно: установка без своей темы падает, а не показывает чужую страницу под своим именем.

Клиенты ​

prvoffice. Витрина перенесена с прежнего стека, переведена на React и TypeScript, с регионами-поддоменами, коммерческими предложениями и прайсом раздела в xlsx. Стоит на демо-стенде за паролем. Боевой prvoffice.ru пока на старой админке и старой витрине.

lpack, бренд «ОптоПак». Магазин упаковки переезжает с OpenCart 2.3. Корзина с кратностью отгрузки (оптовику продают партию, а не штуку), сверка цены при каждом заходе в корзину, заказ по списку артикулов, кабинет покупателя, редиректы со старых адресов, обмен с 1С. Каталог 7 856 позиций, при этом в шапке старого сайта было написано «2 400+»; теперь цифра считается из каталога. Демо открыто на opto-pack.ru, покупатели работают на старом сайте, впереди финальный прогон импорта и отключение от OpenCart.

Что дальше ​

Обе витрины на стендах, и это честная точка: платформа собрана, конверторы прогнаны, обмен с 1С описан для программиста клиента. Дальше - финальный перекат lpack, переключение prvoffice и то, ради чего всё затевалось: третий клиент, который заводится профилем приёма и темой, а не новой админкой.

© 2014-2026 Тимур ТурдыевСайт и справочник работают на VPS от AdminVPS