# MedGen Content Scope And Response Contract For CMX Admin

## 1. Назначение документа

Этот документ описывает, с какими страницами сайта должен работать MedGen, какой контент он должен генерировать и в каком JSON-формате CMX Admin ожидает ответ.

Актуальное публичное ТЗ для MedGen: `https://cmx-medgen-contract.pages.dev/contract.md`. Машинно-читаемые правила по каждой странице: `https://cmx-medgen-contract.pages.dev/page-format-registry.json`. Их смысл: CMX владеет маршрутом, типом страницы, набором модулей, глобальным шаблоном и CSS; MedGen возвращает уже заполненный `result.cmx_page` с готовыми module props и разрешенной внутренней HTML-разметкой для заранее известных слотов. То есть MedGen не присылает "просто текст"; он присылает контент, уже разложенный по CMX skeleton.

Проектное правило синхронизации: если в CMX появляется новая страница, меняется существующая страница, меняется порядок модулей или допустимая разметка, сначала обновляется публичный contract project на том же `cmx-medgen-contract.pages.dev`. Только после этого можно создавать MedGen task для новой/измененной страницы.

MedGen не управляет дизайном, сервером, SSL, деплоем, favicon, логотипом, CSS/JS, обфускацией и GitHub Actions. MedGen отвечает только за контент:

- SEO-тексты;
- технические страницы;
- карточки товаров;
- обзоры товаров;
- страницы экспертов/докторов;
- guide-статьи;
- заголовки, описания, FAQ, источники, предупреждения, микроразметочные данные.

MedGen является внешним независимым микросервисом и не связан с OpenAI аккаунтом владельца CMX. CMX ожидает от него только структурированные ответы по контракту ниже; секрет доступа к MedGen хранится отдельно как `MEDGEN_API_TOKEN` в GitHub Secrets и не передается в публичную админку.

CMX Admin отвечает за:

- выбор активного сайта;
- маршруты;
- slug;
- публикацию JSON;
- SEO-аудит;
- сборку статического сайта;
- деплой на VPS.

## 1.1 Актуальная транспортная оговорка

Этот документ описывает CMX-side content scope и локальные content types. Текущий публичный MedGen API принимает только `type: "content_page" | "tech_page" | "author" | "placeholder"`. Локальные CMX типы вроде `product_review`, `product_card`, `expert_profile`, `technical_page` и `guide_article` не отправляются как top-level `type`; workflow нормализует их в официальный MedGen `type`, а локальный режим кладет в `extra.cmx_content_type`.

Публичный успешный ответ MedGen содержит финальный `article`; `cms_payload` не является обязательным полем текущего API. Новый предпочтительный CMX-формат находится в `result.cmx_page`: это заполненный page skeleton с `version`, `content_type`, `route`, `seo`, `modules`, `faq`, `media` и `relations`. CMX использует `article.body`, `article.html`, `article.text`, `article.metadata`, `article.seo_title` и `article.seo_description` как fallback/SEO-поля, если MedGen еще не вернул полный `result.cmx_page`. После preview и подтверждения CMX запускает validation/build/SEO/assets audit.

## 2. Общая логика сайта

Каждый сайт генерируется под один GEO и один язык в корне домена.

Пример для Болгарии:

```json
{
  "root_locale": "bg_BG",
  "geo": "BG",
  "locale_strategy": "single_root"
}
```

Правильные URL:

```text
https://example.com/
https://example.com/bady/omega-balance-softgels/
https://example.com/obzory/omega-balance-softgels-review/
https://example.com/experts/dr-demo-reviewer/
```

Неправильные URL:

```text
https://example.com/bg/
https://example.com/en/
https://example.com/ru/
```

MedGen должен возвращать контент на языке `root_locale`. Если `root_locale=bg_BG`, все публичные тексты должны быть на болгарском.

## 3. С какими страницами работает MedGen

### 3.1 Главная страница

MedGen генерирует контент для:

```text
route: /
content_path: content/pages/home.json
content_type: home_page
```

Нужные поля:

