Интеграции с Headless CMS
Как AACsearch подключается к headless CMS — Strapi, Sanity, Contentful, Directus и Payload — и когда выбирать плагин против integration guide.
Headless CMS отдают контент через API, а не рендерят страницы сами. AACsearch поддерживает их двумя способами:
- Плагин — код, который работает внутри процесса CMS, слушает lifecycle-хуки и пушит дельты через Connector API. Так устроены Strapi и (запланированы) Directus / Payload.
- Integration guide — без плагина; CMS уже отдаёт вебхуки или change stream, которые вы подключаете к AACsearch небольшим адаптером. Так работают Contentful и Sanity.
Эта страница — зонтик. У каждой платформы есть отдельный гайд.
Матрица паттернов
| Платформа | Паттерн | Статус | Отдельная страница |
|---|---|---|---|
| Strapi 5.x | npm-плагин | Beta | Strapi |
| Sanity.io | GROQ + listener | Integration guide | Sanity |
| Contentful | Webhook-адаптер | Integration guide | Contentful |
| Directus 10+ | npm-extension | Planned | — |
| Payload CMS 2+ | Плагин (collections) | Planned | — |
| Generic / другое | Custom connector | — | Custom Connector |
Когда выбирать плагин
Берите плагин, когда у CMS есть стабильное extension API и она работает как долгоживущий процесс. Плагин даёт:
- Real-time хуки на каждое create / update / delete с payload сущности в области видимости — не нужен повторный API-запрос за сохранённой сущностью.
- Embedded admin-панель в UI CMS, чтобы мерчант или редактор управлял токеном коннектора.
- Локализованный контент через нативные локали платформы, замаппленные в
localeAACsearch.
Плагин Strapi в packages/strapi-plugin/ — эталонная реализация. Использует lifecycles API Strapi (afterCreate, afterUpdate, afterDelete) для вызова enqueueDelta и bootstrap для опциональной полной синхронизации на старте. Исходник переиспользуется как шаблон для Directus и Payload — тот же lifecycle-паттерн, другое host API.
Когда выбирать integration guide
Берите integration guide, когда:
- CMS — SaaS-хостинг и плагин внутри неё запустить нельзя (Contentful, Sanity).
- У CMS есть надёжный webhook или change-stream API с payload сущности в самом событии.
- Нужно индексировать только подмножество content types — плагин под такое overkill.
Для этих платформ документация показывает, как:
- Подписаться на webhook или change feed CMS.
- Настроить небольшой адаптер (serverless-функция, webhook-receiver в вашем существующем API или zap в Zapier), который маппит payload в
SyncProductInput. - Переслать дельту в
POST /api/projects/:projectId/sync/delta.
Рабочие рецепты — в Contentful и Sanity.
Выбор content-модели
Контент headless CMS редко ложится на форму e-commerce-товара. Общая схема документа принимает любую структуру в attributes, поэтому вопрос маппинга сводится к:
- Поисковые поля →
title,description. Всегда отправляйте чистый текст после стрипа markdown или rich-text JSON. - Фасетные фильтры →
attributes.<key>с правильным примитивом. AACsearch выводит тип фасета из первого батча. - Display-поля →
attributes.<key>для всего, что нужно только в карточке результата, не в поисковом запросе. - URL и картинки →
product_url,image_url. Виджет рендерит их по умолчанию. - Локаль — нативная локаль CMS, ограниченная
en | de | es | fr | ru(AACsearch поддерживает только эти пять). Если контент на другом языке, шлите ближайшего соседа и оригинальный код кладите вattributes.language.
Для не-продуктовых сущностей (статьи, рецепты, FAQ) переиспользуйте ту же схему:
{
"external_id": "article-2451",
"title": "Как заварить pour-over",
"description": "Короткий гайд…",
"categories": ["Гайды", "Кофе"],
"tags": ["новичкам", "pour-over"],
"image_url": "https://cms.example.com/img/pour-over.jpg",
"product_url": "https://site.example.com/guides/pour-over",
"locale": "ru",
"attributes": {
"type": "article",
"author": "Ольга Иванова",
"published_at": "2025-01-12",
"read_time_minutes": 4
}
}Используйте attributes.type, чтобы различать content-types в одном индексе, или создавайте отдельные индексы под каждый тип, если мерчанту нужны независимый ранкинг и аналитика.
Стратегия мультилокальности
Headless CMS обычно моделируют локали явно. Конвенция AACsearch — один документ на локаль на сущность:
external_idсуффиксирован локалью:article-2451:en,article-2451:de.- Виджет передаёт
localeс витрины, чтобы пользователь видел результаты только на своём языке. - Обновления одной локали не затрагивают документы других — обработчик событий должен отправлять только ту локаль, что изменилась.
Каноничная реализация этого паттерна — в Strapi.