Telegram-бот и панель диспетчера должны работать с одной записью заказа. Исполнитель принимает задачу и отправляет фотографии через бот; сервер проверяет действие, сохраняет данные и показывает результат в панели. В нашем проекте у диспетчера была канбан-доска на Next.js, у клинера кнопочный Telegram-интерфейс, а фотографии сохранялись в Cloudflare R2. Такая связка помогает держать назначение и фотоотчёт рядом с заявкой. Для запуска нужны учёт исполнителей, правила переходов заказа и обработка отказов. Кнопка «Принять» сама по себе ещё не гарантирует, что задача закрепилась за человеком.
С чего начиналась задача
Диспетчер распределяет выезды, ждёт ответов и собирает фотографии из переписки. Если исполнитель отказался, приходится искать следующего и повторять объяснение. К концу дня нужно восстановить, кто вышел на объект и где лежит отчёт.
Мы собрали для этого собственную платформу: канбан для диспетчера и кнопочный Telegram-бот для исполнителей. Ниже — как она устроена и какие проверки стоит добавить, если делать похожую связку. Историю проекта мы также рассказывали на vc.ru.
Как мы это сделали
Панель диспетчера — канбан-доска на Next.js с TypeScript и Tailwind CSS. Сервер — Node.js и Express с Knex: SQLite для локальной разработки, PostgreSQL в работе.
Для клинеров мы сознательно не делали отдельное приложение: исполнители не хотят его скачивать. Вместо него Telegram-бот, в котором около 90 % действий — inline-кнопки: «Принять», «Начать работу», «Загрузить фото». Текст с клавиатуры почти не нужен. Бот сам напоминает о выездах по утрам и работает на трёх языках: русском, английском и грузинском.
Когда появляется заказ, система ищет свободных исполнителей, которые сейчас online, и предлагает заявку первому по очереди. На ответ даётся 20 минут. Отказ или тишина — заявка уходит следующему, и диспетчеру не нужно никого обзванивать. Этот срок настраивается под процесс компании.
Когда клинер загружает фото «до уборки», происходит сразу несколько вещей: файл уходит в Cloudflare R2, запись сохраняется в таблицу order_photos, для нового клиента создаётся профиль, заказ синхронизируется в Google Sheets для бухгалтерии через syncOrderToSheet. Диспетчер видит в панели готовую галерею. Раз в полгода скрипт удаляет старые фото уборок из хранилища, оставляя документы исполнителей.
R2 выбрали из-за бесплатного исходящего трафика: фотографий много, и они тяжёлые. Официальный @aws-sdk/client-s3 ради одного PUT-запроса тянул бы мегабайты зависимостей, поэтому подпись AWS Signature V4 мы написали сами на модулях Node.js crypto и https — около 300 строк вместе с генерацией presigned URL. Перед повторным использованием такого клиента проверьте подпись, обработку ошибок и совместимость с S3 API R2.
Как проходит одно событие
Для новой реализации сначала нужно записать правила: кто может принять заказ, когда предложение истекает и какое действие разрешено после начала работы. Затем выбирается транспорт Telegram. Bot API поддерживает getUpdates и webhook.
Следующий пример показывает архитектурный шаблон. Это безопасный псевдокод, а не выдержка из найденного проекта:
on_accept(event):
actor = authenticate_executor(event)
command = decode_and_validate_action(event)
transaction:
if event_already_processed(event.key):
return stored_result(event.key)
offer = lock_offer(command.offer_ref)
require offer.executor == actor
require offer.is_active and not offer.is_expired
require order_is_available(offer.order)
assign_order(offer.order, actor)
save_processed_event(event.key)
enqueue_notification(offer.order)
acknowledge_action()Здесь проверка исполнителя и срока предложения происходит на сервере. Блокировка и повторяемый результат защищают назначение при повторном нажатии или одновременном событии.
Какие ошибки проверить до запуска
Перед запуском интеграции проверяем типовые сбои и повторные события:
| Ситуация | Что проверить |
|---|---|
| Исполнитель нажал старую кнопку | Истёкшее предложение отклоняется, человек видит текущий результат |
| Два события пытаются назначить один заказ | В базе закрепляется только одно допустимое назначение |
| Telegram повторно доставил update | Повтор не создаёт вторую заявку и повторное назначение |
| Фото загрузилось в R2, но БД не сохранила запись | Есть восстановление или контролируемая очистка объекта |
| Google Sheets временно недоступен | Принятая задача сохраняется, ошибка учёта видна ответственному |
| Бот не смог доставить предложение | Диспетчер видит ошибку; система не считает сообщение принятием |
Загрузка фотографии тоже требует проверки. Сервер должен знать, к какому заказу относится файл и имеет ли исполнитель право добавлять его. Наличие изображения ещё не доказывает качество уборки. Это оценивает человек.
Что нужно согласовать до разработки
Сначала нужны правила назначения и приёмки: расписание, доступность исполнителей, допустимые переходы, причины отказа, требования к фотографиям и ответственный за исключения. Отдельно решается, что делать, если ни один исполнитель не принял выезд.
Для технического контура нужны бот, сервер, доступы к БД и объектному хранилищу, права менеджера в панели и, при использовании Sheets, разрешение на нужную таблицу. Токены хранятся на сервере. Обезличенный пример для статьи не должен содержать реальные адреса объектов, телефоны и документы работников.
В нашем опубликованном описании есть cleanupOldPhotos, который периодически очищает старые фотографии и сохраняет документы исполнителей. Правило хранения каждого вида файла нужно согласовать отдельно. По одному упоминанию очистки нельзя определить точный срок жизни всех фотографий.
Где остаётся диспетчер
Диспетчер разбирает спорное назначение, перенос выезда, отсутствие доступного исполнителя и неполный фотоотчёт. Человек подтверждает качество работы и решает, можно ли закрыть заказ. Если система показывает лишь факт загрузки, интерфейс должен явно сохранять это различие.
Публичный кейс не описывает применение LLM. Предложение заявки по очереди, срок ответа и сохранение фото можно построить обычной автоматизацией с заданными правилами. Потребность в ИИ появится, если процессу понадобится разбирать свободный текст или оценивать непредусмотренные ситуации; это отдельная задача с собственной проверкой качества.
Как принять результат
На обезличенном тестовом заказе нужно пройти полный путь: предложение исполнителю, принятие, старт, загрузку фото и просмотр отчёта в панели. Затем проверить отказ, истёкшее предложение и повторное нажатие. Для восстановления после сбоя полезны отдельные проверки хранилища и синхронизации учёта.
Эффект внедрения оценивают по одинаковым периодам до и после: время назначения, число ручных контактов диспетчера, доля задач без отчёта и количество исправлений. Подтверждённых замеров экономии в найденном источнике нет, поэтому процент сокращения нагрузки здесь не приводится.
Если у вас заявки уже распределяются через Telegram, принесите один обезличенный маршрут заказа: от назначения до приёмки фото. По нему можно определить поля панели, переходы и ситуации, которые должен разбирать диспетчер.
Связанные материалы: практические кейсы Geron Labs и исходная статья о клининге.