Все проекты

Кейс · 2025 — 2026 · Приложение

Ставь!

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

371 коммит
44 экрана
8 месяцев
Роль Продукт целикомАналитика, дизайн-система, фронтенд, бэкенд, инфраструктура
Срок 8 месяцевОктябрь 2025 — май 2026, семь активных месяцев
Платформы PWA · Telegram · AndroidУстановка на iOS и Android, Mini App внутри Telegram, сборка Capacitor
Стек Angular · NestJS · SupabaseМонорепо из четырёх проектов, один бэкенд, self-hosted база

Задача

Контекст

Гость уже сидит в лаунже: приглушённый свет, шумно, телефон в одной руке. Ему не нужно «изучить меню», нужно собрать микс и отправить его. Владельцу нужна обратная сторона: заказ мгновенно, чат для уточнений, склад табака и понимание, кто возвращается.

Food-delivery решения эту пару задач не закрывают: они спроектированы под доставку, а не под гостя, который уже в зале. Поэтому строили с нуля свою модель данных, свой флоу заказа и свою дизайн-систему под тёмный зал.

90сек цель: от открытия до отправленного заказа
2 роли в одном продукте: гость и заведение
3 канала уведомлений: push, telegram, in-app

Заказ
в три шага

Клиентский флоу

Шаг 1 визарда: карта и карточки заведений рядом

Что рядом

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

Шаг 2 визарда: крепость, холодок и направления вкуса

Какой микс

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

Шаг 3 визарда: сводка заказа и время подачи

К какому времени

Сводка, напитки к кальяну, время подачи чипами или колесом, и одна кнопка. Заказ уходит владельцу мгновенно, дальше статусы и чат по этому заказу.

Приложение
гостя

18 экранов · mobile-only

Главный экран приложения со сториз и активным заказом
Главная
Сториз-вьюер с карточкой заведения
Сториз
Карточка заведения: рейтинг, цены, вкусы
Заведение
Bottom sheet с подкатегориями вкуса
Вкус
Модальное окно выбора времени подачи
Время
Realtime-чат гостя с заведением
Чат
Список заказов гостя
Заказы
Экран уведомлений
Уведомления
Избранные заведения
Избранное
Экран бонусного клуба
Клуб
Онбординг быстрого заказа
Онбординг
Публичный лендинг сервиса
Лендинг
Страница для заведений-партнёров
Партнёрам

← Листайте · клик по экрану — увеличить

Кабинет
заведения

26 экранов · операционка

Второе приложение в том же монорепо: заказы в реальном времени, редактор карты зала, склад табака и напитков, смены персонала, отзывы, CRM гостей, аналитика и подключение внешних систем.

Дашборд владельца заведения
Дашборд
Лента заказов заведения
Заказы
Чат заведения с гостем
Чат
Редактор карты зала с элементами мебели
Карта зала
Список табака заведения по брендам
Табак
Склад с остатками и порогами
Склад
Меню напитков с ценами
Напитки
Аналитика: выручка, активность, эффективность
Аналитика
Подключение iiko и Poster
Интеграции
Управление фотографиями заведения
Фото
Профиль владельца и настройки заведения
Настройки

← Листайте · клик по экрану — увеличить

Каталог
вкусов

1 654 позиции · 24 бренда

Третье приложение отвечает за каталог табака: таблица на 1 654 вкуса, где у каждой позиции есть вектор дескрипторов (сладость, кислинка, свежесть, пряность, травы, конфетность, кулинарность, сливочность, десертность, крепость). На этих числах работает подбор миксов в приложении гостя.

Редактор каталога вкусов: таблица с брендами, категориями и дескрипторами
Редактор каталога · роль catalog_editor 1 654 из 1 654

Как это
устроено

Инфраструктура

Client PWA Angular 19 · mobile Admin PWA Кабинет заведения Catalog Редактор вкусов nginx · TLS статика трёх приложений · /api · websocket upgrade Supabase (self-hosted) GoTrue · PostgREST · Storage Kong · Docker на ру-VPS NestJS API 23 модуля · 174 эндпоинта Socket.IO gateway · чат PostgreSQL 17 25 миграций · шифрование переписки AES-256-GCM Бэкапы и мониторинг wal-g · суточные дампы в Object Storage · watchdog каждые 5 минут Telegram 2 бота · Mini App Cloudflare Worker прокси мимо блокировок Web Push VAPID · iOS · Android Платежи подписки заведений iiko · Poster синхронизация столов LLM (Groq) названия миксов Яндекс.Карты карта заведений supabase-js · auth HTTPS · WSS service role RLS · storage wal-g · pg_dump

Деплой идёт одним bash-скриптом с рабочей машины: сборка, rsync, pm2. Без CI, без контейнеров на прикладном слое.

Что было
сложным

Инженерия