- `h1`;
- `hero_lead`;
- `search_placeholder`;
- `trust_cards`;
- `popular_categories_intro`;
- `product_carousel_heading`;
- `reviews_heading`;
- `experts_heading`;
- `faq`;
- `footer_disclaimer`;
- `seo`.

### 3.2 Технические страницы

MedGen должен уметь генерировать следующие технические страницы:

| page_key | route | content_path | Назначение |
|---|---|---|---|
| `about` | `/about/` | `content/pages/technical/about.json` | О проекте |
| `methodology` | `/methodology/` | `content/pages/technical/methodology.json` | Методология оценки |
| `editorial_policy` | `/editorial-policy/` | `content/pages/technical/editorial-policy.json` | Редакционная политика |
| `information_sources` | `/sources/` | `content/pages/technical/sources.json` | Источники информации |
| `affiliate_disclosure` | `/affiliate-disclosure/` | `content/pages/technical/affiliate-disclosure.json` | Партнерское раскрытие |
| `contact` | `/contact/` | `content/pages/technical/contact.json` | Контакты |
| `faq` | `/faq/` | `content/pages/technical/faq.json` | FAQ |
| `how_to_use` | `/how-to-use/` | `content/pages/technical/how-to-use.json` | Как пользоваться сайтом |
| `suggest_supplement` | `/suggest-supplement/` | `content/pages/technical/suggest-supplement.json` | Предложить добавку |
| `disclaimer` | `/disclaimer/` | `content/pages/technical/disclaimer.json` | Дисклеймер |
| `privacy_policy` | `/privacy-policy/` | `content/pages/technical/privacy-policy.json` | Политика конфиденциальности |
| `terms_of_use` | `/terms/` | `content/pages/technical/terms.json` | Условия использования |
| `cookie_policy` | `/cookie-policy/` | `content/pages/technical/cookie-policy.json` | Cookie Policy |
| `product_picker` | `/podbor/` | `content/pages/technical/podbor.json` | Подбор продукта |

MedGen не должен генерировать визуальную страницу `/sitemap/`. Sitemap должен быть системным SEO-артефактом, который CMX строит автоматически.

### 3.3 Индексные страницы

MedGen должен уметь генерировать вводный SEO-контент для индексных страниц:

| page_key | route | content_path | Назначение |
|---|---|---|---|
| `catalog` | `/bady/` | `content/pages/categories/bady.json` | Каталог товаров/БАДов |
| `reviews_index` | `/obzory/` | `content/pages/categories/obzory.json` | Список обзоров |
| `experts_index` | `/experts/` | `content/pages/authors/experts.json` | Список экспертов |
| `guides_index` | `/guides/` | `content/pages/categories/guides.json` | Гайды и статьи |
| `popular_products` | `/popular-products/` | `content/pages/categories/popular-products.json` | Популярные товары |
| `comparisons` | `/sravneniya/` | `content/pages/categories/sravneniya.json` | Сравнения |
| `brands` | `/brands/` | `content/pages/categories/brands.json` | Бренды |
| `vitamins_minerals` | `/vitamins-minerals/` | `content/pages/categories/vitamins-minerals.json` | Витамины и минералы |

Индексные страницы не должны содержать полный товарный или авторский контент. Они получают:

- SEO title/description;
- H1;
- lead;
- intro sections;
- FAQ;
- короткие подписи к блокам;
- тексты для виджетов.

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

### 3.4 Карточки товаров

MedGen генерирует карточки товаров по шаблону:

```text
route: /bady/{product_slug}/
content_path: content/pages/supplements/{product_slug}.json
content_type: product_card
```

Пример:

```text
/bady/omega-balance-softgels/
content/pages/supplements/omega-balance-softgels.json
```

Нужные поля:

- название товара;
- бренд;
- короткое описание;
- длинное описание;
- рейтинг;
- цена в валюте текущего GEO;
- availability: всегда `Available`, если оператор не передал другое;
- offer URL;
- Buy button label;
- gallery images или image suggestions;
- alt для всех изображений;
- reviewer/expert reference, если есть обзор;
- safety note;
- affiliate note;
- SEO;
- Product JSON-LD hints.

