Insights / Технические материалы

Руководство по внедрению Sveltia CMS

Практическое руководство по добавлению Sveltia CMS в Astro или другой статический сайт: GitHub OAuth, отдельное GitHub App, проверяемая прямая публикация, загрузка изображений и многоязычная эксплуатация.

  • Технологии
  • CMS
  • Astro
  • Cloudflare
  • Безопасность
Руководство по внедрению Sveltia CMS
Содержание
  1. Когда Sveltia CMS подходит
  2. Общая архитектура
  3. 1. Разместить админку в public/admin
  4. 2. Настроить GitHub backend
  5. 3. Добавить OAuth Worker
  6. 4. Заранее определить папку медиа
  7. 5. Разделить collections
  8. 6. Использовать relation и select
  9. 7. Редактировать японские source JSON
  10. 8. Хранить writer credentials только в production
  11. 9. Проверять и публиковать напрямую через save proxy
  12. 10. Перевод только для CMS commits
  13. 11. Отдельный CSP для /admin
  14. Turnstile отдельно
  15. Уроки из PR и commit
  16. Минимальная отправная точка
  17. Ссылки
  18. Итог

Sveltia CMS полезна, когда статическому сайту нужна удобная админка, но переносить контент во внешнюю базу данных не хочется. В этой статье описано, как мы внедрили Sveltia CMS на Astro-сайте Acecore и какие проблемы исправили позже по итогам PR и commit.

Обновлено 28 июля 2026 года: сохранения CMS теперь после синхронной проверки записываются прямо в main одним commit с префиксом cms:. GitHub OAuth проверяет редактора и актуальное право записи, а установленная только в acecore-net GitHub App выполняет операции с репозиторием. До записи проверяются JSON/Markdown schema, сигнатура изображения, активные HTML/URL и expected HEAD.

Заголовок намеренно простой: Руководство по внедрению Sveltia CMS. Это не сравнение CMS, а практический ориентир для внедрения на другом сайте.

Когда Sveltia CMS подходит

Sveltia CMS не владеет отдельной базой данных и не отдаёт контент через отдельный API. Это SPA в браузере, которое редактирует файлы репозитория через GitHub backend.

Она хорошо подходит, если:

  • контент хранится как Markdown или JSON в репозитории
  • изменения статей, авторов, тегов и текстов страниц нужно ревьюить как Git diff
  • не хочется добавлять базу данных или отдельный сервис администрирования
  • изображения можно хранить в public/uploads
  • CMS-сохранение должно сразу запускать публикацию, а изменения кода должны оставаться защищены Pull Request

Если нужны сложные права, развитое планирование публикаций, большая медиатека или редактирование realtime-данных, лучше рассмотреть полноценную headless CMS.

Общая архитектура

public/admin/index.html
  -> загружает @sveltia/cms из CDN

public/admin/config.yml
  -> описывает GitHub backend, collections и media folders

workers/sveltia-cms-auth
  -> Cloudflare Worker для GitHub OAuth

main branch
  -> единственный источник для production

CMS save proxy
  -> проверяет пути и содержимое и пишет cms:-commit с expected HEAD в main

.github/workflows/submit-openai-translation-batch.yml
  -> в течение 15 минут объединяет обновления японского источника и отправляет их в OpenAI Batch

Админская страница — только начало. Аутентификация, пути медиа, preview branches, переводы и стратегия merge тоже становятся частью CMS-дизайна.

1. Разместить админку в public/admin

В Astro каталог public публикуется как статические файлы. Документация Sveltia CMS также указывает public как static folder для Astro, Next.js, Nuxt, Remix и VitePress.

<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8" />
    <meta name="robots" content="noindex,nofollow" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>CMS</title>
  </head>
  <body>
    <script src="https://unpkg.com/@sveltia/cms@0.172.4/dist/sveltia-cms.js"></script>
  </body>
</html>

Не стоит добавлять лишний CSS или type="module" без причины. Стили интерфейса уже включены в JavaScript bundle.

Acecore использует ручную инициализацию для явной настройки backend. Ветка публикации остаётся main во всех окружениях.

CMS.init({
  config: {
    backend: {
      branch: "main",
    },
  },
});

2. Настроить GitHub backend

Минимум — backend.name и backend.repo. Для production также стоит заранее определить branch, OAuth и сообщения commit.

