Продолжение статьи «От монолита и чатов к FMS и FMS App». Читать первую часть не обязательно — нужные вводные дам по ходу, но с ней будет вкуснее.
Всем привет! Меня зовут Даня Сухарев, я директор по продукту внутренних сервисов в каршеринге Ситидрайв. Герой этой статьи — один из таких сервисов: FMS, Fleet Management System. Полтора года назад, ещё в роли продакта FMS, я написал первую статью — про то, как мы за три квартала с нуля построили систему управления автопарком и мобильное приложение FMS App, чтобы победить два монолита, чаты и онлайн-таблички.
Минутка контекста для тех, кто первую часть пропустил. Каршеринг — это не только приложение, в котором клиент берёт машину. За кадром живёт большая полевая операционка: каждое авто нужно мыть, заправлять, перегонять, чинить и иногда откапывать из сугроба. Занимаются этим сотни исполнителей — подрядчики, самозанятые, штатные техники. А Диспетчерская, которая будет часто мелькать в тексте, — это старая админка, через которую всем этим управляли до FMS.

Та статья заканчивалась фразой «FMS — это только начало пути». Перечитывая её сейчас, понимаю: тогда я описал процентов десять того, что мы в итоге построили.
Время честных признаний. На момент публикации первой части в FMS App жил ровно один боевой флоу — стационарная мойка. Один. Вылизанный, с кастомной камерой и динамическими опросниками, но один. Всё остальное — заправки, перегоны, шиномонтаж, поиск авто — продолжало крутиться в старой Диспетчерской, чатах и табличках. То есть в том самом хаосе, с которым мы так яростно боролись.
Сегодня в FMS — 52 типа задач в девяти доменах: от заправки до «Вытащить из сугроба» (да, это официальный тип задачи, и зимой без него никуда). Через систему ежедневно проходят тысячи задач, их выполняют сотни исполнителей.
Историй в этой статье будет две. Первая — про конструктор задач: инструмент, благодаря которому большинство типов задач теперь собирается вообще без разработки. Вторая — про три флоу, которые в конструктор не влезли и потребовали честной кастомной разработки: поиск авто, заправки и задачи техников. Именно связка «конструктор для типового + руки для сложного» позволила нам не растянуть этот путь до 2029 года.
И ещё одно. В первой части я обещал, что следующим шагом станет автоматический диспатч. Его до сих пор нет — и в конце расскажу почему. Спойлер: всё, что вы прочитаете ниже, — на самом деле подготовка к нему.
Поехали! 🚀

Часть 1. Похмелье после MVP
Запуск прошёл хорошо: мойки поехали через приложение, эффективность заметно выросла, метрики стали честными. План дальше выглядел элементарно: берём следующий тип задачи и переносим в FMS. Потом ещё один. И ещё пятьдесят.
Вот только вспомним, что значило «перенести тип задачи» в архитектуре образца первой статьи:
написать микросервис-стратегию — так мы называем сервис с бизнес-проверками задачи (можно ли создать, можно ли взять, корректно ли выполнена);
собрать флоу этапов;
нарисовать и настроить экраны в приложении;
составить опросники осмотров;
всё это протестировать и выкатить.
Первый флоу — мойка — занял у нас три квартала. Справедливости ради, вместе с ним мы строили всю платформу: 11 микросервисов, приложение, процессы. Но даже если оптимистично закладывать две-три недели на каждый следующий тип задачи, умножаем на полсотни типов — и получаем годы чистой разработки. А бизнес не ждёт: каждую неделю прилетало «а можно такую же задачу, но с перламутровыми пуговицами» — чуть другой осмотр, другой порядок этапов, своя специфика в каждом городе.
Какое-то время мы честно пытались взять темпом: перенесли заправки, перегоны, задачи техников и поиск авто — по образу и подобию мойки, копипастой и характером. Стало быстрее, но принципиально ничего не изменилось: каждый новый тип задачи или правка старого — это релиз бэкенда, иногда релиз приложения и всегда — очередь к разработчикам.
Разработка стала бутылочным горлышком собственного продукта. Обидно: систему строили ради скорости, а самым медленным звеном оказались мы сами.
Часть 2. Инсайт: любая задача — это кубики. Почти любая
В какой-то момент мы сели и разложили все типы задач старой Диспетчерской на этапы. Все сто с лишним.
Выяснилось то, что задним числом кажется очевидным: 90% любой задачи состоит из одних и тех же блоков. Доехать до авто. Осмотреть и сфотографировать. Сделать целевое действие. Подтвердить результат. Вернуть авто на линию. Разница между «мойкой» и «перегоном» — не в коде. Она в наборе и порядке этапов, в вопросах осмотра и в проверках.
Теперь вспомним архитектуру из первой статьи — для тех, кто не читал, перескажу в двух словах. С самого начала весь флоу задачи у нас описывался JSON-объектом, который сервер отдаёт приложению: этапы, действия, опросники с условной логикой (нашёл повреждение — фото становится обязательным). В первой части я показывал эти схемы целиком, с примерами. Приложение изначально не знало слова «мойка» — оно умело рендерить этапы, вопросы и кнопки. Мы специально так проектировали, чтобы менять флоу без релиза мобилки.
Ирония в том, что no-code у нас был для приложения, но не для людей. Эти JSON-схемы руками собирали разработчики. Конфигурация вместо кода — да, только конфигурировать могла всё та же небольшая команда бэкенда.
Отсюда решение, которое перевернуло весь роадмап. Точнее, две его половины:
Типовые задачи перестаём переносить руками — строим машину, которая переносит задачи. Так появился конструктор.
Оставшиеся флоу — те самые «не 90%» — делаем по-честному, кастомом. Освободившимися руками.
Дальше по порядку про обе половины.
Часть 3. Конструктор задач
Конструктор — это no-code интерфейс внутри FMS, в котором новый тип задачи собирается как из «Лего»: этапы, экраны, опросники, условия, связи с другими задачами и даже деньги. Без разработчиков, без релизов, без «у нас бэклог, приходите в Q5».

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

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




