ПРОЕКТ
Совместные заказы кофе для команды компании
Внутренний сервис для заказов кофе вскладчину: оптовый каталог, сводная поставка, автозаполнение корзины поставщика, оплаты, приёмка и выдача.
Задача
В офисе IT-компании сотрудники заказывают кофе вскладчину у оптового поставщика: в зерне или молотый, а также чай и сопутствующие товары. Раньше заявки собирались в общей Google Таблице. Организатор по этим строкам вручную собирал корзину в оптовом кабинете Tasty Coffee, считал суммы и сверял оплаты.
В таком процессе легко ошибиться: перепутать помол или фасовку, потерять строку, не заметить, что позиции уже нет у поставщика. Понять, на каком этапе конкретный заказ и оплачен ли он, тоже было непросто.
Что я сделал
Я спроектировал и разработал сервис «Кофе вместе» в сентябре и октябре 2026 года: интерфейс сотрудника, админку, интеграцию с поставщиком, базу и развёртывание. Сервис работает в production на сервере студии в Docker, за Nginx с TLS-сертификатом Let's Encrypt, и я его сопровождаю.
Как это работает
Заказ сотрудника
Сотрудник начинает вводить название сорта и выбирает точную позицию из подсказок. Произвольный текст отправить нельзя, если каталог опубликован. Для кофе обязательно выбрать формат, в зерне или молотый, затем фасовку и количество. Форма показывает только те сочетания, которые реально можно положить в корзину поставщика, а если оптовый API передал остаток, не даст заказать больше.
Цен в форме нет. Сумма появляется в карточке заказа после того, как организатор сверит настоящую корзину поставщика. В истории видно, на каком этапе заказ и что нужно сделать дальше. Сайт можно установить на телефон как PWA.
Сводная поставка и корзина поставщика
В админке заявки копятся в очереди. Одной кнопкой организатор объединяет их в поставку, а сервис сам заполняет корзину оптового кабинета Tasty Coffee: очищает её и добавляет сохранённые строки. Если после этого поставку поправили, корзину можно заполнить заново, и старые количества в ней не останутся. Позицию, которую не удалось перенести, сервис помечает с причиной, а организатор добавляет её вручную и подтверждает галочкой. Оформление и оплата у поставщика остаются ручными: интеграция никогда не нажимает финальную кнопку.
Поздние заявки можно добавить в ещё не принятую поставку. Поставку до приёмки можно исправить, выгрузить повторно или отменить целиком, тогда заявки вернутся в очередь.
Оплата
Организатор фиксирует суммы по фактической корзине после скидки поставщика и открывает сбор. Каждый сотрудник видит свою сумму и ссылку на оплату, отмечает «Я оплатил» и при желании прикладывает скриншот. Оплаченным заказ становится только после того, как организатор сверит поступление денег. Проверенные платежи можно подтвердить по одному или группой до 100 заказов. Отметку «Заказан» сервис разрешит поставить только после проверки всех оплат и реального размещения заказа у поставщика.
Приёмка и выдача
Когда приходит доставка, организатор принимает её построчно: получено полностью, частично, нет в наличии или пришла замена. Если всё на месте, хватает одного действия с подтверждением. Сервис сам считает результат по каждому сотруднику. Выдать можно только полностью полученный заказ, остальные уходят в очередь недостачи.
Работа в админке построена вокруг четырёх очередей: новые заявки, проверка оплат, выдача и недостача. Заказы и поставки выгружаются в CSV и PDF.
Переход со старой таблицы
Пока часть сотрудников ещё пользовалась Google Таблицей, нужен был мягкий переход. Я сделал импорт с предварительным просмотром: каждая строка проверяется на имя и фамилию, точный вариант каталога и количество, а ошибка блокирует перенос, похожий товар не подставляется. Цены и отметки об оплате из таблицы не переносятся. Журнал импорта связывает заказ с номером исходной строки, поэтому повторная загрузка не создаёт дубликатов, а изменённая строка показывается как конфликт. Отдельная сверка сравнивает импортированные заявки с корзиной, собранной вручную, и ничего в ней не меняет.
Инженерные решения
Каталог и точные варианты
Каталог синхронизируется с оптовым API Tasty Coffee вручную или по расписанию, до трёх запусков в неделю. Расписание проверяет сервер, держать админку открытой не нужно, а неудачная попытка не стирает опубликованный каталог. Для каждого варианта база хранит точное соответствие товару, предложению, помолу и упаковке в API поставщика. Этот ключ проходит от заявки до строки корзины, поэтому сервису не приходится угадывать товар по названию.
Безопасность
Все внешние запросы проходят через Nginx и gateway на Node.js. Gateway удаляет присланные клиентом заголовки идентичности и сам определяет пользователя по подписанной HttpOnly cookie. Сессия администратора живёт 8 часов, после пяти неудачных попыток входа с одного адреса вход блокируется на 15 минут, пароль хранится только как scrypt-хеш. Скриншоты оплат лежат в приватном bucket Yandex Object Storage и открываются только через gateway. Логин оптового кабинета хранится в закрытых переменных сервера, токен существует только в памяти. Запросы к поставщику и к Google Таблице идут через внутренние прокси, недоступные из публичной сети.
Работа на небольшом сервере
Приложение написано на React и TypeScript и работает в рантайме Cloudflare Workers с D1 API поверх локальной базы SQLite в Docker volume. Сервер общий, с 2 ГБ памяти, поэтому у контейнеров жёсткие лимиты памяти, а при обновлении старый экземпляр останавливается до запуска нового. Если сборке не хватает памяти, образ собирается вне сервера и загружается готовым.
Результат
Сервис заменил общую таблицу и ручную сборку корзины. Заявки сразу привязаны к точным вариантам каталога, поэтому меньше ошибок с помолом, фасовкой и количеством, а статус заказа и оплаты виден и сотруднику, и организатору. По моей оценке, сервис экономит сотрудникам и администраторам в сумме больше 100 часов рабочего времени в месяц. Это оценка, а не результат отдельного замера.
Обсудим вашу задачу
Если в вашей команде заказы, оплаты или заявки до сих пор живут в таблице и переносятся руками, расскажите, где уходит больше всего времени. Обсудить похожую задачу.
Связанные направления: внутренние рабочие системы, API-интеграции и автоматизация таблиц. Почитать: когда переходить от таблиц к системе.
Те же технологии, другие задачи
Сети, серверы, бэкенд и микроконтроллеры, связанные с интерфейсом управления климатом и параметрами теплиц.
Сервисные операцииЗвонки, CRM и работа сервисной командыБэкенд, показатели команды, TV-дашборды, создание лидов после IVR-звонков и AI-анализ обращений.
HR и онбордингОнбординг сотрудников как единый процессРоли, документы, обучение и напоминания в приложении для онбординга с интеграциями Google Workspace.