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

Исторический документ: результаты относятся к указанной в тексте дате.

История проекта

Перенос контента в Strapi

Дата: 2026-10-02. Статус: схема согласована. Дополнение пользователя: отдельный S3-контейнер вместо local provider; перенос контента ещё не начат.

Результат

Strapi становится единственным рабочим источником редакционного контента: новостей, программы событий, текстов главной, FAQ, маршрутов, размещения, партнёров и правил. Редактор меняет и публикует запись в Content Manager; после публикации сайт показывает новое состояние без пересборки образа Next.js. Снятая с публикации запись перестаёт отображаться; её детальная страница отдаёт 404.

Существующий Next.js/Mantine интерфейс сохраняется. JSON в apps/web/src/data больше не используется как источник и не служит скрытым fallback при отказе CMS.

Объём «весь контент» пока предполагает все публичные информационные разделы оригинального сайта. Формы регистрации, SMS, личные кабинеты и пользовательские данные не переносятся: это отдельная функциональность, а не редакционный контент.

Что найдено на оригинальном сайте

Сайт https://атманки.рф/ — клиентское приложение. Его публичный bundle обращается к https://etnosportapi.npotau.ru; идентификатор праздника — 1. Проверены следующие источники:

ИсточникСодержимое снимка
events/1Описание, фотографии, промо, группы партнёров, маршруты, размещение, правила
news?id_event=194 новости; список содержит неполный текст
news/{id}Полный текст конкретной новости и галерея
events/program?id_event=1Программа на три дня, 22–24 августа 2025 года
sub_events/{id}Подробности конкретного пункта программы
home/faq?id_event=115 вопросов и ответов
dates/list?id_event=110 исторических отметок и наград

Это снимок обнаруженных данных, а не обещание неизменности стороннего API. Новости включают публикации 2026 года; программа относится к 2025 году. Импорт сохраняет исходные даты и не выдаёт старое расписание за будущий праздник.

В ответе API также есть явно тестовые поля: test@test.ru, @newtest, newexample.com, тестовый документ и пробный текст conditions. Их нельзя автоматически показывать как настоящие контакты. Переносится содержимое публичных разделов, а спорные поля записываются в отчёт импорта для проверки.

Модели и редактирование

Используем существующие коллекции «Новости» и «События», добавляем:

  • sourceId, sourceUrl: происхождение и повторяемый импорт;
  • media-поля обложки и галереи, включая подпись/альтернативный текст;
  • datetime публикации новости вместо потери времени в поле date;
  • nullable время окончания события, без выдуманного значения;
  • редакторское тело текста с поддержкой абзацев и ссылок.

Для главной — single type «Сайт»: название, даты, статус праздника, место, слайды, исторические отметки, секции и навигация. Повторяющиеся элементы оформляются компонентами Strapi, чтобы редактор не редактировал произвольный JSON. FAQ, партнёры и информационные страницы — отдельные коллекции с порядком показа. Существующие демонстрационные записи не удаляются автоматически.

При импорте HTML оригинала разбирается и преобразуется в поддерживаемую структуру текста; скрипты, обработчики событий и небезопасные ссылки не отображаются. Исходная разметка сохраняется в архиве импорта для проверки точности переноса.

Фотографии

Хранилище — отдельный контейнер Garage 2.3.0 с S3-совместимым API. Strapi использует официальный @strapi/provider-upload-aws-s3@5.56.0:

  • файлы загружаются в Media Library, а не остаются внешними ссылками;
  • объекты и metadata Garage живут в отдельных постоянных томах s3_data и s3_metadata;
  • прежний том strapi_uploads сохраняется для старых файлов до их явной миграции;
  • обложки и галереи связаны с записями через media-поля;
  • сохраняются подписи и авторство, если они есть в исходнике;
  • повторный импорт распознаёт уже загруженный файл по источнику/контрольной сумме;
  • отсутствующие или неподходящие файлы отражаются в отчёте, не заменяются молча.

Garage запускается одним узлом на том же VPS. Это учебная схема без репликации: S3 API не добавляет резервную копию или защиту от потери VPS. Копировать нужно базу Strapi, объекты, metadata Garage и ключи в отдельное хранилище.

