image

Множество команд сталкиваются с решением вопроса по управлению контентом на различных платформах — от веб-сайтов до мобильных приложений и интернет-магазинов. При этом, как правило, отсутствует единый инструмент, позволяющий эффективно создавать, изменять, хранить и передавать контент для отображения на всех платформах.

Кто-то приходит к самостоятельной разработке инструмента по управлению контентом с нуля. Другие смотрят в сторону готовых CMS решений (content management system/систем управления контентом), которые зачастую позволяют сэкономить время и затраты.

Меня зовут Лена. Мы в команде Enablement Platform провели пилот по сравнению нескольких популярных решений для CMS, накопленный материал показался интересным и полезным для веб-разработчиков, в результате появилась эта статья.

Примечание. Миссия Платформы
Соединять клиентов, индустрии и партнеров, обеспечивая коммерциализацию размещенных на платформе продуктов и предоставляя клиентам лучший опыт взаимодействия с Экосистемой МТС.

Поделюсь с какими проблемами мы столкнулись, какой подход выбрали для управления контентом и доставке данных до витрин. Если бы такой материал мы встретили раньше, он бы сэкономил нам много времени.


Оглавление


1. Вступление


2. Требования и критерии выбора


3. Классы CMS


4. Ситуация на рынке Headless CMS


5. Сравнение Headless CMS


6. UI систем и примеры моделирования


7. Заключение




1. Вступление


Решения класса CMS существенно различаются зрелостью и функциональностью. То, что отлично подходит для простого персонального блога или небольшого сайта, может не справиться с потребностями сложных корпоративных витрин. Для снятия этих ограничений возможностей конфигурирования недостаточно и может потребоваться существенная доработка CMS. Например, ограничения в моделировании данных, подходы к управлению и отображению различных типов контента, механизмы к ограничения доступности контента и т. д. Большинство CMS ориентированы на относительно простую модель данных с ограниченным типом связей между сущностями.

В МТС есть множество различных пользовательских витрин, которые позволяют клиентам узнать о продуктах компании:


И на текущий момент в экосистеме МТС применяются различные инструменты для управления контентом. Возникла идея — проанализировать текущий рынок CMS и провести «пилотирование» выбранных инструментов. По результатам пилота оценить возможность оптимизации и унификации подходов к управлению контентом и передаче данных витринам.

Примечание
Ранее проведенные внутренние обзоры коллег, которые мы исследовали в рамках этой задачи, уже устарели. Зачастую функциональность, отмеченная как отсутствующая в продукте, была со временем реализована. Встречались в обзорах продукты, которые заброшены и больше активно не развиваются.

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

Поэтому сделать выбор только на основании описаний или обзоров, статей (в том числе на Хабре) и тематических рейтингов не удалось.

Задача вносила корректировку к требованиям. В первую очередь нам были интересны решения, которые позволяют работать не с простым контентом (как, например, статьи на сайте), а со сложной иерархичной структурой данных, связанными сущностями, вложенными компонентами и т. д.


2. Требования и критерии выбора


При выборе CMS учитывались общие требования к функциональности, возможности кастомизации и специфические потребности команды, обусловленные используемым ИТ-ландшафтом.

Основные критерии выбора:

  • Open Source решение и лицензии без дополнительных ограничений, в том числе на использование в коммерческих целях — возможность кастомизации под потребности компании, использование в составе других продуктов;
  • Headless CMS — ключевое внимание на управление данными, уровень представления реализуется внешними витринами и зависит от их специфики и потребностей;
  • максимально близкое команде продукта по стеку — backend предпочтительно C#, СУБД MongoDB и PostgreSQL;
  • поддержка GraphQL API — у нас активно внедряется данный подход межсистемного взаимодействия, поддержка GraphQL API упростит интеграцию решения в общий ИТ-ландшафт;
  • возможность создавать свою модель данных — постоянно запускаются новые продукты, у каждой группы продуктов свои особенности и атрибутивный состав, поэтому важно иметь гибкие возможности по моделированию;

    Примечание
    Поддержка иерархичной модели данных, вложенных элементов, в одной родительской сущности можно создать несколько дочерних.
  • поддержка SSO (Single sign-on) — данный механизм является стандартом в компании, позволяет пользователю не тратить время на авторизацию в каждой системе;
  • работа с мультимедийным контентом: управление изображениями в различных разрешениях, видео контентом, бинарными документами и т. п.;
  • наличие локализации — для перевода контента на различные языки;
  • наличие версионирования контента — для отслеживания истории изменений и возможности отката к прошлым версиям;
  • возможность управления workflow — управлением возможными статусами у сущностей, включая поддержку отложенной публикации контента;
  • удобство использования;
  • импорт контента из внешних источников — для упрощения процесса миграции на новую систему;
  • производительность ~2000 RPS;
  • информирование внешних систем об изменении данных;
  • возможность генерации API по созданной модели — для сокращения трудозатрат на разработку;
  • ролевая модель пользователей и API — для разграничения прав доступа к управлению контентом;
  • мультитенантность — возможность управления контентом в одной CMS для нескольких команд, где у каждой из них свое пространство.


3. Классы CMS


Традиционные CMS


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

Типичные представители: WordPress, Joomla, Drupal.

Headless CMS


Предоставляет UI для управления моделью данных, UI для управлениям самими данными и основное — API реализующее набор CRUD операций на данными.

Именно через API происходит потребление этих данных внешними витринами и каналами.

Выделяют следующие типы решений:

  • API Driven — используют СУБД для хранения данных (может использовать объектное хранилище для бинарных файлов);
  • Git-based — используют Git репозиторий для хранения контента, как правило подходят для для простых задач, с небольшой частотой изменений.

Некоторые решения не предоставляет UI для управления моделями, модель описывается программным кодом.


4. Ситуация на рынке Headless CMS


Нас интересовали именно Headless-решения, потому что они позволяют моделировать контент с целью дальнейшего отображения на различных платформах. В нашем случае это вышеупомянутые витрины данных (сайт, мобильное приложение, интернет-магазин, лендинги и т.п.)

Бэкенд при данном подходе существует отдельно от фронта, что дает возможность использовать один бэкенд для хранения и передачи контента для отображения на всех вышеуказанных витринах данных. Это позволяет централизовать ведение данных по продуктам, а задачу их отображения и верстки оставить на стороне витрины. Потенциально мы даем необходимую гибкость продуктовым командам.

На рынке сейчас представлено большое количество Headless CMS. Когда мы делали выбор, какие из систем хотим «пощупать» (установить и попробовать смоделировать данные на примере нескольких продуктов), в первую очередь обращали внимание на популярность системы.

Поэтому первой начали рассматривать Strapi, которая является лидером на рынке и занимает первые места в многочисленных обзорах. В процессе столкнулись с серьезными багами и ограничениями, необходимостью глобальной доработки (включая бэкенд и модель СУБД). Несмотря на то, что в нашей команде есть JS-разработчики, трудно было переключить их от бизнес-задач к полноценной доработке бэка системы для продолжения пилота.

