Овербукінги, яким ніхто не міг запобігти.
Ведення кількох пляжних майданчиків на спільній таблиці — це не проблема робочого процесу. Це проблема узгодженості даних, одягнена в одяг проблеми робочого процесу. Двоє менеджерів відкривають ту саму таблицю одночасно, переходять табуляцією до того самого слота й натискають «зберегти» — один із них завжди перемагає, а другий ніколи не дізнається, що програв. Оператор компенсував незадоволеним гостям двічі-тричі на тиждень саме через це.
Усі PMS-вендори, яких вони розглядали, вимагали локального сервера, ліцензії на кожне місце й тримісячного впровадження. Ніщо з цього не пасувало невеликому оператору із сезонним персоналом, без IT-функції й із сильною перевагою не володіти інфраструктурою. Бриф був чітким: ми хочемо щось, що наші менеджери можуть відкрити в браузері, і хочемо, щоб воно не ламалося.
Консоль бронювань для кількох об'єктів із синхронізацією доступності, що не опитує.
Консоль дала кожному майданчику живу сітку бронювань — заїзди, виїзди, доступність за слотом, заповненість за датою. Менеджер на одному об'єкті міг бачити одночасні зміни з іншого об'єкта в мить, коли вони відбувалися, без оновлення сторінки. Бронювання, зміна й скасування резервації — усе негайно оновлювало спільний стан. Кожна відкрита сесія бачила кожну зміну в момент її надходження.
Під консоллю: 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, не було чергування on-call, щоб передати нам, і не було толерантності до сервера, що падає в суботу в серпні. Керовані Firebase сервіси несуть гарантію доступності; ми несемо логіку застосунку. Межа чиста.
Firebase Auth обробляв керування сесіями без кастомного сервера автентифікації. Багатомовна підтримка для міжнародної бази гостей працювала через ngx-translate. Статичний бандл розгортався на Firebase Hosting менш ніж за дві хвилини. Загальна місячна вартість інфраструктури вкладалася в безкоштовний тариф Firebase упродовж перших шести місяців продакшну.
Нуль подвійних бронювань. Рахунок за інфраструктуру лишався в межах безкоштовного тарифу.
Проблема овербукінгу припинилася. У перші дванадцять місяців роботи оператор зафіксував нуль конфліктних бронювань на той самий слот. Таблиця лишалася відкритою тиждень після запуску як резерв, яким ніхто не скористався.
Система запрацювала на трьох об'єктах одночасно. Власниця сама провела навчання персоналу за один день, бо консоль була достатньо простою, щоб пояснити її за одну сесію. Плинність сезонного персоналу — інша причина, чому таблиця була такою крихкою — перестала бути ризиком для цілісності даних, щойно стан почав жити в базі даних, а не в чиємусь локальному файлі. Нові сезонні працівники отримували запрошення Firebase Auth і ту саму консоль, якою користувалися всі інші.
Продукт працює без бекенд-сервера з 2019 року. Оператор жодного разу не надіслав нам on-call-виклику.
Ми перестали компенсувати гостям. Ось і вся історія.