### 3.5 Обзоры товаров

MedGen генерирует обзор товара по шаблону:

```text
route: /obzory/{product_slug}-review/
content_path: content/pages/technical/{product_slug}-review.json
content_type: product_review
```

Пример:

```text
/obzory/omega-balance-softgels-review/
content/pages/technical/omega-balance-softgels-review.json
```

Обзор должен быть связан с:

- товаром: `/bady/{product_slug}/`;
- экспертом/доктором: `/experts/{expert_slug}/`;
- индексом обзоров: `/obzory/`.

Нужные поля:

- H1;
- lead;
- full review text;
- review summary;
- reviewer;
- updated date;
- verdict;
- rating;
- pros;
- cons;
- safety notes;
- sources;
- FAQ;
- related product route;
- author/expert route;
- SEO;
- Article/Review JSON-LD hints.

### 3.6 Эксперты/доктора

MedGen генерирует страницы экспертов по шаблону:

```text
route: /experts/{expert_slug}/
content_path: content/pages/authors/{expert_slug}.json
content_type: expert_profile
```

Пример:

```text
/experts/dr-demo-reviewer/
content/pages/authors/dr-demo-reviewer.json
```

Нужные поля:

- имя;
- роль;
- короткая специализация;
- bio;
- portrait image suggestion;
- image alt;
- social links;
- research profile link;
- doctor profile link;
- reviews route;
- список review references;
- SEO;
- Person JSON-LD hints.

Важно: если MedGen создает review с новым доктором, он должен вернуть данные для создания/обновления экспертной страницы. Review не должен ссылаться на несуществующего эксперта.

### 3.7 Guide-статьи

MedGen генерирует guide-статьи по шаблону:

```text
route: /guides/{guide_slug}/
content_path: content/pages/technical/{guide_slug}.json
content_type: guide_article
```

Пример:

```text
/guides/how-to-compare-supplement-labels/
content/pages/technical/how-to-compare-supplement-labels.json
```

Нужные поля:

- H1;
- H2/lead;
- hero image suggestion;
- sections;
- FAQ;
- sources;
- related products;
- SEO;
- Article JSON-LD hints.

### 3.8 Legacy/optional sections

Следующие разделы могут существовать в старом шаблоне, но не должны генерироваться MedGen по умолчанию:

```text
/problems/
/problems/{slug}/
```

Их использовать только если CMX Admin явно передаст `enabled: true`.

## 4. Универсальный request от CMX к MedGen

CMX отправляет в MedGen один объект задачи:

```json
{
  "request_id": "cmx-workerwp-store-20260518-001",
  "type": "product_review",
  "site": {
    "site_id": "workerwp-store",
    "domain": "workerwp.store",
    "base_url": "https://workerwp.store",
    "brand_name": "NutriScope",
    "root_locale": "bg_BG",
    "geo": "BG",
    "contact_email": "support@workerwp.store",
    "locale_strategy": "single_root"
  },
  "target": {
    "page_key": "omega_balance_softgels_review",
    "route": "/obzory/omega-balance-softgels-review/",
    "slug": "omega-balance-softgels-review",
    "content_path": "content/pages/technical/omega-balance-softgels-review.json"
  },
  "product": {
    "name": "Omega Balance Softgels",
    "brand": "Demo Brand",
    "slug": "omega-balance-softgels",
    "route": "/bady/omega-balance-softgels/",
    "price": "19.90 USD",
    "offer_url": "https://example.com/demo-offer"
  },
  "expert": {
    "name": "Dr Demo Reviewer",
    "slug": "dr-demo-reviewer",
    "route": "/experts/dr-demo-reviewer/",
    "role": "medical reviewer"
  },
  "content_policy": {
    "ymyl": true,
    "no_medical_promises": true,
    "no_fake_sources": true,
    "fictional_demo_allowed": true,
    "language": "Bulgarian"
  },
  "seo": {
    "canonical": "https://workerwp.store/obzory/omega-balance-softgels-review/",
    "robots": "index,follow",
    "schema_required": true
  },
  "notes": "Generate cautious supplement review content. Do not claim treatment or diagnosis."
}
```