Мы решили посмотреть альтернативные Headless CMS на стеке .NET C#. При этом уже понимали, какие возможности нужны в первую очередь и на чем нужно сфокусироваться:

  • поддержка использования компонент данных (набор элементов разных типов);
  • массивы компонент;
  • различные типы связи;
  • набор UI контроллов для удобного наполнения данными.

Под наши запросы подошли Squidex и Orchard Core.

В процессе рассматривались и тестировались другие системы, но детально не анализировались, так как не удовлетворяли ключевым критериям. Как правило, были ограничения в моделировании данных.

Отпал ряд решений, которые не предоставляют UI для управления моделью, и модель задается прямо в коде.

В обзоре ниже представлены ключевые характеристики и особенности выбранных Headless CMS.


5. Сравнение Headless CMS



Squidex


Сайт squidex.io
Сообщество/поддержка 2k stars
Watchers 100 
Forks 402 
Contributors 60

Open source решение Да.
Лицензия и ее классификация по SAM OSS лицензии | SAM 2.0 (mts.ru) MIT license.
Версия на момент проведения анализа 7.7.0 (01 Jul 2023)
Репозиторий github.com/Squidex/squidex
Стек (frontend) TypeScript / Angular / webpack / Node.js (development only — используется для сборки фронта)
Примечание
NodeJS нужна для разработки, если вы планируете дорабатывать UI админки на Angular. Все скрипты UI пакуются через webpack, а он использует NodeJS.

Стек (backend) C# / .NET 7 / ASP.NET Core
СУБД MongoDB
Наличие GraphQL API image Есть, можно настроить скрытие определенных полей в API.

image Есть возможность фильтрации данных, фильтр передается строкой, формат Odata.

image История запросов GraphQL пользователя (playground) хранится в локальном storage браузера.

image Нельзя фильтровать по атрибутам, значение которых подтягивается из справочника (тип Reference) за исключением поля Id.
Удобство создания и управления моделью данных, включая поддержку вложенности элементов image Можно несколько раз использовать 1 компонент.

image Можно вкладывать компонент в компонент или на поле настраивать выбор из нескольких разных компонентов.

image Очень удобно выбирать значения из справочников, потому что не только можно выбрать существующую запись, но и сразу создать недостающую:
image

image Можно неограниченное количество раз добавлять компонент или выбрать несколько значений из справочника.

image Удобство настройки представления контента для его заполнения (можно задать наименования полей, подсказки при вводе и т. п.).

image При создании сущности сразу можно посмотреть JSON-схему и внести правки в структуру данных через нее:
image

Поддержка SSO-авторизации image
Особенности работы с мультимедийным контентом:

  1. Управление размерами сохраняемых изображений.
  2. Возможность загрузки разных типов файлов (PDF, разные изображения, видео).
1. Изображение загружается с исходными параметрами, есть возможность тегировать изображения. В API есть возможность передать точные размеры и тип файла.

2. Да.
Наличие локализации Да.

image Можно управлять обязательностью полей для страны. Если у языка не поставить is_Optional, если поле обязательное, его нужно будет внести обязательно для данной локализации.

image Можно копировать значения контента из одного языка в другие.
Поддержка версионирования. Рассматривали:

  • возможность версионирования по набору полей;
  • нативная работа с версиями в админке. Т. е. пользователь не должен видеть все версии плоским списком — должна быть иерархия: контент → версии контента;
  • удобство отката к прошлой версии контента.

image Сохраняется история изменений,  можно сравнить с другими версиями и откатиться к нужной:
image

image По умолчанию каждое редактирование формы приводит к созданию новой версии, а мы хотим осознанно управлять этим процессом (не всегда редактирование должно приводить к созданию новой версии), нужна кастомизация.
Возможность управления flow (статусы у сущностей).

  • Возможность вводить собственные статусы помимо основных: draft, published, retired.
  • Наличие отложенной публикации.

image Да, можно настраивать создавать новые статусы и условия перехода в них, а также определять последовательность шагов.

image Есть отложенная публикация, очень удобный интерфейс c графиком запланированных публикаций Scheduled Publishing — Squidex.

image Можно одновременно сделать несколько версий одной сущности, например, 1 черновик, другая опубликована.
Удобство использования image Самый удобный UI из трех, все интуитивно понятно.

image Можно настроить правила валидации для каждого поля.

image Можно управлять представлением при работе с контентом (какие поля отображать и т. д.).

image При внесении контента можно развернуть и посмотреть значения внутри нескольких компонентов (в Strapi можно было раскрыть только 1 за раз).

image В отличии от Strapi корректно работает функция клонирования записей.

image Можно смотреть сколько запланированных публикаций контента в календаре. 

image В отличии от Strapi можно сразу опубликовать запись, а можно сначала сохранить как черновик (там обязательно сначала черновик, потом публикация).

image При редактировании схемы данных надо нажимать кнопку сохранения после изменения данных в каждом блоке (настройки каждого поля) — иначе изменения не сохранятся.

image На форме просмотра/редактирования записи нет кнопки, чтобы создать новую, нужно возвращаться к списку (неудобно при заполнении справочников), но так реализовано и в Strapi.

image Если элементы компонента свернуты, то совсем непонятно, что за сущность.

image
Особенности В структуре JSON есть излишняя вложенность (с тем же столкнулись и в Orchard):

"slug": {

"iv": "super-corp-buys-food-startup"

}

В GraphQL также:

"subgroup": [
                  {
                    "data": {
                      "title": {
                        "iv": "В пределах пакета"
                      }
                    }
                  }
                ]

Причина — реализация партиционирования (partitioning, используется для локализации).
Примечание
The Content API usually returns one object per schema field where the keys are the languages (or iv for non-localized) fields and the values are the actual field value.

Key is iv, which stands for «invariant».

docs.squidex.io/02-documentation/concepts/localization#how-to-use-the-api

Для REST можно использовать заголовок X-Flatten Header, которые сделает плоскими данным с единственным значением.

Для GraphQL можно использовать объект flatData:

query {
  queryCarsContents {
    id,
    data{
      title {
        iv
      },
      vendor {
        iv
    	}
    },
    flatData {
      title,
      vendor
    }
  }
}

