Архитектура
Общая картина системы Ghost Kitchen: что это, из чего состоит и почему выбран именно такой стек.
:::info Для кого этот раздел «Обзор», «Роли и панели» и «Запуск нового бренда» написаны простым языком — их можно показывать заказчику и агентству. «Модель данных» и «Интеграции» в разделе Бэкенд — техническая зона напарника. :::
Что мы строим
Ghost Kitchen — это собственная multi-tenantMulti-tenantАрхитектура, где одна копия приложения и одна база данных обслуживают много изолированных клиентов (тенантов). Здесь тенант = бренд. платформа для управления сетью ресторанов-доставок и брендов. Она заменяет связку из агрегаторовАгрегаторПлатформа-посредник, собирающая заказы для ресторанов (например, доставка еды). Передаёт заказы на кухню и берёт комиссию. (Uber Eats, Lieferando, Bolt Food) и аренды Shopify на одну кодовую базу и одну базу данных, которые обслуживают все бренды сразу.
Платформа даёт: витрину заказов, приём и оплату заказов, управление меню, передачу заказов на кухню (POSPOSPoint of Sale — кассовая система ресторана. Здесь — Liefersoft: принимает заказы от платформы, печатает чеки, ведёт фискальный учёт.), аналитику и управление брендами — при меньшей комиссии, чем у агрегаторов.
Почему не Shopify
Подробный разбор — в материалах для заказчика. Если коротко, Shopify лицензирует каждый магазин отдельно: на 10 брендах это 10 подписок, 10 админок, 10 интеграций и изолированные друг от друга данные клиентов. Самую сложную часть — связь с кухонной кассой — всё равно пришлось бы писать руками. Кастомный multi-tenantMulti-tenantАрхитектура, где одна копия приложения и одна база данных обслуживают много изолированных клиентов (тенантов). Здесь тенант = бренд. стек убирает эту линейную стоимость: новый бренд — это строки в базе, а не новая подписка.
Рекомендуемый стек
| Слой | Технология | Зачем |
|---|---|---|
| Витрина клиента | Nuxt 3NuxtМета-фреймворк поверх Vue.js. Поддерживает серверный рендеринг (SSR) и режим SPA. Используется для витрины клиента и админок. (Vue) в режиме SSRSSRServer-Side Rendering — страница собирается на сервере и отдаётся готовым HTML. Нужен для SEO и скорости первой загрузки витрины. | SEO и скорость food-сайтов |
| Админки | Nuxt / Vue в режиме SPASPASingle-Page Application — приложение рендерится в браузере, без перезагрузки страниц. Подходит для админок за логином, где SEO не нужен. | За логином, SEO не нужен |
| Данные + API + админ-ядро | DirectusDirectusOpen-source headless-платформа поверх PostgreSQL: даёт модель данных, REST/GraphQL API, аутентификацию, RBAC и готовую админку без написания кода. | Модель данных, REST/GraphQL, RBACRBACRole-Based Access Control — управление доступом на основе ролей. Права выдаются роли (Company Admin, Brand Admin, Restaurant Manager), а не каждому пользователю отдельно., готовая админка |
| Бизнес-логика и интеграции | Node-адаптер | Заказы, вебхуки, связь с POS/оплатой |
| База данных | PostgreSQLТенантЛогически изолированный клиент в multi-tenant системе. В Ghost Kitchen тенант — это бренд: его данные отделены от других по `brand_id` и правам доступа. | Единый источник правды |
| Платежи | MollieMollieЕвропейский платёжный провайдер. Принимает оплату (карты, iDEAL, Apple/Google Pay и др.) и присылает статус платежа через вебхуки. | Приём оплаты (ЕС) |
| Касса ресторана | LiefersoftLiefersoftPOS/кассовая система ресторана (Германия) с TSE-фискализацией. Платформа передаёт ей заказы для приготовления и фискального учёта. | Приготовление + TSE-фискализацияTSE-фискализацияТехнические требования Германии (Technische Sicherheitseinrichtung) к кассам: каждая продажа защищённо подписывается. Обеспечивается на стороне POS (Liefersoft). |
| Хостинг | Vercel + Neon + Hetzner | Плоская стоимость, не растёт с числом брендов |
:::note Ответ на вопрос «SPA или нет» Витрина клиента — SSR, не SPA. Поисковая выдача и превью ссылок (Google, мессенджеры) критичны для конверсии в доставке. Админки — SPA: они за логином, индексировать нечего, а интерактивность выше. Nuxt поддерживает оба режима в одном фреймворке. :::
Карта системы (C4 — контекст)
Три слоя бэкенда
Бэкенд намеренно разделён на три части с чёткими границами:
- DirectusDirectusOpen-source headless-платформа поверх PostgreSQL: даёт модель данных, REST/GraphQL API, аутентификацию, RBAC и готовую админку без написания кода. — «80% без кода». Описываем модель данных (бренды, кухни, меню, заказы, пользователи) — и сразу получаем REST/GraphQL API, аутентификацию, RBACRBACRole-Based Access Control — управление доступом на основе ролей. Права выдаются роли (Company Admin, Brand Admin, Restaurant Manager), а не каждому пользователю отдельно. и готовую админку для контент-операций.
- Node-адаптер — «оставшиеся 20%». То, что Directus не делает: оркестрация оформления заказаCheckoutОформление заказа: ввод контактов и адреса, выбор времени/доставки, оплата и подтверждение. В кастомном стеке полностью под нашим контролем., приём вебхуковWebhookHTTP-уведомление, которое внешний сервис (например, Mollie) шлёт платформе при событии — например, «платёж оплачен». Альтернатива постоянному опросу API. Mollie, передача заказа в LiefersoftLiefersoftPOS/кассовая система ресторана (Германия) с TSE-фискализацией. Платформа передаёт ей заказы для приготовления и фискального учёта., повторные попытки, идемпотентностьИдемпотентностьСвойство операции давать один и тот же результат при повторе. Защищает от дублей заказа/платежа при повторной доставке вебхука или ретрае., dead-letter queueDead-letter queueОчередь для сообщений/задач, которые не удалось обработать после всех повторов. Их разбирают вручную, чтобы не потерять заказ при сбое интеграции..
- PostgreSQLТенантЛогически изолированный клиент в multi-tenant системе. В Ghost Kitchen тенант — это бренд: его данные отделены от других по `brand_id` и правам доступа. — единый источник правды. Все бренды в одной базе,
изоляция по
brand_idи правам доступа.
Multi-tenant: тенант = бренд
Каждый брендБрендТорговая марка внутри платформы (например, «Pizza Burger»). Один бренд может иметь несколько ресторанов/кухонь. В архитектуре бренд = тенант. — это логически изолированный тенантТенантЛогически изолированный клиент в multi-tenant системе. В Ghost Kitchen тенант — это бренд: его данные отделены от других по `brand_id` и правам доступа. в общей базе. Данные одного бренда не видны другому, но платформа (Company AdminCompany AdminВладелец платформы. Видит и управляет всеми брендами, ресторанами, заказами и сквозной аналитикой; создаёт новые бренды.) видит всё сразу — отсюда сквозная аналитика «одним SQL-запросом», недостижимая на изолированных магазинах Shopify.
Масштаб
Сейчас разговор с заказчиком — про 3–10 брендов в горизонте двух лет. Но multi-tenant архитектура с самого начала проектируется так, чтобы расти до десятков и сотен брендов без переписывания: добавление бренда не требует деплоя, нагрузка распределяется на уровне одной базы и одного набора сервисов. Конкретные шаги горизонтального масштабирования (реплики БД, кэш, очереди) описываются в разделе Бэкенд по мере роста.
Что дальше
- Роли и панели — кто что видит и чем управляет.
- Жизненный цикл заказа — путь заказа от клика до кухни.
- Запуск нового бренда — как бренд появляется «в несколько кликов».
- Бэкенд и Фронтенд — технические детали.