Если `contact_email` не передан из админки, CMX автоматически подставляет `support@<site.domain>` до создания задачи. CMX также дублирует это значение в `site.contact_email`, `editorial_metadata.contact_email` и `extra.allowed_contact_text`.

MedGen должен использовать email только как plain text контакт. Запрещено превращать его в `mailto:`, HTML anchor или элемент массива `sources`. CMX отправляет защитные флаги `extra.cmx_content_policy.no_mailto_links=true`, `no_email_as_source=true`, `contact_email_plain_text_only=true` и вычищает email-like значения из `sources` перед созданием задачи.

## 5. Универсальный response от MedGen

MedGen должен возвращать стабильный JSON:

```json
{
  "ok": true,
  "task_id": "mg_task_123",
  "request_id": "cmx-workerwp-store-20260518-001",
  "status": "succeeded",
  "content_type": "product_review",
  "result": {
    "locale": "bg_BG",
    "route": "/obzory/omega-balance-softgels-review/",
    "slug": "omega-balance-softgels-review",
    "title": "Omega Balance Softgels Review",
    "seo": {
      "title": "Omega Balance Softgels Review | NutriScope",
      "description": "Evidence-aware review of Omega Balance Softgels with pricing, safety notes and reviewer context.",
      "robots": "index,follow",
      "open_graph_title": "Omega Balance Softgels Review",
      "open_graph_description": "Review summary for supplement buyers.",
      "open_graph_image_alt": "Omega Balance Softgels product review"
    },
    "fields": {},
    "sections": [],
    "faq": [],
    "sources": [],
    "media": [],
    "relations": {},
    "schema_hints": {},
    "warnings": []
  },
  "validation_report": {
    "ok": true,
    "issues": [],
    "warnings": []
  }
}
```

`fields`, `sections`, `relations` и `schema_hints` зависят от типа страницы.

## 6. Response format by content type

### 6.1 `home_page`

```json
{
  "content_type": "home_page",
  "result": {
    "route": "/",
    "title": "NutriScope",
    "seo": {
      "title": "NutriScope | Evidence-first supplement reviews",
      "description": "Independent supplement catalog with reviews, expert context and transparent safety notes.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "Supplement reviews that check evidence first",
      "hero_lead": "Short value proposition for the site.",
      "search_placeholder": "Search supplements, ingredients, brands...",
      "product_carousel_heading": "Popular products",
      "reviews_heading": "Latest reviews",
      "experts_heading": "Expert reviewers",
      "footer_disclaimer": "The materials of the site are informative and are not medical recommendations."
    },
    "trust_cards": [
      {
        "title": "Authorship",
        "body": "Every review shows reviewer attribution."
      }
    ],
    "faq": [
      {
        "question": "Is this medical advice?",
        "answer": "No. Content is informational."
      }
    ]
  }
}
```

### 6.2 `technical_page`

```json
{
  "content_type": "technical_page",
  "result": {
    "route": "/privacy-policy/",
    "title": "Privacy Policy",
    "seo": {
      "title": "Privacy Policy | NutriScope",
      "description": "How the site handles privacy, cookies and user requests.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "Privacy Policy",
      "lead": "Short page lead.",
      "updated_label": "Last updated"
    },
    "sections": [
      {
        "h2": "What information we handle",
        "body": "Section text."
      },
      {
        "h2": "How users can contact us",
        "body": "Section text."
      }
    ],
    "faq": [
      {
        "question": "Can users request corrections?",
        "answer": "Yes, they can contact the editorial team."
      }
    ]
  }
}
```

### 6.3 `category_index`

