# Универсальное ТЗ для 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) |
| **Задача** | Инъекция `<title>`, `<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}</title>
  <meta name="description" content={description} />
  <meta name="robots" content={noindex ? "noindex, nofollow" : "index, follow"} />
  <link rel="canonical" href={canonicalUrl} />
  {/* OG, Twitter, JSON-LD */}
</Helmet>
```

### ⚠️ Согласованность

> Данные в `seoConfig.ts` и `ai-seo.json` должны быть **ИДЕНТИЧНЫМИ** для каждого маршрута.  
> `seoConfig.ts` — для клиентского рендеринга (JS-браузеры).  
> `ai-seo.json` — для серверной инъекции через Worker (боты без JS).  
> Рассогласование = разные метатеги для пользователей и ботов = проблемы с индексацией.

---

## §5. index.html, noscript, JSON-LD

### Требования к `<head>`

Обязательные элементы:

```html
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<link rel="canonical" href="https://DOMAIN/" />
<link rel="icon" href="/favicon.png" type="image/png" />
```

### Статические JSON-LD в `<head>`

Минимальный набор для каждого домена:

1. **`EducationalOrganization`** — с `@id`, `name`, `url`, `logo`, `sameAs` (другие домены экосистемы)
2. **`WebSite`** — с `name`, `url`, `publisher`, `inLanguage`
3. **`BreadcrumbList`** — ключевые разделы навигации
4. Опционально: **`Course`** (если есть флагманский курс)

### noscript — AI-friendly fallback

В `<body>` `<noscript>` должен содержать:

- `<h1>` с названием проекта
- Полную навигацию со ссылками на ВСЕ публичные страницы
- Текстовое описание КАЖДОГО раздела с ключевыми данными и аргументами
- Для МСХ-страниц: все 10 вкладок с описаниями

### ⚠️ Правило паритета

> Содержимое `<noscript>` не должно противоречить `ai-context.json` / `ai-context.md`.  
> Это место, куда бот (и человек без JS) заглянет и получит реальный контент.

---

## §6. sitemap.xml + robots.txt

### sitemap.xml

Для каждого домена:

```xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://DOMAIN/</loc>
    <lastmod>2026-03-25</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <!-- Все публичные маршруты -->
  <!-- AI-контекстные файлы -->
  <url>
    <loc>https://DOMAIN/ai-context.json</loc>
    <lastmod>2026-03-25</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.3</priority>
  </url>
</urlset>
```

### Правила sitemap

1. Каждый публичный маршрут из `seoConfig.ts` (кроме `noindex: true`) должен быть
2. `<lastmod>` — реальная дата последнего изменения контента страницы
3. AI-файлы (`ai-context.json`, `ai-context.md`) тоже включать в sitemap
4. `priority` — адекватная: главная = 1.0, основные = 0.8, вспомогательные = 0.6-0.7

### robots.txt

```
# SEO и AI Crawlers
User-agent: Googlebot
Allow: /

User-agent: GPTBot
Allow: /

User-agent: PerplexityBot
Allow: /

User-agent: ClaudeBot
Allow: /

# ... остальные боты

User-agent: *
Allow: /

Disallow: /admin/
Disallow: /corp?key=
Disallow: /offer?key=

Sitemap: https://DOMAIN/sitemap.xml
Host: DOMAIN
```

Обязательно:
- Явно разрешить всех AI-ботов из списка BOT_AGENTS Worker'а
- Явно запретить закрытые разделы
- Указать Sitemap и Host

---

## §7. Sync-протокол — порядок обновления

### При добавлении новой страницы или изменении существующей

Выполнять строго в этом порядке:

```
┌─────────────────────────────────────────────────────┐
│  ШАГ 1. seoConfig.ts                                │
│  → Добавить/обновить запись для маршрута             │
│  → title, description, keywords, canonicalPath,      │
│    type, jsonLd                                      │
├─────────────────────────────────────────────────────┤
│  ШАГ 2. ai-seo.json                                 │
│  → СКОПИРОВАТЬ title, description, canonical из      │
│    seoConfig.ts                                      │
│  → Добавить ogImage и jsonLd                         │
│  → Данные ДОЛЖНЫ быть идентичны seoConfig.ts         │
├─────────────────────────────────────────────────────┤
│  ШАГ 3. ai-context.json                              │
│  → Добавить запись в pages[] с path, type, title,    │
│    description                                       │
│  → description может быть длиннее (для LLM)          │
│  → Обновить lastUpdated на текущую дату              │
├─────────────────────────────────────────────────────┤
│  ШАГ 4. ai-context.md                                │
│  → Добавить описание новой страницы в разделе         │
│    «Основные разделы»                                │
│  → Обновить версию и дату                            │
├─────────────────────────────────────────────────────┤
│  ШАГ 5. index.html (noscript)                        │
│  → Добавить ссылку в навигацию                       │
│  → Добавить <section> с описанием                    │
├─────────────────────────────────────────────────────┤
│  ШАГ 6. sitemap.xml                                  │
│  → Добавить <url> с loc, lastmod, changefreq,        │
│    priority                                          │
├─────────────────────────────────────────────────────┤
│  ШАГ 7. Финальная проверка lastUpdated               │
│  → ai-context.json.lastUpdated = сегодня             │
│  → ai-context.md: «Последнее обновление» = сегодня   │
│  → sitemap.xml: lastmod обновлённых страниц = сегодня │
└─────────────────────────────────────────────────────┘
```

### Мнемоника

> **S**eo → **A**i-seo → **C**ontext → **M**d → **I**ndex → **S**itemap → **L**astUpdated  
> **SACMISL** — «Сначала Автомат, Потом Ручная Сверка»

---

## §8. Cache-Control и Cloudflare Purge

### Проблема

Cloudflare кэширует статические файлы (.json, .md, .xml) с длинным TTL. После деплоя Lovable боты (Perplexity, GPT) могут читать **СТАРУЮ** версию из кэша часами или днями.

### Решение 1: Cache-Control в Worker (рекомендуется)

Добавить в Worker для JSON/MD/XML файлов:

```javascript
// В handleRequest(), после получения response от origin:
if (pathname.endsWith('.json') || pathname.endsWith('.md') || pathname.endsWith('.xml')) {
  const headers = new Headers(response.headers);
  headers.set('Cache-Control', 'public, max-age=300'); // 5 минут
  return new Response(response.body, { status: response.status, headers });
}
```

### Решение 2: Manual Purge (после каждого деплоя)

В Cloudflare Dashboard → Caching → Purge Cache:

```
Файлы для purge после деплоя:
- https://DOMAIN/ai-context.json
- https://DOMAIN/ai-seo.json
- https://DOMAIN/ai-context.md
- https://DOMAIN/sitemap.xml
```

### Решение 3: Cache Busting через query string

В sitemap.xml и robots.txt можно ссылаться с версией:

```
https://DOMAIN/ai-context.json?v=20260325
```

> **ОБЯЗАТЕЛЬНО** после каждого деплоя с изменениями SEO-файлов выполнить Purge Cache  
> или дождаться истечения TTL (до 24ч по умолчанию в Cloudflare).

---

## §9. Чеклист проверки (curl-команды)

### После каждого деплоя выполнить:

#### 1. Проверка ai-seo.json (Worker читает с origin)

```bash
curl -s https://{ORIGIN}.lovable.app/ai-seo.json | python3 -c "
import json,sys; d=json.load(sys.stdin)
print(f'Pages: {len(d[\"pages\"])}')
for p in d['pages']:
    print(f'  {p[\"path\"]:45s} → {p[\"title\"][:50]}')
"
```

**Ожидаемый результат:** Все маршруты перечислены с корректными title.

#### 2. Проверка ai-context.json (LLM читают с домена)

```bash
curl -s https://DOMAIN/ai-context.json | python3 -c "
import json,sys; d=json.load(sys.stdin)
print(f'lastUpdated: {d[\"lastUpdated\"]}')
print(f'Pages: {len(d[\"pages\"])}')
for p in d['pages']:
    print(f'  {p[\"path\"]:45s} → {p[\"title\"]}')
"
```

