Веб-сайт ресторана и
Система бронирования на Edge
Land of Fire — азербайджанский ресторан на Каледониан-роуд в Кингс-Кросс. Сайт должен был рассказать свою историю, принимать заказы на столики без стороннего виджета и предоставить сотрудникам одно личное место для работы перед домом.
Я создал кинематографический веб-сайт на трех языках, общедоступный процесс бронирования и частное рабочее пространство для сотрудников для бронирования и электронной почты для гостей, и все это работает как один Cloudflare Worker, поддерживаемый PostgreSQL.
Гости запрашивают столик онлайн и получают информацию по электронной почте. Сотрудники подтверждают, изменяют и экспортируют бронирования из одного места. Здесь нет серверов, которые нужно обслуживать, а также аналитических или рекламных файлов cookie.
- ОТПРАВНАЯ ТОЧКА
Веб-сайт, на котором перечислена еда, но ничего не сказано о месте.
У Land of Fire уже был веб-сайт, созданный на основе шаблона онлайн-заказа. Там было меню, адрес и часы работы. Он не показал, чем отличается ресторан: домашняя азербайджанская кухня, чай, подаваемый в стаканах армуду, и всегда место для еще одного человека за столом.
- ЧТО Я ЗАМЕТИЛ
Старый сайт противоречил сам себе
На главной странице в трех местах было написано «Заказать онлайн», при этом встроенное в страницу уведомление сообщало, что онлайн-заказ отключен, а плавающие вкладки предлагали гостям зарегистрировать для него учетную запись. Понедельник был указан как «00:00, 00:00», когда ресторан закрыт по понедельникам. Всплывающее окно с объявлением о закрытии в августе все еще отображалось в октябре. И сайт был только на английском языке, хотя гости азербайджанского ресторана с одинаковой вероятностью читают как по-азербайджански, так и по-русски. Каждая проблема была небольшой, но вместе они сказали впервые зашедшему посетителю, что за сайтом никто не присматривает.
- ИДЕЯ
«Всегда есть место еще для одного»
Я перестал относиться к сайту как к каталогу еды на вынос и превратил его в приветствие. Эта строка стала нитью через весь сайт. Он начинается с полноэкранного фильма, затем знакомит с людьми, блюдами, приготовленными для совместного использования, и стоящими за ними азербайджанскими корнями. Он заканчивается указанием направления к двери. Золотые линии, изображающие Девичью башню, чайный сервиз, ковер и смолу, придают ему индивидуальность, которую не мог бы создать шаблон.
- ЗАСТАВИТЬ ЭТО РАБОТЬТЬ
Красивый сайт – это только половина дела
Ресторан сам подтверждает каждый столик, поэтому форма бронирования обещает запрос, а не мгновенное подтверждение, и говорит об этом прямо. За ним я создал частное рабочее пространство, где сотрудники подтверждают, изменяют и экспортируют бронирования, а также отвечают на электронные письма гостей из одного места. Приведенная ниже технология существует для того, чтобы выполнить это единственное обещание: запрос никогда не теряется, никогда не дублируется и никогда не утекает.
- СЕГОДНЯ
Одно место, где можно найти, принять решение и забронировать
Теперь гость может прочитать историю, просмотреть полное меню с ценами, проверить отзывы и запросить столик на одной странице на английском, азербайджанском или русском языке. Сотрудники работают с единой панели управления вместо почтового ящика и телефона. Нет серверов, которые нужно обслуживать.


ОРИГИНАЛ СТРАНИЦА ЗАКОНЧАЕТСЯ ЗДЕСЬ


