Files
veilix.app/docs/02-architecture.md
T
2026-10-21 03:30:38 +02:00

11 KiB
Raw Blame History

02. Архитектура

1. Стек

Что Версия на 20.10.2026 Комментарий
Node.js 24 LTS (на сервере 24.22)
pnpm 12.x ставится root через corepack enable pnpm; версия фиксируется полем packageManager
Next.js 16.4.x App Router, React Server Components
React 19.x
Payload CMS 3.91.x Payload 4 в бете; переход после стабильного релиза (D-002)
PostgreSQL 18 (на хосте) адаптер @payloadcms/db-postgres, idType: 'uuid'
Tailwind CSS 4.x токены из макета как CSS-переменные
next-intl 4.x переводы интерфейса, префиксы языков в URL
Nodemailer через @payloadcms/email-nodemailer транспорты SMTP, sendmail, «только журнал»
ALTCHA 3.x капча без третьих сторон
grammY 1.x Telegram-боты, этап 3
Stripe SDK актуальный этап 4

Точные версии фиксируются в package.json на этапе 1a. Если к старту этапа 1a выйдет стабильный Payload 4, начинаем сразу на нём.

2. Одно приложение на все домены

  1. Одно Next.js-приложение, Payload установлен внутрь как библиотека: админка, API и фронтенды — один процесс (D-001).
  2. Proxy Next.js (src/proxy.ts, бывший middleware) по заголовку Host находит запись в коллекции «Домены» и узнаёт сайт (dedicated или mass) и тип фронтенда: сайт, кабинет или MiniApp. Список доменов кэшируется в памяти и сбрасывается при изменении записи.
  3. Proxy переписывает запрос во внутренний маршрут вида /{тип}/{сайт}/{язык}/…, для маркетинговых страниц ещё и /{валюта}/. Снаружи эти пути недоступны: прямой запрос к ним даёт 404.
  4. Хост админки (plc.veilix.cc, dev.plc.veilix.cc) задаётся в .env. Только на нём работают /admin и REST API Payload. На доменах брендов эти пути закрыты.
  5. Сайтам, кабинетам и MiniApp хост админки не нужен: a. данные Payload они читают в том же процессе через Local API — это вызов функции, а не HTTP-запрос; b. запросы браузера (формы, вход, действия в кабинете) идут на тот домен, где открыта страница: server actions и эндпоинты /svc/…; c. вебхуки платёжных систем и Telegram приходят на публичные домены, не на хост админки; d. файлы медиатеки отдаются через домены сайтов.
  6. Ядро общее (биллинг, ключи, вход, рефералы, почта), UI-кит общий, а страницы у каждого бренда свои: данные в дизайнах представлены по-разному.

3. Структура кода (план)

src/
  proxy.ts                  — домен → сайт, тип фронтенда, язык, валюта
  payload.config.ts
  app/
    (payload)/              — админка и REST API Payload (стандартные файлы)
    (front)/m/[site]/[locale]/[currency]/…  — маркетинговые сайты
    (front)/c/[site]/[locale]/…             — кабинеты и оформление заказа
    (front)/t/[site]/…                      — MiniApp (этап 3)
    svc/…                   — свои эндпоинты: ALTCHA, вебхуки, health
  payload/
    collections/  globals/  hooks/  access/  fields/
  core/                     — бизнес-логика без привязки к UI
    billing/  keys/  auth/  referral/  email/  payments/  currency/  geo/
  brands/
    dedicated/  mass/       — страницы и компоненты каждого бренда
  ui/                       — общие компоненты: кнопки, поля, шиты, переключатели, флаги, карта
  i18n/                     — конфиг next-intl и messages/{en,ru,de,fr,es}.json
  styles/                   — Tailwind, токены брендов, темы

Бизнес-логика живёт в core/ и вызывается одинаково из хуков Payload, server actions, вебхуков, фоновых задач и (на этапе 3) бота.

4. Окружения