Продакшн жил на облачном Supabase в Ирландии: 100–200 мс на запрос через границу, требования к хранению персональных данных и санкционный риск. Перевезли весь стек на собственный VPS в Москве: Postgres, авторизация, storage, шлюз. План разложили на восемь ранбуков: провижининг, разворачивание, DNS и SSL, бэкапы, тестовый прогон полного дампа, чеклист дня миграции и процедуры отката. Окно простоя составило 15–25 минут ночью, старое облако держали ещё неделю как страховку. После переезда до базы 3–10 мс.

Supabase OSSDockerCaddyRunbooks

Диапазоны, где хостилось облако, фильтровались по DPI, и логин у части пользователей не работал без VPN. Поставили перед ними Cloudflare Worker: через anycast-прокси пошли и Telegram Bot API, и SDK-скрипты, и трафик фронтенда к базе. На бэкенде прокси включается переменной окружения, прямые адреса остаются рабочим дефолтом.

Cloudflare WorkersAnycastFallback

Socket.IO-gateway внутри того же бэкенда: комнаты по заказу, статусы прочтения и присутствия, аутентификация соединения по токену и проверка источника по вайтлисту. Тексты сообщений и вложения лежат в базе зашифрованными AES-256-GCM с версионированным префиксом, а уже накопленную переписку зашифровали отдельным скриптом миграции.

Socket.IOAES-256-GCMRooms

Клиентский и админский боты живут в одном процессе: уведомление маршрутизируется по типу получателя: новый заказ и сообщение гостя уходят владельцу, смена статуса и ответ заведения возвращаются гостю. Оба приложения работают и как Telegram Mini App: серверный прокси SDK с прогревом кэша, чтобы фронтенд не ходил на внешние домены.

Telegram Bot APIMini AppinitData HMAC

Микс собирается из реального остатка табака конкретного заведения. Каждый вкус описан вектором из семи дескрипторов, поверх — правила несочетаемости категорий: кулинарный вкус не ставится с десертным, безароматка не дублируется. Состав считается детерминированно, языковая модель подключается только на последнем шаге, для названия и описания. Отдельным контуром шёл python-прототип на оценках «ок / не ок» с обучением RandomForest и GradientBoosting.

ДескрипторыGroqscikit-learn

Приложение живёт в трёх средах сразу: браузер, установленная PWA и Telegram WebView. Отступы собраны трёхуровневым каскадом: статичный fallback, затем env(safe-area-inset), затем переменные Telegram. Web Push на iOS работает только в установленной PWA начиная с 16.4, а ключи VAPID нельзя менять после первых подписок. Плюс вендорные префиксы для backdrop-filter и clip-path и фоллбек 100vh перед 100dvh.

PWAService WorkeriOS SafariCapacitor

Дизайн-
система

Язык интерфейса

Ощущение приглушённого лаунжа ночью, а не дашборда в полдень. Тёплый тёмный вместо холодного tech, редакторский разворот вместо формы ввода.

Направление зафиксировано в коде как система токенов: 124 переменных, 65 миксинов, 34 анимации. Огонь остаётся резервируемым ресурсом: один основной CTA на экран, одна пульсация, один градиентный wordmark. Стекло с размытием и тёплый ambient-градиент на фоне; вес шрифта ограничен 600, основной текст мягкий #F5F5F5 вместо чистого белого, чтобы не слепить в темноте.

Анти-референсы прописаны так же строго, как токены: утилитарные серые списки доставки, казино-золото во всю ширину, яркий consumer-tech и кофейные приложения со штампами. Всё mobile-only, 320–430 px: hover-состояний нет вообще, только нажатие, тап-зоны от 44 px, анимации выключаются при системном запросе уменьшить движение.

124 токена в дизайн-системе
109 компонентов Angular
0 UI-фреймворков: только свой SCSS

Стек

Технологии

Фронтенд

  • Angular 19 · standalone, lazy routes
  • TypeScript 5.6
  • SCSS · своя дизайн-система
  • Монорепо: client, admin, catalog, shared
  • PWA · собственный service worker
  • Capacitor · сборка под Android

Бэкенд

  • NestJS 11 · Node.js 20
  • Socket.IO 4.8 · realtime-чат
  • class-validator · Swagger · throttler
  • web-push · nodemailer · pdfkit · sharp
  • Планировщик задач и авто-уведомления

Данные

  • PostgreSQL 17
  • Supabase OSS · self-hosted в Docker
  • GoTrue · PostgREST · Storage · Kong
  • 25 миграций · RLS
  • wal-g · pg_dump · Object Storage

Интеграции

  • Telegram Bot API · Mini App
  • Cloudflare Workers
  • Яндекс.Карты · Метрика · DaData
  • iiko Cloud · Poster
  • Groq · платёжный провайдер

Экраны сняты на локальной сборке проекта с демонстрационными данными.