```json
{
  "content_type": "category_index",
  "result": {
    "route": "/bady/",
    "title": "Popular products",
    "seo": {
      "title": "Popular supplement products | NutriScope",
      "description": "Browse supplement product cards with prices, reviews and safety context.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "Popular products",
      "lead": "Short index page intro.",
      "empty_state": "No products found yet.",
      "filter_hint": "Use filters to compare product cards."
    },
    "sections": [
      {
        "h2": "How to read product cards",
        "body": "Explain ratings, price, offer links and review buttons."
      }
    ],
    "faq": []
  }
}
```

### 6.4 `product_card`

```json
{
  "content_type": "product_card",
  "result": {
    "route": "/bady/omega-balance-softgels/",
    "slug": "omega-balance-softgels",
    "title": "Omega Balance Softgels",
    "seo": {
      "title": "Omega Balance Softgels: price and review context | NutriScope",
      "description": "Product card for Omega Balance Softgels with price, availability, offer link and review context.",
      "robots": "index,follow"
    },
    "fields": {
      "name": "Omega Balance Softgels",
      "brand": "Demo Brand",
      "rating": 4.3,
      "price": "19.90 USD",
      "availability": "Available",
      "seller_label": "Buy",
      "seller_url": "https://example.com/demo-offer",
      "short_description": "Short product card description.",
      "long_description": "Long product page description.",
      "important_notice": "Informational content only. Consult a qualified clinician before using supplements.",
      "affiliate_note": "Offer links may be affiliate links."
    },
    "media": [
      {
        "kind": "product_image",
        "url": "https://example.com/image.webp",
        "alt": "Omega Balance Softgels bottle",
        "license_note": "Public/demo image or supplied asset."
      }
    ],
    "relations": {
      "review_route": "/obzory/omega-balance-softgels-review/",
      "expert_route": "/experts/dr-demo-reviewer/"
    },
    "schema_hints": {
      "types": ["Product", "Review", "BreadcrumbList"],
      "brand": "Demo Brand",
      "offers": {
        "price": "19.90",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock"
      }
    }
  }
}
```

### 6.5 `product_review`

```json
{
  "content_type": "product_review",
  "result": {
    "route": "/obzory/omega-balance-softgels-review/",
    "slug": "omega-balance-softgels-review",
    "title": "Omega Balance Softgels Review",
    "seo": {
      "title": "Omega Balance Softgels Review | NutriScope",
      "description": "Review of Omega Balance Softgels with safety notes, pricing and reviewer context.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "Omega Balance Softgels Review",
      "lead": "Short review lead.",
      "review_summary": "Two sentence review summary.",
      "verdict": "Context-dependent supplement review.",
      "rating": 4.3,
      "updated_at": "2026-05-18",
      "important_notice": "This review is informational and is not medical advice."
    },
    "sections": [
      {
        "h2": "What this product is",
        "body": "Section text."
      },
      {
        "h2": "What to check before buying",
        "body": "Section text."
      }
    ],
    "pros": [
      "Clear public product positioning"
    ],
    "cons": [
      "Evidence and label data should be verified before production"
    ],
    "sources": [
      {
        "title": "Source title",
        "url": "https://example.com/source",
        "note": "Why this source is relevant"
      }
    ],
    "relations": {
      "product_route": "/bady/omega-balance-softgels/",
      "expert_route": "/experts/dr-demo-reviewer/",
      "reviews_index_route": "/obzory/"
    },
    "schema_hints": {
      "types": ["Article", "Review", "BreadcrumbList"],
      "author_name": "Dr Demo Reviewer",
      "reviewed_item_name": "Omega Balance Softgels"
    }
  }
}
```

### 6.6 `expert_profile`