Импорт контента из внешних источников При создании новой схемы в UI есть возможность импорта JSON-схемы,
пример
{
    "previewUrls": {},
    "properties": {
        "validateOnPublish": false
    },
    "category": "products",
    "scripts": {},
    "isPublished": true,
    "fieldRules": [],
    "fieldsInLists": [],
    "fieldsInReferences": [],
    "fields": [
        {
            "name": "title",
            "properties": {
                "isRequired": false,
                "isRequiredOnPublish": false,
                "isHalfWidth": false,
                "fieldType": "String",
                "createEnum": false,
                "editor": "Input",
                "inlineEditable": false,
                "isEmbeddable": false,
                "isUnique": false,
                "contentType": "Unspecified"
            },
            "isLocked": false,
            "isHidden": false,
            "isDisabled": false,
            "partitioning": "invariant"
        },
        {
            "name": "vendor",
            "properties": {
                "isRequired": false,
                "isRequiredOnPublish": false,
                "isHalfWidth": false,
                "fieldType": "String",
                "createEnum": false,
                "editor": "Input",
                "inlineEditable": false,
                "isEmbeddable": false,
                "isUnique": false,
                "contentType": "Unspecified"
            },
            "isLocked": false,
            "isHidden": false,
            "isDisabled": false,
            "partitioning": "invariant"
        }
    ],
    "type": "Default"
}

sq content export myschema --format=JSON

sq content import myschema myschema_2020-05-20-09-14-34.json --format=JSON

Импорт/экспорт данных с помощью CLI (подробнее тут: docs.squidex.io/02-documentation/developer-guides/automation-tools):
Хранение бинарных файлов (assets)/мультимедиа (S3 compatible) или интеграция с такой системой AssetStore:

  • Folder (local folder)
  • MongoDb (GridFS)
  • GoogleCloud (hosted in Google Cloud only)
  • AzureBlob
  • AmazonS3
  • FTP (not recommended)

Нефункциональные требования.

  • Нагрузка: ~2000 rps.

Можно написать свой плагин для кэша.

Есть механизмы кэширования данных.
Расширяемость (дорабатываемость) системы.

  • Какие компоненты используются внутри системы.
  • Модульное построение системы: да/нет.

Предусмотрена расширяемость с помощью плагинов.
Публикация событий об изменении контента Да.
Возможность генерации API по созданной модели Генерация OpenAPI спецификации по модели и базовым методам.

Встроенный GraphQL браузер и документация по API.
Ролевая модель пользователей и API Есть различные роли и можно добавлять свои:
image
Мультитенантность Можно создавать пространства для различных команд: 
image


Strapi CMS


Сайт strapi.io
Сообщество/поддержка 54.9k stars
Watchers: 661 
Forks: 6.7k 
Contributors 895
Примечание
Данные с github.com/strapi/strapi

Open source решение Да.
Лицензия и ее классификация по SAM OSS лицензии | SAM 2.0 (mts.ru) MIT Expat для Публичной версии.
Версия на момент проведения анализа 4.11.7 (19 Jul 2023) + плагины — установлена 21.07.2023
Репозиторий github.com/strapi/strapi
Стек (frontend) JS/TypeScript

Angular
Стек (backend) JS/TypeScript, Nodejs
СУБД PostgreSQL
MySQL/MariaDB
SQLite
Наличие GraphQL API image Поддержка GraphQL с помощью плагина GraphQL | Strapi Market

image История запросов GraphQL пользователя (playground) хранится в локальном storage браузера.
Удобство создания и управления моделью данных, включая поддержку вложенности элементов image В рамках коллекции можно использовать несколько раз 1 компонент.

image Можно вкладывать компонент в компонент.

image Можно настроить дефолтные значения для компонента, который встраивается в коллекцию (в нашем случае применимо, например, для стоимости звонков по миру, которая почти везде одинакова).

image Удобно настраивается связь между сущностями, можно управлять типом связи 1 к 1, 1 к* и т. п.).

image

image Допускается использование при создании атрибута в его наименовании служебного имени ID, но при этом возникает ошибка, которую нельзя исправить без правок на уровне базы данных (надо вновь добавленное поле «ID» переименовать).

image Нельзя сконфигурировать порядок полей при связи таблиц, выбор из списка значений будет по первому полю. Если ошибиться с порядком полей при создании объекта, исправить можно можно только через пересоздание объекта.
Поддержка SSO-авторизации Есть плагин.
Особенности работы с мультимедийным контентом:

  1. Управление размерами сохраняемых изображений.
  2. Возможность загрузки разных типов файлов (PDF, разные изображения, видео).
1. Изображения сохраняются сразу в трех размерах.
Примечание
Есть несколько плагинов, которые можно применить, если дефолтные настройки нас не устраивают:

  • Local Image Sharp | Strapi Market
  • strapi-plugin-img — npm (npmjs.com)


2. Да.
Наличие локализации Да.
Поддержка версионирования. Рассматривали:

  • возможность версионирования по набору полей;
  • нативная работа с версиями в админке. Т. е. пользователь не должен видеть все версии плоским списком — должна быть иерархия: контент → версии контента;
  • удобство отката к прошлой версии контента.

image Нет.

Можно было бы создавать новые версии, используя функцию дублирования, но с учетом ее некорректной работы (не все поля дублировались, только простые, без компонентов) это проблематично.

Для реализации версионирования нужны доработки.

image Есть плагин New Community Plugin: Content Versioning (strapi.io), который позволяет иметь одновременно несколько версий (черновик и опубликованная, несколько черновиков + бонусом логирование изменений) — его не тестировали.
Возможность управления flow (статусы у сущностей).

  • Возможность вводить собственные статусы помимо основных: draft, published, retired.
  • Наличие отложенной публикации.

image Для ввода доп.статусов можно использовать плагин Review Workflows.

Также по ссылке есть пример, как использовать внешний автоматизатор n8n.

image Отложенную публикацию можно настроить Scheduled Publication — Strapi Developer Documentation.

  
Удобство использования image Не очень дружелюбный интерфейс бесплатной версии (не критично):

  • Отдельные кнопки создания и публикации (нельзя одним кликом опубликовать запись).
  • Чтобы создать новый элемент всегда нужно возвращаться назад к списку элементов.
  • Не в полном объёме работает функция дублирования записей.

    image
    UPD. Сейчас добавили информационное сообщение, о том что не дублируются данные, где есть ссылки на другие сущности(например, подстановка из справочника). Раньше сообщения не было, просто часть полей не копировалась.
  • Часто приходится принудительно перегружать страницу после создания объектов. Возникает следующее окно:
    image
    Страница так и не перегружается:
    image

Особенности 1. Есть два режима запуска:

  • режим разработки (запускаем: yarn develop) — можно изменять модель данных;
  • режим эксплуатации (запускаем: yarn start) — можно изменять данные, но не модель.

2. Слабая защита от «дурака» в UI можно изменить модель так, что система перестанет стартовать, и потребуется исправлять ошибки модели в исходных файлах проекта. Разработчикам (если они увидят нашу статью) было бы здорово обратить внимание на валидацию данных на UI (ограничение на количество символов в названиях объектов, запрет создания поля с именем «ID» и т. п.).
Импорт контента из внешних источников Есть плагин.
 
Хранение бинарных файлов (assets)/мультимедиа (S3 compatible) или интеграция с такой системой 1. В виде файлов в public/uploads на веб-сервере.
2. Коннекторы к объектным облачным хранилищам.
Нефункциональные требования.

  • Нагрузка: ~2000 rps.

