Управление контентом
pacod-cms
Один стек — много редакционных сайтов. Статьи, реклама и статистика со встроенным AI-переводом.
pacod-cms — система управления контентом с открытым исходным кодом для редакционных сайтов. Одна инсталляция обслуживает множество сайтов, у каждого из которых своя база данных, файлы и кэш; редакторы работают в многоязычной студии, а читатели получают быстрые публичные сайты с маршрутизацией по хосту.
- Apache-2.0
- Версия 0.0.1
- Предварительная
Возможности
-
Редакционное ядро
Статьи, рубрики, авторы, теги и постоянные страницы, а также общая библиотека изображений для всего сайта.
-
Мультисайтовость изначально
У каждого сайта своя база данных MongoDB, файлы и кэш, и он отвечает на тех хостах, которые за ним закреплены.
-
Реклама
Размещение рекламы с конструктором HTML5-баннеров, а также страница link-in-bio для профилей в соцсетях.
-
Статистика
Статистика по читателям, рекламе и краулерам, чтобы редакторы видели, что читают и что индексируют.
-
Многоязычность
Контент на многих языках с настраиваемым языком оригинала; сама студия — на английском, болгарском, немецком и русском.
-
AI-перевод
Переводите статью или целый сайт в виде задачи; любой ответ отклоняется, если в нём не сохранена в точности разметка статьи.
-
Организации и роли
Организации, сайты и приглашения, с ролями на уровне организации и сайта, которые хранятся в pacod-id.
-
Настраиваемые PDF
PDF статей в виде фоновой задачи, в печатном оформлении сайта или в научном формате в две колонки, с аннотацией и ключевыми словами из статьи или написанными AI.
-
Выпуски журнала
Статьи, собранные в выпуск, — по одному PDF на каждый язык с обложкой, редакционной статьёй, содержанием и нумерацией страниц, опубликованный в архиве сайта.
Место в экосистеме
Один стек, множество сайтов
pacod-cms обслуживает множество сайтов множества организаций из одного стека. У каждого сайта своя база данных MongoDB, своя папка с файлами и свои записи в кэше, и он отвечает на тех хостах, которые за ним закреплены. Любой зарегистрировавшийся может создать организацию, стать её администратором, создавать в ней сайты и приглашать людей для работы над ними; лимиты задаёт администратор платформы.
Архитектура исходит из того, что владелец сайта может быть враждебен ко всем остальным в инсталляции. Сайты выполняют скрипты, написанные их владельцами, — HTML5-баннеры, менеджеры тегов, тексты статей, — и платформа должна держать эти скрипты и эти данные там, где им место.
Как устроены части
| Часть | Что делает |
|---|---|
pacod-cms-core |
Библиотека: документы, сервисы, мультиарендность, управляющий слой, начальное содержимое, модель дизайна и порт движка правил pacod-id на Java. |
pacod-cms-site |
Публичный сайт сразу для всех сайтов: страницы, JSON только для чтения под /web/v1/**, медиафайлы, счётчики трафика. |
pacod-cms-studio |
Студия: портал для организаций, сайтов и участников, экраны редактирования, фоновые задачи, AI. |
| Caddy | Входная дверь, маршрутизирует по хосту: хост студии — в студию, хост pacod-id — в pacod-id, любой другой хост — на сайт. |
| Gotenberg | Создаёт PDF статей и выпусков журнала из версий сайта для печати. |
Два приложения никогда не обращаются друг к другу. Оба работают с MongoDB напрямую, поэтому правка, сделанная в студии, доходит до публичного сайта через базу данных; кэши сайта истекают через 60 секунд, а не сбрасываются, так что правка появляется на сайте в течение минуты.
От хоста до страницы
Каждая единица работы относится ровно к одному сайту, который привязан к ней на всё время её выполнения.
- Caddy передаёт запрос сайту. В продакшене Caddy запрашивает сертификат сайта при первом посещении, но только после того, как сайт подтвердит, что хост принадлежит активному сайту.
- Сайт ищет хост в управляющем слое раньше, чем выполняется что-либо ещё. Хост, который не закреплён ни за одним активным сайтом, получает простой 404, а не сайт по умолчанию.
- Когда сайт привязан, каждая операция с MongoDB идёт в базу данных этого сайта. Если сайт не привязан, слой доступа к данным выбрасывает ошибку, а не угадывает.
- Макет типа страницы — области с упорядоченными секциями — разрешается относительно набора шаблонов сайта, а данные каждой секции загружаются заранее. Шаблоны никогда не делают запросов; секция, данные которой не загрузились, пропускается и записывается в лог, а страница всё равно отображается.
В студии сайт определяется по пути (/sites/<id>/mgmt/…); фоновая работа привязывает тот сайт,
для которого выполняется.
Где хранятся данные
| Где | Что |
|---|---|
pacod_cms |
Управляющий слой: организации, сайты, домены, настройки платформы, очередь задач. |
site_<id> |
Отдельная база данных для каждого сайта: статьи, страницы, изображения, баннеры, меню, настройки, макеты, тема, статистика. |
sites/<id>/ |
Файлы сайта: изображения к статьям, рекламные креативы, PDF. PDF черновика выпуска лежат в закрытой папке, которую отдаёт только студия. |
| pacod-id | Люди, сессии и назначенные роли. CMS не хранит учётных записей. |
Идентичность сайта — название, логотипы, контактные данные, идентификаторы сторонних сервисов — это данные, а не разметка. Сторонний идентификатор выводится, только если он задан и имеет формат своего поставщика, поэтому новый сайт не загружает никакого отслеживания. Исходный язык содержимого сайта — последний запасной вариант при отсутствии перевода и юридически определяющий текст.
Дизайн без кода
В разделе Дизайн студии каждый сайт выбирает набор шаблонов — editorial, журнал с колонкой
рядом с содержимым, или minimal, одна спокойная колонка — и составляет макет для каждого типа
страницы: главная, статья, рубрика, последние, постоянная страница и поиск. Среди секций — списки
статей (последние, из рубрики или самые читаемые), форматированный текст, призыв к действию, поле
поиска и ссылки на соцсети. Тема задаёт цвета со значениями для ночного режима, шрифты и ширины.
Смена набора сначала показывает, что будет потеряно, и ничего не удаляется: секции, которые новый набор не может показать, сохраняются и возвращаются при обратной смене. Макеты и тема остаются черновиками, пока их не опубликует тот, у кого есть на это право. Предпросмотр показывает черновики с собственного адреса сайта, в ширине компьютера, планшета или телефона, по подписанному токену, действующему 30 минут, и ничего не учитывает в статистике.
Новый набор шаблонов — это код, который устанавливает оператор, а не загружаемый файл: шаблон Thymeleaf может всё, что может сам сайт.
PDF и выпуски журнала
Долгая работа выполняется в студии как задача, по одной организации за раз, с живым логом и кнопкой отмены. Экспорт в PDF — одна из таких задач: Gotenberg превращает каждую статью в отдельный PDF на каждом языке, на котором она написана, а статья ссылается на свой PDF, как только он появится.
- Два формата. Стандартный — это версия сайта для печати. Научный — макет научной статьи: шапка на всю ширину с заголовком, авторами, аннотацией и ключевыми словами, затем текст в две колонки.
- Два способа создания. Только код берёт аннотацию и ключевые слова из описания и тегов статьи. С AI поручает pacod-gw написать аннотацию, ключевые слова и короткий колонтитул для каждой статьи и каждого языка. Текст статьи никогда не меняется.
- Настройки PDF хранят значения по умолчанию для каждого сайта: формат и способ, бумагу (A4, Letter или A5) и поля, название журнала на каждом языке и его ISSN, колонтитул и номера страниц. Любой запуск может выбрать другой формат и способ.
Выпуск журнала собирает статьи в один PDF на каждый язык. У него есть том, номер и месяц,
заголовок и редакционная статья на каждом языке и, по желанию, изображение для обложки; статьи
выбираются по одной или подбираются по его месяцу, а затем упорядочиваются. При генерации создаются
обложка, редакционная статья, содержание с номерами страниц, а затем статьи, с закладкой для каждой
статьи и сквозной нумерацией страниц. PDF черновика выпуска скачиваются только из студии. После
публикации выпуск и его PDF появляются на сайте по адресу /issues и в карте сайта.
Модель безопасности
Кто что может
Учётные записи и роли принадлежат pacod-id. Токены не несут ролей: студия следит за потоком
назначенных ролей pacod-id и сама решает каждое разрешение по манифесту CMS (authz/cms.yaml). Роли
таковы: администратор платформы, провижнер, администратор организации, администратор сайта,
дизайнер, редактор, автор и аналитик — на уровне платформы, организации или сайта. Автор пишет;
редактор ещё и публикует.
- Каждый обработчик студии объявляет нужное ему разрешение; обработчик, который ничего не объявил, отклоняется. Неявных ролей нет.
- Если поток pacod-id не отвечал минуту, студия отвечает 503, а не принимает решение по ролям, которые, возможно, уже отозваны. Публичные сайты это не затрагивает.
Сайты изолированы друг от друга
- Студия находится на другом регистрируемом домене, чем сайты, иначе она не запускается. В противном случае скрипт сайта мог бы устанавливать cookie для студии и обойти её защиту от CSRF.
- Студия никогда не отдаёт HTML или скрипты сайта. Предпросмотр черновиков и HTML5-баннеров встраивается с собственного origin сайта.
- Gotenberg изолирован: он может обращаться только к внутреннему адресу сайта и не выполняет JavaScript.
- До читателя доходят только опубликованные статьи — на каждом маршруте, в каждом списке, ленте, карте сайта и PDF. Черновик выпуска журнала никогда не бывает публичным.
AI, который не трогает ваши ключи
Каждый вызов AI проходит через pacod-gw; студия никогда не хранит ключ поставщика. Для новых организаций AI по умолчанию выключен: администратор платформы включает его для организации, а администратор сайта может отключить его для своего сайта.
- Перевод статей выполняется как задача. Переведённый текст должен в точности сохранить
разметку оригинала — меняться могут только
alt,title,aria-labelиplaceholder, — иначе он отклоняется. - Перевод сайта охватывает постоянные страницы, названия разделов, меню, страницу ссылок и, если отмечено, теги, не перезаписывая правки, сделанные во время выполнения; не более 2000 вызовов за запуск.
- Помощь в написании переформулирует выделенный текст шестью способами и предлагает анонс и теги.
- Альтернативный текст на каждом языке предлагает модель компьютерного зрения по самому изображению.
- Помощник по дизайну набрасывает тему или макет по нескольким словам и записывает только в черновик.
- Шапка PDF: для PDF, созданных с AI, аннотация, ключевые слова и колонтитул для каждой статьи и каждого языка, проверенные как обычный текст. Они используются повторно, пока статью не отредактируют.
Шлюз видит только непрозрачные идентификаторы, никогда не имена и не адреса электронной почты.
Три окружения, один Makefile
| dev | stage | prod | |
|---|---|---|---|
| Входная дверь | HTTP, плюс HTTPS от локального CA Caddy | HTTPS (Let's Encrypt) | HTTPS (Let's Encrypt) |
| Почта pacod-id | перехватывает mailpit | перехватывает mailpit | ваш релей |
| AI | мок-шлюз | мок-шлюз | ваш pacod-gw или выключен |
| Демонстрационные сайты | да | да | нет |
Stage — это конфигурация продакшена с перехваченной почтой и имитацией AI. make check не даёт
запуститься, пока не хватает секрета или конфигурация небезопасна. Делайте резервные копии .env,
баз данных MongoDB, файлов сайтов и PostgreSQL pacod-id. /mgmt-health студии проверяет только, что
она жива: студия, которая не может достучаться до pacod-id, остаётся «здоровой», пока её экраны
отвечают 503, и сообщает об этом в своём логе.
Каждое окружение работает в pacod-net, Docker-сети, общей для всех проектов pacod. Собственные
сервисы CMS — сайт, студия, MongoDB и Gotenberg — описаны в одном compose-файле; её собственные копии
общих компонентов — Caddy, pacod-id со своим PostgreSQL, шлюз для разработки и перехватчик почты — во
втором, который Makefile загружает вместе с первым. На одной машине помещается только один стек с
общими компонентами. pacod-demo загружает только первый файл
и запускает CMS вместе с остальными проектами за одним Caddy, одним pacod-id, одним PostgreSQL и
одним шлюзом; он доступен по адресу demo.pacod.io.
Ограничения и что почитать
Известные ограничения v1:
- У идентичности сайта (
siteSettings) пока нет экрана в студии; она редактируется в базе данных. - Демонстрационное содержимое есть только на английском.
- Список участников не показывает роли уровня платформы.
Дорожная карта перечисляет, что v1 откладывает, в том числе API для записи, ключ шлюза и бюджет на AI для каждой организации, отдельный обработчик, хранилище S3 и импорт содержимого.
В репозитории:
- Архитектура — как запрос находит свой сайт
- Безопасность — что разделяет сайты и студию
- Наборы шаблонов — как написать собственный набор
- Запуск и Развёртывание — окружения, TLS, хосты, настройки
- Дорожная карта — что входит в v1 и что отложено
Скриншоты
Технологии
- Языки
- Java
- Технологии
- Java 25
- Spring Boot 4.1
- Thymeleaf
- MongoDB
- Maven
- Caddy
- Gotenberg
- Docker
Быстрый старт
make initmake upopen http://studio.localhost:8000/make site-create SLUG=acme NAME="Acme News" HOSTS=acme.localhost DEMO=1Работает с
Лицензия
Apache-2.0
Собственный код проекта распространяется под Apache-2.0. Студия включает редактор TinyMCE (GPL-2.0-or-later), поэтому собранная студия в целом распространяется на условиях GPL-3.0. Публичный сайт его не содержит.