Цепочки задач. Завершение одной задачи автоматически рождает следующую. Диагностика нашла проблему — создаётся мелкий ремонт. Мойка выполнена — создаётся задача на валидацию мойки. Раньше такие связки жили в головах координаторов и чатах, теперь это просто настройка.

Тарифы. Сколько исполнитель получит за задачу — настраивается там же, в админке тарифов.
Технически под капотом ничего мистического: конструктор — это редактор всё тех же JSON-схем флоу и опросников. На выходе — конфигурация, которую сервер отдаёт приложению. Бэкенд и мобилка при этом не меняются — именно поэтому 52 типа задач не потребовали 52 релизов мобилки. Специфические проверки для отдельных задач по-прежнему живут в микросервисах-стратегиях, но большинству задач хватает стандартных кубиков.
Эффект проще всего показать на времени. Раньше новый тип задачи — это недели разработки и место в очереди бэклога. Теперь — десять минут. И главное, кто эту работу делает: не разработчик и даже не продакт, а операционная команда. Люди, которые лучше всех знают процесс «на земле», впервые могут менять его сами.
Часть 4. Три флоу, которые в конструктор не влезли
Теперь вторая история. Конструктор прекрасен, пока задача складывается из стандартных кубиков. Но есть флоу, где сама механика работы другая — и никакими опросниками её не соберёшь. Таких у нас оказалось три, и каждый потребовал полноценной разработки с кастомными экранами.
Поиск авто
Иногда машину нужно найти в плотной застройке: во дворах, на закрытых парковках, среди десятков похожих авто. Такой поиск — отдельная дисциплина со своими профессионалами.
Флоу выглядит так: исполнитель видит на карте координаты машины и её фотографии, едет в район — и дальше начинается детектив. Обходишь дворы, заглядываешь за углы. И тут главный инструмент — сканер. Видишь похожую машину — открываешь сканер в FMS App, наводишь камеру на номер, приложение распознаёт ГРЗ и сразу отвечает: наша или нет, та машина или соседняя. Нашёл — отмечаешь фактическое местоположение. Кроме сканера, есть поиск по фото: в карточке машины лежат её свежие фотографии с последних осмотров — опознать по ним авто во дворе сильно проще.

Почему это не собрать в конструкторе, думаю, очевидно: кастомная карта, камера с распознаванием, своя логика работы с картой.
Заправки
Заправка звучит как самая простая задача на свете: приехал, вставил пистолет, уехал. На деле это семейство из семи типов задач со своей внутренней логистикой. Есть срочная и целевая заправки. Есть заправка из канистры и «заправка канистр» — задача, которая обслуживает другие задачи. И есть моя любимая механика — сопутствующая заправка. Исполнитель делает любую основную задачу и видит: баку нужна заправка. Кнопкой в приложении он создаёт себе задачу-прицеп — заправить, раз уж всё равно рядом с машиной. Система сама следит за уровнем топлива и даёт создать сопутствующую только тогда, когда она действительно нужна.
Кастомной разработки здесь тоже хватило, и почти вся она о том, чтобы избавить исполнителя от лишней ручной работы. Флоу такой: взял задачу → нажал «Выбрать АЗС» — приложение показывает заправки на карте → приехал, выбрал колонку в приложении → нажал «Старт заправки» → приложил отчёт. Расчёты за топливо проходят на стороне системы. Эффект почувствовали быстро: заправок делаем заметно больше меньшими силами, а машины меньше простаивают в деактивации.