Есть плагин для кэширования данных.
Расширяемость (дорабатываемость) системы.

  • Какие компоненты используются внутри системы.
  • Модульное построение системы: да/нет.

Магазин плагинов.

Кастомные типы данных, для сложных случаев можно использовать объект с типом JSON (потребуется реализовать UI для управления данными).
Публикация событий об изменении контента Да.
Возможность генерации API по созданной модели GraphQL playground с документаций по API (после установки плагина).
Ролевая модель пользователей и API Есть различные роли и можно добавлять свои:

image
Мультитенантность Через разработку, из коробки решения нет, но есть возможности настройки, которые не тестировались:
Strapi-v4 | refine

Есть плагин (также не тестировали):
strapi-plugin-multi-tenant — npm Package Overview — Socket


Orchard Core


Сайт orchardcore.net
Сообщество/поддержка 6.7k stars
Watchers 339
Forks 2.2k 
Contributors 242

This project is supported by the .NET Foundation.
Open source решение Да.
Лицензия и ее классификация по SAM OSS лицензии | SAM 2.0 (mts.ru) BSD-3-Clause license.
Версия на момент проведения анализа 1.5.0 (04 Nov 2022) — была актуальна по состоянию на март 2023
Репозиторий github.com/OrchardCMS/OrchardCore
Стек (frontend) JS/ASP.NET Core
Стек (backend) ASP.NET Core
СУБД SQL Server
MySQL
PostgreSQL
SQLite

using a document abstraction (YesSql)
Наличие GraphQL API image Есть.

image Можно настроить скрытие определенных полей в GraphQL.
Удобство создания и управления моделью данных, включая поддержку вложенности элементов image Можно добавить Part в Content Type несколько раз (если выбрать настройку reusable).

image Не удалось добавить несколько элементов в одном Part; нельзя вложить один part в другой, только простые поля.

image Можно сделать подстановку элементов из справочника (в том числе выбрать несколько значений), но в списке непонятно, что за элементы, т. к. выводится id, который не видно в UI.
image

Поддержка SSO-авторизации Есть плагин OpenId.
Особенности работы с мультимедийным контентом:

  1. Управление размерами сохраняемых изображений.
  2. Возможность загрузки разных типов файлов (PDF, разные изображения, видео).
1. Можно менять через appsettings.json. 

2. Да.
Наличие локализации Да.
Поддержка версионирования. Рассматривали:

  • возможность версионирования по набору полей;
  • нативная работа с версиями в админке. Т. е. пользователь не должен видеть все версии плоским списком — должна быть иерархия: контент → версии контента;
  • удобство отката к прошлой версии контента.

Судя по всему функция версионирования реализована через данный модуль Audit Trail module (Lombiq Technologies: OCORE-23) by domonkosgabor · Pull Request #6679 · OrchardCMS/OrchardCore · GitHub, но возможности не тестировались.
Возможность управления flow (статусы у сущностей).

  • Возможность вводить собственные статусы помимо основных: draft, published, retired.
  • Наличие отложенной публикации.

image Возможность самостоятельно управлять статусами, а также событиями, по которой происходит их смена; допустима даже отложенная публикация/архивация через заранее заданное время Workflows — Orchard Documentation (orchardcore.net)

image Отложенная публикация есть.
Удобство использования image Можно настроить правила валидации для формы.

image Пробовали разные комбинации настроек, но все созданные сущности имеют одно наименование в списке:
image

image Не работают массовые операции, даже если выделить несколько записей и попробовать удалить, удаляется одна:
image
 
Особенности 1. Может работать в трех режимах, в том числе как Headless CMS:

  • Full CMS. В этом режиме веб-сайт использует тему и шаблоны для отображения вашего контента, практически не прибегая к пользовательской разработке. 
  • Decoupled CMS. Сайт разрабатывается с нуля, если не считать серверной части управления контентом. Вы создаете все необходимые шаблоны с помощью Razor Pages или MVC actions и получаете доступ к своему контенту через контент-сервисы.
  • Headless CMS. Сайт управляет только контентом, и вы создаете отдельное приложение, которое будет извлекать управляемый контент с помощью GraphQL или REST API.

2. Субъективно кажется, что структура в JSON усложняется неоправданно (добавляется формат поля), например:

"title": {
      "Text": "Входящие вызовы"
    },

вместо 

"title":  "Входящие вызовы"

Импорт контента из внешних источников Попробовали сделать импорт, структура по JSON не создается, импорт прошел успешно, но при этом результат никуда не сохранился.

Похоже, только импорт данных в уже созданную структуру.
Хранение бинарных файлов (assets)/мультимедиа (S3 compatible) или интеграция с такой системой
  • Media folder
  • Slugify 
  • Amazon S3
  • Azure

Нефункциональные требования.

  • Нагрузка: ~2000 rps.

Можно написать свой плагин для кэша.

Есть механизмы кэширования данных.
Расширяемость (дорабатываемость) системы.

  • Какие компоненты используются внутри системы.
  • Модульное построение системы: да/нет.

Предусмотрена расширяемость с помощью плагинов.
Публикация событий об изменении контента Да.
Возможность генерации API по созданной модели Встроенный GraphQL браузер.
Ролевая модель пользователей и API image Есть различные роли и можно добавлять свои:
image
Мультитенантность image Материалы про настройку:

Tenants — Orchard Core Documentation



6. UI систем и примеры моделирования



Squidex


Панель управления Squidex включает два ключевых раздела:

image

Работа с созданием структуры данных проводится в разделе «Sсhemas», как выглядит управление данными в этом разделе можно посмотреть на скрине ниже:

image

Для моделирования доступны следующие типы данных:

image

Особенность, которую не обнаружили в других CMS, тип данных Components — позволяет к одному блоку привязать сразу несколько несколько схем данных. 

Например, можно настроить заполнение в одном месте всех групп, в состав которых входит продукт. При этом может заполняться либо одна группа, либо другая, либо обе, в зависимости от кейса.

image

На этапе внесения сотрудник выбирает — о какой из сущностей хочет внести информацию в данный момент:

image

При этом сущности Category и Group могут иметь различный атрибутивный состав:

image

Доступно много возможностей для настройки валидации полей, причем перечень настроек зависит от типа данных. Ниже пример для текстового поля:

image

Для типа данных можно выбрать более подходящий «редактор», который предлагает подходящий интерфейс и дополнительные ограничения и валидации. Например, для текстового поля можно выбрать следующие варианты:

image

Удобно вносить текстовые данные в «MarkDown». В редакторе можно встраивать в текст гиперссылки, списки и т. п. И сразу просматривать результат:

image

Что касается моделирования сложной структуры данных, инструмент позволяет моделировать данные даже для прайс-листов. Например:

image

Внутри прайс-листа элементы группируются (группы — «В пределах пакета»/«После исчерпания пакета»/«Не включено в пакет в примере выше»).