backend:
  name: github
  repo: owner/repository
  branch: main
  base_url: https://your-sveltia-cms-auth-worker.example.workers.dev
  api_root: /admin/api/github
  graphql_api_root: /admin/api/graphql
  auth_methods: [oauth]
  commit_messages:
    create: 'cms: create {{collection}} "{{slug}}"'
    update: 'cms: update {{collection}} "{{slug}}"'
    delete: 'cms: delete {{collection}} "{{slug}}"'
    uploadMedia: 'cms: upload "{{path}}"'
    deleteMedia: 'cms: delete media "{{path}}"'

Оставьте main веткой публикации и направляйте чтение и сохранение через same-origin proxy. Перед каждым сохранением proxy повторно проверяет право GitHub-пользователя на запись, использует установленное только в acecore-net GitHub App для доступа к репозиторию и проверяет пути, содержимое и последний HEAD main, прежде чем создать один direct commit.

По состоянию на 20 июля 2026 года Editorial Workflow не реализован в Sveltia CMS. Настройка Decap CMS publish_mode: editorial_workflow не заставляет Sveltia CMS автоматически создавать временные ветки или PR.

Постоянная ветка вроде cms-content требует непрерывной синхронизации и повышает риск конфликтов или неверной настройки источника deploy. Acecore сохраняет main единственным источником истины и отклоняет параллельные обновления через expectedHeadOid.

3. Добавить OAuth Worker

Personal Access Token подходит для теста, но не для нескольких редакторов. Acecore использует Sveltia CMS Authenticator на Cloudflare Workers и указывает его как base_url.

Callback URL в GitHub OAuth App указывает на /callback Worker. В Worker задаются GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET и при необходимости ALLOWED_DOMAINS.

Это не то же самое, что Turnstile. OAuth защищает вход в CMS, а Turnstile защищает формы или API комментариев от ботов.

4. Заранее определить папку медиа

Sveltia CMS может сохранять медиа в репозитории. Для Astro практичная настройка такая:

media_folder: public/uploads
public_folder: /uploads

Acecore позже исправила этот момент в PR #116. Путь в репозитории и публичный URL нужно выбирать одновременно при внедрении CMS.

5. Разделить collections

collection Цель Правило
blog src/content/blog/*.md Редактировать только японские source-статьи
authors src/content/authors/*.json Редактировать профили и локализованные имена
tags src/content/tags/*.json Редактировать теги и локализованные имена
page text src/i18n/source/ja/**/*.json Редактировать японские source-тексты страниц и UI

Не обязательно открывать в CMS все переведённые Markdown-файлы. Acecore считает японский source каноническим, а переводы обновляет через Как вести многоязычный блог с Sveltia CMS.

6. Использовать relation и select

Теги лучше выбирать через relation, а не вводить свободным текстом.

- name: tags
  label: Теги
  widget: relation
  collection: tags
  value_field: name
  display_fields: ["{{name}} ({{id}})"]
  search_fields: [name, id]
  multiple: true
  required: false

Авторы, иконки и стили уведомлений работают по той же логике. Хорошая CMS не только позволяет редактировать, но и мешает сохранить плохие значения.

7. Редактировать японские source JSON

Тексты фиксированных страниц тоже можно отдать в CMS. Acecore хранит японский source в src/i18n/source/ja/**/*.json.

Урок простой: не добавлять все поля сразу. config.yml быстро растёт. Начните с блога, авторов, тегов, объявлений и часто меняющихся страниц.

8. Хранить writer credentials только в production

Client ID, installation ID и private key GitHub App настраиваются только в production-окружении Cloudflare Pages. Preview не получает writer credentials, поэтому чтение и запись репозитория там отключены. Контент сохраняется и публикуется только через production /admin/, а Pages preview используется для обычных PR кода и конфигурации.

CMS.init({
  config: {
    backend: {
      branch: "main",
    },
  },
});

9. Проверять и публиковать напрямую через save proxy

Same-origin save proxy синхронно проверяет разрешённую область и содержимое и создаёт ровно один commit в main.

backend:
  name: github
  repo: owner/repository
  branch: main
  api_root: /admin/api/github
  graphql_api_root: /admin/api/graphql

GitHub OAuth непосредственно перед сохранением повторно проверяет редактора и его право записи. Короткоживущий installation token GitHub App, установленной только в acecore-net, выполняет чтение и запись. Допускаются только разрешённый контент и изображения; SVG и PDF отклоняются.

