Овербукинги, которые никто не мог предотвратить.
Управление несколькими пляжными площадками в общей таблице — это не проблема рабочего процесса. Это проблема согласованности данных, переодетая в одежду проблемы рабочего процесса. Два менеджера открывают один и тот же лист одновременно, доходят табуляцией до одного и того же слота и жмут «сохранить» — один из них всегда выигрывает, а второй так и не узнаёт, что проиграл. Оператор делал бесплатные компенсации недовольным гостям два-три раза в неделю именно из-за этого.
Все вендоры PMS, которых они рассматривали, требовали локального сервера, лицензии на каждое рабочее место и трёхмесячного внедрения. Ничего из этого не подходило небольшому оператору с сезонным персоналом, без ИТ-функции и с твёрдым нежеланием владеть инфраструктурой. Бриф был ясен: мы хотим нечто, что наши менеджеры могут открыть в браузере, и мы хотим, чтобы оно не ломалось.
Консоль бронирований по нескольким объектам с синхронизацией доступности без опроса.
Консоль дала каждой площадке живую сетку бронирований — заезды, выезды, доступность по слотам, заполненность по датам. Менеджер на одном объекте мог видеть одновременные изменения с другого объекта в момент, когда они происходили, не обновляя страницу. Бронирование, изменение и отмена брони — всё немедленно обновляло общее состояние. Каждая открытая сессия видела каждое изменение в момент его поступления.
Под консолью: Firestore для данных бронирований, Realtime Database для слоя синхронизации доступности, Firebase Auth для управления сессиями и Firebase Hosting для статического SPA. Никакого Node-сервера. Никакого Express-процесса, который нужно перезапускать. Никакого пайплайна развёртывания, кроме одной команды CLI.
Аналитическая поверхность работала рядом с операционной: демография гостей, графики трендов бронирований через Highcharts и режим прогнозирования выручки, подтягиваемый из тех же коллекций Firestore, которые уже читала сетка бронирований. Встроенное формирование счетов (jsPDF) и экспорт в CSV/XLSX закрывали процесс закрытия месяца у владельца без отдельного инструмента. Три с половиной месяца от первого коммита до продакшена.
- F · 01Живая синхронизация доступности
- Firestore + Realtime Database доставляют обновления в каждую открытую сессию в момент изменения брони. Без опроса. Без обновления страницы.
- F · 02Панель по нескольким объектам
- Одна консоль охватывает все площадки. У каждого объекта своя сетка; владелец видит полную картину в одной вкладке.
- F · 03Слой сессий Firebase Auth
- Firebase Auth управляет сессиями пользователей-владельцев, менеджеров и сотрудников. Никакого собственного сервера аутентификации, никакой таблицы прав для поддержки. Проверки ролей на уровне приложения разграничивают поверхности.
- F · 04Формирование счетов
- Подтверждения бронирований и счета формируются на стороне клиента через jsPDF и отправляются по почте напрямую — без отдельного биллингового инструмента.
- F · 05Массовый импорт / экспорт
- Импорт CSV и XLSX для сезонной массовой загрузки. Экспорт для бухгалтера владельца в конце месяца. Оба выполняются в браузере.
- F · 06Аналитика
- Демография гостей, тренды бронирований и режим прогнозирования выручки на Highcharts, читающие те же коллекции Firestore, что и сетка бронирований.
Выбор только Firebase и почему он пережил продакшен.
Одновременные попытки бронирования одного и того же слота — два менеджера бронируют последний пляжный шезлонг на вторую половину дня — были именно тем сбоем, за который оператор продолжал платить. Решением была не блокировка на стороне записи; решением была истина на стороне чтения. Realtime-слушатели Firestore означали, что каждая открытая сессия на каждом устройстве видела бронь в момент её записи. Как только слот был занят, экран каждого менеджера это показывал. Сбой координации, свойственный таблице — два человека работают с устаревшими видами одной и той же строки — не мог произойти, потому что никто не работал с устаревшим видом.
Решение полностью отказаться от бэкенд-сервера не было экономией ради экономии. Это была верная архитектура под ограничения этого оператора. Не было DevOps-команды, чтобы нянчиться с Node-процессом, не было дежурной смены, которую нам можно было бы передать, и не было терпимости к тому, чтобы сервер упал в субботу в августе. Управляемые сервисы Firebase несут гарантию доступности; мы несём логику приложения. Граница чистая.
Firebase Auth взял на себя управление сессиями без собственного сервера аутентификации. Поддержка нескольких языков для международной аудитории гостей работала через ngx-translate. Статический бандл развёртывался в Firebase Hosting менее чем за две минуты. Суммарная месячная стоимость инфраструктуры укладывалась в бесплатный тариф Firebase в течение первых шести месяцев продакшена.
Ноль двойных бронирований. Счёт за инфраструктуру остался в пределах бесплатного тарифа.
Проблема овербукинга прекратилась. За первые двенадцать месяцев работы оператор зафиксировал ноль конфликтующих бронирований одного и того же слота. Таблица оставалась открытой неделю после запуска — как запасной вариант, которым никто не воспользовался.
Система запустилась на трёх объектах одновременно. Владелица провела обучение персонала сама, за одну половину дня, потому что консоль была достаточно простой, чтобы объяснить её за один сеанс. Текучесть сезонного персонала — другая причина, по которой таблица была столь хрупкой — перестала быть риском целостности данных, как только состояние стало жить в базе данных, а не в чьём-то локальном файле. Новые сезонные сотрудники получали приглашение Firebase Auth и ту же консоль, которой пользовались все остальные.
Продукт работает без бэкенд-сервера с 2019 года. Оператор ни разу не поднимал нас по тревоге.
Мы перестали делать гостям бесплатные компенсации. Вот и вся история.