При этом у элементов есть значения (стоимость) и различные единицы измерения (за сообщение/за минуту и т. п.).

Сами группы и единицы измерения — это не просто текст, это значения, которые должны выбираться из справочников.
Примечание
Данный пример взят, чтобы более наглядно проиллюстрировать возможности системы.

Моделирование подобных структур данных возможно при добавлении в схему данных компонентов (тип Components).

image

Наш компонент в разделе «Sсhemas» имеет следующую структуру:

image

Структура данных для продукта в Squidex
{
    "id": "6a2abfe1-cf0c-4453-b449-3886171668c5",
    "created": {
        "value": "2023-06-21T06:05:12.000Z"
    },
    "createdBy": "subject:6437d117ed1a95c0fc81c021",
    "lastModified": {
        "value": "2023-06-22T05:03:11.000Z"
    },
    "lastModifiedBy": "subject:6437d117ed1a95c0fc81c021",
    "version": {
        "value": "10"
    },
    "status": "Published",
    "statusColor": "#4bb958",
    "scheduleJob": null,
    "isDeleted": false,
    "data": {
        "title": {
            "iv": "МТС Music"
        },
        "slug": {
            "iv": "mts-music"
        },
        "channel": {
            "iv": [
                "323377a9-c720-43a4-aab0-7df9b7ad4f65"
            ]
        },
        "region": {
            "iv": null
        },
        "validFrom": {
            "iv": "2023-05-20T00:00:00Z"
        },
        "validTo": {
            "iv": "9999-12-31T00:00:00Z"
        },
        "icon": {
            "iv": [
                "299224cf-20e5-4936-9ad5-073721ce7938"
            ]
        },
        "mainImage": {
            "iv": [
                "e0fa12c6-ddcb-48c3-ae95-15a9afa2c92a"
            ]
        },
        "otherMedia": {
            "iv": null
        },
        "description": {
            "iv": "Персональные подборки под любое настроение в приложении МТС Music"
        },
        "shortDescription": {
            "iv": "Месяц музыки бесплатно без рекламы"
        },
        "addInformation": {
            "iv": [
                {
                    "schemaId": "0b417452-e2df-486f-8f92-09aae9ad2d03",
                    "title": "Почему стоит подключить:",
                    "text": "*Два месяца бесплатно\n* Без рекламы\n* Можно скачивать и слушать офлайн\n* Персональные рекомендации\n* Бесплатный трафик для абонентов МТС\n* Более 65 млн треков в высоком качестве"
                }
            ]
        },
        "productSpecId": {
            "iv": "93c20eac-e70b-4364-9626-fdf36148745e"
        },
        "advantages": {
            "iv": [
                {
                    "schemaId": "a518c845-f85f-4342-9e71-675d4f6a7ad0",
                    "title": "Выбирайте готовый плейлист",
                    "description": "В дороге, дома, на работе или тренировке",
                    "icon": null,
                    "image": [
                        "4036fcb7-e4aa-496f-a60c-eb502d036982"
                    ]
                },
                {
                    "schemaId": "a518c845-f85f-4342-9e71-675d4f6a7ad0",
                    "title": "Детский режим",
                    "description": "С аудиосказками, песнями и подборками из мультфильмов",
                    "icon": null,
                    "image": [
                        "70debf41-5106-47d7-871c-057ac378e4eb"
                    ]
                }
            ]
        },
        "faq": {
            "iv": [
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Если у меня уже была подписка МТС Music, будет ли доступено  два месяца бесплатно?\n              ",
                    "answer": "Нет. Предложение доступно только новым пользователям, которые никогда не подключали платную подписку МТС Music."
                },
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Зачем подключать подписку МТС Music?\n              ",
                    "answer": "По подписке вы получаете полный доступ ко всему функционалу приложения и сайта, в том числе к поиску и офлайн-режиму прослушивания музыки."
                },
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Что будет, если отключить подписку в пробный период?\n              ",
                    "answer": "При отключении услуги до истечения 30 дней и повторном её подключении услуга будет предоставляться на платной основе, бесплатные дни предоставляться не будут.\n\nПосле отключения платной подписки прослушивание своих сохранённых треков и плейлистов в режиме офлайн становится недоступным."
                },
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Сколько будет стоить подписка после двух месяцев бесплатного доступа?\n              ",
                    "answer": "169 рублей в месяц."
                },
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Как оплачивать МТС Music после пробного периода?\n              ",
                    "answer": "Для абонентов ПАО «МТС» списание средств за подписку будет производиться с лицевого счёта абонента.\n\nАбоненты других операторов мобильной связи смогут оплатить подписку, привязав банковскую карту с помощью сервиса МТС Деньги, который будет открываться непосредственно в приложении МТС Music – дополнительная авторизация не потребуется. Списания будут производиться с БК в соответствии с графиком списания подключённой услуги, безакцептно. История списаний за пользование сервисом будет отображаться в истории платежей по банковской карте абонента. Управлять подпиской пользователь сможет в приложении МТС Music, в разделе «Моя музыка» —> «Профиль»."
                },
                {
                    "schemaId": "f51d088d-6758-41c5-9d5a-674a5786a899",
                    "question": "Условия использования",
                    "answer": "*Если в течение 30 дней пробного бесплатного периода вы не пользовались сервисом, услуга будет предоставляться на платной основе, бесплатные дни предоставляться не будут.\n\n* Под «первые 30 дней для новых пользователей в подарок» понимается скидка в размере 100% стоимости первых по времени 30 дней пользования сервисом.\n\n* Подписка продлевается автоматически на месяц, если автопродление не отключено до окончания текущего периода, до 24:00. Неиспользованная часть бесплатного пробного периода аннулируется после приобретения подписки. Вы можете управлять своими подписками после покупки и отключить автопродление в настройках своей учётной записи.\n\n* Обращаем ваше внимание, что для онлайн-прослушивания музыки необходимо наличие доступа к сети интернет. В случае если включённая в основной и дополнительный пакет квота интернет-трафика будет превышена, вы сможете прослушивать только сохранённые в приложении композиции, онлайн-прослушивание музыки будет недоступно.\n\n* Бесплатный интернет-трафик при прослушивании музыки в приложении МТС Music не тарифицируется только для абонентов МТС.\n\n* Бесплатный интернет-трафик предоставляется только при прослушивании музыки в приложении МТС Music, загрузка прочего содержимого оплачивается согласно условиям тарифного плана.\n\n* Сервис доступен абонентам сети мобильной связи любого оператора на всей территории Российской Федерации и предназначен для смартфонов и планшетов на базе операционных систем Android (4.1 и выше), iOS (7.0 и выше), а также ПК.\n\n* Услугу предоставляет ПАО «МТС» при поддержке ООО «Стрим» и ООО «Яндекс.Медиасервисы».\n\n* Все цены указаны с учётом НДС."
                }
            ]
        },
        "price": {
            "iv": [
                {
                    "schemaId": "7766d9e4-5d1a-4853-8ff3-0896544b2851",
                    "currentPrice": "0",
                    "oldPrice": "169",
                    "unit": [
                        "c229c4a8-2d3e-4634-9ccc-45778b357193"
                    ],
                    "title": "Триальный период",
                    "shortDescription": "30 дней бесплатно, далее 169 ₽/мес",
                    "description": null
                }
            ]
        }
    },
    "schemaName": "contentspecifiction",
    "schemaDisplayName": "contentspecifiction",
    "referenceFields": [
        {
            "fieldId": 1,
            "name": "title",
            "properties": {
                "isRequired": false,
                "isRequiredOnPublish": false,
                "isHalfWidth": false,
                "fieldType": "String",
                "createEnum": false,
                "editor": "Input",
                "inlineEditable": false,
                "isEmbeddable": false,
                "isUnique": false,
                "contentType": "Unspecified",
                "label": "Наименование"
            },
            "isLocked": false,
            "isHidden": false,
            "isDisabled": false,
            "_links": {},
            "canAddField": false,
            "canDelete": false,
            "canDisable": false,
            "canEnable": false,
            "canOrderFields": false,
            "canHide": false,
            "canLock": false,
            "canShow": false,
            "canUpdate": false,
            "partitioning": "invariant",
            "nested": []
        }
    ],
    "_links": {
        "self": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5",
            "method": "GET"
        },
        "previous": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5/9",
            "method": "GET"
        },
        "draft/create": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5/draft",
            "method": "POST"
        },
        "status/Archived": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5/status",
            "method": "PUT",
            "metadata": "#eb3142"
        },
        "status/Draft": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5/status",
            "method": "PUT",
            "metadata": "#8091a5"
        },
        "delete": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5",
            "method": "DELETE"
        },
        "patch": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5",
            "method": "PATCH"
        },
        "update": {
            "href": "/api/content/mts/contentspecifiction/6a2abfe1-cf0c-4453-b449-3886171668c5",
            "method": "PUT"
        }
    },
    "canDelete": true,
    "canDraftCreate": true,
    "canDraftDelete": false,
    "canCancelStatus": false,
    "canUpdate": true,
    "statusUpdates": [
        {
            "status": "Archived",
            "color": "#eb3142"
        },
        {
            "status": "Draft",
            "color": "#8091a5"
        }
    ]
}