Сохранение использует начальный HEAD как expectedHeadOid; конкурентное изменение возвращает 409. При потере ответа GitHub операция считается успешной только при совпадении marker запроса, parent SHA, всех путей и blob SHA.

Прямой commit сохраняет subject вида cms: create ... или cms: update .... Тот же push GitHub App запускает Pages deploy и задачу перевода. Код, schema, workflows, конфигурация CMS и переводы по-прежнему проходят через PR и CI.

10. Перевод только для CMS commits

PR #98 добавил --cms-only, чтобы push-triggered задачи перевода создавались только для CMS commits.

function isCmsCommitSubject(subject) {
  return /^cms: (create|update|delete) /.test(subject || "");
}

cms: — это контракт workflow, а не декоративный префикс.

11. Отдельный CSP для /admin

Админка подключается к CDN, GitHub API, OAuth Worker и blob URL. Поэтому Acecore задаёт отдельный CSP для /admin/* и помечает эту область как noindex.

Turnstile отдельно

Старая версия статьи смешивала CMS и Cloudflare Turnstile. Это размывало тему.

Sveltia CMS — про GitHub backend, OAuth, collections, медиа и PR. Turnstile — про защиту форм или API от ботов. Это разные уровни.

Уроки из PR и commit

  • При смене CMS нужно обновлять статьи и внутренние ссылки.
  • OAuth должен быть частью реального setup, а не задачей на потом.
  • Пути медиа нужно зафиксировать до загрузок.
  • config.yml лучше расширять постепенно.
  • cms: — контракт автоматизации.
  • Writer credentials находятся только в production; preview без доступа к репозиторию используется для обычных PR кода и конфигурации.

Минимальная отправная точка

public/admin/index.html
public/admin/config.yml
public/admin/init.js
public/admin/runtime-config.js

Затем добавляйте relation для авторов и тегов, изображения, source JSON, синхронную проверку direct publish и задачи перевода.

Ссылки

Итог

Sveltia CMS легко положить в public/admin, но production-внедрение требует решений о branch, OAuth, media folders, source language, workflow переводов и merge strategy. Когда эти правила понятны, Astro-сайт остаётся статическим и лёгким, но получает рабочий процесс обновления контента.

Поток внедрения Sveltia CMS

Админку, аутентификацию, редактируемый контент, медиа и PR-процесс стоит проектировать отдельно.

  1. Добавить админку

    Разместить index.html и config.yml в public/admin и загрузить Sveltia CMS.

  2. Настроить GitHub

    Заранее определить repo, branch, OAuth Worker и сообщения commit для CMS.

  3. Ограничить область редактирования

    Открыть в CMS только блог, авторов, теги и японские source JSON, которые действительно нужно редактировать.

  4. Автоматизировать эксплуатацию

    Использовать main как ветку публикации и связать проверяемые direct commits, Pages deploy и задачи перевода.

До и после CMS

Ручное редактирование Markdown

  • Обновлять удобно только тем, кто уверенно пользуется GitHub или редактором
  • Пути изображений, ID авторов и теги вводятся вручную
  • Изменения японского source и переводов легко смешать
  • Цель сохранения и доступные для записи пути могут быть неясны

Редактирование в Sveltia CMS

  • Markdown и JSON редактируются через формы в браузере
  • relation, image и select уменьшают число некорректных значений
  • Только CMS commits запускают задачи перевода
  • Same-origin proxy проверяет разрешённый контент и пишет один direct commit в main

Чеклист внедрения

  • Загрузить Sveltia CMS из public/admin/index.html
  • Описать GitHub backend и collections в public/admin/config.yml
  • Использовать OAuth Worker для нескольких редакторов
  • Согласовать media_folder и public_folder с каталогом public в Astro
  • Определить, как CMS commits запускают перевод или публикацию

Частые вопросы

Для каких сайтов подходит Sveltia CMS?

Для статических сайтов, где Markdown или JSON находятся в репозитории, например Astro, Hugo или VitePress. CMS можно добавить без внешней базы данных.

Можно ли использовать только GitHub Personal Access Token?

Для теста можно. Но для нескольких редакторов или нетехнических пользователей OAuth Worker безопаснее и понятнее.

Нужно ли редактировать все языки в CMS?

Для небольшой команды безопаснее редактировать в CMS только японский source, а переводы обновлять через PR.