Aristocrat — закрытый B2B бизнес-клуб и его админ-панель
Сайт для бакинского бизнес-клуба, который принимает членов только по приглашению. Собран как full-stack на Next.js: многошаговая форма заявки, календарь мероприятий и админ-панель, которой клуб управляет сам — мероприятия, новости и входящие заявки. Базы данных сознательно нет; все данные лежат в JSON-файлах на сервере.
Открыть сайт- Клиент
- Aristocrat Social & Business Club — закрытая B2B сеть, Баку
- Роль
- Full-stack разработка — архитектура страниц, логика многошаговой формы, route handler'ы Next.js, слой контента на JSON, админ-панель под защитой JWT, система компонентов, анимации и деплой на VPS (PM2 + Nginx).
- Стек
- Next.js · TypeScript · JWT Auth · JSON Storage · Tailwind CSS
- Дата
- август 2026
- Языки
- 3 — AZ / EN / RU
Сайт клуба, работающего по приглашениям, должен одновременно выполнять две противоречивые задачи: представить клуб, но не пригласить всех подряд. Большая кнопка «зарегистрироваться» разрушает заявку на эксклюзивность на первом же экране; сайт без пути подачи заявки остаётся нефункциональным. Вторая проблема начинается после запуска. Календарь мероприятий — единственное видимое доказательство того, что клуб живой, а календарь, заполненный прошедшими датами, говорит обратное. С заявками то же самое: через эту форму проходит весь приток членов клуба, и она не должна теряться в почтовом ящике. То есть сайт нужно было не только построить — им должен был уметь управлять сам клуб.
- Многошаговая форма заявки — вопросы по одному, с индикатором прогресса
- Годовой календарь мероприятий 2026 с датами и площадками
- Сегменты аудитории: предприниматели, стартапы, топ-менеджеры
- Раздел преимуществ: закрытая сеть, эксклюзивные мероприятия, доступ к инвестициям, обмен знаниями
- Раздел партнёров
- Редакционные разделы, объясняющие философию клуба
- Отдельная страница мероприятий — предстоящие события по дате и категории (Закрытый саммит, Неформальная встреча, Гала)
- Отдельная страница новостей
- Членство разделено на два трека: индивидуальный (Персоны) и корпоративный (Компании)
- Админ-панель: добавление, редактирование и удаление мероприятий — дата, площадка, категория
- Публикация новостей из админ-панели
- Ответы из формы заявки в виде списка внутри панели
- Загрузка изображений мероприятий и новостей прямо из панели
- Вход в админку под защитой JWT — маршруты панели закрыты на уровне middleware
- Фронтенд
- Next.js App Router. Главная страница, треки членства, мероприятия, новости и страницы заявки. Интерфейс работает на трёх языках, выбор сохраняется в браузере — отдельного адреса у каждого языка нет, этот компромисс объяснён ниже в технических решениях.
- Бэкенд
- Отдельного API-сервера нет — бэкенд это route handler'ы внутри того же приложения Next.js: приём заявок, запись мероприятий и новостей, загрузка изображений. Админ-панель живёт на маршрутах `/admin` того же проекта, то есть типы, компоненты и процесс деплоя общие с публичным сайтом.
- Слой данных
- Базы данных нет. Мероприятия, новости и входящие заявки хранятся на диске сервера в виде JSON-файлов: админ-панель пишет файл, страницы его читают. Обоснование — в решении «Почему нет базы данных?» ниже.
- Аутентификация
- Собственный поток JWT: токен подписывается на сервере и записывается в `httpOnly` cookie. Всё, что под `/admin`, проверяется и на уровне middleware, и внутри каждого route handler'а.
- Медиа
- Изображения мероприятий и новостей загружаются из админ-панели и записываются на диск VPS; на сайте отдаются через `next/image`.
- Инфраструктура
- Серверный процесс Next.js работает на VPS под управлением PM2, впереди стоит Nginx как reverse proxy — SSL, сжатие и кеширование статики на нём.
Почему многошаговая форма?
Заявка на членство требует множества вопросов. Показать их все на одном экране — значит отпугнуть человека. Я разбил форму на шаги и добавил индикатор прогресса: когда на экране один вопрос, человек гораздо охотнее доводит начатое до конца.
Дизайн фильтрует аудиторию
Клуб не массовый, и визуальный язык должен об этом говорить: спокойные цвета, широкие отступы, редакционная типографика. Яркий и весёлый дизайн противоречил бы сообщению — сайт показывает, кого он приглашает, не только словами, но и внешним видом.
Статическая генерация ради мгновенного открытия
Содержание презентационных страниц меняется редко, поэтому они собираются в готовый HTML на этапе сборки. Ожидания сервера нет — человек, пришедший по приглашению, видит сайт уже открытым. Меняющийся контент — мероприятия и новости — читается с сервера.
Членство разделено на два трека
Индивидуальное членство предпринимателя и корпоративный пакет компании — не один и тот же продукт: отличаются цена, привилегии и человек, принимающий решение. Разделение этих двух путей в меню отправляет каждого покупателя на свою страницу с первого клика. Единая страница «членство» ответила бы обоим наполовину.
Страница мероприятий даёт календарь вместо обещания
Главное сомнение насчёт закрытого клуба — происходит ли там что-то на самом деле. Список мероприятий с датами и категориями закрывает это сомнение с одного взгляда: отвечает не текст, а сами данные. Именно этот раздел превращает сайт из статичной брошюры в живую витрину клуба.
На фоне силуэт Баку, а не стоковое фото
Клуб — не международная сеть, а деловая среда конкретного города. В hero стоит узнаваемый силуэт Баку: посетитель за секунду понимает, где и среди кого построен этот клуб. Нейтральная стоковая фотография заняла бы то же место и не сказала бы ничего.
Почему нет базы данных?
Все данные клуба — это горстка записей: десятки мероприятий в год, несколько десятков новостей, несколько заявок в месяц. Ставить реляционную базу на такой объём значит завести ещё один процесс, ещё режим резервного копирования и дисциплину миграций — без всякой реальной пользы. Данные лежат в JSON-файлах на сервере: админ-панель пишет файл, страница его читает. Резервная копия — это скопированная папка, а история контента видна в самих файлах. Это не решение «не успел поставить базу» — это решение по размеру нагрузки. База понадобится, когда вырастет частота записи и редактировать начнут несколько человек одновременно; до этого — нет. Сложное в инженерии не добавить технологию, а удержаться от добавления ненужной.
Календарь остаётся доказательством, только пока он свежий
Выше я писал, что страница мероприятий — живая витрина клуба; это верно лишь пока календарь актуален. Страница, забитая прошедшими датами, показывает не работающий клуб, а остановившийся. Поэтому мероприятия живут не в коде, а в админ-панели: клуб добавляет новую дату сам, без моего участия. В этом проекте админ-панель не дополнительная функция — это механизм, который удерживает главный аргумент сайта.
Заявки попадают в панель, а не в почтовый ящик
Заявка на членство — самые ценные данные, с которыми работает этот клуб. Форма, полагающаяся только на почтовое уведомление, исчезает за одним спам-фильтром, и хуже всего то, что никто не знает о пропаже. Поэтому каждая заявка сохраняется на сервере и отображается списком в админ-панели — клуб может вернуться к ней в любой момент.
Токен сессии лежит в httpOnly cookie
В панели хранятся план мероприятий клуба и личные данные подающих заявку бизнесменов — в клубе, вся суть которого в закрытости, это самая чувствительная часть системы. Если бы токен лежал в `localStorage`, его могла бы прочитать любая XSS-дыра. `httpOnly` cookie не видна из JavaScript, а `SameSite` не даёт токену прицепиться к запросу с другого сайта. Проверка стоит не только в middleware, но и внутри каждого route handler'а: спрятать интерфейс — не защита, а видимость.
VPS, потому что записанные файлы должны сохраняться
Сайт пишет свои данные на диск сервера: JSON-файлы и загруженные изображения. В serverless-среде файловая система временная — панель что-то записывает, а следующий деплой это стирает. Поэтому приложение работает на VPS: PM2 держит процесс Next.js живым, Nginx впереди отвечает за SSL и статику. Работа с JSON имеет смысл только там, где есть постоянный диск — это не два отдельных выбора, а один.
Три языка по одному адресу — компромисс сделан осознанно
Интерфейс работает на трёх языках, но отдельного адреса у каждого нет: выбор сохраняется в браузере. Цена этого в том, что поисковые системы не индексируют три языка как отдельные страницы. Здесь компромисс приемлем, потому что член клуба приходит не из поиска Google — он приходит по приглашению, по прямой ссылке. Если бы органический поиск был каналом, язык пришлось бы разделять на уровне маршрутов; в этом проекте такая работа была бы сложностью, которая никому не служит.
Сайт работает с августа 2026 года. Клуб сам управляет календарём мероприятий, новостями и входящими заявками на членство через админ-панель — то есть актуальность календаря, главного аргумента сайта, больше не зависит от разработчика. Мобильная производительность измерена и находится ниже цели; оптимизация запланирована, цифра появится здесь после улучшения.
- Нужно ли клубу обращаться к разработчику, чтобы добавить мероприятие или новость?
- Нет. Мероприятия, новости и их изображения управляются из админ-панели — клуб обновляет календарь сам, без изменений в коде.
- Куда попадают данные из формы заявки?
- Каждая заявка сохраняется на сервере и отображается списком в админ-панели, то есть ничего не зависит только от почтового уведомления. Клуб может вернуться к прошлым заявкам в любой момент.
- Почему в проекте нет базы данных?
- Объём данных клуба невелик — десятки мероприятий и новостей в год, несколько заявок в месяц. При такой нагрузке реляционная база потребовала бы отдельного процесса и режима резервного копирования, ничего не добавив. Данные хранятся в JSON-файлах на сервере; переход на базу — запланированный шаг на случай роста частоты записи, а не незакрытая задача.
- Кто сделал сайт и админ-панель?
- Все слои — фронтенд, route handler'ы Next.js, слой контента, админ-панель, аутентификация и деплой на VPS — написаны Нурланом Кадировым.
- На скольких языках работает сайт?
- Интерфейс работает на трёх: азербайджанском, английском и русском. Отдельного адреса у каждого языка нет — выбор сохраняется в браузере. Это осознанный компромисс, потому что аудитория клуба приходит по приглашению, а не из поиска.
Расскажите о проекте — обычно отвечаю в тот же день.
Nurlan Qadirov — Baku, Azerbaijan