S3 API доступен контейнерам по http://s3:3900, на хосте — только loopback. Для публичных изображений Garage website endpoint отдаёт bucket media через Caddy на media.gheilt.mxsource.xyz. Запись/удаление требует S3 key; public website не предоставляет admin/API. Фотографии, включая загруженные к черновикам, являются публичными файлами — Draft & Publish регулирует документы, а не приватность media.

В provider необходимо задать forcePathStyle: true, region garage и явное params: { Bucket: "media", ACL: undefined }: иначе provider подставит public-read ACL, который Garage не реализует. Адрес для записи внутренний, baseUrl публичный; не публикуются signed URL с внутренним именем контейнера.

С 2026-10-04 панель CMS использует собственный вход Strapi; Basic Auth Caddy отключён из-за конфликта с Bearer-запросами. Сайт предоставляет ограниченный same-origin media endpoint, читающий только strapi/ prefix bucket media через внутренний website endpoint Garage с фиксированным Host. Он не принимает произвольные URL и не открывает admin/API. Для preview Media Library Strapi допускается публичный media origin в CSP. Конкретная совместимость проверяется настоящими upload/get/delete через закреплённый Strapi provider, не только наличием S3 API.

Получение данных сайтом

Серверный адаптер Strapi REST → Zod → контракты приложения используется процедурами tRPC, страницами и metadata. Секретный read-only API token находится только на сервере. Public role Strapi не получает права создавать/изменять записи. Выбираются опубликованные записи; media явно populate'ятся; списки учитывают pagination, чтобы не обрезать импорт до первой страницы REST API.

Чтение выполняется во время запроса (no-store) — простой исходный вариант без окна устаревшего кэша. Сборка Next.js не обращается к живой CMS и не требует токена. generateStaticParams на CMS-страницах удаляется. Недоступная CMS приводит к явному состоянию ошибки/503; она не маскируется пустым списком или учебным JSON.

Текущая линия webhook → Hatchet остаётся доступной для изучения фоновых задач. При чтении без кэша webhook не нужен для публикации на сайте. Введение кэширования и revalidation — отдельное последующее изменение.

Импорт и развёртывание

Импорт — явная команда, а не bootstrap при каждом старте CMS.

  1. Снять проверяемый снимок всех открытых источников и отдельных текстов.
  2. Скачать media, проверить типы и доступность, составить manifest и отчёт.
  3. Применить новые схемы на локальной CMS, не удаляя старые данные.
  4. Загрузить файлы и создать отсутствующие записи с исходными идентификаторами.
  5. Повторный запуск пропускает уже импортированные записи; ручные правки редактора не перезаписываются. Принудительное обновление — отдельный явный режим.
  6. Проверить локально полный сценарий редактор → publish → сайт.
  7. Снять резервную копию production-базы, объектов/metadata Garage, прежних uploads и конфигурации до миграции.
  8. Развернуть CMS и импортировать данные, проверить количество и media.
  9. Переключить сайт на CMS после готовности данных, проверить публичные страницы.

На переходном этапе старый JSON-сайт продолжает работать, пока новая CMS готовится. Финальная версия сайта читает только Strapi. Деплой не должен автоматически переимпортировать оригинал или перезаписывать записи на каждом push.

Проверки и критерии готовности

  • Серверные тесты адаптера: опубликованная запись, pagination, media, nullable endsAt, неверный ответ CMS, отказ CMS и неизвестный slug.
  • tRPC сохраняет типы и правильные HTTP/error semantics после смены источника.
  • Сборка и typecheck workspace, lint, format, Jest; отдельная сборка образа CMS.
  • Редактор создаёт/публикует учебную запись обычным действием Strapi; список, детали и metadata показывают её без rebuild. После unpublish детали отдают 404.
  • Все исходные новости и пункты программы учтены отчётом: импортировано либо явно указана причина пропуска. Файлы не зависят от работоспособности оригинала.
  • Повтор импорта не создаёт дубликаты и не стирает ручную правку.
  • Проверены публичная загрузка фотографий, защита admin и отсутствие токена в браузере.
  • Документация обновлена: запуск требует CMS; прежние утверждения про JSON и «публикация не меняет сайт» больше не описывают актуальное поведение.

Автоматические UI-тесты не добавляются. Проверка редакторского сценария выполняется вручную; серверные проверки не выдаются за подтверждение этого сценария.

Официальные источники

После согласования этого решения составляется план выполнения с отдельными коммитами: модели и импорт → адаптер и страницы → deployment/media → документация.