Учебное руководство
Главы руководства
На этой странице

Архитектура и границы приложений

Оглавление · Далее: сайт

Для чего нужен каждый компонент

КомпонентЗадачаГраница
Next.jsServer Components, страницы, tRPC, webhook, media proxyТолько опубликованный контент через CMS API
MantineКомпоненты, тема и Styles APIДанные приходят через props
contracts/ZodТипы и проверка HTTP данныхTypeScript не заменяет runtime validation
StrapiРедактирование, Draft & Publish, REST и upload providerСобственные npm/React 18/TS 5
GarageS3 API и public website bucketОдин узел, без AWS ACL и без HA
Hatchet LiteСобытия, очередь, выдача задачВоркеры исполняют код отдельно
Node.js functionsДолгоживущий worker SDKНет HTTP server и scale-to-zero
PostgreSQLРаздельные базы Strapi/HatchetОбщий физический процесс
CaddyTLS, reverse proxyНе заменяет права CMS/API token

Картина на одном VPS

Исходник схемы
flowchart LR
  Visitor[Посетитель] --> Caddy
  Caddy --> Web[Next.js]
  Caddy --> CMS[Strapi]
  Caddy -->|media origin| S3[Garage]
  Web -->|read-only / tagged cache| CMS
  Web -->|media proxy| S3
  CMS -->|S3 upload| S3
  CMS --> CMSDB[(strapi)]
  CMS -->|webhook| Web
  Producer[Отдельный producer] --> Hatchet[Hatchet Lite]
  Hatchet --> Worker[Node worker]
  Hatchet --> QueueDB[(hatchet)]

Две базы находятся в одном PostgreSQL; все контейнеры — на одном VPS. Сбой базы, CMS или хоста отражается на обновлении контента. Готовые страницы кеширует Next.js. Read-only token не передаётся браузеру; панель защищена собственным входом Strapi, а публичные изображения читаются без пароля. Draft media-файлы не становятся приватными автоматически.

Структура монорепозитория

apps/
  web/             Next.js, Mantine, CMS adapter и серверные тесты
  functions/       Долгоживущий Node.js-воркер
packages/
  contracts/       Zod-схемы, типы и имя события
infra/
  strapi/          Самостоятельный npm-проект CMS
  postgres/        Первичное создание пользователей и баз
  Caddyfile*       Локальный и production reverse proxy
scripts/
  setup-env.mjs    Локальные секреты
  hatchet-token.mjs
  deploy/          Подготовка хоста и применение релизов
.github/workflows/ CI и деплой
docs/              Это руководство

В pnpm workspace входят только apps/* и packages/*. infra/strapi использует свой package-lock.json, React 18 и TypeScript 5. Изоляция позволяет использовать современные версии в сайте, не заставляя Strapi разделять несовместимые зависимости.

Зависимости пакетов

Исходник схемы
flowchart TD
  Contracts[contracts: Zod] --> Web[web: Next.js + tRPC + Mantine]
  Contracts --> Functions[functions: Hatchet SDK]
  Strapi[Strapi: отдельный npm lockfile]

Стрелки обозначают направление использования: web и functions импортируют contracts. workspace:* означает локальный пакет, а не скачивание одноимённого пакета из npm. pnpm -r build учитывает зависимости workspace: сначала собирается contracts. Turborepo здесь не установлен; команды выполняет pnpm.

Два пути данных

Чтение: Strapi REST → серверный CMS client → Zod/contracts → repository → Server Component или tRPC → посетитель. Все страницы используют одну модель данных. Полная pagination читается до конца; ошибка второй страницы не выдаётся за полный список.

Обновление: Strapi webhook → HTTP handler → Zod → инвалидирование кеша Next.js. Страницы обновляются при следующем посещении без полной пересборки. Учебный Hatchet worker остаётся отдельным примером фоновой обработки.

Импорт: явный снимок публичного источника → нормализация HTML/дат → upload → Document Service create/publish. Архив нужен для аудита, не для runtime fallback.

Сборка, запуск и проверка типов

  • Сборка превращает TypeScript воркера/contracts в JavaScript, а Next.js — в production-приложение со статически сгенерированными страницами и ISR.
  • Запуск исполняет уже подготовленный код. В dev воркер запускает .ts через Node 24.
  • Проверка типов ищет ошибки без выполнения бизнес-операций.
  • Runtime-валидация проверяет данные, поступившие от внешнего источника.

TypeScript не защищает автоматически от неверного HTTP JSON: сетевой клиент может не использовать TypeScript вообще. Поэтому webhook проверяется Zod как в web, так и в воркере.

Принятые решения

Next.js выбран для страниц и серверного API. Vike в репозитории не используется. Mantine выбран для интерфейса. Jest работает через next/jest, поэтому отдельный Vite-проект для тестирования не нужен. Vitest и Playwright не установлены.

Hatchet даёт удобное объявление функций через SDK, очередь и панель выполнения. Процесс воркера при этом постоянно работает на нашем VPS: автоматического масштабирования, оплаты за вызов и отдельного контейнера для каждой функции нет.

Strapi собирается из стандартного проекта своим Dockerfile. Мы не полагаемся на неопределённый сторонний «готовый Strapi image».

Где смотреть код

Workspace, root scripts, Dockerfile, Compose, контракты.