Таксосервис кажется простым: пассажир заказал, водитель приехал. На деле это четыре приложения, которые должны видеть одну и ту же реальность в одну и ту же секунду. Если они рассинхронизировались — пассажир ждёт машину, которой уже нет, а водитель едет на отменённый заказ.

Разбираем на реальном проекте — «Авто-Таксист», локальный таксопарк, который ушёл от диспетчера на телефоне и комиссий агрегаторов. В проде: 1000+ пользователей, 100+ водителей.

01 · Зачем парку своя система вместо агрегатора

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

Задача была не «сделать ещё один Uber», а собрать систему, которой парк сам управляет и в которой сам устанавливает правила — без чужой комиссии.

02 · Четыре роли — но одна система

Сервис состоит из четырёх частей, и это не четыре отдельных проекта, а одна система с общим бэкендом:

  • Приложение пассажира. Вход по SMS, заказ с точками на карте и расчётом цены до поездки, отслеживание машины вживую.
  • Приложение водителя. Выход на линию одной кнопкой, лента заказов с тарифом и ценой, карта с пинами, экран заработка.
  • Операторская панель. Живая карта водителей и заказов, ручное создание и назначение — для звонков и сложных случаев.
  • Админка владельца. Водители (с модерацией новых), заказы, тарифы, зоны города, метрики и выручка — вся сеть в одной сводке.

Все четыре работают поверх общего бэкенда: Node.js, Express, MongoDB, Redis. Мобильные — на Flutter (одна кодовая база на iOS и Android), панели — на React.

03 · Сердце всего: real-time

Главная инженерная задача такого проекта — реальное время. Координаты водителей, появление заказа, его принятие, отказ, статус поездки — всё обновляется вживую у пассажира, водителя, оператора и в админке одновременно. Это построено на Socket.IO: одно событие расходится по всем подключённым ролям сразу.

Отдельная боль, которую важно закрыть — честные статусы. «Водитель онлайн» должно значить, что он реально на линии сейчас, а не «заходил два часа назад». Протухшие статусы — частая болячка таких систем; мы сделали так, что статус отражает текущее состояние, а не последнее известное.

Почему это сложно. Real-time — это не «добавить вебсокеты». Это переподключение при потере сети, согласованность состояния между ролями, борьба с гонками (двое водителей жмут «принять» одновременно) и с устаревшими данными. Именно здесь живёт качество таких систем.

04 · Распределение заказов — это отдельный сервис

Наивная реализация — «показать заказ всем водителям». На практике это хаос. Правильно — отдельный сервис распределения, который:

  • предлагает заказ подходящим водителям (по зоне подачи, тарифу, статусу);
  • даёт время на принятие;
  • если отказались — передаёт дальше, ведя список отказавшихся, чтобы не предлагать повторно.

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

05 · Оператор как страховка автоматики

Не всё решает автоматика. Звонок от пожилого пассажира, сложный адрес, спорная ситуация — здесь нужен человек. Поэтому оператор может создать заказ вручную, назначить водителя, поправить или отменить — поверх той же real-time системы, а не в отдельной программе.

Хорошая система автоматизирует 95% и оставляет человеку рычаги на оставшиеся 5%. Полная автоматизация без «ручного руля» ломается на первом нестандартном случае.

06 · Что забрать из этого кейса себе

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

  1. Несколько ролей — это одна система, а не несколько проектов. Общий бэкенд и общий источник правды экономят на стыках.
  2. Real-time — это архитектурное решение, а не фича. Закладывайте его с самого начала, если роли должны видеть общую картину.
  3. Логику распределения выносите в отдельный сервис. «Показать всем» — не стратегия.
  4. Оставьте человеку ручное управление. Оператор поверх автоматики спасает в нестандартных случаях.

Задумали систему с несколькими ролями и реальным временем? Опишите задачу — разложим её на части и дадим смету по архитектуре, как в этом кейсе.