- —Верхняя панель с электронной почтой, телефоном, четырьмя значками социальных сетей и кнопкой «Резервировать» над вторым рядом ссылок.
- —«Меню» открывает раскрывающийся список из 12 категорий продуктов питания, каждая из которых имеет отдельную страницу.
- —Вкладки входа и регистрации расположены на левом краю каждой страницы для учетной записи для заказа.
- —На телефонах: небольшая панель с четырьмя ссылками, плюс фиксированная панель из пяти кнопок, включая «Заказать онлайн» для отключенной системы заказа.
- —Четыре тихие текстовые ссылки и логотип по центру; ничто не может конкурировать с фильмом
- —Одна кнопка «Меню» открывает полноэкранное изображение с пятью пронумерованными пунктами назначения, заканчивающееся надписью «Забронировать столик».
- —Адрес, телефон, Deliveroo, электронная почта и ссылки на социальные сети расположены рядом с меню, поэтому контактные данные находятся на расстоянии одного касания.
- —Одно и то же наложение на экране любого размера, открывается и закрывается как с помощью клавиатуры, так и касанием.
| ОБЛАСТЬ | ОРИГИНАЛЬНЫЙ САЙТ | РЕДИЗАЙН |
|---|---|---|
| Первое впечатление | Общий текст «Добро пожаловать на официальный сайт» и четыре ссылки на изображения без надписей. | Полноэкранный фильм о ресторане «Немного огня. Много души». и единственная кнопка «Забронировать столик» |
| Рассказывание историй | Никакой истории, наследия или людей; один абзац шаблона | Главы «Наша история», «За нашим столом» и «Наши корни» с карточками наследия, связанными с источниками ЮНЕСКО. |
| Визуальная идентичность | Готовый шаблон заказа с плитками категорий запасов | Сделанный на заказ набор золотых линий (Девичья башня, чайный стакан армуду, ковер, смола, гранат), используемый на территории. |
| Меню | Двенадцать отдельных страниц категорий, каждая из которых загружается одним щелчком мыши. | Одно меню с вкладками с описаниями блюд и ценами, а также загрузкой PDF-файла и ссылкой на Deliveroo. |
| Бронирование | Форма, отображаемая рядом с кнопкой «заказать сейчас» для отключенной системы заказа; Призыв к бронированию повторяется около пяти раз | Одна понятная форма с реальными часами работы, набором от 1 до 8 гостей, согласием и честной формулировкой «просьба, а не подтверждение». |
| Часы работы | Понедельник отображается как «00:00, 00:00»; блок часов дублируется как «Часы бронирования» | «Понедельник: закрыто», указывается один раз и применяется тем же модулем, который использует API бронирования. |
| Языки | только английский; переключатель EN/DE присутствует в коде, но скрыт от посетителей | Английский, азербайджанский и русский, с альтернативами hreflang для поисковых систем. |
| Доверие и социальное доказательство | Всплывающее окно, объявляющее о закрытии в августе, все еще отображается в октябре, заполнители «Загрузка…» и опечатки в тексте. | Цитаты Tripadvisor над формой бронирования, ссылки на Google и Tripadvisor, неработающих ссылок нет. |
| Доступность | Ссылки только на изображения без альтернативного текста | Пропустить ссылку, семантические ориентиры, средства выбора с помощью клавиатуры и полную поддержку ограниченного движения. |
Первое впечатление
Общий текст «Добро пожаловать на официальный сайт» и четыре ссылки на изображения без надписей.
Полноэкранный фильм о ресторане «Немного огня. Много души». и единственная кнопка «Забронировать столик»
Рассказывание историй
Никакой истории, наследия или людей; один абзац шаблона
Главы «Наша история», «За нашим столом» и «Наши корни» с карточками наследия, связанными с источниками ЮНЕСКО.
Визуальная идентичность
Готовый шаблон заказа с плитками категорий запасов
Сделанный на заказ набор золотых линий (Девичья башня, чайный стакан армуду, ковер, смола, гранат), используемый на территории.
Меню
Двенадцать отдельных страниц категорий, каждая из которых загружается одним щелчком мыши.
Одно меню с вкладками с описаниями блюд и ценами, а также загрузкой PDF-файла и ссылкой на Deliveroo.
Бронирование
Форма, отображаемая рядом с кнопкой «заказать сейчас» для отключенной системы заказа; Призыв к бронированию повторяется около пяти раз
Одна понятная форма с реальными часами работы, набором от 1 до 8 гостей, согласием и честной формулировкой «просьба, а не подтверждение».
Часы работы
Понедельник отображается как «00:00, 00:00»; блок часов дублируется как «Часы бронирования»
«Понедельник: закрыто», указывается один раз и применяется тем же модулем, который использует API бронирования.
Языки
только английский; переключатель EN/DE присутствует в коде, но скрыт от посетителей
Английский, азербайджанский и русский, с альтернативами hreflang для поисковых систем.
Доверие и социальное доказательство
Всплывающее окно, объявляющее о закрытии в августе, все еще отображается в октябре, заполнители «Загрузка…» и опечатки в тексте.
Цитаты Tripadvisor над формой бронирования, ссылки на Google и Tripadvisor, неработающих ссылок нет.
Доступность
Ссылки только на изображения без альтернативного текста
Пропустить ссылку, семантические ориентиры, средства выбора с помощью клавиатуры и полную поддержку ограниченного движения.

