# Универсальное ТЗ для SEO‑апгрейда — v8.6 > **Версия:** 8.6 > **Дата:** 2026-04-06 > **Область:** Все домены экосистемы Dragon Education > **Целевой воркер:** Cloudflare Worker v6.5 > **Автор:** AI-SEO архитектор Dragon Education --- ## Содержание - [§0. Архитектура: два файла, две роли](#§0-архитектура-два-файла-две-роли) - [§1. Cloudflare Worker v6.5](#§1-cloudflare-worker-v65) - [§1.1. Канонический домен, www и боты](#§11-канонический-домен-www-и-боты) - [§2. ai-seo.json — ОБЯЗАТЕЛЬНЫЙ файл для Worker](#§2-ai-seojson--обязательный-файл-для-worker) - [§3. ai-context.json — AI-контекст для LLM](#§3-ai-contextjson--ai-контекст-для-llm) - [§4. seoConfig.ts + Seo-компонент (фронт)](#§4-seoconfigts--seo-компонент-фронт) - [§5. index.html, noscript, JSON-LD](#§5-indexhtml-noscript-json-ld) - [§6. sitemap.xml + robots.txt](#§6-sitemapxml--robotstxt) - [§7. Sync-протокол — порядок обновления](#§7-sync-протокол--порядок-обновления) - [§8. Cache-Control и Cloudflare Purge](#§8-cache-control-и-cloudflare-purge) - [§9. Чеклист проверки (curl-команды)](#§9-чеклист-проверки-curl-команды) - [§10. Правила по умолчанию](#§10-правила-по-умолчанию) --- ## Что изменилось с v7 → v8 | Проблема в v7 | Исправление в v8 | |---------------|------------------| | `ai-seo.json` упомянут, но нет чёткого требования «создать ПЕРВЫМ» | **Явный шаг 0:** создать `ai-seo.json` ДО всего остального | | Ссылка на Worker v6.4 | Обновлено на **v6.5** с описанием актуальной логики | | Кэширование CDN не упомянуто | Новая **§8:** Cache-Control + purge после деплоя | | Sync-протокол размытый | **Жёсткий чеклист** с порядком: seoConfig → ai-seo.json → ai-context.json → sitemap → lastUpdated | | lastUpdated забывается | **Явное правило:** обновлять при КАЖДОМ деплое | | Проверка не формализована | **Конкретные curl-команды** с ожидаемым выводом | | Путаница ai-context.json vs ai-seo.json | **Чёткое разделение ролей** — §0 | --- ## §0. Архитектура: два файла, две роли В экосистеме Dragon Education для каждого домена используются **ДВА** JSON-файла с принципиально разными ролями: ### `ai-seo.json` — для Cloudflare Worker | Параметр | Значение | |----------|----------| | **Потребитель** | Cloudflare Worker v6.5 (HTMLRewriter) | | **Задача** | Инъекция ``, `<meta description>`, `<link canonical>`, JSON-LD в HTML для ботов | | **Формат** | `{ default: {...}, pages: [{path, title, description, canonical, ogImage, jsonLd}] }` | | **Расположение** | `public/ai-seo.json` → `https://{ORIGIN}.lovable.app/ai-seo.json` | | **Кто читает** | ТОЛЬКО Worker при обработке запроса бота | ### `ai-context.json` — для LLM-краулеров | Параметр | Значение | |----------|----------| | **Потребитель** | PerplexityBot, GPTBot, ClaudeBot, Anthropic-AI и другие LLM | | **Задача** | Объяснить ИИ-системам что такое этот сайт, какие страницы есть, какова экосистема | | **Формат** | `{ version, lastUpdated, site, ecosystem, pages[], services[], aiInstructions }` | | **Расположение** | `public/ai-context.json` → `https://DOMAIN/ai-context.json` | | **Кто читает** | AI-боты напрямую (fetch JSON), поисковые роботы | ### ⚠️ Критическое правило > **НИКОГДА** не путать эти файлы. Worker не читает `ai-context.json`. LLM не читают `ai-seo.json`. > При добавлении новой страницы — обновлять **ОБА** файла. ### Дополнительные файлы | Файл | Роль | |------|------| | `ai-context.md` | Человекочитаемая версия ai-context.json для ботов без JSON-парсинга | | `ai-lovable-guide.md` | Инструкция для AI-агента (Lovable) по работе с конкретным доменом (опционально) | | `ai-lovable-update.md` | Журнал изменений для AI-агента (опционально) | --- ## §1. Cloudflare Worker v6.5 ### Архитектура Общий Cloudflare Worker обслуживает **все** домены экосистемы Dragon Education. ``` Запрос → Worker → configureByHost(request) → определяет ORIGIN + SITE_URL → fetchOrigin() → получает HTML с Lovable → isBot(UA)? → да → fetchSeoManifest() → HTMLRewriter → ответ → нет → ответ как есть ``` ### Функция `configureByHost(request)` Сопоставляет `Host` заголовок запроса с origin: | Host | ORIGIN_SUBDOMAIN | SITE_URL | |------|------------------|----------| | `dragon-english.biz` | `dragon-english-biz.lovable.app` | `https://dragon-english.biz` | | `dragon-education.ru` | `dragon-education.lovable.app` | `https://dragon-education.ru` | | `tv140380.ru` | `tv140380.lovable.app` | `https://tv140380.ru` | | `dragon-russian.ru` | `dragon-russian.lovable.app` | `https://dragon-russian.ru` | | `skills-panel.ru` | `skills-panel.lovable.app` | `https://skills-panel.ru` | ### Функция `getOrigins()` ``` LOVABLE_ORIGIN = https://{ORIGIN_SUBDOMAIN}.lovable.app SEO_URL = {LOVABLE_ORIGIN}/ai-seo.json GEO_URL = {LOVABLE_ORIGIN}/ai-geo.json (опционально) ``` ### BOT_AGENTS (v6.5) Worker определяет ботов по подстроке в `User-Agent`: ``` Googlebot, Bingbot, YandexBot, DuckDuckBot, Baiduspider, Twitterbot, facebookexternalhit, LinkedInBot, WhatsApp, Slackbot, Telegrambot, Discordbot, Applebot, Applebot-Extended, GPTBot, ChatGPT-User, Claude-Web, ClaudeBot, Anthropic-AI, anthropic-ai, PerplexityBot, Google-Extended, Amazonbot, CCBot, AI2Bot, Cohere-AI, Bytespider, meta-externalagent ``` ### HTMLRewriter — что делает Для ботов + HTML-ответов Worker: 1. **Заменяет** содержимое `<title>` на `title` из ai-seo.json для данного `path` 2. **Заменяет/вставляет** `<meta name="description">` 3. **Заменяет/вставляет** `<link rel="canonical">` 4. **Вставляет** `<meta property="og:title">`, `og:description`, `og:url`, `og:image` 5. **Вставляет** JSON-LD `<script type="application/ld+json">` из поля `jsonLd` 6. Если `path` не найден в `pages[]` — использует `default` ### ⛔ Что НЕЛЬЗЯ делать с Worker - Не переписывать, не дублировать, не менять архитектуру - Не создавать второй Worker - Работать ТОЛЬКО через данные (`ai-seo.json`, `ai-geo.json`) - Разрешены только точечные правки (добавить нового бота в `BOT_AGENTS`) --- ## §1.1. Канонический домен, www и боты Эти правила едины для **всех** доменов экосистемы, независимо от проекта. ### 1. Канонический домен для людей и ботов - Для каждого проекта существует **один канонический домен** вида `https://example.ru` **без `www`**. - Все внутренние ссылки в контенте, `seoConfig.ts`, `ai-seo.json`, `ai-context.json`, `sitemap.xml` и `<link rel="canonical">` должны указывать именно на канонический домен **без `www`**. - В Cloudflare Worker поле `SITE_URL` всегда задаётся **без `www`** и используется как базовый URL для: - `og:url`, - `canonical`, - JSON-LD (`@id`, `url`, `mainEntityOfPage`). Пример: ```ts // ПРАВИЛЬНО SITE_URL = 'https://dragon-education.ru'; // НЕЛЬЗЯ SITE_URL = 'https://www.dragon-education.ru'; ``` ### 2. Поддержка www на уровне Worker - Cloudflare Worker обязан принимать оба варианта хоста: с `www` и без `www`. - В `configureByHost(request)` для каждого домена всегда прописываются обе формы: ```js if (host === 'www.example.ru' || host === 'example.ru') { ORIGIN_SUBDOMAIN = 'example'; SITE_URL = 'https://example.ru'; // каноника без www return; } ``` - Это правило универсально: добавляя новый домен, **всегда** вносите обе формы хоста и указывайте `SITE_URL` без `www`. ### 3. Что видят разные типы ботов #### 3.1. Поисковые роботы и предпросмотры - Googlebot, YandexBot, соцсети и др. могут приходить как на домен без `www`, так и на `www`‑версию — Worker обрабатывает оба варианта одинаково. - Worker подтягивает `ai-seo.json` с Lovable‑origin (`https://{ORIGIN_SUBDOMAIN}.lovable.app/ai-seo.json`) и инжектирует: - `<title>`, `<meta name="description">`, - `<link rel="canonical" href="https://example.ru/…">`, - OG‑теги и JSON-LD. #### 3.2. LLM-краулеры (PerplexityBot, GPTBot, ClaudeBot и др.) - Такие боты **не обязаны исполнять JavaScript** и часто видят только исходный HTML без React‑контента. - Для глубокого понимания сайта они читают четыре слоя: 1. `https://example.ru/ai-context.json` - Главная карта маршрутов и смыслов: структура сайта, список страниц, `contentSummary` для каждой. - Обновляется при каждом изменении важного контента. 2. `https://example.ru/ai-context.md` - Полноценная человекочитаемая версия `ai-context.json` (если присутствует). - Используется как длинный нарратив для ботов и людей, которые не парсят JSON. 3. `<noscript>` в `index.html` - **Обязательно содержит полные тексты ключевых страниц**, а не сокращённые пересказы. - Правило: всё, что мы шлифуем для людей (структура, формулировки, аргументация), дублируется в `<noscript>` как полноценный контент того же уровня детализации. - Недопустимо "резать" смыслы ради краткости — `<noscript>` должен быть равноправным источником истины, а не анонсом. Это важно для: - сохранения всех нюансов аргументации, - работы с академической и государственной аудиториями, - будущих AI‑систем, которые используют только HTML‑слой. 4. Метаданные из `ai-seo.json` (через Worker) - `<title>`, `<meta description>`, canonical, JSON-LD дают краткий контур, но не заменяют полнотекстовый слой. ### 4. Универсальное правило для всех проектов Для любого нового домена/проекта, подключаемого к этому Worker: 1. В `configureByHost`: - добавить пару `www` / без `www` с **одним и тем же `SITE_URL` без `www`**; - задать `ORIGIN_SUBDOMAIN` для Lovable‑origin. 2. В `ai-seo.json`: - во всех `canonical` использовать домен без `www`. 3. В `ai-context.json`: - `site.url` и все `pages[].url` указывать без `www`, - для всех значимых маршрутов заполнять `contentSummary`, - при обновлении содержательных текстов обновлять соответствующие summaries. 4. В `index.html`: - поддерживать `<noscript>` как полный текстовый слой ключевых страниц (без выхолащивания смысла). - Любое обновление важного контента на странице должно сопровождаться синхронным обновлением его копии в `<noscript>`. 5. В `sitemap.xml`: - перечислять только URL без `www`. 6. В `robots.txt`: - явно разрешить `ai-context.json`, `ai-context.md` и `index.html` (включая `<noscript>`) для всех честных ботов. > **Принцип:** нигде не делать "урезанных версий" — `<noscript>` и `ai-context.*` являются полноценными носителями тех же смыслов, что и основной контент. --- ## §2. ai-seo.json — ОБЯЗАТЕЛЬНЫЙ файл для Worker ### ⚡ Это файл №1 по приоритету создания > При SEO-апгрейде любого домена — **ПЕРВЫМ ДЕЛОМ** создай или обнови `ai-seo.json`. > Без него Worker не сможет инжектировать метатеги, и боты увидят пустой SPA-шаблон. ### Расположение ``` public/ai-seo.json → деплоится на https://{ORIGIN}.lovable.app/ai-seo.json ``` ### Структура ```json { "default": { "title": "DOMAIN — Главный заголовок сайта", "description": "Описание до 160 символов", "ogImage": "https://DOMAIN/og-image.jpg", "locale": "ru_RU", "siteName": "Название сайта" }, "pages": [ { "path": "/", "title": "DOMAIN — Главная страница (до 60 символов)", "description": "Описание главной страницы до 160 символов", "canonical": "https://DOMAIN/", "ogImage": "https://DOMAIN/og-image.jpg", "jsonLd": { ... } }, { "path": "/technology", "title": "Технология — DOMAIN", "description": "...", "canonical": "https://DOMAIN/technology", "ogImage": "https://DOMAIN/og-image.jpg" } ] } ``` ### Правила для каждой записи в `pages[]` | Поле | Правило | |------|---------| | `path` | Строгое соответствие маршруту SPA. Без `/index`, без trailing slash (кроме `/`) | | `title` | До ~60 символов, уникальный, отражает суть страницы | | `description` | До ~160 символов, ясный конспект страницы | | `canonical` | `https://DOMAIN` + `path`. Всегда полный URL | | `ogImage` | Осмысленная картинка. Общий доменный OG или специфическая | | `noindex` | `true` только для админок, черновиков, служебных страниц | | `jsonLd` | Объект или массив объектов Schema.org. Обязателен для содержательных страниц | ### Правила для JSON-LD в ai-seo.json | Тип страницы | Рекомендуемые @type | |--------------|---------------------| | Главная / Hub | `WebPage` + `EducationalOrganization` | | Статья / лендинг | `Article` с `headline`, `author`, `publisher`, `datePublished`, `dateModified` | | Курс / учебный план | `Course` с `provider`, `educationalLevel`, `timeRequired` | | Каталог / библиотека | `CollectionPage` или `ItemList` | | Организация / О нас | `EducationalOrganization` с `sameAs` | ### StableSEO-страницы Если страница помечена как `stableSEO: true` в `ai-context.json`: - **НЕЛЬЗЯ** менять смысл `title` / `description` - **МОЖНО** улучшить формулировки (орфография, чёткость, длина) - **ОБЯЗАТЕЛЬНО** синхронизировать `canonical` и `ogImage` с реальным URL --- ## §3. ai-context.json — AI-контекст для LLM ### Назначение Этот файл LLM-краулеры (PerplexityBot, GPTBot и др.) читают **напрямую** через HTTP GET. Он объясняет ИИ-системам: - Что это за сайт - Какие страницы есть - Как этот домен связан с другими доменами экосистемы - Какие услуги предоставляются ### Обязательные поля верхнего уровня ```json { "version": "2.1", "lastUpdated": "2026-03-25", "site": { "name": "...", "domain": "DOMAIN", "type": "...", "language": "ru", "targetAudience": [...], "uniqueSellingPoints": [...] }, "ecosystem": { "mainSite": "https://dragon-english.ru", "b2bPortal": "https://dragon-english.biz", "learningPlatform": "https://dragon-english.school", "affiliateSystem": "https://from.dragon-english.ru" }, "pages": [ { "path": "/", "type": "landing|info|product|catalog|hub|partner|interactive|restricted", "title": "Краткое название", "description": "Что на этой странице" } ], "organization": { ... }, "services": [ ... ], "aiInstructions": { "summarization": "Краткое описание для ИИ", "keyTopics": [...], "contentContext": "..." } } ``` ### Правила 1. **`lastUpdated`** — обновлять при КАЖДОМ деплое на текущую дату 2. **`pages[]`** — КАЖДЫЙ публичный маршрут SPA должен быть перечислен 3. **`ecosystem`** — все домены Dragon Education с актуальными ролями 4. Поля `pages[].description` здесь могут быть длиннее, чем в ai-seo.json (нет ограничения 160 символов) 5. Закрытые страницы (`/corp`, `/offer`, `/admin/*`) можно включить с пометкой `"type": "restricted"` ### ai-context.md Человекочитаемый аналог. Должен содержать: - Версию и дату обновления - Описание платформы и ключевых особенностей - Таблицу экосистемы доменов - Описание всех разделов сайта с путями - Контактную информацию - Пометку «для AI-систем» > **Синхронизация:** при изменении `ai-context.json` всегда обновляй `ai-context.md` --- ## §4. seoConfig.ts + Seo-компонент (фронт) ### seoConfig.ts Централизованный словарь SEO-данных для React-приложения: ```typescript export const seoConfig: Record<string, PageSeoConfig> = { "/": { title: "...", description: "...", keywords: "...", canonicalPath: "/", type: "website", jsonLd: { ... } }, "/technology": { ... }, // ...каждый маршрут }; ``` ### Правила 1. **Каждый** маршрут приложения (статический и динамический) должен иметь запись 2. Для динамических маршрутов (`/lessons/:id`) — фабрика (например `getLessonSeo(lesson)`) 3. **НИКАКИХ** захардкоженных `<title>` / `<meta>` в компонентах страниц 4. Все страницы используют компонент `<Seo {...seoConfig[path]} />` ### Seo.tsx ```tsx <Helmet> <title>{title} {/* OG, Twitter, JSON-LD */} ``` ### ⚠️ Согласованность > Данные в `seoConfig.ts` и `ai-seo.json` должны быть **ИДЕНТИЧНЫМИ** для каждого маршрута. > `seoConfig.ts` — для клиентского рендеринга (JS-браузеры). > `ai-seo.json` — для серверной инъекции через Worker (боты без JS). > Рассогласование = разные метатеги для пользователей и ботов = проблемы с индексацией. --- ## §5. index.html, noscript, JSON-LD ### Требования к `` Обязательные элементы: ```html ``` ### Статические JSON-LD в `` Минимальный набор для каждого домена: 1. **`EducationalOrganization`** — с `@id`, `name`, `url`, `logo`, `sameAs` (другие домены экосистемы) 2. **`WebSite`** — с `name`, `url`, `publisher`, `inLanguage` 3. **`BreadcrumbList`** — ключевые разделы навигации 4. Опционально: **`Course`** (если есть флагманский курс) ### noscript — AI-friendly fallback В `` `