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

Начало

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

Оглавление

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

КомпонентЗадачаГраница
Next.jsСтраницы, 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
PostgreSQLБаза StrapiОтдельный контейнер, тот же VPS
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 -->|legacy media proxy| S3
  CMS -->|S3 upload| S3
  CMS --> CMSDB[(PostgreSQL: strapi)]
  CMS -->|webhook| Web

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

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

apps/
  web/             Next.js, CMS adapter и серверные тесты
  docs/            Статический сайт учебника
packages/
  contracts/       Zod-схемы и типы
  ui/              Независимый React/UIKit на Mantine и Storybook
infra/
  strapi/          Самостоятельный npm-проект CMS
  postgres/        Первичное создание пользователей и баз
  garage/          S3-совместимое объектное хранилище
  docs/            Образ и конфигурация учебника
  storybook/       Образ и конфигурация каталога компонентов
  Caddyfile*       Локальный и production reverse proxy
scripts/
  setup-env.mjs    Локальные секреты
  deploy/          Подготовка хоста и применение релизов
.github/workflows/ CI и деплой
docs/              Это руководство

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

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

Исходник схемы
flowchart TD
  Web[web: Next.js] --> Contracts[contracts: Zod]
  Web --> UI[ui: React и Mantine]
  UI --> Mantine[Mantine]
  Docs[docs: Next.js и MDX]
  Strapi[Strapi: отдельный npm lockfile]

Стрелки обозначают импорты: web использует contracts и ui. UIKit не импортирует Next.js или CMS; приложение передаёт данные и адаптер ссылок. Docs самостоятельно читает Markdown/MDX и не обращается к CMS. workspace:* означает локальный пакет, а не скачивание одноимённого пакета из npm. pnpm -r build учитывает зависимости workspace: сначала собирается contracts. Для сборки workspace отдельный оркестратор не нужен; команды выполняет pnpm.

Пути данных

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

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

Медиа: браузер → Caddy → Garage website endpoint. CMS-адаптер нормализует адрес до публичного /filename; Caddy добавляет внутренний префикс strapi/. Next.js участвует в передаче только для старых local uploads через /api/media/.

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

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

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

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

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

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

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

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

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

Наблюдаемость

Новый самостоятельный Compose-стек описан в infra/observability: браузер → Umami, ошибки Next.js → GlitchTip, Node/Blackbox Exporter → Prometheus → Grafana. UIKit не импортирует SDK аналитики или ошибок; интеграция находится в apps/web. Базы аналитики и ошибок отделены от Strapi ролями и владельцами.

Внешняя доставка алертов отключена; Telegram является учебным упражнением. Все системы наблюдения размещаются на том же VPS и разделяют его отказ. Пояснение DevOps · Практическая глава.