Служба доставки цветов, еды и документов, 12 курьеров на линии.
Диспетчер раскидывал заказы в общем чате, курьеры отписывались «взял».
Часть заказов брали вдвоём, часть не брал никто - сообщение улетало вверх и терялось.
Где курьер сейчас, диспетчер знал только со слов самого курьера.
Клиенты звонили в офис узнать, где заказ, на это уходила половина дня оператора.
Выплату за смену считали вечером в тетради по скриншотам из чата, и курьеры с этой цифрой регулярно спорили.
Попросили приложение курьеру и ссылку клиенту, чтобы общий чат перестал быть системой учёта.
Mini App на React внутри Telegram, бот и серверная часть - Python, aiogram 3 и FastAPI, база PostgreSQL, карта на MapLibre и тайлах OpenStreetMap.
Экран курьера - список своих заказов на смену: адрес забора, адрес доставки, окно времени, комментарий диспетчера.
Кнопка одна и меняется по ходу - взял, приехал на забор, забрал, приехал к клиенту, передал.
При передаче приложение просит фото, снимок уходит на сервер вместе с координатами и временем и прикрепляется к заказу.
Маршрут строится по точкам смены с учётом окон времени, порядок курьер может поправить рукой.
Координаты берутся не из браузера: на смену курьер включает боту живую геопозицию Telegram, и точка живёт, даже когда приложение закрыто.
Так-же трансляция гаснет сама в конце смены - своего фонового демона в приложении нет, и телефон доживает до вечера.
Оффлайн-очередь: в подвалах и лифтах связи нет, статусы копятся в локальной базе и уходят пачкой при появлении сети.
Порядок статусов сервер сверяет по времени события на телефоне, а не по времени, когда пакет до него доехал.
Клиенту уходит короткая ссылка - карта с точкой курьера, расчётное время прибытия и телефон, ставить ничего не нужно.
Диспетчер видит всех на одной карте, свободный заказ назначает в один клик, курьеру сразу падает уведомление.
Двойного взятия больше нет: заказ уходит из общего пула первому, кто нажал, у остальных он просто пропадает из списка.
Выплата считается по закрытым заказам - ставка за смену, доплата за заказ и за километры сверх зоны, курьер видит цифру у себя.
Заказы перестали дублироваться и теряться, общий чат оставили только для разговоров.
Оператор больше не отвечает на «где мой заказ» - за первый месяц таких звонков около десяти, раньше столько набегало до обеда.
Спор о выплатах закрылся: курьер видит свою смену по заказам и километрам, то-есть считать вечером уже нечего.
Диспетчер держит смену на одной карте и назначает заказ за пару секунд.
Исходники, админка и инструкция остались у заказчика, ставки и зоны он правит сам.
Уже после приёмки добавил отметку о неудачной доставке с причиной - клиента нет дома, адрес не тот, отказ на месте.
Демо приложения и скриншоты экранов приложены к работе.