Задача
Ristorante Gina, ресторан морской кухни, работал на бумаге: официанты записывали заказы от руки, кухня и бар читали одни и те же листки, а счёт подсчитывали на кассе. Владельцы хотели единую систему для зала, кухни и управляющего, построенную так, чтобы позже она могла обслуживать не один ресторан.
Что я сделал
Я создал RistoFlow — веб-приложение для управления рестораном — и запустил его с Gina в качестве первого ресторана.
- План зала — столы сгруппированы по залам, с состояниями в реальном времени (свободен, занят, заказы готовятся, заказы готовы) и числом гостей, которое указывается при открытии стола.
- Заказы с телефона — официанты собирают заказ по категориям, с комментариями к каждому блюду. При отправке он автоматически делится между кухней и баром, и каждый участок видит только свою работу.
- Экран кухни — экран обновляется каждые 5 секунд, переводит каждый заказ из статуса «отправлен» в «готовится», «готов» и «подан», подсвечивает задержки и печатает чек шириной 72 мм, при необходимости автоматически.
- Счета — сумма по столу с платой за куверт, предварительный счёт для печати и закрытие. Начиная с версии 1.5.0 цены видит только управляющий, который закрывает счёт, а не официанты и не кухня.
- Редактор меню и отчёты — категории, цены (в том числе за 100 г), мгновенная отметка блюд «нет в наличии», а также дневная выручка, число гостей и самые продаваемые блюда.
- Четыре роли, много ресторанов — администратор платформы, управляющий, официант и кухня. У каждого ресторана свои пользователи и данные, которые хранятся отдельно.
- Пакет для локального сервера — установщик, который разворачивает приложение с реальным меню и столами Gina на компьютере внутри ресторана, вместе со скриптом ежедневного резервного копирования.
Технологии
PHP 8 и MySQL с PDO, чистый JavaScript без внешних библиотек. Все запросы обрабатывает один эндпоинт API. Сессии с CSRF-токенами и хешированные пароли. Меню и винная карта Gina загружены в 9 категорий.
Почему именно так
Я оставил приложение без зависимостей и использовал простой polling вместо websockets, чтобы оно работало на обычном виртуальном хостинге. Тот же выбор упростил перенос на локальный сервер: заказы и счета продолжают работать по Wi-Fi ресторана, даже когда пропадает интернет.


