Маркетплейс · объявления

Admister — семь маркетплейсов с одним движком

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

Категория
Маркетплейс · объявления
Оценка стоимости
от €32 000
Сервисов
семь, одна кодовая база
Языки
EN, UK · четыре валюты показа
Стек
PHP 8.3, MariaDB, без фреймворка
admister.org
Admister
Главная страница проекта — admister.org

01О проекте

Admister — мульти-вертикальный маркетплейс. Под одной крышей работают доска объявлений, авто с запчастями, недвижимость с продажей и арендой, товарный рынок с магазинами продавцов, цифровые товары, купонный сервис и прайс-агрегатор. У каждого свой поддомен, своя главная и своё представление о том, что такое «объявление».

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

02Контекст и проблема

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

Обратная крайность не лучше. Сайт с категорией «Авто» не умеет спрашивать пробег, двигатель и номер так, как это делает авто-доска, а поиск недвижимости без этажа и числа комнат — не поиск недвижимости. Задача была в том, чтобы оставить один движок и при этом не делать вид, будто семь очень разных каталогов — это один каталог.

03Задачи проекта

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

04Что мы сделали

Реестр сервисов встроен в загрузку приложения. Приходит запрос, адрес сверяется с реестром — и дальше приложение знает, какая оно вертикаль: какие модули поднимать, какой набор атрибутов брать, какую главную и какое меню рисовать. Голый домен — доска объявлений, поэтому самый короткий адрес заодно и самый общий.

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

05Семь сервисов — семь каталогов

  • Объявления — общая доска: от велосипеда до дивана, публикация бесплатна.
  • Авто — транспорт, номера и запчасти, со своим набором из нескольких десятков атрибутов и фильтрами поверх него.
  • Недвижимость — продажа и аренда, свой набор атрибутов, карты и поиск по районам.
  • Маркет — товары с магазинами продавцов: витрина на продавца, остатки, заказы.
  • Цифровые товары — ключи, гифт-карты и eSIM: то, что доставляют, а не отправляют.
  • Купоны — промокоды и акции магазинов-партнёров.
  • Прайс — агрегатор цен: один товар в разных магазинах, сравнение и учтённые переходы.

У них общие аккаунт, баланс, очередь модерации и поисковый индекс — и ничего общего в атрибутах, ради чего всё и затевалось.

06Деньги: баланс, крипто-инвойсы, сверка

Платное — продвижение, тарифы магазинов, цифровые товары — оплачивается с внутреннего баланса, а баланс пополняется криптой через Payora, наш же шлюз. Тело инвойса собирается ровно в одной функции, потому что то же тело повторяет крон сверки под тем же ключом идемпотентности: одно разошедшееся поле вернулось бы конфликтом и подвесило платёж.

Две детали, которые мы повторим на любом шлюзе. В инвойс уходит язык самого покупателя из его строки в базе, а не из веб-запроса: у крона запроса нет, и иначе всем уходил бы английский. И адрес возврата ведёт в кабинет на голом домене — покупатель, начавший с авто-вертикали, возвращается залогиненным, а не на страницу «войдите снова».

07Доверие: модерация, бейджи, споры

Маркетплейс судят по худшему объявлению, поэтому модерация здесь не боковой экран. Каждое решение — одобрить, отклонить, снять — проходит через один обработчик, и «отклонить» намеренно не то же самое, что «снять»: первое — ответ автору с причиной, второе убирает то, что уже висело. Два глагола, два разных письма, два разных состояния в записи.

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

09Мобильное приложение со своим бэкендом

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

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

10SEO на семь фронтов

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

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

11Один канал наружу

Всё, что приложение отправляет наружу — вызовы API, вебхуки, партнёрские фиды, забираемые картинки, почта, — идёт через один модуль, привязанный к SOCKS5-прокси, и DNS резолвится через тот же прокси. Модуль работает fail-closed: недоступен прокси — запрос блокируется, а не уходит тихо с адреса сервера.

Это не украшение. Маркетплейс целый день тянет партнёрские фиды и чужие картинки, и каждый такой запрос иначе относил бы адрес площадки третьей стороне. Почта идёт тем же путём, через YourTrend: письма подписаны, а имя сервера не появляется в заголовках.

12Технологии

  • PHP 8.3 без фреймворка, тонкая обёртка над PDO и подготовленные запросы везде;
  • MariaDB, схема живёт нумерованными файлами миграций, а не в чьей-то памяти;
  • медиа лежат вне вебрута и отдаются контроллером — загруженный файл никогда не становится исполняемым путём;
  • сборка ассетов с хешем в имени и без инлайна того, что должно кэшироваться, с выключателем на случай сбоя;
  • SOCKS5 наружу для каждого исходящего вызова, почта через SMTP YourTrend;
  • Payora — крипто-инвойсы, Astrina — вход и материалы, Adgora — собственная реклама.

13Результат

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

Владельцу это даёт одно место, куда смотреть. Модерация, деньги, продавцы и контент ведутся из общей панели управления всей группы проектов, а маркетплейс отдаёт их подписанным админским API, а не вторым собственным админ-сайтом.

14Выводы

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

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

Если вы строите маркетплейс, доску объявлений или мульти-вертикальную площадку на одном движке — это работа, которую мы делаем целиком.

На какие запросы отвечает эта страница

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