name: metravel-seo-audit description: >- SEO-аудит существующих статей metravel.by: найти проблемы (заголовки, meta_description, тонкий текст, внутренние ссылки), приоритизировать по трафику, дополнить достоверным контентом — без замены фото. Триггеры: «проанализируй SEO статей», «вывести сайт в топ», «SEO-аудит автора».
metravel-seo-audit
Регламент SEO-аудита и дотягивания существующих путешествий до топа поисковой
выдачи (Google + Yandex). Не путать с metravel-travel-article — там создание
статей из папок с фото; здесь — улучшение УЖЕ опубликованного контента.
Жёсткие правила
- Фото не меняем. Разрешено только ДОБАВЛЯТЬ достоверную информацию в текст (история места, легенды, топонимика, факты, практика). Существующие фото и обложку не трогаем; можно лишь добавлять фото при явном запросе.
- Только достоверное. Даты, имена, цены, часы — проверяй веб-поиском. Где не уверен — формулируй как «по местным преданиям…», а не как факт. Цены/часы помечай «актуально на <год>, уточняйте».
- Текст не выхолащивай. Дополняй живой авторский текст, не переписывай его в
шаблон. Запрещённые секции-маркеры генерации: «Вступление / Что увидели /
Итог / Точки / Описание». Заголовки — осмысленные (
<h2>): названия мест или тематические («Что посмотреть», «Как добраться», «История», «Легенды и факты», «Практическая информация», «Маршрут в цифрах»).
Шаг 1 — Аудит (найти проблемы)
npm run seo:audit # автор по умолчанию user_id=1 (Julia)
node scripts/seo-audit.js --user-id 1 --json /tmp/seo-report.json
node scripts/seo-audit.js --user-id 1 --limit 50 --min-words 500
Скрипт тянет все опубликованные путешествия автора и проверяет каждое:
| Проблема | Порог | Почему важно |
|---|---|---|
title-too-long |
> 60 симв. | заголовок обрезается в выдаче |
title-too-short |
< 25 симв. | нет поискового ключа в заголовке |
weak-lead |
первые 160 симв. не содержат ключ из заголовка | сниппет выдачи берётся из НАЧАЛА тела; если он не по теме (личный крючок) — выдача слабая |
thin-content |
< 400 слов | слабая релевантность и время на странице |
no-headings |
0 × h2/h3 | нет структуры под подзапросы |
no-internal-links |
0 ссылок на /travels/ |
теряется ссылочный вес и обход |
Важно про сниппет: поле meta_description фронтендом/SSG НЕ используется —
сниппет в выдаче строится из первых ~160 символов тела описания
(generate-seo-pages.js → buildTravelSeoDescription). Поэтому «мету» чинят не
отдельным полем, а сильным фактическим лидом в начале текста (ключ + суть),
а личный рассказ автора остаётся ниже без изменений.
priority = число проблем × вес трафика (страницы с трафиком, но тонкие/без меты —
самый высокий ROI). Бери worklist из вывода или из --json.
Шаг 2 — Улучшить текст (по одной статье)
Для каждой статьи из worklist:
- Получи текущий текст:
GET https://metravel.by/api/travels/{id}/(поляname,description). Прочитай рассказ — его НЕ переписываем, только дополняем. 1a. Опирайся на точки-достопримечательностиtravelAddress[]из того же GET. Каждая точка ={address, categoryName, coord, travelImageThumbUrl}— это именно те объекты, вокруг которых построена статья (название, тип: Часовня/ Костёл/Усадьба/Озеро, координаты, фото). Используй их как карту тем: по каждой значимой точке добавляй полезную и интересную достоверную инфо о МЕСТЕ (история, легенды, топонимика, год/стиль постройки, чем известно, практика) — и ставь её ИНЛАЙН рядом с этим объектом в теле (см. п.3). СовпадениеcategoryName/названия точки с заголовком в теле = тот самый объект, к которому крепится справка. - Проверь факты веб-поиском (Википедия, гос. кадастр, офсайты): глубина/площадь озера, год постройки усадьбы, часы/цены. Неуверенное — как предание.
- Вставляй текст ПО КОНТЕКСТУ, а не валом в конец. Сначала прочитай тело и
составь карту существующих разделов/фото. Каждый новый кусок ставь туда, где он
по смыслу связан:
- lead (
--prepend-file) — 1 абзац в НАЧАЛО подweak-lead: ключ из заголовка + суть места (это и есть будущий сниппет выдачи). Естественно, не робот. - справка об объекте (история/легенды/топонимика конкретного костёла,
усадьбы, озера) — ИНЛАЙН рядом с уже существующим заголовком и фото этого
объекта, а НЕ отдельным дублирующим
<h2>в конце. Иначе текст отрывается от своих фото и плодятся повторные заголовки («…(1600 год)» вверху и «…в Жодишках» в конце об одном и том же). Если подходящего заголовка ещё нет — создай его на месте объекта в теле, а не в хвосте. - финальные блоки (
--append-file) — в КОНЕЦ только то, что по смыслу завершающее и не дублирует разделы выше: Маршрут в цифрах, Практическая информация (координаты, как добраться, билеты/часы «актуально на <год>, уточняйте»), Что рядом — 2–4 ссылки<a href="/travels/{slug}">…</a>на соседние статьи автора (slug бери изseo:audit --json).
- lead (
- Применяй БЕЗОПАСНЫМ редактором
scripts/seo-edit.js(npm run seo:edit). Он эхом сохраняет publish/moderation/галерею/точки/plus/minus, меняет только текст, делает бэкап перед записью, после записи верифицирует и при регрессии авто-откатывается.- Для контекстной вставки собери ПОЛНОЕ тело (перемести/вставь блоки в
нужные места) и пиши через
--desc-file(replace whole body). --prepend-file/--append-file— только для лида и реально финальных блоков, которые не дублируют существующие разделы.
node scripts/seo-edit.js --id <ID> --desc-file full.html --dry-run node scripts/seo-edit.js --id <ID> --desc-file full.html [--meta "…"] # лид + финальные блоки (без контекстного перемещения): node scripts/seo-edit.js --id <ID> --prepend-file lead.html --append-file blocks.html --dry-run node scripts/seo-edit.js --restore <ID> # откатить из последнего бэкапаБэкапы —
scripts/.seo-backups/(в .gitignore). Токен —~/.metravel_token, секреты не логируй. НЕ используйmetravel_publish.py/_put_with_descна живых статьях — он снимает их с публикации (publish=False) и шлёт draft-placeholder'ы.title-too-long(сменаname) меняет slug и ломает URL — НЕ трогай заголовки в этом потоке без отдельного редиректа. - Для контекстной вставки собери ПОЛНОЕ тело (перемести/вставь блоки в
нужные места) и пиши через
Чек-лист (уроки практики)
- Лид содержит тему. Первые ~160 символов должны называть объект из заголовка. Аудит сравнивает по основе слова (стем 5 симв.), так что словоформа не важна («Ошмянах» ↔ «Ошмяны» засчитываются) — но сам ключ в лиде быть обязан.
- Цель ≥ 420 слов. Порог
thin-content= 400; делай запас, иначе статья вернётся в worklist. У пограничных (300–400) добавь фактов/практики, не воды. - Повторная обработка — сперва GET, не дублируй. Если статья уже дополнялась
(вернулась из-за weak-lead/thin), прочитай текущее тело и правь точечно: не
добавляй второй раз те же
<h2>/«Что рядом». Через--desc-fileотдавай чистое тело без повторов. - Лид не задваивай. Главная причина «дублей после редактирования» —
--prepend-fileповерх статьи, где SEO-лид уже есть: на выходе ДВА вводных абзаца, оба определяющие объект (часто с конфликтующими фактами).seo-edit.jsтеперь сам ловит и ЗАМЕНЯЕТ near-dup лид (идемпотентный prepend, ≥2 общих 3-словных фразы), но это страховка, а не индульгенция: всегда сперва GET и смотри первые 2 абзаца. Если оба — определения объекта («X — это…»), оставь ОДИН (сильный фактический), перенеси уникальные факты второго внутрь и удали его через--desc-file(чистое тело). Сверять задвоение по автору массово —node scripts/seo-find-dupes.js --user-id 1(отчётscripts/.seo-dupes-report.json). - Спорные цифры автора не затирай молча. Если источник расходится с числом автора (глубина, длина, год) — оставь авторскую формулировку и добавь официальную как уточнение со ссылкой/пометкой «по данным <источник>». Исправляй только явные опечатки в фактах (имена/топонимы: «Слацьвинских» → «Слотвинских», «Рерихово» → «Репиховское») — с веб-подтверждением.
- Внутренние ссылки — только на реально существующие опубликованные статьи
автора из
seo:audit --json; выбирай тематически/географически близкие. - Опечатки правим, стиль — нет. Чини орфографию/пунктуацию/согласование, но сохраняй авторский голос, диалектизмы и личные обороты.
Шаг 3 — Опорные (pillar) статьи для топа
Чтобы вытянуть кластер в топ, добавляй хабовые статьи (1500–2500 слов) со
ссылками на 8–15 существующих материалов. Сильные кластеры автора: Беларусь
(усадьбы, озёра, экотропы, веломаршруты), Польша/Краков (окрестности, купание,
Татры/Закопане), сезонные (Energylandia/парки). Создание pillar-статьи — через
скилл metravel-travel-article.
Шаг 4 — Проверка
npm run seo:audit -- --limit <N>повторно — проблемы по обновлённым статьям должны уйти.npx jest __tests__/scripts/seo-audit.test.ts __tests__/scripts/seo-edit.test.ts— зелёные тесты аудита и редактора.- После релиза статичные страницы
dist/prod/travels/{slug}.htmlобязаны нести свой<title>,meta description,og:imageи текст в HTML (генеритnpm run seo:generate-pages); проверьnpm run test:seo:prod.
Важно про прод
Per-page SEO собирается на сборке (generate-seo-pages.js) в статические HTML.
Если прод отдаёт ботам генерик Путешествие | Metravel и og:url=.../[param] —
значит статические страницы не передеплоены или новые статьи добавлены после
последней сборки. Лечится пересборкой+деплоем (build:web:prod →
seo:generate-pages), не правкой кода рантайма.