Land of Fire — это полноценная ресторанная веб-платформа: многоязычный маркетинговый сайт, публичный процесс бронирования и частное рабочее пространство для персонала, созданное с помощью Следующий.js 16 и PostgreSQL и развернут как один Облачный работник.
Публичные страницы предварительно визуализируются и представляют собой статический контент; только API бронирования и персонала выполняют код по каждому запросу. Корректность обеспечивается базой данных: ключи идемпотентности, консультативные блокировки, блокировки строк, оптимистические версии и транзакционная исходящая электронная почта, с интеграционными тестами на реальных почтовых серверах PostgreSQL и синтетических TLS.
Нет серверов, низкие эксплуатационные расходы
В ресторане нет операционной команды. Платформа должна была работать без серверов для обслуживания, а также без оплаты или зависимости от стороннего виджета бронирования.
Гостевые данные являются личными данными
Имена, электронные письма, номера телефонов и заметки о питании никогда не должны просачиваться на общедоступные страницы, кэши, журналы или создавать артефакты.
Каждое бронирование подтверждено вручную
Ресторан сам подтверждает каждое бронирование. Система записывает запросы и информирует людей; он не распределяет таблицы и не выполняет автоматическое подтверждение.
Ненадежная сеть
Люди бронируют билеты на телефонах, в поездах и дважды нажимают кнопку «Отправить». Повторная попытка или повторный запрос никогда не должны создавать второе бронирование.
- 01
Запрос
Браузер генерирует UUID, когда гость впервые нажимает кнопку «Отправить», и повторно использует его при каждой повторной попытке.
- 02
Сторожить
Проверка того же происхождения, тип контента JSON, ограничение размера тела 8 КБ, скрытое поле-приманка и проверка на соответствие реальным часам работы.
- 03
Замок
Консультативная блокировка PostgreSQL на уровне транзакции, введенная в электронную почту гостя, сериализует одновременные запросы между экземплярами Worker.
- 04
Писать
Бронирование, событие аудита и электронные письма гостей и персонала вставляются в одну транзакцию. Вместо этого при повторной попытке возвращается исходная ссылка.
- 05
Доставлять
После фиксации Worker отправляет поставленные в очередь электронные письма в максимально возможном порядке и отвечает 201 со ссылкой на бронирование.
UUID, сгенерированный клиентом, является первичным ключом бронирования, поэтому двойное касание или повторная попытка после тайм-аута возвращает исходную ссылку. Повторная попытка, поступившая с другого адреса электронной почты, отклоняется, поэтому предполагаемый идентификатор не может проверить чужое бронирование.
Один модуль определяет часы работы и импортируется как через форму, так и через API: выходной по понедельникам, получасовые интервалы, последнее посещение за два часа до закрытия, 1–8 гостей, до 90 дней вперед, всегда оценивается по лондонскому времени.
Если база данных недоступна, форма отображает номер телефона ресторана, а не выдает ошибку. Публичный сайт никогда не зависит от базы данных.
Электронные письма обрабатываются и вставляются в папку «Исходящие» в той же транзакции, что и бронирование, каждое из которых имеет уникальный ключ дедупликации, поэтому повторный запрос не может поставить в очередь дубликат.
Ожидающие сообщения запрашиваются по одному с надписью FOR UPDATE SKIP LOCKED. Сбои возвращаются в состояние ожидания, и сообщение, ожидающее отправки более пяти минут, снова становится доступным для запроса.
Обработанный HTML, обычный текст и вложение .ics сохраняются в строке, поэтому при повторной попытке отправляется именно то, что было составлено. Время преобразуется из лондонских настенных часов в UTC, поэтому приглашения остаются верными даже при переходе на летнее время.
Шестизначные коды действительны в течение десяти минут, одноразовые, с максимум пятью попытками угадать внутри замка строки. В базе данных хранятся только дайджесты SHA-256 токена и кода вызова.
Argon2id в формате PHC, со старыми хеш-кодами, обновляемыми при следующем успешном входе в систему и пятнадцатиминутной блокировкой после пяти неудач. Сеансы представляют собой 32 случайных байта в файле cookie HttpOnly, Secure, SameSite=Strict; сохраняется только дайджест.
Одна оболочка обеспечивает проверку происхождения при записи, проверяет сеанс, устанавливает Cache-Control: частный, без хранения, очищает журнал ошибок и всегда закрывает соединение с базой данных. Все кадровые изменения записываются в таблицу аудита.
Каждое бронирование имеет номер редакции. Сервер блокирует строку, сравнивает и возвращает 409 Conflict, если коллега сохранил запись первым, поэтому два планшета не могут незаметно перезаписать друг друга.
Ячейки, начинающиеся с =, +, - или @, имеют префикс, поэтому программное обеспечение для работы с электронными таблицами обрабатывает их как текст. Заметки, предоставленные гостем, не могут выполняться как формулы, если экспорт открыт в Excel.
Почтовый ящик IMAP открывается только для чтения, флаги непрочитанного остаются нетронутыми и отображается только обычный текст. Удаленный HTML-код и изображения никогда не отображаются на панели управления для персонала.
В Workers TCP-сокет принадлежит запросу, который его открыл. Каждый вызов API открывает ровно одно соединение с отключенными подготовленными операторами и закрывает его в блокеfinally.
Помечен postgres.js как внешний, поэтому OpenNext выбирает сборку рабочего файла, при этом на этапе сборки утверждается, что драйвер сокета Cloudflare находится на выходе. Исправлен SMTP STARTTLS путем передачи nodemailer сокета, подключенного по имени хоста, при этом проверка сертификата оставалась полностью включенной.
Next.js 16.4 генерирует манифест, который не был включен в OpenNext 1.20, что нарушает работу Worker во время выполнения. Отследил его до одного шаблона glob и добавил однострочный патч, автоматически применяемый при установке.
Сценарий после сборки перезаписывает модуль среды адаптера, чтобы сохранить только значения NEXT_PUBLIC_, затем сканирует каждый выходной файл на предмет буквального URL-адреса базы данных и почтовых паролей, а также на наличие случайных файлов .env. Развертывание завершается неудачей, если что-то найдено.
Настоящие секреты загружаются отдельно в виде зашифрованных секретов Worker, передаваемых через стандартный ввод, поэтому они никогда не появляются в истории оболочки, аргументах процесса или журналах.
Одна команда создает приложение, преобразует его с помощью OpenNext, запускает секретное сканирование и развертывает с помощью Wrangler. 223 статических ресурса загружаются постепенно.
Введение в временную шкалу GSAP, встроенные сцены SVG, анимированные с помощью ScrollTrigger и плавной прокрутки Lenis, координируемые с помощью пользовательских событий DOM. Меню выбора даты и выбора созданы с нуля с поддержкой клавиатуры.
Все функции анимации предпочитают уменьшенное движение: вступление пропускается, главное видео приостанавливается, а эффекты прокрутки отключаются. Пропуск ссылок, семантические ориентиры, атрибуты языка для каждого языка и видимый элемент управления паузой видео.
Метаданные на каждой странице от одного помощника, обратный hreflang чередуется с x-default, сгенерированной картой сайта и файлами robots, а также Restaurant JSON-LD. В структурированных данных не заявлены ни звезды обзора, ни совокупные рейтинги.
Тесты резервирования запускают одноразовый кластер PostgreSQL и рабочий сервер, затем проверяют постоянство, идемпотентность, одновременные повторные попытки, проверку, согласие, защиту источника и ограничения скорости.
Миграция схемы из исходной версии, вход в систему и сеансы, конфликты редактирования, экспорт CSV и доставка электронной почты, сбои и повторные попытки на синтетических почтовых серверах TLS на настольных компьютерах и мобильных устройствах.
Каждый маршрут, иллюстрации, загрузка PDF-файла с точностью до байта, запросы видеодиапазона, подтверждение бронирования и защита происхождения. Ни один тест не затрагивает реальную базу данных ресторана и не отправляет настоящую электронную почту.
Персонал подтверждает бронирование вручную
Нет живой доступности; возможно двойное бронирование
Инвентаризация таблиц и проверка емкости на слот
Повторные попытки электронной почты инициируются запросами или персоналом.
Неудачное электронное письмо ожидает следующего действия или повторной попытки вручную.
Триггер Cloudflare Cron опустошает исходящие сообщения
Одно подключение к базе данных на каждый запрос
Задержка установки соединения при каждом вызове API
Cloudflare Hyperdrive для периферийного пула
Ограничение скорости вводится только по электронной почте
Скрипт может вращать адреса
Ограничения на основе IP или вызов турникета
Форма бронирования и внутренние страницы только на английском языке.
Книга посетителей Азербайджана и России на английском языке
Переведите процесс бронирования и меню
Аутентификация встроенная
Больше кода для владения и аудита
Приемлемо в этом объеме; повторно посетите, если требуется SSO или MFA
Есть идея проекта?
Расскажи мне, чего ты пытаешься достичь. Вам не нужно знать, какая технология вам нужна: я помогу определить технический подход, объем, сроки и стоимость до начала разработки.
- ЭЛЕКТРОННАЯ ПОЧТА // info@artursdev.co.uk
- ТЕЛЕФОН // 07460 162893
- ПРЕДПОЧИТАЕТЕ ОБСУДИТЬ ГОЛОСОМ? // Напишите, чтобы договориться о звонке
- ЛИНКЕДИН // арадионовы ↗
- МЕСТОПОЛОЖЕНИЕ // Барнет, Северный Лондон, Великобритания. Работа с клиентами где угодно.