Задачи техников
Флоу выше выполняют в основном самозанятые. Но есть и штатные полевые сотрудники — техники, и их мир устроен иначе. У техника есть смена и есть техничка — служебный автомобиль с инвентарём и расходниками. По сути, передвижной мини-склад.
Смена техника — отдельный флоу: принял техничку, пополнил со склада, поехал по задачам. Каждая деталь и жидкость на борту — учтённая ТМЦ (товарно-материальная ценность) с QR-кодом: установил на машину — отсканировал — списалось. Раньше весь этот учёт жил в xls-файлах. Теперь в приложении живёт аналог складского ТСД — только склад ездит по городу. Под капотом — интеграции со складами, списания прямо в задаче и автоматические перемещения ТМЦ между авто.

А самая красивая механика здесь — диагностика. Техник приезжает на неё, не зная заранее, что именно чинить: в приложении его ждёт большой автоматический чек-лист. Дальше срабатывают цепочки из части 3: отметил «не горят фары» — система тут же создаёт ему следующую оплачиваемую задачу на замену, а новая фара при закрытии спишется как ТМЦ. Осмотр сам превращается в план работ, без координатора.

Плюс у самой технички есть собственные задачи: пополнение со склада, пополнение из другой технички, «доехать до технички». Да, у задач есть свои задачи — я предупреждал, что операционка каршеринга глубже, чем кажется.
Часть 5. Что под капотом
Теперь немного для тех, кто пришёл за технической частью.
С момента первой статьи платформа выросла с 11 микросервисов до нескольких десятков — плюс шлюзы, фронт админки и вспомогательные сервисы. Всё по-прежнему на Go, крутится в Kubernetes, у каждого сервиса своя PostgreSQL. Снаружи общаемся по REST API, между сервисами — gRPC, асинхронные события гоняем через Kafka.
Сервисы нарезаны по доменам, а не по техническим слоям — узкие и предметные, по одному ограниченному контексту на сервис: машины, задачи, тарифы.
Типичный поток такой. Синхронно — gRPC: скажем, один сервис запрашивает у другого данные по автомобилю. Асинхронно — Kafka: задача сменила статус, событие улетело в топик — и соседний сервис завёл валидационную задачу. Это та самая цепочка «мойка → валидация» из части 3 — вид со стороны бэкенда.

Каждый сервис собран по одному шаблону, feature-first: внутри фичи лежат бизнес-логика, доступ к данным, транспортный слой и модели.
Ключевое правило — зависимости через интерфейсы: бизнес-логика принимает абстракции чтения и записи, а не конкретные типы, поэтому юнит-тесты живут без базы. CI у всех сервисов общий: линт, покрытие, проверка миграций.
С наблюдаемостью всё по-взрослому: каждый сервис из коробки отдаёт метрики и логи в единое хранилище. Сверху два уровня дашбордов, подробный по каждому сервису и общая сводка по всей платформе.
По периметру — интеграции со смежными системами компании. И пунктиром на схеме — диспатч, про который в самом конце.
Часть 6. 52 типа задач: полная карта
Сложим всё вместе. Девять доменов, которые сегодня живут в FMS:
Перегоны и релокации — самый большой домен: вернуть авто в зону, перегнать на ТО, доставить новые машины в город, релоцировать парк между городами.
Заправки и незамерзайка — про них вы уже всё знаете.
Сервис и диагностика — диагностика, мелкий ремонт, замена АКБ, оклейка.
Логистика исполнителей и техничек — смены, пополнения, довоз подрядчиков.
Мойки — с них всё началось: стационарная, приоритетная, срочная и отдельная для «электричек».
Шиномонтаж — включая сезонный. Представьте пиковую неделю, когда «переобуть» нужно весь парк.
Поиск авто — детектив из части 4.
Клиентские и полевые — выезд к клиенту и легендарное «Вытащить из сугроба».
Служебные — статусы смены и компенсации.



