Deadline.by
Deadline.by

Опишите задачу — посчитаем смету и сроки за день

реальный проект

Мини-приложение для заказа в двух мессенджерах

Проект показываем обезличенно: без названия, отрасли и ссылок

Заказчик продавал товар по каталогу, а заявки принимал в переписке: клиент присылал фотографию документа на изделие, менеджер вручную искал позиции и вручную заводил заказ в учётную систему. Мы собрали мини-приложение, которое живёт внутри двух мессенджеров одновременно и делает то же самое само: распознаёт документ, подбирает позиции, оформляет заказ и отдаёт его в CRM и в учётную систему.

Кейс — Мини-приложение для заказа в двух мессенджерах
React · Vite · TanStack QueryNestJS · Prisma · PostgreSQLRedis · очередь обменовРаспознавание документовИнтеграции: CRM, учётная система, оплата

Задача

  • Подбор по фотографии документа занимал у менеджера минуты на каждую заявку, а пик приходился на часы, когда менеджеров меньше всего. Заявки жили в трёх мессенджерах и в голове у сотрудника, остатки сверялись руками, оплата собиралась переводами. Нужен был один вход, который работает круглосуточно и сам кладёт заказ туда, где он должен оказаться.

Что сделали

  • Мини-приложение на одной кодовой базе для двух мессенджеров: общий фронтенд, разные слои авторизации и разные способы открытия
  • Распознавание документа по фотографии с камеры: подготовка снимка, извлечение полей, оценка уверенности по каждому полю
  • Подбор позиций по распознанным данным с ручным подтверждением там, где система не уверена
  • Обмен с CRM: заявка создаётся сразу, с источником и историей обращения, и попадает в общую воронку
  • Обмен с учётной системой: остатки и цены тянутся из неё, заказ уходит обратно, справочники сверяются по одному ключу
  • Подключение онлайн-оплаты и рассрочки через сторонние сервисы, с раздельной обработкой подтверждений
  • Работа в стране, где прямой доступ к API мессенджера с сервера закрыт: доставка обновлений через прокси и опрос вместо вебхуков

Результат

  • Заказ оформляется целиком внутри мессенджера — без перехода на сайт и без установки приложения
  • Заявка попадает в CRM в момент отправки, а не после того, как менеджер её перепишет
  • Подбор по фотографии занимает у клиента секунды и не зависит от рабочего времени
  • Одна кодовая база обслуживает обе площадки: правка интерфейса выкатывается сразу в оба мессенджера

Почему два мессенджера, а не один

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

Практический выигрыш проявился не на запуске, а через месяц. Любая правка витрины, каталога или сценария заказа делается один раз и выкатывается сразу в обе площадки, а платформенные различия остаются в изолированных файлах, которые почти не меняются.

Распознавание, которое не притворяется идеальным

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

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

Обмен с внешними системами и сбои

У каждой сущности в проекте один хозяин: цены и остатки живут в учётной системе, клиент и сделка — в CRM, платёж — на стороне провайдера. Мини-приложение не хранит собственных справочников, поэтому расхождений между двумя реальностями просто не возникает. Каждый обмен идёт с ключом идемпотентности: повтор с тем же ключом ничего не создаёт, и двойное нажатие кнопки не превращается в два заказа.

Отдельно проектировалось поведение при недоступности внешней системы. Заказ принимается всегда: он ставится в очередь, пользователь получает подтверждение, а обмен повторяется по нарастающей задержке. Если и это не помогло, обмен попадает на экран ручного разбора, где его повторяют кнопкой. Примерно четверть времени интеграции ушла именно на сценарии, где что-то пошло не так, и это нормальная пропорция.

Ограничение, которое всплыло на боевом контуре

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

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

Заполнить бриф