Это сквозной пример сайта. Я взял типичный разговор «давайте я повторю, как понял задачу» — то, что обычно происходит после первой встречи с заказчиком, перед тем как браться за оценку и архитектуру.
Здесь нет ни строчки про базы данных, очереди и агрегаты. Здесь только бизнес — словами, какими о нём говорят сами участники. Этот текст потом отдаётся скиллам методологии, которые из него выводят технические артефакты: контракты API, доменную модель, UseCase-ы.
О чём вообще речь
Вы делаете маркетплейс — площадку, на которой одни люди продают свои товары другим людям. Сами вы при этом ничего не производите и не складируете: ваша роль — посредник с гарантиями.
Продавцы у вас разные: и крупные магазины с тысячами позиций, и частники, которые продают пару вещей в месяц. Покупатели — обычные люди. Между ними стоит ваша команда: модераторы карточек, операторы споров, бухгалтерия, поддержка.
Деньги вы зарабатываете двумя способами. Главный — комиссия с каждой подтверждённой продажи. Вспомогательные — платное продвижение в выдаче, сервисные сборы за упаковку и страховку.
Кто пользуется платформой
У платформы три основных «лица», и для каждого нужен свой интерфейс.
Покупатель заходит, чтобы найти и купить. Ему важны: цена, наличие, отзывы, скорость доставки. Логинится он чаще всего через телефон или соцсеть — пароли никто запоминать не хочет.
Продавец заходит, чтобы зарабатывать. Ему важны: быстро добавить товар, увидеть свои заказы, получить деньги в срок, быстро решить спор, если он возник. Логинится по корпоративному аккаунту — обычно с двухфакторной защитой.
Оператор маркетплейса — это ваши сотрудники: модераторы, специалисты по спорам, финансовый отдел. Они работают изнутри, через корпоративный SSO с обязательной MFA. У них самые широкие права, поэтому каждое действие пишется в аудит.
Есть ещё курьер и пункты выдачи — но они с платформой общаются через свои API, а не через интерфейсы. Их мы рассматриваем как внешние сервисы.
Что есть на платформе
Чтобы дальше говорить на одном языке, давайте зафиксирую, как мы называем вещи.
Товар — конкретное изделие у конкретного продавца. Один и тот же iPhone у двух разных продавцов — это два разных товара, потому что у них разная цена, остаток, рейтинг, продавец отвечает за свой. Это важно: товары не «склеиваются».
Карточка товара — то, что покупатель видит на витрине: фото, описание, цена, остаток, отзывы.
Корзина — временный набор товаров. Пока она не превратилась в заказ, ничего не зарезервировано: остаток может уйти к другому покупателю.
Заказ — финансовый документ. После оформления заказа товары резервируются, и продавец видит «ко мне приехала продажа».
Платёж — попытка списания денег. Один заказ может оплачиваться несколькими попытками: ввели не ту карту, не прошёл 3DS, попробовали ещё раз. Заказ становится оплаченным только после того, как банк подтвердил списание.
Возврат — обратное движение денег, когда товар возвращается. Не путать с отменой: отмена возможна до отправки, возврат — после получения.
Спор — это когда покупатель говорит «не то/брак/не пришло», а продавец не согласен. Тогда в дело вступает оператор и принимает решение.
Комиссия — ваш процент с подтверждённой продажи. Расчёт продавцу — это сумма, которую вы переводите ему раз в неделю: продажи минус комиссия минус возвраты.
Промокод — купон, дающий скидку на корзину или конкретные товары.
Как происходит покупка
Расскажу как историю, по шагам — так понятнее.
Покупатель открывает сайт или приложение. Ищет товар — через поиск или каталог. Открывает карточку, видит наличие, цену, продавца, отзывы. Если устраивает — кладёт в корзину.
В корзине покупатель может ввести промокод и выбрать способ доставки (адрес или ПВЗ). Итоговая сумма пересчитывается: товары × количество, минус скидки, плюс доставка.
Дальше нажимает «Оформить». Система резервирует остаток у каждого продавца, который попал в корзину, и переводит покупателя на форму оплаты. На эту операцию мы даём, например, 15 минут — если за это время оплата не пришла, резерв снимается, заказ помечается «истекший».
Когда платёж прошёл — заказ переходит в статус «оплачен». Продавец получает уведомление, собирает посылку и передаёт курьеру. Заказ становится «отправлен».
Курьер доставляет — заказ становится «доставлен». Если за следующие 14 дней покупатель не открыл спор — заказ закрывается, продавцу начисляется выручка.
Что бывает, когда что-то идёт не так
Счастливый сценарий пишут все. Разница — в обработке проблем.
Покупатель передумал до отправки. Например, заказ оплачен, но продавец ещё не передал курьеру. Покупатель нажимает «Отменить». Резерв снимается, деньги возвращаются через тот же платёжный шлюз. Здесь всё просто.
Покупатель передумал, но посылка уже едет. Сложнее — нужно либо ждать, пока курьер вернёт пакет, либо договариваться, чтобы покупатель сам вернул в ПВЗ. Деньги возвращаются только после того, как товар физически вернулся продавцу.
Покупатель получил, но что-то не так. Брак, не тот цвет, кто-то распечатал коробку. Покупатель открывает спор, прикладывает фото и описание. Платформа уведомляет продавца — у него три дня на ответ. Если согласен — оформляется возврат. Если нет или молчит — спор уходит к оператору, тот разбирается и принимает решение. Решение фиксируется в системе как часть истории заказа — на случай, если кто-то потом захочет проверить.
Платёжный шлюз отвалился. Покупатель ввёл карту, банк не отвечает 30 секунд. Мы не можем оставить его в подвешенном состоянии — у нас должна быть стратегия: показать «попробуйте снова», заморозить заказ на короткое время, проверить через минуту через альтернативный канал шлюза. К этому ещё вернёмся, когда дойдём до отказоустойчивости.
Деньги уже выплачены продавцу, а покупатель открыл возврат. Самый болезненный случай. Платформа не может «отозвать» уже отправленную выплату — деньги списываются с внутреннего баланса продавца, и в следующих расчётах он получит меньше. Если баланс ушёл в минус — заказы продавца замораживаются до выяснения.
Оплата пришла на шестнадцатой минуте. Резерв уже снят, заказ помечен истекшим — а деньги списаны. Со шлюзами это регулярная ситуация, а не редкость: подтверждение задержалось в сети или банк ответил медленно. Решаем так: платёж, пришедший после истечения срока, не воскрешает заказ автоматически. Система пробует зарезервировать остаток заново; получилось — заказ оживает и переходит в «оплачен», покупателя уведомляем. Не получилось (товар разобрали) — деньги возвращаются полностью и автоматически, без обращения в поддержку, покупателю приходит объяснение.
Отсюда два требования, которые надо держать в голове: срок в 15 минут — это срок для покупателя, а не жёсткое время отказа от денег; и любой платёж по заказу должен быть опознан, даже если заказа в ожидании оплаты уже нет. Платёж, который не удалось сопоставить ни с одним заказом, попадает в отдельный список для финансового отдела, а не теряется.
Товар не пришёл вовсе. Правило «спор в течение 14 дней после получения» не работает, если статуса «доставлен» нет: курьер потерял посылку, ПВЗ не отметил выдачу, продавец не передал в доставку. Поэтому у нас два срока, и считаются они от разного:
- 14 дней с даты получения — для спора о качестве и комплектности, когда товар на руках.
- Срок ожидания доставки — обещанная дата плюс запас (скажем, 10 дней). Если к его истечению статуса «доставлен» нет, покупатель может открыть спор «товар не пришёл», а система сама напоминает ему об этом.
Второй срок важнее первого по последствиям: без него заказ, застрявший в доставке, висит вечно, деньги не возвращаются покупателю и не выплачиваются продавцу. Поэтому заказ, у которого нет движения статуса дольше предельного срока, уходит к оператору сам, без обращения покупателя.
Возврат части заказа и промокод. Первый вопрос бухгалтерии, и ответ на него нужен до первой строчки кода. Покупатель купил три товара на 3000 ₽, применил промокод на 300 ₽ и возвращает один товар за 1000 ₽. Сколько вернуть?
Правило: скидка распределяется по позициям пропорционально их стоимости, и возвращается позиция вместе со своей долей скидки. В примере на позицию за 1000 ₽ пришлось 100 ₽ скидки, покупатель заплатил за неё 900 ₽ — столько и возвращаем. Остальные позиции сохраняют свои доли.
Что из этого следует и что нужно зафиксировать:
- Доля скидки считается один раз, при оформлении, и хранится в позиции заказа. Пересчитывать её при возврате нельзя: цены и условия промокода могли измениться.
- Промокод не «возвращается» покупателю при частичном возврате: он был применён к заказу, и заказ существует. Если возвращается весь заказ целиком — промокод считается неиспользованным и может быть применён снова, если не истёк.
- Скидка на конкретный товар возвращается целиком вместе с ним, а не размазывается: если промокод был на одну позицию, при её возврате уходит вся его сумма.
- Доставка при частичном возврате не возвращается, если остальная часть заказа доставлена. Возвращается целиком, если возвращается весь заказ и виноват продавец или платформа.
- Округление — в пользу покупателя, и суммы долей обязаны сходиться к сумме скидки до копейки. Это тот самый случай, где «расхождение на копейку» ломает сверку.
Продавец ушёл с платформы, а возврат открыт. Продолжение самого болезненного случая: списывать с внутреннего баланса не с кого — продавец закрыл аккаунт, вывел деньги и больше не торгует. Правила такие:
- Аккаунт нельзя закрыть мгновенно. После заявки на закрытие продавец переходит в состояние «завершает работу»: новые заказы не принимает, но остаётся ответственным по уже закрытым до истечения всех сроков спора.
- Последняя выплата удерживается до истечения сроков. Часть суммы, покрывающая возможные возвраты по недавним заказам, выплачивается не сразу, а после того, как окно споров закрылось.
- Если денег всё равно не хватило — возврат делает платформа за свой счёт, а сумма становится задолженностью продавца. Покупатель не должен страдать от того, что мы не удержали достаточно: это решение о репутации, и оно принимается один раз.
- Порог удержания — параметр, а не константа в коде: финансовый отдел будет его менять по статистике возвратов.
То же касается продавца, которого мы заблокировали сами: блокировка останавливает продажи, но не отменяет обязательств по уже совершённым.
Что делает продавец
У продавца своя жизнь на платформе.
Размещает товары. Создаёт карточку, заполняет описание, ставит цену и остаток, выбирает категорию. Карточка идёт на модерацию — оператор проверяет, что нет запрещённых вещей и категория правильная. Если ОК — карточка появляется в каталоге; если нет — возвращается с комментарием.
Обрабатывает заказы. Видит у себя в кабинете «вот четыре новых заказа». Собирает, передаёт курьеру, отмечает в системе.
Получает выплаты. Раз в неделю система собирает все его закрытые заказы, считает: продажи минус ваша комиссия минус возвраты минус штрафы, если были. Если итог больше порога выплаты (например, 1000 ₽) — деньги уходят на расчётный счёт продавца. Если меньше — остаток копится до следующей недели.
Видит отчёты. Сколько продал, какая средняя комиссия, какие товары вернули чаще всего. Это и для самого продавца полезно, и снимает нагрузку с поддержки — меньше вопросов «а где мои деньги».
Что делает оператор маркетплейса
Операторы — это ваша команда внутри. Они закрывают всё, что не получается автоматизировать.
Модераторы смотрят новые карточки товаров. Специалисты по спорам разбирают конфликты между покупателями и продавцами. Финансовый отдел проверяет крупные выплаты и решает, что делать с заблокированными аккаунтами. Поддержка отвечает покупателям и продавцам по обычным вопросам.
У оператора широкие права, поэтому каждое его действие пишется в аудит — кто, когда, на каком заказе, что изменил. Это нужно и для безопасности, и на случай разбирательств.
Что важно держать в голове
Несколько правил, которые звучат очевидно, но определяют половину работы.
- Сумма заказа = всегда сумма позиций минус скидки плюс доставка и сервисные сборы (упаковка, страховка). Никаких «расхождений на копейку», иначе бухгалтерия сломается.
- Резервировать можно только то, что есть в наличии. Отрицательных остатков не бывает — резерв либо успешен, либо отказан.
- Один промокод — одно применение в одном заказе. Не складываются.
- Продавец не может изменить цену уже оформленного заказа. Защита покупателя.
- После отправки заказ нельзя «отменить» одной кнопкой — только оформить возврат с обратным движением товара.
- Возврат денег невозможен, если они уже выплачены продавцу — компенсируется с его внутреннего баланса.
- Спор может открыть только покупатель и только в течение 14 дней после получения. Защита от злоупотреблений.
- Покупатель видит только свои заказы. Продавец — только заказы со своими товарами. Оператор — все. Никто не видит чужого.
- Платёж считается успешным только при подтверждении от банка, не до. Никаких «оптимистичных» подтверждений.
Какие у нас цели по объёмам
Чтобы понимать, что мы строим — небольшой стартап или платформу национального масштаба, — давайте зафиксирую целевые цифры. Это не то, что у вас сейчас, а то, к чему вы готовитесь.
| Что | Сколько |
|---|---|
| Активных продавцов | 200 000 — 500 000 |
| Карточек товаров на витрине | 50 — 100 миллионов |
| Активных покупателей в месяц | 10 — 15 миллионов |
| Заказов в обычный день | около 500 000 |
| Заказов в пиковый день (Чёрная пятница, 11.11) | до 2 миллионов |
| Запросов к поиску и каталогу | до 50 000 в секунду |
| Запросов на оформление заказа в пик | 200 — 500 в секунду |
| Подключённых платёжных шлюзов | 5 — 10 |
При таких числах «один сервер с одной базой» физически не работает — придётся разносить нагрузку, делать кэши, использовать очереди. Это уже инженерная часть, на которую переходим в следующих главах.
Что вы хотите по надёжности и срокам
В разговорах с заказчиком обычно опускают эту часть, а зря — без неё инженеры не могут оценить стоимость.
Каталог и поиск должны работать «всегда» — потому что если упадут, не будет ни одной продажи. Целимся в 99.95% доступности — это примерно четыре с половиной часа простоя в год.
Оформление заказа немного попроще — 99.9% (около 9 часов в год). Если коротко полежит ночью — это переживаемо.
Личный кабинет продавца — самый «терпимый» — 99.5%. Если он упал на полчаса в обед — продажи продолжаются, продавец зайдёт позже.
Персональные данные покупателей (адрес, телефон, ФИО) — храним зашифрованно, все обращения пишем в аудит. Удаляем по запросу покупателя: 152-ФЗ требует уничтожить данные, когда цель обработки достигнута, а после отзыва согласия — в тридцатидневный срок. Сроков хранения сам закон не назначает: пять лет после последнего заказа у нас держатся не из-за него, а из-за бухгалтерских и налоговых правил.
Карты и счета — не храним вообще. Только токены от платёжного шлюза, который сам сертифицирован по PCI DSS. Это снимает с нас огромный пласт работы и риски.
Чеки, налоги и статус продавца
Раз мы работаем в России, берём рубли и удерживаем комиссию с каждой продажи — без этого раздела описание неполное. Детали уточняем с вашей бухгалтерией, но требования к системе понятны уже сейчас.
Платформа продаёт не свой товар. Деньги покупателя проходят через нас, но принадлежат продавцу, а нам принадлежит комиссия. Это означает, что платформа выступает посредником, и у операции две финансовые стороны, а не одна: расчёт с покупателем и расчёт с продавцом.
Чек покупателю формируется в момент оплаты. Не при отгрузке и не при закрытии заказа. В чеке — позиции заказа с ценами и ставками налога, способ оплаты и признак того, что продажа идёт от имени продавца. Электронный чек уходит покупателю на почту или телефон, и он обязан быть доступен позже — значит храним ссылку на него в заказе.
При возврате формируется чек возврата. На ту же сумму, что вернули, с теми же позициями. Частичный возврат — чек на возвращённые позиции с их долями скидки, о чём раздел выше. Это второй довод за то, чтобы доли скидки хранились в позициях: без них чек возврата не собрать.
Ставка налога — свойство товара, а не платформы. У разных категорий она разная, и указывает её продавец при создании карточки; модерация проверяет, что категория и ставка не противоречат друг другу. Ошибка здесь дорога: неверная ставка в чеке — проблема продавца и наша одновременно.
Статус продавца меняет правила расчётов. Продавцы бывают разного юридического статуса, и для системы это не косметика:
| Что зависит от статуса | Почему важно |
|---|---|
| Какие документы нужны при регистрации | без них не выплатить деньги |
| Кто формирует чек по продаже | часть продавцов делает это сама, часть — через платформу |
| Какие налоги удерживаются и кем | влияет на сумму выплаты |
| Есть ли ограничение на оборот | при превышении статус меняется, и правила тоже |
Отсюда требование: статус продавца — поле с правилами, а не справочная информация. Изменение статуса меняет расчёт выплаты и набор документов, поэтому оно проходит через проверку, а не правится как обычный профиль.
Выплата сопровождается документами. Продавец должен видеть не только сумму, но и расшифровку: какие заказы вошли, какая комиссия удержана, какие возвраты вычтены, какие штрафы. Это и снижает нагрузку на поддержку, и нужно ему для собственной отчётности.
Что нужно уточнить до реализации — список для встречи с бухгалтерией: кто именно выступает отправителем чека по каждому типу продавца; как оформляется комиссия платформы; в какой момент доход считается полученным; сколько лет храним чеки и расчётные документы; как оформляются компенсации за счёт платформы из раздела про ушедшего продавца.
Что мы не делаем в первой версии
Чтобы запуск был реалистичным, специально ограничиваем объём.
- Только Россия и только рубли. Без международной доставки, таможни, мультивалютности.
- Только обычные продавцы и покупатели. Без подмаркетплейсов, B2B-витрин с прайс-листами, реферальных программ.
- Только хранение у продавца. Без своих складов платформы, без FBO/FBM моделей.
- Без собственной курьерской службы. Только интеграции со внешними логистами.
Это бизнес-упрощения, не технические. Если позже захотите добавить — суть процессов и ролей не меняется, только усложняются детали. Архитектура должна позволять это сделать без переписывания.
Но упрощения не равноценны: снятие одних добавляет работы, снятие других ломает модель. Это стоит знать заранее, потому что закладываться надо только на второе.
| Что снимаем | Что произойдёт | Готовиться сейчас |
|---|---|---|
| Мультивалютность | ломает модель: сумма перестаёт быть числом, появляется валюта, курс и момент его фиксации; ломается сравнение сумм, формула заказа, комиссия, выплаты, чеки | да |
| Международная доставка и таможня | добавляет шаги в доставку, новые статусы, документы; формула заказа не меняется | нет |
| Свои склады платформы | добавляет владельца остатка: резерв идёт не только у продавца; меняется, кто отвечает за отгрузку | частично |
| Подмаркетплейсы и B2B-витрины | добавляет уровень над продавцом и свои цены для сегментов; меняется, чей это товар и чья комиссия | частично |
| Собственная курьерская служба | ещё одна интеграция доставки среди существующих | нет |
| Реферальные программы | добавляет источник скидки; если доля скидки уже хранится в позиции, встраивается спокойно | нет |
Мультивалютность — единственное, что ломает наверняка. Причина в том, что деньги в системе сейчас число, а должны быть парой «сумма и валюта». Складывать позиции в разных валютах нельзя, сравнивать нельзя, а комиссия и выплата требуют курса — и решения, на какой момент он фиксируется (оформление, оплата, выплата). Это затрагивает заказ, платёж, возврат, выплату, отчёты и чеки одновременно.
Дешёвая страховка, которую стоит заложить сразу: везде, где хранится сумма, рядом хранится валюта, пусть даже она всегда «RUB». Одно поле сегодня против переписывания шести сервисов потом. Всё остальное из таблицы честно откладывается.
И симметричное предупреждение: упрощения «только обычные продавцы» и «только хранение у продавца» не ломают модель, но меняют владельца данных — кто владеет остатком и кому принадлежит цена. Это стоит заранее назвать в описании понятий, чтобы потом не выяснять на ходу.
Что дальше
Этот текст — то, как я понял ваш бизнес. Если что-то описано неверно — скажите сейчас, потому что на этом тексте дальше строится всё: API, интерфейсы, сроки, бюджет.
Когда мы согласуем понимание, дальше начинается уже инженерная часть:
- Контракты API — что именно может вызывать покупатель, продавец и оператор. Здесь помогут скиллы проектирования API.
- Что внутри — какие у нас будут сервисы, какие у них зоны ответственности, как они общаются. На этом этапе из бизнес-описания выводятся агрегаты, события, сценарии, а из них — конкретные UseCase + Handler-ы.
- Где может упасть — обработка ошибок шлюзов, ретраи, идемпотентность; см. паттерны отказоустойчивости и распределённые паттерны.
Артефакты по каждому сервису публикуются отдельными статьями кейса. Как они связаны с этим бизнес-описанием — описано в Use Case спецификации.
Коротко
- Платформа сводит покупателей и продавцов и удерживает комиссию: товар, остаток и цена принадлежат продавцу, платформа отвечает за витрину, расчёты, споры и выплаты.
- Путь заказа: резерв остатка и 15 минут на оплату, оплата, сборка и передача курьеру, доставка, 14 дней на спор, закрытие и начисление выручки продавцу.
- Платёж после истечения срока не воскрешает заказ сам: система пробует зарезервировать заново, иначе возвращает деньги; платёж без заказа уходит в отдельный разбор.
- Для заказа, который не доехал, действует не срок спора, а срок ожидания доставки, и застрявший заказ уходит к оператору без обращения покупателя.
- Доля скидки считается при оформлении и хранится в позиции: частичный возврат отдаёт позицию вместе с её долей, а промокод возвращается только при полном возврате заказа.
- Продавец не может закрыть аккаунт мгновенно: последняя выплата удерживается до истечения сроков спора, а нехватку покрывает платформа, записывая долг.
- Чек формируется при оплате и при возврате, ставка налога — свойство товара, а юридический статус продавца меняет правила расчётов и потому проверяется, а не правится как профиль.
- Из ограничений первой версии модель ломает только мультивалютность, поэтому рядом с каждой суммой сразу хранится валюта; остальное откладывается без последствий.
- Сквозные правила: сумма заказа сходится до копейки, отрицательных остатков не бывает, цена оформленного заказа не меняется, после отправки только возврат, никто не видит чужих заказов, платёж успешен только по подтверждению банка.
Что почитать дальше
- Карта сервисов — как от бизнес-задачи прийти к границам сервисов и их связям.
- Notification Service — уведомления: потребитель событий заказа, каналы, идемпотентность и журнал доставки.
- Catalog Service — каталог товаров: жизненный цикл карточки, доступ, схема базы и контракт.
- Catalog Service: walkthrough — от бизнес-описания до работающего сервиса за один день.
- Order Service — заказы: три агрегата, события между ними, споры и возвраты.