Семь секунд на экране: как мы делали сервис для «всё включен

«Нужно просто проверить, есть ли у гостя “всё включено”».

С этого начался один из наших проектов. Сотрудник бара сканирует QR-код, видит результат и продолжает обслуживание.

Но за этим «просто» появились вопросы. Гость уже выехал? Код перевыпустили? Сервер недоступен или пропуск действительно заблокирован? И как встроить проверку в рабочее место, где уже открыто другое ПО?

Расскажу без названий компании и внутренних данных.

Как устроен процесс

На ресепшн добавляют гостя, указывают тариф и оформляют пропуск с QR-кодом. На станции в баре код отправляется серверу для проверки.

Для сотрудника предусмотрели карточку в правом нижнем углу: гость, номер, даты проживания и статус тарифа. Она появляется на семь секунд. Не нужно открывать отдельный сайт и искать человека вручную.

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

Что под капотом

Backend — Python и Django, база — PostgreSQL, запуск через Gunicorn и Nginx. Для размещения предусмотрели Ubuntu Server 24.04 LTS.

Стартовый ориентир: 2 vCPU, 2–4 ГБ RAM, 30–50 ГБ диска. Здесь преимущественно короткие запросы и проверки по базе. Эти характеристики закладывали при проектировании; за результаты нагрузочного теста их не выдаю.

Основные сущности: гость, тариф, пропуск, рабочая станция и событие сканирования.

Гостя и пропуск разделили. Можно перевыпустить код, сохранив карточку человека. Станции учитываются отдельно — чтобы понимать, откуда приходят проверки, и следить за связью.

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

Сканер — маленькое устройство с нюансами

В режиме клавиатуры сканер просто отправляет символы. Агенту нужно отличить код от обычного ввода и определить, где он начинается и заканчивается.

В требования заложили обработку STX/ETX — служебных символов границ сканирования — и нормализацию русской раскладки.

На схеме всё красиво: «считал → проверил → показал». На станции открыта рабочая программа, курсор стоит в каком-нибудь поле, включён русский язык. Именно в таких условиях и нужно проверять клиент.

Что предусмотрели для Windows

Формат агента — однофайловый EXE под x64. В задании на разработку указали регистрацию станции через API при первом запуске, хранение настроек и логов в ProgramData.

Для результата — семисекундная карточка с цветовой индикацией. Для состояния самого агента — небольшой постоянный индикатор.

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

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

И ещё: heartbeat подтверждает связь с агентом. Он не доказывает, что сканер работает и карточка появляется. Весь сценарий проверяется отдельно.

Что получили

В первой версии собрали серверную основу: панель гостей, генерацию QR, API проверки, блокировку и перевыпуск пропусков, оформление выезда и мониторинг агентов. Для Windows-клиента проработали взаимодействие со сканером, интерфейс и восстановление связи.

Не буду писать «ускорили обслуживание на 40%» — таких замеров не было. Конкретный результат: единый сервис для управления пропусками и проверки их актуального состояния.

Мне в этом проекте интереснее всего разница между тем, что внутри, и тем, что видит сотрудник. У него — несколько строк на семь секунд. За ними — тарифы, сроки, состояния, устройства и обработка сбоев.

Генерация QR оказалась одной из самых простых частей.

А у вас какая «небольшая доработка» в итоге выросла в отдельный сервис?