```json
{
  "content_type": "expert_profile",
  "result": {
    "route": "/experts/dr-demo-reviewer/",
    "slug": "dr-demo-reviewer",
    "title": "Dr Demo Reviewer",
    "seo": {
      "title": "Dr Demo Reviewer | NutriScope",
      "description": "Expert profile and review archive.",
      "robots": "index,follow"
    },
    "fields": {
      "name": "Dr Demo Reviewer",
      "role": "Medical reviewer",
      "specialty": "Supplement review and safety context",
      "bio": "Short expert biography.",
      "reviews_label": "View reviews"
    },
    "media": [
      {
        "kind": "portrait",
        "url": "https://example.com/portrait.webp",
        "alt": "Dr Demo Reviewer portrait"
      }
    ],
    "social_links": [
      {
        "label": "LinkedIn",
        "url": "https://example.com/in/dr-demo-reviewer"
      },
      {
        "label": "Research profile",
        "url": "https://example.com/research/dr-demo-reviewer"
      }
    ],
    "relations": {
      "reviews_index_route": "/obzory/",
      "review_routes": [
        "/obzory/omega-balance-softgels-review/"
      ]
    },
    "schema_hints": {
      "types": ["Person", "ProfilePage", "BreadcrumbList"]
    }
  }
}
```

### 6.7 `guide_article`

```json
{
  "content_type": "guide_article",
  "result": {
    "route": "/guides/how-to-compare-supplement-labels/",
    "slug": "how-to-compare-supplement-labels",
    "title": "How to Compare Supplement Labels",
    "seo": {
      "title": "How to Compare Supplement Labels | NutriScope",
      "description": "Guide to reading supplement labels, claims and safety notes.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "How to Compare Supplement Labels",
      "lead": "Short educational lead."
    },
    "sections": [
      {
        "h2": "Start with the serving size",
        "body": "Section text."
      }
    ],
    "faq": [],
    "sources": [],
    "media": [
      {
        "kind": "hero_image",
        "url": "https://example.com/guide.webp",
        "alt": "Supplement label comparison"
      }
    ],
    "schema_hints": {
      "types": ["Article", "BreadcrumbList"]
    }
  }
}
```

## 7. Task lifecycle response

Создание задачи:

```json
{
  "ok": true,
  "task_id": "mg_task_123",
  "status": "queued",
  "poll_after_seconds": 30
}
```

Промежуточный статус:

```json
{
  "ok": true,
  "task_id": "mg_task_123",
  "status": "running",
  "stage": "draft",
  "progress": 55,
  "poll_after_seconds": 60
}
```

Ошибка:

```json
{
  "ok": false,
  "task_id": "mg_task_123",
  "status": "failed",
  "stage": "safety_review",
  "failed_stage": "safety_review",
  "error": {
    "code": "ymyl_claim_rejected",
    "message": "Unsupported medical claim detected.",
    "human": "Материал содержит неподтвержденное медицинское обещание.",
    "retryable": false
  }
}
```

## 8. Что нельзя возвращать

MedGen не должен возвращать:

- HTML целой страницы;
- CSS/JS;
- секреты;
- SSH/деплой данные;
- языковые папки `/bg/`, `/en/`, `/ru/`;
- fake medical sources без явной пометки demo;
- claims про лечение, диагностику или предотвращение заболеваний;
- каноникалы на другой домен;
- `noindex`, если CMX явно не запросил это;
- неструктурированный текст без JSON-обертки.

## 9. Минимально достаточный формат для старта

Если партнеру нужно начать с самого простого варианта, достаточно поддержать:

```json
{
  "ok": true,
  "task_id": "mg_task_123",
  "status": "succeeded",
  "content_type": "technical_page",
  "result": {
    "route": "/about/",
    "title": "About",
    "seo": {
      "title": "About | Site Name",
      "description": "SEO description.",
      "robots": "index,follow"
    },
    "fields": {
      "h1": "About",
      "lead": "Short lead."
    },
    "sections": [
      {
        "h2": "Section title",
        "body": "Section body."
      }
    ],
    "faq": [],
    "sources": [],
    "warnings": []
  }
}
```

CMX сможет конвертировать этот формат в свои JSON-страницы.

## 10. Главный принцип интеграции

MedGen должен возвращать не "готовую страницу сайта", а структурированный контент для конкретного route и content_type.

CMX Admin сам:

- знает, куда записать JSON;
- знает, какие модули отрисовать;
- знает, как построить sitemap;
- знает, как собрать JSON-LD;
- знает, как задеплоить статический сайт.

MedGen должен стабильно отдавать контентные поля, связи и SEO-данные в JSON.