Исполнитель может вести до трёх задач одновременно — на скрине «Моей смены» их как раз три. Так машины обслуживаются быстрее.
И маленькое признание. Все эти флоу существуют ради автоматизации и экономии — но мы следим и за тем, чтобы приложение было просто красивым, и периодически делаем редизайн. FMS App — инструмент, который исполнитель открывает десятки раз за смену: работать целый день в аккуратном приложении приятнее, а системе, которая выглядит собранно, больше доверяют. Свежий редизайн обновил карточки задач и навигацию — их вы и видите на скринах.
А что Диспетчерская? Оставшиеся её задачи переносятся в FMS.
Часть 7. Вид из офиса: задача как на ладони
В первой статье я жаловался: во времена Диспетчерской о задаче мы знали ровно два факта — когда исполнитель начал и когда закончил. Всё остальное тонуло в чатах.
Теперь у каждой выполняемой задачи есть карточка в админке, где видно всё. Этапы с таймингами: когда взял, когда прибыл, сколько занял осмотр. Трек движения исполнителя на карте: как, куда и сколько он ехал, заезжал ли на мойку. Все фото и видео осмотров, заполненные опросники — по каждому этапу.


После закрытия задачи каждый осмотр складывается в историю карточки авто — по датам и исполнителям. Через год можно поднять любую задачу и посмотреть, кто, когда и в каком состоянии оставил машину.
Что это даёт на практике: спорные ситуации с исполнителями разбираются по факту, а не по переписке; контроль качества опирается на фото и трек, а не на честное слово; а метрики показывают не «задача заняла четыре часа», а из чего эти четыре часа состояли.
Часть 8. Вокруг задач выросла экосистема
Пока число задач росло, FMS оброс модулями, о которых в первой статье не было ни слова.
Исполнители. Полноценный реестр подрядчиков и самозанятых: стаж, навыки, типы выполняемых задач, история. Отдельно — мойки как объекты системы: у каждой свой профиль и часы работы, плюс связки «мойка — исполнитель», чтобы система понимала, кто куда может везти авто. И биллинг: расчёты с исполнителями за задачи считаются прямо в FMS.

Интеграция с 1С. При закрытии задачи автоматически списываются ТМЦ: кто, когда, что и в какое авто установил или залил. Звучит скучно, но это тот случай, когда бухгалтерия впервые сказала нам спасибо.
Модерация. Выполненные задачи проходят контроль качества.

Карточка авто и модели. Карточка из первой статьи выросла в полный профиль машины, а рядом появился модуль моделей и комплектаций: характеристики правятся массово на весь парк, а не по одной машине.
Часть 9. Планы: Ремонты и Диспатч
Расскажу про два больших фронта, которые в работе прямо сейчас.
Ремонты. Последний крупный контур, который ещё живёт в старой админке, экселях и чатах. Переносим его в FMS целиком: канбан ремонта по этапам СТО (новый → входной контроль → ждёт ремонта → в ремонте → готов к проверке), карточка ремонта со сроками, связанными задачами и лентой событий, учёт пропускной способности сервисов.


Диспатч. Теперь — обещанный ответ, почему его до сих пор нет. Всё просто: полтора года назад диспатчить было нечего. Чтобы система могла сама раздавать задачи, ей нужно знать все задачи (а не один флоу мойки), всех исполнителей с их навыками и цену каждой операции. Ровно это мы и собирали полтора года — и теперь ингредиенты на месте. Сегодня исполнитель сам выбирает задачу с карты — это уже неплохо, но система знает больше, чем человек: где какие задачи, кто с какими навыками свободен, сколько стоит каждая операция. Хотим перевернуть модель: не исполнитель ищет задачу, а задача находит исполнителя — по гео, навыкам, загрузке и бюджету операции. Под капотом это уже не CRUD, а честная алгоритмика (привет, задача маршрутизации) плюс отдельный квест: сделать так, чтобы людям, привыкшим выбирать самим, автоназначение было выгодно. Если долетим — это тема для третьей статьи.
Вместо заключения


Главный урок этих полутора лет: платформа бьёт фичи. Мы могли ещё пару лет добросовестно переносить задачи по одной — и со стороны это даже выглядело бы как прогресс. Вместо этого мы остановились, построили конструктор и перестали быть бутылочным горлышком собственного продукта.
Но есть и второй урок, не менее важный: платформа не отменяет рук. Три самых сложных флоу — поиск, заправки, задачи техников — мы всё равно писали кастомом, и это нормально. Смысл конструктора не в том, чтобы разработчики стали не нужны, а в том, чтобы они не тратили себя на типовое.
Спасибо команде, которая всё это построила: Руслан Ибрагимов, Вероника Репина, Георгий Гулуа, Кристина Ширяева, Никита Заикин, Владислав Иванов, вся команда Proil, Константин Свиридов, Олеся Багаева, Данил Севрюков, Кристина Ким, Александр Молявин, Александр Зильбер. И отдельное спасибо тем, кто каждый день выполняет все эти задачи в полях.
Вопросы, скепсис и «а как у вас с…» — жду в комментариях. Про диспатч и ремонты расскажу в следующей серии 🚀