А вот пример запроса и ответа в GraphQL API.

Запрос
{
  queryContentspecifictionContents(
    filter: "data/productSpecId/iv eq '93c20eac-e70b-4364-9626-fdf36148745e' and status eq 'Published' and data/channel/iv eq '323377a9-c720-43a4-aab0-7df9b7ad4f65' and data/validFrom/iv gt 2023-05-19T00:00:00Z"
   ) {
    id
    status
    version
    flatData {
      title
      validFrom
      validTo
      productSpecId
      channel {
        id
        ... on Channel {
          flatData {
            externalid
            title
          }
        }
      }
      description
      shortDescription
      addInformation {
        title
        text {
          text
        }
      }
      advantages {
        title
        description
        icon {
          type
          metadata
          url
        }
      }
      icon {
        type
        metadata
        url
        tags
      }
      mainImage {
        type
        metadata
        url
        tags
      }
      otherMedia {
        type
        metadata
        url
        tags
      }
      faq {
        question {
          text
        }
        answer {
          text
        }
      }
      price {
        title
        description
        shortDescription
        oldPrice
        currentPrice
        unit {
          id
          flatData {
            title
            alias
            titleInGenitiveCase
            fullTitle
          }
        }
      }
    }
  }
}


Ответ
{{
  "data": {
    "queryContentspecifictionContents": [
      {
        "id": "6a2abfe1-cf0c-4453-b449-3886171668c5",
        "status": "PUBLISHED",
        "version": 10,
        "flatData": {
          "title": "МТС Music",
          "validFrom": "2023-05-20T00:00:00Z",
          "validTo": "9999-12-31T00:00:00Z",
          "productSpecId": "93c20eac-e70b-4364-9626-fdf36148745e",
          "channel": [
            {
              "id": "323377a9-c720-43a4-aab0-7df9b7ad4f65",
              "flatData": {
                "externalid": "741ba712-3069-48e3-928c-8631e5ed186e",
                "title": "Personal"
              }
            }
          ],
          "description": "Персональные подборки под любое настроение в приложении МТС Music",
          "shortDescription": "Месяц музыки бесплатно без рекламы",
          "addInformation": [
            {
              "title": "Почему стоит подключить:",
              "text": {
                "text": "*Два месяца бесплатно\n* Без рекламы\n* Можно скачивать и слушать офлайн\n* Персональные рекомендации\n* Бесплатный трафик для абонентов МТС\n* Более 65 млн треков в высоком качестве"
              }
            }
          ],
          "advantages": [
            {
              "title": "Выбирайте готовый плейлист",
              "description": "В дороге, дома, на работе или тренировке",
              "icon": null
            },
            {
              "title": "Детский режим",
              "description": "С аудиосказками, песнями и подборками из мультфильмов",
              "icon": null
            }
          ],
          "icon": [
            {
              "type": "UNKNOWN",
              "metadata": {},
              "url": "http://127.0.0.1/api/assets/mts/299224cf-20e5-4936-9ad5-073721ce7938/",
              "tags": [
                "type/svg",
                "image"
              ]
            }
          ],
          "mainImage": [
            {
              "type": "IMAGE",
              "metadata": {
                "pixelWidth": 934,
                "pixelHeight": 937,
                "imageQuality": 100,
                "description": "JFIF File"
              },
              "url": "http://127.0.0.1/api/assets/mts/e0fa12c6-ddcb-48c3-ae95-15a9afa2c92a/",
              "tags": [
                "type/jpg",
                "image",
                "image/medium"
              ]
            }
          ],
          "otherMedia": null,
          "faq": [
            {
              "question": {
                "text": "Если у меня уже была подписка МТС Music, будет ли доступено  два месяца бесплатно?\n              "
              },
              "answer": {
                "text": "Нет. Предложение доступно только новым пользователям, которые никогда не подключали платную подписку МТС Music."
              }
            },
            {
              "question": {
                "text": "Зачем подключать подписку МТС Music?\n              "
              },
              "answer": {
                "text": "По подписке вы получаете полный доступ ко всему функционалу приложения и сайта, в том числе к поиску и офлайн-режиму прослушивания музыки."
              }
            },
            {
              "question": {
                "text": "Что будет, если отключить подписку в пробный период?\n              "
              },
              "answer": {
                "text": "При отключении услуги до истечения 30 дней и повторном её подключении услуга будет предоставляться на платной основе, бесплатные дни предоставляться не будут.\n\nПосле отключения платной подписки прослушивание своих сохранённых треков и плейлистов в режиме офлайн становится недоступным."
              }
            },
            {
              "question": {
                "text": "Сколько будет стоить подписка после двух месяцев бесплатного доступа?\n              "
              },
              "answer": {
                "text": "169 рублей в месяц."
              }
            },
            {
              "question": {
                "text": "Как оплачивать МТС Music после пробного периода?\n              "
              },
              "answer": {
                "text": "Для абонентов ПАО «МТС» списание средств за подписку будет производиться с лицевого счёта абонента.\n\nАбоненты других операторов мобильной связи смогут оплатить подписку, привязав банковскую карту с помощью сервиса МТС Деньги, который будет открываться непосредственно в приложении МТС Music – дополнительная авторизация не потребуется. Списания будут производиться с БК в соответствии с графиком списания подключённой услуги, безакцептно. История списаний за пользование сервисом будет отображаться в истории платежей по банковской карте абонента. Управлять подпиской пользователь сможет в приложении МТС Music, в разделе «Моя музыка» —> «Профиль»."
              }
            },
            {
              "question": {
                "text": "Условия использования"
              },
              "answer": {
                "text": "*Если в течение 30 дней пробного бесплатного периода вы не пользовались сервисом, услуга будет предоставляться на платной основе, бесплатные дни предоставляться не будут.\n\n* Под «первые 30 дней для новых пользователей в подарок» понимается скидка в размере 100% стоимости первых по времени 30 дней пользования сервисом.\n\n* Подписка продлевается автоматически на месяц, если автопродление не отключено до окончания текущего периода, до 24:00. Неиспользованная часть бесплатного пробного периода аннулируется после приобретения подписки. Вы можете управлять своими подписками после покупки и отключить автопродление в настройках своей учётной записи.\n\n* Обращаем ваше внимание, что для онлайн-прослушивания музыки необходимо наличие доступа к сети интернет. В случае если включённая в основной и дополнительный пакет квота интернет-трафика будет превышена, вы сможете прослушивать только сохранённые в приложении композиции, онлайн-прослушивание музыки будет недоступно.\n\n* Бесплатный интернет-трафик при прослушивании музыки в приложении МТС Music не тарифицируется только для абонентов МТС.\n\n* Бесплатный интернет-трафик предоставляется только при прослушивании музыки в приложении МТС Music, загрузка прочего содержимого оплачивается согласно условиям тарифного плана.\n\n* Сервис доступен абонентам сети мобильной связи любого оператора на всей территории Российской Федерации и предназначен для смартфонов и планшетов на базе операционных систем Android (4.1 и выше), iOS (7.0 и выше), а также ПК.\n\n* Услугу предоставляет ПАО «МТС» при поддержке ООО «Стрим» и ООО «Яндекс.Медиасервисы».\n\n* Все цены указаны с учётом НДС."
              }
            }
          ],
          "price": [
            {
              "title": "Триальный период",
              "description": null,
              "shortDescription": "30 дней бесплатно, далее 169 ₽/мес",
              "oldPrice": "169",
              "currentPrice": "0",
              "unit": [
                {
                  "id": "c229c4a8-2d3e-4634-9ccc-45778b357193",
                  "flatData": {
                    "title": "₽/мес",
                    "alias": null,
                    "titleInGenitiveCase": "рублей в месяц",
                    "fullTitle": null
                  }
                }
              ]
            }
          ]
        }
      }
    ]
  },
  "extensions": {
    "tracing": {
      "version": 1,
      "startTime": "2023-06-26T05:20:49.9570693Z",
      "endTime": "2023-06-26T05:20:50.0001375Z",
      "duration": 43068200,
      "parsing": {
        "startOffset": 1100,
        "duration": 43300
      },
      "validation": {
        "startOffset": 45100,
        "duration": 1028900
      },
      "execution": {
        "resolvers": []
      }
    }
  }
} }