dev prod
Пользователь ОС vx_dev (под ним работают редактор и сессии Claude) vx_prod (без редактора и ИИ-агентов)
Папка /home/vx_dev/veilix_dev — рабочая копия git /home/vx_prod/veilix — releases/, симлинк current, shared/
Запуск pnpm dev (горячая перезагрузка) pnpm start из current после pnpm build
Порт 3100 3000
База veilix_dev veilix_prod
Схема базы синхронизируется автоматически (push) миграции Payload, применяются при выкладке
Домены dev.*, dev.plc.veilix.cc основные, plc.veilix.cc
Секреты /home/vx_dev/veilix_dev/.env /home/vx_prod/veilix/shared/.env
Файлы (media) /home/vx_dev/veilix_dev/media /home/vx_prod/veilix/shared/media
  1. Без Docker: оба окружения — обычные процессы Node, каждый под своим пользователем ОС, запускаются одинаково — systemd user-юнитами: veilix-dev.service у vx_dev, veilix.service у vx_prod. У vx_dev нет доступа к файлам, секретам, логам и базе prod. Подробно — D-003, D-004.
  2. Dev закрыт от посторонних в nginx и запрещён к индексации, см. 09-infrastructure.md.
  3. Платёжные системы в dev — только в тестовом режиме.

5. Выкладка в prod

  1. В dev: изменения схемы оформляются миграцией (payload migrate:create), коммит, push в Gitea, тег релиза.
  2. Выкладка — команда deploy <тег> пользователя vx_prod, появится на этапе 1h. Запускает её пользователь; по желанию — sudo-правило, разрешающее vx_dev запускать только эту команду (Q-18). Шаги: a. взять тег из Gitea (у vx_prod ключ только на чтение) в новую папку releases/<дата-тег>; b. pnpm install --frozen-lockfile и pnpm build; ссылки на shared/.env и shared/media; c. применить миграции к veilix_prod; d. переключить симлинк current на новый релиз и перезапустить veilix.service; e. проверить /svc/health; хранить 5 последних релизов.
  3. Откат: переключить current на прошлый релиз и перезапустить. Миграции пишем так, чтобы прошлый релиз продолжал работать с новой схемой (сначала добавляем, удаляем позже).
  4. Простой при выкладке — только время перезапуска процесса, несколько секунд.

6. Рендеринг и кэширование

  1. Маркетинговые страницы собираются статически во всех вариантах «язык × валюта» и кэшируются. Proxy выбирает вариант по префиксу языка и cookie валюты.
  2. Изменение в админке (цена, статус локации, FAQ) вызывает хук Payload, и Next.js пересобирает затронутые страницы за секунды (on-demand revalidation по тегам). Запасной вариант — плановое обновление раз в 5 минут.
  3. При оформлении заказа наличие и цена проверяются заново на сервере. Устаревшая страница не может продать то, чего нет.
  4. Кабинет рендерится на сервере (SSR) для каждого запроса, без кэша.
  5. Маркетинговые домены не ставят cookies, кроме выбора языка, валюты и темы.

7. Фоновые задачи

Встроенная очередь Payload (Jobs Queue) с расписанием cron. Исполнитель работает внутри процесса приложения (autoRun), в dev его можно отключить переменной окружения.

Задача Расписание Что делает
renewals каждые 15 минут продление ключей, у которых срок подходит (см. 04-billing.md)
reminders каждый час напоминания за 3 дня до окончания
expiry каждые 15 минут перевод в льготный период и в «истёк»
send-email по событию отправка письма с повторами при ошибке
cleanup раз в сутки старые коды входа, сессии, записи журнала писем
reconcile раз в сутки сверка кэша баланса с суммой движений по счёту

8. Чего не используем

  1. Docker — не нужен ни в dev, ни в prod (D-003).
  2. n8n — боты пишем в коде на grammY (D-015).
  3. listmonk — шаблоны писем в Payload, отправка своим транспортом (D-014).
  4. Redis — стоит на сервере, но пока не нужен: лимиты запросов и очередь задач работают на PostgreSQL.