Перенос контента в 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=1 | 94 новости; список содержит неполный текст |
news/{id} | Полный текст конкретной новости и галерея |
events/program?id_event=1 | Программа на три дня, 22–24 августа 2025 года |
sub_events/{id} | Подробности конкретного пункта программы |
home/faq?id_event=1 | 15 вопросов и ответов |
dates/list?id_event=1 | 10 исторических отметок и наград |
Это снимок обнаруженных данных, а не обещание неизменности стороннего 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.
- Снять проверяемый снимок всех открытых источников и отдельных текстов.
- Скачать media, проверить типы и доступность, составить manifest и отчёт.
- Применить новые схемы на локальной CMS, не удаляя старые данные.
- Загрузить файлы и создать отсутствующие записи с исходными идентификаторами.
- Повторный запуск пропускает уже импортированные записи; ручные правки редактора не перезаписываются. Принудительное обновление — отдельный явный режим.
- Проверить локально полный сценарий редактор → publish → сайт.
- Снять резервную копию production-базы, объектов/metadata Garage, прежних uploads и конфигурации до миграции.
- Развернуть CMS и импортировать данные, проверить количество и media.
- Переключить сайт на 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 → документация.