Strapi


А теперь посмотрим, как выглядит Strapi.

Панель управления:

image

Ключевыми разделами Strapi CMS являются:

  • Content-Type Builder — инструмент создания объектов, который позволяет создавать таблицы для хранения данных и связывать их между собой, а также настраивать их отображение (порядок полей при заполнении и прочее) для пользователя;
  • Сontet Manager — раздел для заполнения созданных объектов данными.

С чем ведется работа в Content-Type Builder:

  • коллекции «COLLECTION TYPES» — набор данных разных типов, который может включать множество записей;
  • компоненты — объект данных, упрощающий внесение данных в коллекции. Например, когда нужно создать подряд несколько однотипных записей внутри коллекции;
  • диночные типы «SINGLE TYPES» — набор данных разных типов. В отличие от коллекции может включать только одну запись. Полезно для создания простых страниц. Например, для создания раздела «Контакты» на сайте.

image

Подробнее про создание объектов в Strapi CMS можно почитать тут.

Наполнять контент можно данными следующих типов:

image

image

В отличии от Squidex нельзя настроить отдельное наименование поля и подсказку для отображения пользователю при внесении:

image

Гораздо меньше настроек по валидации и формату ввода данных (также на примере текстового поля):

image

Моделирование сложных структур данных и данных с несколькими элементами в составе производится с помощью компонентов (как и в Squidex):

image

Что касается моделирования сложной структуры данных, рассмотрим их заведение (как и для Squidex) на этом примере:

image

Напомним, что внутри прайс-листа элементы группируются. При этом группы и единицы измерения — это не просто текст, а значения, которые должны выбираться из справочников.

Моделирование подобных структур данных возможно при добавлении в схему данных компонентов (тип Components).

image

Наш компонент имеет следующую структуру:

image

В отличие от Squidex на этом экране нет функции перетаскивания и нельзя изменить очередность заполнения полей и компонентов на форме.

Есть кнопка конфигурирования представления
image
и только после клика по ней происходит переход к виду, где можно менять очередность блоков:

image

Так будет выглядеть внесение информации в разделе «Сontet Manage» UI Strapi для первого элемента данных:

Подсказка
Выбор значения из списка для справочников (коллекций) проходит по умолчанию по первому полю, которое было создано для данного справочника. Т. е. если для коллекции Group при ее создании первым полем было «title», то и при внесении контента из списка выбираются значения по этому полю. Для других справочников первым в списке оказалось поле «slug», из-за чего на форме видим такие некрасивые значения. Изменить это можно только полностью пересоздав коллекцию и заново заполнив ее значения.

Поэтому не повторяйте наших ошибок, следите, чтобы поле «title» всегда шло первым, если используете данную CMS.

image

В отличие от Squidex при внесении данных нельзя добавить новую запись в справочник, например, в перечень групп, только выбрать существующую из списка значений.

Остальные заполняются аналогично — путем добавления нового экземпляра компонента:
image
Ниже можно посмотреть, как будет выглядеть данная информация в GraphQL API.