**Ожидаемый результат:** `lastUpdated` = сегодня, все страницы перечислены.

#### 3. Проверка инъекции Worker для бота

```bash
# Главная
curl -s -H "User-Agent: PerplexityBot" https://DOMAIN/ | grep -oP '<title>\K[^<]+'

# МСХ-страница
curl -s -H "User-Agent: PerplexityBot" https://DOMAIN/ministries/minselkhoz | grep -oP '<title>\K[^<]+'

# Несуществующая страница (должен вернуть default title)
curl -s -H "User-Agent: PerplexityBot" https://DOMAIN/nonexistent | grep -oP '<title>\K[^<]+'
```

**Ожидаемый результат:** Уникальные title для каждого маршрута, default для 404.

#### 4. Проверка canonical и description

```bash
curl -s -H "User-Agent: GPTBot" https://DOMAIN/technology | grep -E '(canonical|description)' | head -3
```

**Ожидаемый результат:**
```html
<meta name="description" content="Уникальная запатентованная технология..."/>
<link rel="canonical" href="https://DOMAIN/technology"/>
```

#### 5. Проверка в обычном браузере

Открыть те же URL без спец. UA:
- Layout и дизайн не сломаны
- React-приложение загружается
- Навигация работает
- Ошибок в консоли нет

#### 6. Проверка sitemap

```bash
curl -s https://DOMAIN/sitemap.xml | grep -c '<url>'
```

**Ожидаемый результат:** Количество URL = количество публичных маршрутов + AI-файлы.

---

## §10. Правила по умолчанию

### Принцип «не навреди»

1. **Сначала прочитай** `ai-context.json` и `ai-context.md` текущего домена
2. **StableSEO-страницы** (`stableSEO: true`) — менять только формальную сторону (длина, орфография), без смены смысла
3. **Всегда** можно вернуть предыдущий вариант SEO-записи как backup, но не выбрасывай информацию

### Принцип «не ломай»

1. **НЕЛЬЗЯ** ломать существующий layout, дизайн и React-логику
2. **НЕЛЬЗЯ** переписывать или дублировать Cloudflare Worker
3. **НЕЛЬЗЯ** создавать альтернативные SEO-системы — работать через `seoConfig.ts` + `ai-seo.json`

### Принцип «всегда синхронизируй»

1. Любое SEO-изменение = обновить **ВСЕ** файлы по протоколу §7
2. `lastUpdated` обновлять при **КАЖДОМ** деплое
3. После деплоя — **ВСЕГДА** purge Cloudflare cache для JSON/XML файлов

### Порядок создания файлов при SEO-апгрейде нового домена

```
1. public/ai-seo.json        ← ПЕРВЫЙ! Worker без него бессилен
2. src/data/seoConfig.ts      ← фронтовый SEO-конфиг
3. public/ai-context.json     ← для LLM
4. public/ai-context.md       ← человекочитаемый
5. public/sitemap.xml         ← карта сайта
6. public/robots.txt          ← правила для ботов
7. index.html (noscript)      ← fallback для ботов без JS
```

### Текущий статус dragon-english.biz (референс v8)

| Файл | Страниц | lastUpdated | Статус |
|------|---------|-------------|--------|
| `seoConfig.ts` | 27 маршрутов | — | ✅ OK |
| `ai-seo.json` | 27 записей в pages[] | — | ✅ OK |
| `ai-context.json` | 27 записей в pages[] | 2026-03-25 | ✅ OK |
| `ai-context.md` | Полное описание | 2026-03-25 | ✅ OK |
| `sitemap.xml` | 27 URL | 2026-03-25 | ✅ OK |
| `robots.txt` | 14 ботов | — | ✅ OK |
| `index.html noscript` | 27 секций | — | ✅ OK |

---

*Эта инструкция (v8.0) применяется одинаково для всех доменов экосистемы Dragon Education, обслуживаемых общим Cloudflare Worker v6.5.*