Запрос
query {
  tariffs(
    filters: {
      tp: { title: { eq: "Тарифище" } }
      and: [
        { region: { title: { eq: "Краснодар" } } }
        { vaidFrom: { gte: "2010-08-25T10:15:30Z" } }
        { validTo: { lte: "2050-08-25T10:15:30Z" } }
      ]
    }
  ) {
    data {
      id
      attributes {
        detailInformation {
          group {
            data {
              attributes {
                title
                iconURL
              }
            }
          }
          sub_gr {
            data {
              attributes {
                title
                slug
              }
            }
          }

          title {
            data {
              attributes {
                slug
                title
              }
            }
          }
          value
          unit {
            data {
              attributes {
                title
                slug
              }
            }
          }
        }
      }
    }
  }
}

Ответ
{
  "data": {
    "tariffs": {
      "data": [
        {
          "id": "6",
          "attributes": {
            "detailInformation": [
              {
                "group": {
                  "data": {
                    "attributes": {
                      "title": "SMS и MMS, за сообщение",
                      "iconURL": "//contents.mts.ru/b-icon_envelope.svg"
                    }
                  }
                },
                "sub_gr": {
                  "data": {
                    "attributes": {
                      "title": "В пределах включенного пакета SMS",
                      "slug": "SMS-v-predelah-vklyuchennogo-paketa"
                    }
                  }
                },
                "title": {
                  "data": {
                    "attributes": {
                      "slug": "SMSRussiaOperators",
                      "title": "SMS на номера любых операторов России"
                    }
                  }
                },
                "value": "3.70",
                "unit": {
                  "data": {
                    "attributes": {
                      "title": "₽ за сообщение",
                      "slug": "rub-msg"
                    }
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}



Orchard Core


В Orchard Core столкнулись с ограничениями в моделировании данных и прочими сложностями, которые представлены в сравнительном анализе (таблица выше). Поэтому покажем только базовые элементы интерфейса. Примеры моделирования данных будут приведены только для Strapi и Squidex.

image

В основном работа ведется с Типами (Parts) и Частям контента.

image

Части контента — это что-то вроде компонентов в других системах:

image

Подробнее вопрос терминологии системы раскрывается тут.

Можно встроить в контент следующие типы данных:

image

Перечень доступных настроек очень ограничен.  

image



7. Заключение


Выбор и применение современных CMS является важным вопросом для команд, которые хотят эффективно управлять контентом на различных платформах. Решение в каждом случае необходимо принимать исходя из собственных потребностей и ИТ-ландшафта.

Сводная таблица со сравнением CMS по ключевым для нашей команды критериям.


Критерий Strapi CMS Squidex Orchard Core
Сообщество/поддержка Большое, частые обновления Среднее, тесное взаимодействие с пользователями Среднее, поддержка .NET Foundation
Open source решение image image image
Стек:
  • frontend
  • backend

Angular + Node.js (JS/TypeScript) Angular (TypeScript) + C# JS + ASP.NET Core
СУБД SQL (PostgreSQL, MySQL/MariaDB, SQLite) NoSQL (MongoDB) SQL (SQL Server, MySQL, PostgreSQL, SQLite)
Удобство использования Среднее Высокое Низкое
Контроль над ошибками в UI и возможность «сломать» систему Низкий Высокий Средний
Гибкость системы при моделировании данных Средняя Высокая Низкая
Поддержка GraphQL API image С помощью плагина GraphQL | Strapi Market image image
Наличие локализации image image image
Поддержка версионирования image Есть плагин image image Через модуль
Возможность управления flow image Есть плагин image image
Импорт контента из внешних источников image Есть плагин image image
Хранение бинарных файлов (assets)/мультимедиа (S3 compatible) или интеграция с такой системой image image image
Расширяемость системы image Есть свой магазин плагинов image Предусмотрена расширяемость с помощью плагинов image Предусмотрена расширяемость с помощью плагинов
Публикация событий об изменении контента image image image
Ролевая модель пользователей и API image image image
Мультитенантность из коробки image image image

image — решение из коробки соответствует критерию/поддерживает данный функционал.
image — решается частично либо с установкой расширений/плагинов.
image — отсутствует.

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

В Strapi постоянно сталкивались с различными багами. Есть замечания к пользовательскому интерфейсу, не все операции интуитивны и понятных даже для специалистов с опытом работы с другими CMS.

В UI Orchard Core были большие сложности с моделированием контента. В CMS не оказалось ряда критичных для нас функций (к которым мы уже привыкли после Strapi и Squidex), например, создание нескольких экземпляров одного компонента при внесении контента или возможность вложить компонент в компонент.

У Squidex интуитивно понятный UI, гибкие возможности по созданию модели данных. Мы не столкнулись с какими-либо ограничениями при моделировании.

Это решение отвечает всем исходным требованиям, которые мы предъявляли к Headless CMS.

Из-за особенностей предметной области у нас есть дополнительные требования по регионализации и версионированию контента, которые не поддерживаются ни одной из систем, но базовая функциональность и стек Squidex являются хорошей основной для последующей кастомизации и доработок.

Будем рады, если статья оказалась вам полезной. В комментариях поделитесь, интересны ли вам другие возможности CMS или, возможно, хотелось бы поподробнее узнать про какую-то функциональность. Если тема будет интересна, обязательно расскажем подробнее в будущих статьях.



CloudMTS поможет гибко управлять и разворачивать системы любого масштаба: от сайтов-визиток и простых CMS до высоконагруженных e-commerce-проектов. Сервис позволяет быстро выстраивать отказоустойчивую систему и масштабировать виртуальные машины под разный уровень нагрузки.

Комментарии (6)


  1. Pitcentr0
    30.08.2023 07:55

    обратите внимание на directus cms


  1. tsm2107
    30.08.2023 07:55

    modx??


  1. aol-nnov
    30.08.2023 07:55

    1. elkorotch Автор
      30.08.2023 07:55
      +1

      Нам для детального рассмотрения были интересны CMS, которые соответствовали ключевым критериям отбора: не только создание постов, а поддержка моделирования сложных структур данных (вложенность и переиспользуемость компонентов и т.п.), QraphQL API и другие. Не было задачи рассмотреть детально каждую систему на рынке, по максимальному соответствию критериям для пилота были выбраны 3 CMS, одна из них полностью подошла, поэтому дальнейшее исследование было нецелесообразным.


  1. garikmk
    30.08.2023 07:55

    А как же вот эта CSM https://quantumart.ru/products/cms, которая у вас уже используется ? Она всем вашим требованиям удовлетворяет.


    1. elkorotch Автор
      30.08.2023 07:55
      +1

      Как было написано в статье, на текущий момент в экосистеме МТС применяются различные инструменты для управления контентом. Возникла потребность в оптимизации и унификации текущих подходов к управлению контентом и передаче данных витринам. Развитие данной CMS требует привлечения внешней экспертизы, а также было интересно сравнить функциональность и удобство использования с другими решениями, поэтому начали заниматься исследованием рынка.