From d27e6ee43dea4cd7595a04812a3b886f6eb9cf5c Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Sun, 28 Jun 2026 12:05:49 +0300 Subject: [PATCH] Add SEO mode project workflow --- .gitignore | 36 + seo_mode/seo_mode/.editorconfig | 8 + seo_mode/seo_mode/.env.example | 27 + seo_mode/seo_mode/.gitignore | 29 + seo_mode/seo_mode/README.md | 58 + .../seo_mode/SEO-farm/CHECK_OVERSEO_SPEC.md | 636 ++ seo_mode/seo_mode/SEO-farm/DESIGN_SYSTEM.md | 36 + .../SEO-farm/IMPLEMENTATION_GUARDRAILS.md | 459 ++ seo_mode/seo_mode/SEO-farm/README.md | 44 + .../SEO-farm/SEO_FARM_ARCHITECTURE.md | 833 ++ seo_mode/seo_mode/SEO-farm/SEO_FARM_BRIEF.md | 1021 +++ seo_mode/seo_mode/SEO-farm/TASK_MANAGER.md | 1050 +++ seo_mode/seo_mode/SEO-farm/UI_UX_SPEC.md | 1014 +++ seo_mode/seo_mode/SEO-farm/USER_FLOW.md | 642 ++ seo_mode/seo_mode/SEO-farm/start.txt | 0 seo_mode/seo_mode/app/index.html | 12 + seo_mode/seo_mode/app/package.json | 25 + seo_mode/seo_mode/app/src/App.tsx | 4881 ++++++++++++ .../seo_mode/app/src/ProjectScopeFlow.tsx | 1355 ++++ seo_mode/seo_mode/app/src/api.ts | 1017 +++ seo_mode/seo_mode/app/src/main.tsx | 9 + seo_mode/seo_mode/app/src/styles.css | 6952 +++++++++++++++++ seo_mode/seo_mode/app/src/vite-env.d.ts | 1 + seo_mode/seo_mode/app/tsconfig.json | 9 + seo_mode/seo_mode/app/vite.config.ts | 10 + seo_mode/seo_mode/infra/README.md | 15 + seo_mode/seo_mode/infra/docker-compose.yml | 39 + seo_mode/seo_mode/package-lock.json | 4382 +++++++++++ seo_mode/seo_mode/package.json | 21 + .../server/migrations/001_initial_schema.sql | 245 + .../002_add_browser_folder_source_type.sql | 1 + .../migrations/003_unique_project_name_ci.sql | 1 + .../migrations/004_add_page_selection.sql | 2 + .../005_wordstat_provider_evidence.sql | 36 + .../006_external_service_settings.sql | 9 + seo_mode/seo_mode/server/package.json | 30 + .../server/src/analysis/semanticAnalysis.ts | 3237 ++++++++ seo_mode/seo_mode/server/src/config/env.ts | 73 + seo_mode/seo_mode/server/src/db/client.ts | 15 + seo_mode/seo_mode/server/src/http/server.ts | 53 + seo_mode/seo_mode/server/src/index.ts | 8 + .../server/src/market/marketEnrichment.ts | 372 + .../server/src/market/wordstatProvider.ts | 370 + .../server/src/market/wordstatRepository.ts | 693 ++ .../seo_mode/server/src/preview/routes.ts | 859 ++ .../server/src/preview/snapshotCache.ts | 189 + .../server/src/projects/localFolder.ts | 43 + .../server/src/projects/projectRepository.ts | 712 ++ .../seo_mode/server/src/projects/routes.ts | 599 ++ .../server/src/scans/projectScanner.ts | 1917 +++++ .../seo_mode/server/src/scripts/migrate.ts | 63 + .../src/settings/externalServiceSettings.ts | 764 ++ .../seo_mode/server/src/settings/routes.ts | 63 + .../server/src/storage/S3StorageProvider.ts | 171 + .../server/src/storage/StorageProvider.ts | 27 + seo_mode/seo_mode/server/src/storage/index.ts | 3 + .../server/src/workspace/pageWorkspace.ts | 823 ++ .../server/src/workspace/previewTargets.ts | 162 + seo_mode/seo_mode/server/tsconfig.json | 12 + seo_mode/seo_mode/tsconfig.base.json | 13 + 60 files changed, 36186 insertions(+) create mode 100644 .gitignore create mode 100644 seo_mode/seo_mode/.editorconfig create mode 100644 seo_mode/seo_mode/.env.example create mode 100644 seo_mode/seo_mode/.gitignore create mode 100644 seo_mode/seo_mode/README.md create mode 100644 seo_mode/seo_mode/SEO-farm/CHECK_OVERSEO_SPEC.md create mode 100644 seo_mode/seo_mode/SEO-farm/DESIGN_SYSTEM.md create mode 100644 seo_mode/seo_mode/SEO-farm/IMPLEMENTATION_GUARDRAILS.md create mode 100644 seo_mode/seo_mode/SEO-farm/README.md create mode 100644 seo_mode/seo_mode/SEO-farm/SEO_FARM_ARCHITECTURE.md create mode 100644 seo_mode/seo_mode/SEO-farm/SEO_FARM_BRIEF.md create mode 100644 seo_mode/seo_mode/SEO-farm/TASK_MANAGER.md create mode 100644 seo_mode/seo_mode/SEO-farm/UI_UX_SPEC.md create mode 100644 seo_mode/seo_mode/SEO-farm/USER_FLOW.md create mode 100644 seo_mode/seo_mode/SEO-farm/start.txt create mode 100644 seo_mode/seo_mode/app/index.html create mode 100644 seo_mode/seo_mode/app/package.json create mode 100644 seo_mode/seo_mode/app/src/App.tsx create mode 100644 seo_mode/seo_mode/app/src/ProjectScopeFlow.tsx create mode 100644 seo_mode/seo_mode/app/src/api.ts create mode 100644 seo_mode/seo_mode/app/src/main.tsx create mode 100644 seo_mode/seo_mode/app/src/styles.css create mode 100644 seo_mode/seo_mode/app/src/vite-env.d.ts create mode 100644 seo_mode/seo_mode/app/tsconfig.json create mode 100644 seo_mode/seo_mode/app/vite.config.ts create mode 100644 seo_mode/seo_mode/infra/README.md create mode 100644 seo_mode/seo_mode/infra/docker-compose.yml create mode 100644 seo_mode/seo_mode/package-lock.json create mode 100644 seo_mode/seo_mode/package.json create mode 100644 seo_mode/seo_mode/server/migrations/001_initial_schema.sql create mode 100644 seo_mode/seo_mode/server/migrations/002_add_browser_folder_source_type.sql create mode 100644 seo_mode/seo_mode/server/migrations/003_unique_project_name_ci.sql create mode 100644 seo_mode/seo_mode/server/migrations/004_add_page_selection.sql create mode 100644 seo_mode/seo_mode/server/migrations/005_wordstat_provider_evidence.sql create mode 100644 seo_mode/seo_mode/server/migrations/006_external_service_settings.sql create mode 100644 seo_mode/seo_mode/server/package.json create mode 100644 seo_mode/seo_mode/server/src/analysis/semanticAnalysis.ts create mode 100644 seo_mode/seo_mode/server/src/config/env.ts create mode 100644 seo_mode/seo_mode/server/src/db/client.ts create mode 100644 seo_mode/seo_mode/server/src/http/server.ts create mode 100644 seo_mode/seo_mode/server/src/index.ts create mode 100644 seo_mode/seo_mode/server/src/market/marketEnrichment.ts create mode 100644 seo_mode/seo_mode/server/src/market/wordstatProvider.ts create mode 100644 seo_mode/seo_mode/server/src/market/wordstatRepository.ts create mode 100644 seo_mode/seo_mode/server/src/preview/routes.ts create mode 100644 seo_mode/seo_mode/server/src/preview/snapshotCache.ts create mode 100644 seo_mode/seo_mode/server/src/projects/localFolder.ts create mode 100644 seo_mode/seo_mode/server/src/projects/projectRepository.ts create mode 100644 seo_mode/seo_mode/server/src/projects/routes.ts create mode 100644 seo_mode/seo_mode/server/src/scans/projectScanner.ts create mode 100644 seo_mode/seo_mode/server/src/scripts/migrate.ts create mode 100644 seo_mode/seo_mode/server/src/settings/externalServiceSettings.ts create mode 100644 seo_mode/seo_mode/server/src/settings/routes.ts create mode 100644 seo_mode/seo_mode/server/src/storage/S3StorageProvider.ts create mode 100644 seo_mode/seo_mode/server/src/storage/StorageProvider.ts create mode 100644 seo_mode/seo_mode/server/src/storage/index.ts create mode 100644 seo_mode/seo_mode/server/src/workspace/pageWorkspace.ts create mode 100644 seo_mode/seo_mode/server/src/workspace/previewTargets.ts create mode 100644 seo_mode/seo_mode/server/tsconfig.json create mode 100644 seo_mode/seo_mode/tsconfig.base.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d59ebc3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Dependencies +node_modules/ + +# Builds +dist/ +build/ +.vite/ + +# Environment and secrets +.env +.env.* +!.env.example + +# Local runtime data +data/ +tmp/ +temp/ +logs/ +*.log + +# Local infrastructure volumes +.postgres/ +.minio/ + +# Unpacked archive references kept local; source archives stay tracked. +/SEO-farm/ +/seo_mode_test_site/ + +# Nested VCS metadata from unpacked archives +.git/ + +# OS / editor +.DS_Store +Thumbs.db +.idea/ +.vscode/ diff --git a/seo_mode/seo_mode/.editorconfig b/seo_mode/seo_mode/.editorconfig new file mode 100644 index 0000000..a4b824b --- /dev/null +++ b/seo_mode/seo_mode/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/seo_mode/seo_mode/.env.example b/seo_mode/seo_mode/.env.example new file mode 100644 index 0000000..4a9a418 --- /dev/null +++ b/seo_mode/seo_mode/.env.example @@ -0,0 +1,27 @@ +SERVER_PORT=4100 +DATABASE_URL=postgres://seo_farm:seo_farm@localhost:5432/seo_farm + +S3_ENDPOINT=http://localhost:9000 +S3_REGION=us-east-1 +S3_ACCESS_KEY_ID=seo_farm +S3_SECRET_ACCESS_KEY=seo_farm_secret +S3_BUCKET=seo-farm-artifacts +S3_FORCE_PATH_STYLE=true + +WORDSTAT_PROVIDER=disabled +# WORDSTAT_PROVIDER=mcp_kv +# WORDSTAT_MCP_ENDPOINT=http://localhost:4120/wordstat/collect +# WORDSTAT_PROVIDER=yandex_api +# WORDSTAT_API_BASE_URL=https://searchapi.api.cloud.yandex.net/v2/wordstat +# WORDSTAT_API_TOKEN=change-me +# WORDSTAT_AUTH_TYPE=api_key +# WORDSTAT_FOLDER_ID=b1g... +# WORDSTAT_REGION_IDS=225 +# WORDSTAT_DEVICES=DEVICE_ALL +# WORDSTAT_NUM_PHRASES=50 + +SERP_PROVIDER=disabled +# SERP_API_BASE_URL=https://serp-provider.internal +# SERP_API_TOKEN=change-me + +VITE_API_BASE_URL=http://localhost:4100 diff --git a/seo_mode/seo_mode/.gitignore b/seo_mode/seo_mode/.gitignore new file mode 100644 index 0000000..990ec93 --- /dev/null +++ b/seo_mode/seo_mode/.gitignore @@ -0,0 +1,29 @@ +# Dependencies +node_modules/ + +# Builds +dist/ +build/ +.vite/ + +# Environment and secrets +.env +.env.* +!.env.example + +# Local runtime data +data/ +tmp/ +temp/ +logs/ +*.log + +# Local infrastructure volumes +.postgres/ +.minio/ + +# OS / editor +.DS_Store +Thumbs.db +.idea/ +.vscode/ diff --git a/seo_mode/seo_mode/README.md b/seo_mode/seo_mode/README.md new file mode 100644 index 0000000..0547066 --- /dev/null +++ b/seo_mode/seo_mode/README.md @@ -0,0 +1,58 @@ +# seo_mode Workspace + +Рабочая папка для разработки seo_mode. + +Архитектурная документация лежит в `SEO-farm/`. + +## Текущий статус + +Код приложения уже инициализирован. + +Готов текущий MVP-срез: + +- React/Vite UI и Node.js backend. +- Postgres + MinIO через `infra/docker-compose.yml`. +- Миграции базовой проектной модели. +- Создание, переименование, копирование и удаление проектов. +- Импорт папки через browser folder picker / drag-and-drop в MinIO. +- Скан проекта, `scan_version`, stable `pages/media`, повторный scan. +- `project-index.json` как JSON-снимок скана в MinIO. +- Baseline audit по выбранным страницам: title, description, H1/headings, видимый текст, media/ALT/filename. +- UI выбора страниц деревом по путям, severity-фильтры, media issue list и просмотр ошибок только по выбранным страницам. +- Page Workspace MVP: preview страницы, ошибки выбранной страницы, логические секции, section editor, save/reset без изменения исходного проекта. + +Текущий этап: довести `Page Workspace / Draft Model` до кликабельного редакторского сценария и подготовить следующий шаг `Model Provider / Codex Exec`. + +## Базовые решения + +- `Postgres` — основной источник истины. +- `MinIO/S3` — хранилище raw artifacts, snapshots, reports, backups и exports. +- `browser_folder` — текущий рабочий source adapter для импорта папки в MinIO и будущей hosted-версии. +- `local_folder` — dev/local adapter для ручного абсолютного пути. +- `scan_version + reconcile` — модель повторного скана без потери утверждённых решений. +- `Apply` проходит через changeset, dry-run, backup и rollback. + +## Структура + +```text +app/ React/Vite UI +server/ Node.js backend +infra/ Postgres + MinIO local infrastructure +SEO-farm/ архитектурная документация +``` + +## Запуск + +```powershell +npm install +Copy-Item .env.example .env +docker compose -f infra/docker-compose.yml up -d +npm run db:migrate +npm run dev +``` + +Если Docker Desktop не установлен, backend можно запустить без deep health checks: + +```powershell +npm run dev:server +``` diff --git a/seo_mode/seo_mode/SEO-farm/CHECK_OVERSEO_SPEC.md b/seo_mode/seo_mode/SEO-farm/CHECK_OVERSEO_SPEC.md new file mode 100644 index 0000000..dd3d5b9 --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/CHECK_OVERSEO_SPEC.md @@ -0,0 +1,636 @@ +# checkOverseo Specification + +## 1. Цель + +`checkOverseo` — локальный инструмент проверки перетошноты, заспамленности, водности и ключевых повторов в SEO-правках. + +Это не платная интеграция и не внешний API. Мы используем Text.ru только как референс по смыслу показателей и устройству SEO-анализа текста. + +Главный вопрос инструмента: + +```text +Текст нормально оптимизирован или уже переблеван ключами? +``` + +## 2. Референс: что берём из Text.ru как идею + +Из Text.ru SEO-анализатора берём не API, а логику показателей: + +- количество символов; +- количество слов; +- процент водности; +- процент заспамленности; +- список ключей; +- группы ключей; +- смешанные слова из разных алфавитов; +- подсветка проблемных повторов, если получится реализовать. + +Источники для ориентира: + +- Text.ru API/check description: https://text.ru/api-check +- Text.ru SEO-анализ: https://text.ru/seo +- Text.ru FAQ SEO-анализ: https://text.ru/faq/instrukcii/seo-analiz-teksta + +Важно: Text.ru — только ориентир. Мы не подключаем их API и не платим за него. + +## 2.1. Разбор публичной модели Text.ru + +По публичному описанию Text.ru SEO-анализатор устроен как набор параллельных проверок текста: + +```text +raw text + | + +-- character/word counter + +-- keyword extractor + +-- keyword group builder + +-- water detector + +-- spam detector + +-- mixed alphabet detector + +-- highlighter / word position mapper +``` + +### 2.1.1. Базовые счётчики + +Text.ru считает: + +```text +count_chars_with_space +count_chars_without_space +count_words +``` + +Нам нужно повторить это локально на каждом scope: + +```text +page +section +title +description +heading +alt +filename +``` + +### 2.1.2. Ключи + +Text.ru описывает поиск поисковых ключей в тексте, количество вхождений и морфологические варианты. В API manual это выражено как: + +```text +list_keys: + key_title + count +``` + +Где `count` — количество вхождений ключа во всех формах. + +Наша локальная версия: + +```text +known_keys: + - берём из keywords.yml + - exact phrase + - soft_forms + +detected_keys: + - считаем частотные unigram/bigram/trigram + - отбрасываем служебный мусор правилами + - показываем как "detected", не как утверждённый SEO-ключ +``` + +Важно: мы не обязаны идеально повторять морфологию Text.ru. Для MVP достаточно: + +```text +exact phrase ++ manually/model-defined soft_forms ++ detected repeated phrases +``` + +### 2.1.3. Группы ключей + +Text.ru группирует ключи по составу слов и сортирует по числу значимых слов. В API manual это: + +```text +list_keys_group: + key_title + count + sub_keys: + key_title + count +``` + +Пример идеи: + +```text +"check text" -> group + "check" + "text" +``` + +Наша локальная версия: + +```text +keyword group: + parent phrase: + - full phrase + - single-word subkeys + - soft_forms + - repeated close phrases +``` + +Зачем это нужно: + +```text +- видеть, что текст не только повторяет один точный ключ; +- видеть, что одна группа терминов забила секцию; +- ловить ситуацию, когда разные формы одного смысла всё равно создают перетошноту. +``` + +### 2.1.4. Водность + +Text.ru определяет воду как процент стоп-слов, фразеологизмов, оборотов, соединительных слов и фраз, которые не несут смысловой нагрузки. + +Публичные пороги: + +```text +до 15% естественное содержание воды +15-30% превышенное содержание воды +от 30% высокое содержание воды +``` + +Наша локальная версия не должна быть обычным stopword-remover. Нам нужен редакторский сигнал: + +```text +water_score = + служебные слова + + слабые бизнес-фразы + + общие SEO-обороты + + абстрактные фразы без объекта + + предложения без конкретного действия/сущности +``` + +То есть мы считаем приблизительный процент, но в отчёте показываем не только число, а конкретные причины. + +### 2.1.5. Заспамленность + +Text.ru описывает заспамленность как количество поисковых ключевых слов в тексте. + +Публичные пороги: + +```text +до 30% естественное содержание ключевых слов +30-60% оптимизированный текст +от 60% сильно оптимизированный / заспамленный текст +``` + +Наша локальная версия считает это по двум слоям: + +```text +1. known-key spam: + - primary keywords + - secondary keywords + - soft_forms + +2. detected-key spam: + - частотные слова + - частотные биграммы + - частотные триграммы + - группы похожих ключей +``` + +Для нас важнее не общий процент по странице, а риск по секции: + +```text +section spam > page spam +``` + +Потому что лендинг может быть нормальным целиком, но отдельная карточка будет переблевана ключом. + +### 2.1.6. Mixed words + +Text.ru ищет слова, где смешаны символы разных алфавитов со схожим написанием. + +Наша локальная версия: + +```text +mixedWordsDetector: + - кириллица + латиница внутри одного слова + - похожие символы: а/a, о/o, е/e, р/p, с/c, х/x + - выдавать позиции и snippets +``` + +Это не SEO-ключи, но полезная техническая проверка качества текста. + +### 2.1.7. Подсветка и позиции + +В Text.ru API есть режимы, где возвращаются: + +```text +words +text_view +words_pos +``` + +Это значит, что их интерфейс может подсвечивать проблемные слова/ключи по позициям. + +Наша локальная версия должна с самого начала хранить offsets: + +```ts +type Token = { + text: string; + normalized: string; + start: number; + end: number; + sentenceIndex: number; + paragraphIndex: number; +}; +``` + +Зачем: + +```text +- подсветить ключ в UI; +- показать proximity; +- показать повтор рядом; +- показать water phrase; +- показать mixed word; +- дать Codex точный snippet для правки. +``` + +## 3. Архитектура + +```text +checkOverseo + | + +-- TextNormalizer + | +-- normalize spaces + | +-- normalize quotes/dashes where needed + | +-- lowercase for counting + | +-- keep original text for report snippets + | + +-- Tokenizer + | +-- words + | +-- sentences + | +-- bigrams + | +-- trigrams + | + +-- KeywordCounter + | +-- exact keywords + | +-- soft_forms from keywords.yml + | +-- key groups + | + +-- NauseaAnalyzer + | +-- classic nausea + | +-- academic nausea + | +-- phrase repetition + | + +-- WaterAnalyzer + | +-- local water-word dictionary + | +-- weak phrase markers + | +-- business-cliche markers + | + +-- ProximityAnalyzer + | +-- same keyword too close + | +-- repeated key in neighboring sentences + | + +-- ScopeAnalyzer + | +-- page + | +-- section + | +-- title + | +-- description + | +-- h1/h2 + | +-- alt + | +-- filename + | + +-- ReportBuilder + +-- warnings + +-- scores + +-- snippets + +-- verdict +``` + +## 4. Вход + +```ts +type CheckOverseoInput = { + text: string; + originalText?: string; + scope: "page" | "section" | "title" | "description" | "heading" | "alt" | "filename"; + sourceId: string; + sectionId?: string; + keywords: KeywordEntry[]; + pageMap: PageMap; + options?: CheckOverseoOptions; +}; +``` + +## 5. Источник правил + +### 5.1. `keywords.yml` + +```yaml +keywords: + - phrase: "операционная модель бизнеса" + type: "primary" + section: "hero" + exact_limit: 1 + max_section_count: 2 + soft_forms: + - "операционная модель" + - "модель бизнеса" + status: "use" +``` + +### 5.2. `page-map.yml` + +```yaml +page: + primary_intent: "главный смысл страницы" + forbidden_intents: [] + +sections: + hero: + meaning: "смысл секции" + primary_keywords: [] + secondary_keywords: [] + max_lines_hint: 6 +``` + +### 5.3. Local dictionaries + +```text +data/rules/ + water-words-ru.yml + weak-business-phrases.yml + negative-keyword-intents.yml + safe-technical-terms.yml +``` + +Словари нужны не для автоматического переписывания, а для предупреждений. + +## 6. Проверки + +### 6.1. Counts + +```text +- chars_with_space +- chars_without_space +- words_count +- sentences_count +- average_sentence_length +``` + +### 6.2. Keyword counts + +```text +- exact keyword count +- soft_forms count +- primary keyword count +- secondary keyword count +- key group count +- keyword density by page +- keyword density by section +``` + +### 6.3. Classic nausea + +Классическая тошнота считается как корень из максимальной частоты самого повторяемого слова или ключевой фразы. + +```text +classic_nausea = sqrt(max_term_frequency) +``` + +Используется как локальный индикатор частого повторения. + +### 6.4. Academic nausea + +Академическая тошнота считается как доля самого частого слова/термина в общем количестве слов. + +```text +academic_nausea_percent = max_term_frequency / words_count * 100 +``` + +Также считаем отдельно: + +```text +keyword_academic_nausea_percent +``` + +Чтобы видеть не просто частое служебное слово, а именно перебор нужного нам ключа. + +### 6.5. Phrase repetition + +```text +- repeated exact phrase +- repeated bigram +- repeated trigram +- same sentence starts +- repeated sentence skeleton +``` + +### 6.6. Proximity + +```text +- один и тот же ключ повторяется в соседних предложениях; +- один и тот же ключ повторяется в соседних абзацах; +- primary keyword стоит слишком близко к прошлому вхождению; +- alt повторяет heading без причины; +- filename повторяет alt и ключ без смысла. +``` + +### 6.7. Water score + +Локальная водность — не попытка идеально повторить Text.ru. Это наш сигнал: + +```text +water_score = water_words_count / words_count * 100 +``` + +Плюс отдельные предупреждения: + +```text +- слабые бизнес-фразы; +- общие SEO-фразы; +- много абстрактных существительных; +- длинные предложения без конкретного объекта; +- фразы, которые не добавляют смысла. +``` + +### 6.8. Scope rules + +Разные зоны проверяются по-разному: + +```text +page: + - общий риск заспамленности + - общий список ключей + +section: + - соответствие ключей секции + - локальный перебор + - конфликт с meaning секции + +title/description: + - нет ли повторения одного ключа дважды + - нет ли набора ключей вместо нормального сниппета + +heading: + - нет ли keyword stuffing + - заголовок соответствует секции + +alt: + - описывает изображение + - ключ встроен естественно + - нет списка ключей + +filename: + - имя файла осмысленное + - нет набора ключей через дефисы + - имя файла не конфликтует с содержанием изображения +``` + +## 7. Пороговые значения MVP + +Пороги должны быть настраиваемыми, потому что B2B/технические тексты неизбежно повторяют термины. + +```yaml +thresholds: + keyword_density: + section_warning: 3 + section_problem: 5 + exact_keyword: + default_limit: 2 + classic_nausea: + warning: 4 + problem: 7 + academic_nausea_percent: + warning: 7 + problem: 10 + proximity: + min_sentences_between_same_keyword: 2 + water_percent: + warning: 20 + problem: 30 +``` + +Пороги не должны автоматически запрещать текст. Они создают предупреждения. + +## 8. Report + +```ts +type OverSeoReport = { + scope: "page" | "section" | "title" | "description" | "heading" | "alt" | "filename"; + sourceId: string; + sectionId?: string; + + counts: { + charsWithSpace: number; + charsWithoutSpace: number; + words: number; + sentences: number; + }; + + scores: { + waterPercent?: number; + classicNausea?: number; + academicNauseaPercent?: number; + maxKeywordDensityPercent?: number; + }; + + keys: Array<{ + phrase: string; + count: number; + densityPercent: number; + type?: "primary" | "secondary" | "soft_form" | "detected"; + sectionAllowed?: boolean; + }>; + + keyGroups: Array<{ + phrase: string; + count: number; + subKeys: Array<{ + phrase: string; + count: number; + }>; + }>; + + warnings: Array<{ + severity: "info" | "warning" | "critical"; + code: string; + message: string; + phrase?: string; + count?: number; + limit?: number; + snippet?: string; + }>; + + verdict: { + status: "ok" | "review" | "problem"; + summary: string; + }; +}; +``` + +## 9. UI + +UI должен показывать: + +```text +Summary: + - status + - words count + - water score + - classic nausea + - academic nausea + - max keyword density + +Keywords: + - phrase + - count + - density + - allowed section + - warnings + +Warnings: + - severity + - reason + - snippet + - suggested action + +Scopes: + - page + - sections + - title/description + - headings + - alt + - filename +``` + +## 10. Codex role + +Codex не считает метрики вместо инструмента. + +Codex используется после отчёта: + +```text +1. Объяснить предупреждения человеческим языком. +2. Предложить варианты исправления. +3. Сохранить смысл и тон. +4. Не увеличивать текст без необходимости. +5. Не вставлять ключи, если отчёт показывает перебор. +``` + +## 11. Главное ограничение + +`checkOverseo` не должен становиться тупой машиной запретов. + +Он показывает риски: + +```text +перебор +слишком близко +слишком часто +слишком водно +слишком похоже на набор ключей +``` + +Финальное решение принимает пользователь. diff --git a/seo_mode/seo_mode/SEO-farm/DESIGN_SYSTEM.md b/seo_mode/seo_mode/SEO-farm/DESIGN_SYSTEM.md new file mode 100644 index 0000000..5b91369 --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/DESIGN_SYSTEM.md @@ -0,0 +1,36 @@ +# seo_mode design system notes + +Короткая памятка, чтобы интерфейс не расползался при быстрых итерациях. + +## Визуальный тон + +- База: светлая Apple-like система, много воздуха, мягкие панели, скругления и спокойный серый фон. +- Главный акцент: тёмный градиент `#1f1f21 -> #3a332e`, как у активного этапа и основных submit/action-кнопок. +- Вторичный акцент: оранжевый `--accent: #f27a1a`, только для выбора папки, drag-and-drop и редких импортных действий. +- Избегаем случайной зелени/голубого/фиолета, если это не специально введённый статус. + +## Кнопки + +- Primary actions: `Создать проект`, `Анализировать`, будущие основные шаги этапов. Используют тёмный градиент активного этапа. +- Import action: `Выбрать папку`. Остаётся оранжевой, потому что это отдельное действие загрузки/импорта. +- Icon actions: копировать, удалить, настройки. Круглые `42x42`, нейтральная светлая поверхность, тонкая граница, мягкая тень. +- Danger icon: нейтральная круглая поверхность в покое, красный значок; красная заливка только на hover. + +## Типографика + +- Заголовки секций: плотные, тёмные, без лишних декоративных цветов. +- Helper copy под инпутами: `13px`, `font-weight: 400`, приглушённый `--muted`, line-height около `1.38`. +- Placeholder: всегда normal/400, приглушённый, без жирности. +- Иконки рядом с заголовками секций выравниваем по первой строке заголовка, а не по центру всего блока с описанием. +- Не смешивать в одной карточке слишком много жирных уровней: жирный только у заголовка и главного действия. + +## Карточки и сетки + +- Основная ширина страницы: не заужать без причины, держать рабочую ширину около `min(1180px, 100%)`. +- Карточки: светлая полупрозрачная поверхность, `var(--radius-lg/xl)`, тонкая линия `var(--line)`, мягкая тень только на крупных контейнерах. +- Не вкладывать много одинаковых карточек друг в друга без визуальной причины. +- Каждый этап сверху должен быть отдельной логической страницей, а предыдущие настройки на следующих этапах показываем компактно. + +## Рабочее правило + +Перед новой UI-правкой сначала проверяем, нет ли уже подходящего класса/паттерна. Если стиль повторяется второй раз, выносим его в общий паттерн, а не лепим ещё один локальный костыль. diff --git a/seo_mode/seo_mode/SEO-farm/IMPLEMENTATION_GUARDRAILS.md b/seo_mode/seo_mode/SEO-farm/IMPLEMENTATION_GUARDRAILS.md new file mode 100644 index 0000000..11de3f6 --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/IMPLEMENTATION_GUARDRAILS.md @@ -0,0 +1,459 @@ +# SEO Farm Implementation Guardrails + +## 1. Зачем этот документ + +Этот файл фиксирует порядок разработки и технические ограничения, чтобы user flow, backend pipeline и инструменты не начали спорить друг с другом. + +Главная идея: + +```text +UI показывает понятный SEO-процесс. +Backend внутри выполняет строгую техническую последовательность. +Инструменты не смешивают зоны ответственности. +Target project меняется только после ручного Apply. +``` + +## 2. User Flow vs Backend Pipeline + +Для пользователя первый смысловой шаг после создания проекта — “Проанализировать проект”. + +В UI это один сценарий: + +```text +Create Project + -> Analyze Project + -> Baseline Audit Result +``` + +Но backend не может делать audit без технической подготовки. Внутренний порядок должен быть таким: + +```text +1. validate targetProjectPath +2. scan filesystem +3. filter ignored folders/files +4. detect candidate files +5. parse HTML/MD/text/CSS references +6. build projectIndex +7. map pages +8. map sections +9. map media assets +10. create source mapping +11. run baseline audit +12. save scan + audit result +13. return UI-ready report +``` + +Для будущих источников backend должен мыслить не только `targetProjectPath`, а `project source`: + +```text +MVP: + local_folder -> targetProjectPath + +Later: + git_repo + zip_upload + site_crawl +``` + +Нельзя делать: + +```text +Baseline Audit + -> потом parse +``` + +Правильно: + +```text +Scan / Parse / Map + -> Baseline Audit +``` + +В UI слово “parse” лучше не выносить отдельным этапом. Это внутренняя операция. + +## 3. Строгий MVP Pipeline + +```text +Project Setup + input: project name, project source + output: project record + +Project Scan + input: project source + output: projectIndex + +Baseline Audit + input: projectIndex + output: audit report, page/media/source issues + +Page Workspace + input: selected page/group + output: originalText, workingText, sectionMap + +Meaning Extraction + input: originalText, sectionMap, meta/headings/media context + output: section meanings, seed queries, competing intents + +Seed Review + input: proposed seeds + output: approved seeds + +Wordstat Collection + input: approved seeds + output: raw Wordstat results, ВЧ/СЧ/НЧ groups + +Keyword Cleaning + input: raw Wordstat results + output: approved keyword decisions + +Keyword Map + input: approved keywords, section meanings, current text + output: approved keyword-to-section map + +Optimization Plan + input: keyword map, audit, current workingText, design limits + output: approved edit plan + +Rewrite Workspace + input: approved edit plan + output: edited workingText + +Media SEO + input: media map, section context, keyword map + output: approved alt/title/aria/caption/filename suggestions + +Final Validation + input: workingText, keyword map, media map, approved media changes + output: validation report + +Apply / Export + input: approved text/media changes + output: changeset, updated target project, reports/export +``` + +## 4. Tool Boundaries + +### 4.1. `checkOverseo` + +Отвечает за SEO-перебор: + +```text +- точные вхождения; +- soft forms; +- перетошнота; +- заспамленность; +- повторы рядом; +- повторяющиеся биграммы/триграммы; +- перебор ключа в title/description/h1/h2; +- keyword stuffing в alt/filename; +- конфликт ключа со смыслом секции. +``` + +Не отвечает за: + +```text +- стиль бренда; +- красивость текста; +- смысловую редактуру; +- выбор ключей из Wordstat. +``` + +### 4.2. `ru-text` + +Отвечает за редакторский фильтр после SEO-правок: + +```text +- тон; +- читаемость; +- канцелярит; +- мутные формулировки; +- редакторские и типографические проблемы. +``` + +Не отвечает за: + +```text +- сбор ключей; +- частотность; +- Wordstat; +- карту ключей; +- SEO-плотность. +``` + +### 4.3. `keywordService` + +Отвечает за чистку Wordstat-результатов: + +```text +- нормализация запросов; +- дедупликация; +- project blacklist; +- мусорные интенты; +- группировка близких запросов; +- Codex-классификация спорных запросов; +- user approval. +``` + +Это не `stopword`-инструмент и не удаление слов из текста. + +### 4.4. Wordstat MCP + +Wordstat MCP — только “рука в Wordstat”. + +Он: + +```text +- получает seed; +- возвращает запросы и частотность; +- сохраняет raw data. +``` + +Он не: + +```text +- решает, что использовать; +- пишет текст; +- строит карту ключей; +- проверяет переспам. +``` + +### 4.5. Codex Exec + +Codex через `codex exec` используется для смысловых задач: + +```text +- выделить темы; +- предложить seed queries; +- классифицировать спорные ключи; +- предложить keyword map; +- сформировать optimization plan; +- предложить варианты правки; +- предложить alt/caption/filename. +``` + +Codex не должен напрямую менять target project до `Apply`. + +## 5. Apply Safety Rules + +До ручного Apply target project считается read-only. + +Разрешённые изменения после approval: + +```text +- visible text; +- title; +- description; +- headings; +- alt/title/aria; +- captions; +- approved filenames. +``` + +Запрещено без отдельного подтверждения: + +```text +- менять layout; +- менять CSS/JS-логику; +- рефакторить код сайта; +- удалять файлы; +- менять структуру приложения SEO Farm; +- публиковать на хостинг. +``` + +Перед Apply UI обязан показать: + +```text +- affected files; +- text diff; +- media diff; +- filename rename plan; +- validation status; +- changeset summary. +``` + +Apply должен идти транзакционно: + +```text +1. build changeset +2. run dry-run +3. backup affected files to object storage +4. apply text/media/filename changes through backend +5. verify references and rename results +6. rollback if any critical step fails +``` + +## 5.1. Repeated Scan / Reconcile Rules + +Повторный scan не должен перетирать уже принятые решения. + +Правильно: + +```text +new scan + -> create scan_version + -> create page/section/media versions + -> run reconcile + -> preserve stable logical IDs + -> show review summary to user +``` + +Стабильные идентификаторы: + +```text +page_id +section_id +media_id +``` + +Текущий `DOM selector` — это версия привязки, а не identity. + +Статусы reconcile: + +```text +matched +changed +new +orphaned +conflicted +``` + +Решения пользователя должны ссылаться на logical IDs: + +```text +- keyword decisions +- drafts +- media approvals +- changesets +``` + +## 6. Storage Risks + +Нельзя хранить всё только в памяти. + +Минимально нужно: + +```text +Postgres: + - projects + - project_sources + - scan_versions + - pages / page_versions + - sections / section_versions + - media_assets / media_versions + - runs + - seeds + - wordstat_jobs / wordstat_results + - keyword_decisions + - keyword_map_items + - drafts / draft_items + - validations / validation_issues + - changesets / changeset_items + +Object Storage: + - raw Wordstat dumps + - originalText snapshots + - workingText drafts + - reports + - previews / video frames + - backups + - exports +``` + +Правило: + +```text +Postgres = source of truth +Object Storage = heavy artifacts +YAML/JSON/Markdown = export/debug only +``` + +Риск: + +```text +Если workingText не отделить от originalText, +модельная ошибка может испортить исходник без понятного отката. +``` + +MVP может хранить одну активную рабочую версию на секцию, но scan versions, snapshots и changesets должны быть полноценными уже с первого релиза. + +## 7. Development Risk Checklist + +### 7.1. Pipeline risks + +- Audit запущен до parse/map. +- UI показывает parse как отдельную пользовательскую задачу. +- Project scan требует ручного выбора файлов. +- Многостраничный сайт превращается в ручной список `index.html`. +- Повторный scan затирает уже утверждённые решения без предупреждения. +- Решения по секции привязаны только к текущему selector и теряются после перестройки DOM. + +### 7.2. Model risks + +- Codex меняет target project до Apply. +- Prompt не ограничивает зону правок. +- Model output невалидный JSON, а backend применяет его без проверки. +- Модель смешивает SEO-правки с редизайном или рефакторингом кода. + +### 7.3. Keyword risks + +- Wordstat results считаются готовой keyword map. +- Keyword Cleaning превращается в ручную таблицу без assisted classification. +- ВЧ-запросы насильно пихаются в каждую секцию. +- `article`-ключи запихиваются в главную страницу вместо будущих материалов. +- Нет user approval перед использованием ключей. + +### 7.4. Text quality risks + +- `checkOverseo` пытается оценивать тон вместо переспама. +- `ru-text` используется как SEO-решатель вместо редакторского фильтра. +- Проверка длины игнорирует дизайн-блоки. +- Правки раздувают текст и ломают визуальную секцию. + +### 7.5. Media SEO risks + +- Alt набивается ключами без связи с изображением. +- Decorative media получают SEO-alt. +- Видео обрабатывается как ``, хотя у video нет обычного alt. +- Filename меняется без обновления ссылок в HTML/CSS/srcset. +- Rename plan применяется без diff. + +### 7.6. Apply/export risks + +- Apply происходит без changeset. +- Apply происходит без dry-run и backup. +- Rename/update references падает посередине без rollback. +- Export не включает отчёты. +- После apply невозможно понять, какие SEO-решения были приняты. +- Автопубликация появляется раньше ручного контроля. + +## 8. Recommended Development Order + +Чтобы не собрать хаос, реализация должна идти так: + +```text +1. Project storage + Postgres + Object Storage +2. Project setup screen +3. project source validation +4. project scan +5. scan_versions + reconcile +6. projectIndex +7. baseline audit +8. page workspace with originalText/workingText +9. CodexExecProvider +10. meaning extraction +11. seed review +12. Wordstat MCP integration +13. keywordService +14. keyword map +15. optimization plan +16. rewrite workspace +17. media SEO +18. checkOverseo +19. ru-text +20. final validation report +21. diff + changeset +22. apply with dry-run/backup/rollback +23. export/history +``` + +Нельзя начинать с rewrite UI до появления `originalText/workingText`, иначе легко получить приложение, которое красиво пишет текст, но не умеет безопасно применять изменения. diff --git a/seo_mode/seo_mode/SEO-farm/README.md b/seo_mode/seo_mode/SEO-farm/README.md new file mode 100644 index 0000000..318e8b9 --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/README.md @@ -0,0 +1,44 @@ +# SEO Farm + +Локальный SEO-редакторский контур для работы с существующими сайтами: scan проекта, baseline audit, Wordstat, keyword map, rewrite workspace, media SEO, final validation и ручной Apply через changeset. + +## Статус + +Архитектурная документация остаётся источником направления, но код приложения уже инициализирован. + +Готов текущий MVP-срез: + +- базовый React/Vite UI; +- Node.js backend; +- Postgres как source of truth; +- MinIO/S3-compatible storage для артефактов; +- создание, переименование, копирование и удаление проектов; +- импорт папки сайта через browser folder picker / drag-and-drop; +- scan project + `project-index.json`; +- stable pages/media records и repeated scan; +- baseline audit; +- выбор страниц для дальнейшей работы деревом по путям; +- severity-фильтры и отдельный media issue list; +- отображение ошибок только по выбранным страницам; +- Page Workspace MVP: preview страницы, ошибки выбранной страницы, логические секции, section editor, save/reset без изменения исходного проекта. + +Текущий рабочий этап: довести `Page Workspace / Draft Model` до кликабельного редакторского сценария. + +## Основные документы + +- `SEO_FARM_BRIEF.md` — общее ТЗ, цели продукта и MVP scope. +- `SEO_FARM_ARCHITECTURE.md` — архитектура, storage, backend/frontend слои. +- `USER_FLOW.md` — пользовательский сценарий. +- `IMPLEMENTATION_GUARDRAILS.md` — pipeline, границы инструментов и риски. +- `UI_UX_SPEC.md` — UI/UX экраны, состояния и safety-паттерны. +- `TASK_MANAGER.md` — поэтапный план реализации. +- `CHECK_OVERSEO_SPEC.md` — спецификация локальной проверки переспама. + +## Зафиксированные архитектурные решения + +- `Postgres` — основной источник истины. +- `MinIO/S3` — хранилище raw artifacts, snapshots, reports, backups и exports. +- `browser_folder` — текущий рабочий adapter для импорта папки в MinIO и будущего hosted-сценария. +- `local_folder` — dev/local adapter для ручного абсолютного пути. +- `scan_version + reconcile` — модель повторного скана без потери утверждённых решений. +- `Apply` проходит через changeset, dry-run, backup и rollback. diff --git a/seo_mode/seo_mode/SEO-farm/SEO_FARM_ARCHITECTURE.md b/seo_mode/seo_mode/SEO-farm/SEO_FARM_ARCHITECTURE.md new file mode 100644 index 0000000..715a575 --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/SEO_FARM_ARCHITECTURE.md @@ -0,0 +1,833 @@ +# SEO Farm Architecture + +## 1. Общая схема + +```text +React/Vite UI + | + v +Local Backend + | + +-- Project Storage + | | + | +-- Postgres DB (source of truth) + | +-- Object Storage + | | +-- MinIO in local/dev + | | +-- S3 in hosted mode later + | +-- Project Source Adapters + | | +-- local_folder (MVP) + | | +-- later: git_repo + | | +-- later: zip_upload + | | +-- later: site_crawl + | +-- project_sources + | +-- scan_versions + | +-- page/section/media logical records + | +-- page_versions / section_versions / media_versions + | +-- originalText snapshots + | +-- workingText drafts + | +-- run history + | +-- changesets + | +-- backups + | +-- exports + | +-- reports/raw dumps/previews/frames + | + +-- Task Runner + | + +-- Model Provider + | | + | +-- MVP: Codex Exec Provider + | | | + | | +-- codex exec + | | + | +-- Later: OpenAI API Provider + | +-- Later: Other API Provider + | +-- Later: Local LLM Provider + | + +-- SEO Tools + | | + | +-- HTML/Text Extractor + | +-- Structure Checker + | +-- Keyword Checker + | +-- Over-SEO Checker + | +-- Page Map Checker + | + +-- Wordstat Layer + | | + | +-- MCP-KV Wordstat + | + +-- Text Quality Layer + | | + | +-- ru-text + | + +-- Media SEO Layer + | + +-- HTML media parser + +-- optional: image-size + +-- optional: Sharp + +-- optional: FFmpeg + +-- Model Provider for image/video description +``` + +## 1.1. Статус инструментов + +```text +MVP, точно используем: + - React + - Vite + - Node.js backend + - codex exec + - ModelProvider abstraction + - MCP-KV Wordstat + - ru-text + - Cheerio + - local SEO checks + - Postgres + - MinIO or other S3-compatible object storage + - structured JSON model outputs + - YAML/JSON/Markdown exports for debug/import-export only + +Опционально для Media SEO, подключать когда дойдём до медиа: + - image-size + - Sharp + - FFmpeg + +Не используем в MVP: + - автопостинг + - Яндекс Метрика + - robots/sitemap editor + - hosted/cloud mode + - Codex skills as dependency +``` + +Future enhancement: + +```text +Codex skills can be added later to improve repeatable model workflows: + - seo-seed-extractor + - seo-keyword-classifier + - seo-copy-editor-ru + - media-seo-alt-writer + +Skills are not required for MVP. First stabilize tools and reports. +``` + +## 1.2. Project Source Adapters + +```text +SourceAdapter + | + +-- local_folder + | +-- MVP source type + | +-- uses targetProjectPath + | + +-- git_repo + | +-- future hosted/local source + | + +-- zip_upload + | +-- future hosted/local source + | + +-- site_crawl + +-- future audit-only source +``` + +For MVP we start with `local_folder`, but the application should keep the source type in the database from day one so local and hosted modes use the same upper pipeline. + +## 2. Основной поток данных + +```text +1. User creates/selects SEO Farm project + | + v +2. User sets project source for the tested site/codebase + | + +-- MVP: local_folder -> targetProjectPath + | + v +3. Backend creates scan_version, scans source, and builds projectIndex + | + v +4. Baseline Audit runs on discovered pages/assets/media + | + v +5. User selects page or page group for SEO work + | + v +6. Backend creates originalText snapshots and workingText drafts + | + v +7. Model Provider extracts meanings and seed queries + | + v +8. User reviews/edits seed queries + | + v +9. Wordstat Layer collects keyword data + | + v +10. keywordService cleans/classifies keyword results + | + v +11. User reviews keyword decisions + | + v +12. Keyword Map Builder proposes section mapping and limits + | + v +13. User approves/edits Keyword Map + | + v +14. Optimization Plan is generated and approved + | + v +15. Model Provider proposes text edits into workingText + | + v +16. Media SEO proposes alt/caption/filename edits + | + v +17. SEO Tools + ru-text validate text and media edits + | + v +18. UI shows report and diff + | + v +19. User applies changes to target project + | + v +20. User can export archive/reports +``` + +MVP works with existing code/text only: + +```text +existing HTML / existing draft / existing site + -> analyze + -> collect keywords + -> edit + -> final validate +``` + +Creating text from scratch is a future mode, not part of MVP. + +## 3. UI Modules + +```text +app/ + Projects + -> create/select local project + -> set target project path + -> scan project + + Project Dashboard + -> project status + -> discovered pages + -> baseline audit status + -> recent runs + -> working drafts + -> changesets + -> exports + + Baseline Audit + -> project/page structure + -> title/description/h1/h2 + -> discovered text blocks + -> media issues + -> technical SEO issues + + Pages / Source + -> discovered pages + -> selected page + -> extracted sections + -> extracted headings + -> original text + -> working text + + Seeds + -> seed queries from source text + -> manual seed editing + -> select seeds for Wordstat + + Wordstat + -> run MCP-KV Wordstat + -> show frequency/dynamics/regions + -> raw keyword results + -> high/mid/low groups + + Keyword Cleaning + -> normalize/deduplicate Wordstat queries + -> mark obvious trash + -> classify ambiguous queries through Codex + -> approve/edit statuses: use/support/article/risky/trash + + Keyword Map + -> suggested keyword-to-section map + -> approve/edit suggestions + -> primary/secondary keywords + -> soft forms + -> exact-match limits + + Optimization Plan + -> sections to edit + -> sections to leave unchanged + -> keywords to add/reduce + -> media tasks + -> length/tone risks + + Rewrite + -> select section + -> edit working text + -> generate variants through Model Provider + -> run SEO checks + -> run ru-text + -> show original vs working diff + -> apply only after user approval + + Media SEO + -> list images/videos/posters + -> current alt/title/aria/captions + -> preview + -> suggested alt/descriptions + -> media SEO warnings + + Final Validation + -> title/description/h1/h2 + -> competing meanings + -> keyword usage + -> over-SEO warnings + -> text length/design limits + -> ru-text status + -> media SEO status + + Apply / Export + -> affected files + -> changeset + -> manual approval + -> apply to target project + -> zip target project + -> export reports + + History / Reports + -> scans + -> audits + -> Wordstat runs + -> validation reports + -> media SEO reports + -> keyword decisions + -> rewrites + -> changesets + -> exports +``` + +## 4. Backend Modules + +```text +server/ + routes/ + projects + scan + pages + sources + seeds + wordstat + keywords + keyword-cleaning + keyword-map + optimization-plan + audit + rewrite + media + validate + apply + export + history + reports + + providers/model/ + ModelProvider.ts + CodexExecProvider.ts + OpenAiApiProvider.ts # future + CustomHttpProvider.ts # future + + providers/storage/ + StorageProvider.ts + MinioStorageProvider.ts + + services/ + db + projectSourceService + storageProvider + taskRunner + projectStorage + projectScanService + reconcileService + pageWorkspaceService + wordstatService + keywordService + keywordMapService + optimizationPlanService + seoAuditService + ruTextService + mediaAuditService + validationService + changesetService + applyService + exportService + reportService +``` + +## 5. Tool Responsibilities + +| Layer | Tool | Responsibility | +|---|---|---| +| UI | React | Interface, state, workflows | +| UI | Vite | Dev server and build | +| Backend | Node.js | Local server and task orchestration | +| Backend | Express/Fastify | HTTP API for UI | +| Storage | Postgres | Source of truth for projects, sources, versions, approvals, runs, validations, changesets | +| Storage | MinIO/S3 | Raw dumps, previews, reports, exports, backups, scan snapshots | +| Model | `codex exec` | MVP model execution | +| Model | ModelProvider | Switch between Codex/API/local models | +| Wordstat | MCP-KV Wordstat | Raw keyword data from Yandex Wordstat | +| Text parsing | Cheerio | Parse HTML and extract title, meta, headings, text blocks, media tags | +| SEO checks | Local scripts | Title, description, h1/h2, keywords, spam, length | +| Text quality | ru-text | Editorial SEO correction, tone, readability, typographic checks | +| Media parsing | Cheerio | Find img/picture/video/source/poster | +| Images | image-size, optional | Read image dimensions for media report | +| Images | Sharp, optional | Generate previews/thumbnails if browser preview is not enough | +| Video | FFmpeg, optional | Extract representative frames from videos | +| Files | YAML/JSON/Markdown | Export, debug, import/export artifacts only; not the main storage layer | + +## 6. Model Provider Abstraction + +```text +ModelProvider + | + +-- CodexExecProvider + | +-- calls: codex exec + | +-- use case: local MVP + | + +-- OpenAiApiProvider + | +-- calls: OpenAI API + | +-- use case: remote app / hosted version + | + +-- CustomHttpProvider + | +-- calls: any compatible API + | +-- use case: future integrations + | + +-- LocalLlmProvider + +-- calls: local model runtime + +-- use case: offline/private mode +``` + +## 7. Wordstat Flow + +```text +Seed queries + | + v +wordstatService + | + v +MCP-KV Wordstat + | + +-- top requests + +-- related requests + +-- dynamics + +-- regions + | + v +raw keyword dump + | + v +keywordService + | + +-- clean by local rules + +-- classify + +-- frequency type: high/mid/low + +-- status: use/support/article/risky/trash +``` + +## 7.1. Keyword Cleaning Logic + +Чистка мусора — это не stopword/удаление частых слов. Это смысловая фильтрация Wordstat-ключей на релевантность проекту. Делает её `keywordService`: локальные правила проекта плюс Codex-классификация спорных запросов. + +```text +Raw Wordstat keywords + | + v +keywordService + | + +-- normalize text + +-- remove duplicates + +-- apply negative intents + +-- apply project blacklist + +-- group close phrases + +-- mark obvious trash + +-- ask Model Provider to classify ambiguous phrases + | + v +User review +``` + +Базовые причины выкинуть запрос: + +```text +- вакансии +- обучение / курсы +- скачать +- бесплатно +- реферат / диплом +- бытовой смысл вместо B2B +- чужая отрасль +- слишком широкий запрос без связи с продуктом +- запрос конфликтует с primary_intent страницы +``` + +Результат хранится как статус: + +```text +use / support / article / risky / trash +``` + +## 8. Text SEO Flow + +```text +Source text / HTML + | + v +extractText + | + +-- sections + +-- headings + +-- visible text + | + v +Model Provider + | + +-- meanings + +-- seed queries + | + v +SEO audit + | + +-- title/description/h1/h2 + +-- competing meanings + +-- keyword usage + +-- over-SEO + +-- length/design limits + | + v +Rewrite variants + | + v +ru-text + SEO checks + | + v +User approval +``` + +## 8.1. Over-SEO Checker + +Проверка перетошноты/переблева ключами описана отдельно в `CHECK_OVERSEO_SPEC.md`. + +Text.ru используется только как референс по смыслу показателей. Их API не подключаем. + +`seo-analyzer` и похожие HTML-аудиторы не заменяют этот слой: они полезны для title/h1/alt/структуры, но не решают именно перетошноту текста. + +```text +checkOverseo + | + +-- exact keyword count + +-- soft_forms count from keywords.yml + +-- keyword density by section + +-- classic nausea: sqrt(max word/phrase frequency) + +-- academic nausea: top word/phrase share in text + +-- repeated exact phrases + +-- repeated bigrams/trigrams + +-- proximity: same keyword too close + +-- title/description/h1 overuse + +-- alt keyword stuffing + +-- section-level warnings +``` + +Источник правил: + +```text +keywords.yml + - phrase + - soft_forms + - section + - exact_limit + - max_section_count + - status + - notes + +page-map.yml + - primary_intent + - section meanings + - forbidden_intents + - max_lines_hint +``` + +В MVP не нужен сложный морфологический движок. Для русского текста сначала используем: + +```text +- точные ключи; +- вручную/моделью заданные soft_forms; +- нормализацию регистра и пробелов; +- подсчёт повторов по секциям. +``` + +Если этого станет мало, позже можно добавить отдельный морфологический модуль, но он не входит в MVP. + +## 9. Media SEO Flow + +```text +Source HTML/CSS + | + v +extractMedia + | + +-- img + +-- picture/source/srcset + +-- video/source/poster + +-- CSS backgrounds + | + v +mediaAuditService + | + +-- current alt/title/aria + +-- filename + +-- captions + +-- section context + +-- dimensions + +-- file size + | + +-- optional image-size + +-- optional Sharp previews + +-- optional FFmpeg video frames + | + v +Model Provider + | + +-- describe image/video frame + +-- suggest alt/caption/description + | + v +SEO checks + | + +-- missing alt + +-- weak alt + +-- duplicate alt + +-- decorative media + +-- weak/non-descriptive filename + +-- keyword stuffing in alt + +-- missing video context + | + v +User approval +``` + +## 10. Storage Layout + +```text +Postgres + - projects + - project_sources + - scan_versions + - pages + - page_versions + - sections + - section_versions + - media_assets + - media_versions + - runs + - seeds + - wordstat_jobs + - wordstat_results + - keyword_decisions + - keyword_map_items + - optimization_plans + - drafts + - draft_items + - validations + - validation_issues + - changesets + - changeset_items + - exports + +Object Storage + - projects/project-id/scans/scan-version-id/project-index.json + - projects/project-id/raw/wordstat/*.json + - projects/project-id/snapshots/original/*.json + - projects/project-id/snapshots/working/*.json + - projects/project-id/reports/*.md + - projects/project-id/previews/* + - projects/project-id/video-frames/* + - projects/project-id/backups/changeset-id/* + - projects/project-id/exports/* +``` + +`project.json` can exist as export/debug metadata, but the source of truth lives in Postgres: + +```json +{ + "id": "nodedc", + "name": "Node.DC", + "source": { + "type": "local_folder", + "targetProjectPath": "C:/Users/const/Desktop/landing-correction" + }, + "scan": { + "include": ["**/*.html", "**/*.md", "css/**/*.css", "images/**/*", "video/**/*"], + "exclude": ["node_modules/**", "dist/**", ".git/**"] + } +} +``` + +Postgres stores project state and history: + +```text +projects +project_sources +scan_versions +pages +page_versions +sections +section_versions +media_assets +media_versions +runs +seeds +wordstat_jobs +wordstat_results +keyword_decisions +keyword_map_items +optimization_plans +drafts +draft_items +validations +validation_issues +changesets +changeset_items +exports +``` + +Rules: + +```text +Postgres = source of truth +Object Storage = heavy/snapshot/report artifacts +YAML/JSON/Markdown = export/debug/import-export only +``` + +## 10.1. Repeated Scan / Reconcile Model + +Every scan creates a new `scan_version`. + +Important rule: + +```text +DOM selector != entity identity +``` + +Stable identities: + +```text +page_id +section_id +media_id +``` + +Versioned snapshots: + +```text +page_version +section_version +media_version +``` + +When a new scan is created, backend runs reconcile: + +```text +matched +changed +new +orphaned +conflicted +``` + +Matching should use more than one signal: + +```text +- source path/url +- heading/context +- normalized text hash +- selector fingerprint +- neighboring structure +``` + +Approvals, keyword decisions, drafts, and media decisions must link to stable logical IDs, not only to the current selector. + +Text editing model: + +```text +target project file + | + v +extract text + | + +-- originalText snapshot + | + +-- workingText draft + | + +-- user edits + +-- Codex edits + +-- SEO checks + +-- ru-text checks + | + v + diff + | + v + user approval + | + v + changeset + | + +-- dry-run + +-- backup affected files to object storage + +-- apply through backend + +-- verify references/renames + +-- rollback on failure + | + v + apply to target project +``` + +MVP stores one `workingText` draft per source/section. Full draft versioning and rollback history are future enhancements. + +## 11. External Links + +Related local docs: + +- `SEO_FARM_BRIEF.md` +- `USER_FLOW.md` +- `CHECK_OVERSEO_SPEC.md` +- `IMPLEMENTATION_GUARDRAILS.md` +- `UI_UX_SPEC.md` +- `TASK_MANAGER.md` + +- Codex exec: https://developers.openai.com/codex/noninteractive +- Codex with ChatGPT plan: https://help.openai.com/en/articles/11369540-using-codex-with-your-chatgpt-plan +- React: https://react.dev/ +- Vite: https://vite.dev/guide/ +- MCP-KV Wordstat: https://mcp-kv.ru/docs/wordstat-mcp-setup +- MCP-KV SEO tools, optional/reference: https://mcp-kv.ru/mcp-server-seo +- ru-text: https://github.com/talkstream/ru-text +- Cheerio: https://cheerio.js.org/docs/api/ +- image-size: https://github.com/image-size/image-size +- Sharp: https://www.npmjs.com/package/sharp +- FFmpeg: https://ffmpeg.org/ffmpeg-doc.html +- Text.ru SEO analysis reference: https://text.ru/seo +- Text.ru API/check description, reference for analysis model only: https://text.ru/api-check diff --git a/seo_mode/seo_mode/SEO-farm/SEO_FARM_BRIEF.md b/seo_mode/seo_mode/SEO-farm/SEO_FARM_BRIEF.md new file mode 100644 index 0000000..f1f72ab --- /dev/null +++ b/seo_mode/seo_mode/SEO-farm/SEO_FARM_BRIEF.md @@ -0,0 +1,1021 @@ +# SEO Farm: локальный SEO-редакторский контур + +## 1. Вводная + +SEO Farm — локальное приложение для автоматизации ручной SEO-работы с текстами сайта: + +- анализ существующей страницы или чернового текста; +- извлечение смысловых тем и seed-запросов из уже сформированного текста; +- сбор реальных ключевых запросов через Яндекс Wordstat; +- чистка, группировка и привязка ключей к секциям страницы; +- проверка SEO-структуры, переспама, конкурирующих смыслов и длины текста под дизайн; +- редактор SEO-правок и фильтр качества текста через `ru-text`; +- аудит изображений, видео, alt-текстов, постеров, подписей и медиа-контекста; +- генерация аккуратных вариантов правок через Codex; +- ручное утверждение перед внесением изменений. + +Ключевая идея: не заставлять модель "напихать ключи", а построить управляемый процесс: + +```text +черновик / готовая страница + -> смыслы и секции + -> seed-запросы + -> Wordstat + -> ключи и частотность + -> карта ключей по секциям + -> SEO-правки текста и медиа-описаний + -> анти-переспам + -> редакторский ru-text-фильтр + -> ручное утверждение + -> сайт +``` + +Продукт не должен быть автопостингом. Это рабочий инструмент для редактора/дизайнера/SEO-специалиста, который снижает ручную рутину, но не убирает человеческое утверждение смысла и тона. + +## 2. Почему это нужно + +Текущая боль: + +- ключевые слова приходится искать руками; +- Wordstat требует ручного копирования, фильтрации и группировки; +- нейросети часто вставляют ключи формально, портят смысл и делают текст похожим на SEO-портянку; +- платные сервисы вроде Rush Analytics, Text.ru, Тургенева и NeuronWriter частично закрывают задачу, но не дают гибкого локального процесса под конкретный сайт и дизайн; +- сайт может иметь жёсткие визуальные ограничения: текст нельзя просто раздувать ради SEO; +- нужен контроль не только по ключам, но и по тону, структуре, конкурентным смыслам и длине блоков. + +SEO Farm должна стать локальной "панелью управления" для этого процесса. + +Важно: инструмент работает не только с видимым текстом страницы. Он должен проверять медиа-слой сайта: изображения, видео, постеры, подписи, alt-тексты, aria-label/title и контекст вокруг медиа. Для SEO и доступности это отдельная зона работы, а не побочный пункт. + +## 3. Основной пользовательский сценарий + +### 3.1. Project Setup + +MVP работает с уже существующим кодом, страницей или черновым текстом. Создание текста с нуля не входит в MVP. + +Пользователь создаёт проект в SEO Farm и указывает `targetProjectPath` — папку подопытного сайта. Пользователь не выбирает вручную `index.html`, `css`, `images` и другие файлы. Приложение само сканирует проект. + +```text +Project Setup + -> create project + -> choose project source + -> MVP source: local_folder -> targetProjectPath + -> save project + source config to Postgres + -> run project scan +``` + +Codex через `codex exec` должен запускаться с явным контекстом target project: + +```text +- может читать source через local_folder adapter +- или prompt получает абсолютные пути к extracted snapshot/projectIndex файлам +- результат возвращается как structured JSON +- target project не меняется напрямую моделью +``` + +### 3.2. Project Scan + +Приложение сканирует папку проекта и строит `projectIndex`: + +- HTML/Markdown/текстовые страницы; +- CSS; +- изображения; +- видео; +- возможные entry points; +- игнорируемые технические папки: `.git`, `node_modules`, `dist`, build-артефакты. + +Пользователь видит найденные страницы и может исключить лишнее, но не обязан вручную собирать список файлов. + +### 3.3. Baseline Audit + +Baseline audit — первый смысловой шаг пользователя после scan. Парсинг и извлечение текста происходят внутри аудита технически, но в UI пользователь видит именно аудит проекта/страницы. + +Проверки: + +- структура страниц; +- `title`; +- `description`; +- `h1/h2`; +- видимые тексты; +- media-объекты; +- alt/title/aria; +- filename; +- desktop/adaptive дубли; +- пустые/слабые SEO-зоны; +- первичные проблемы, которые есть до работы с Wordstat. + +### 3.4. Page Workspace + +Пользователь выбирает страницу или группу страниц для SEO-цикла. + +Для выбранной страницы создаются: + +```text +originalText + - неизменённый снимок текста из target project + +workingText + - рабочая копия для SEO-правок + +sectionMap + - sectionId + - DOM selector + - source file + - context +``` + +Codex и пользователь работают только с `workingText`. Target project не меняется до ручного `Apply`. + +### 3.5. Meaning Extraction + +Codex через `codex exec` анализирует выбранную страницу и извлекает: + +- главный смысл страницы; +- смыслы секций; +- продуктовые сущности; +- потенциальные seed-запросы; +- возможные конкурирующие интенты; +- зоны с риском SEO-размытия; +- зоны с ограничением по длине. + +Важно: seed-запросы рождаются из уже существующего смысла текста, а не из головы. + +### 3.6. Seed Review + +UI показывает seed-запросы. Пользователь: + +- включает/выключает seeds; +- добавляет свои; +- объединяет похожие; +- помечает приоритет. + +После утверждения seeds идут в Wordstat. + +### 3.7. Wordstat Collection + +Wordstat MCP в этой архитектуре — просто "рука в Wordstat": + +- получает похожие запросы; +- получает частотность; +- получает динамику; +- получает региональные данные, если нужно. + +Результаты сохраняются в истории проекта. Запросы группируются по частотности: + +- ВЧ — высокочастотные, широкие, использовать осторожно; +- СЧ — среднечастотные, основные рабочие; +- НЧ — низкочастотные, точные и часто полезные для секций. + +### 3.8. Keyword Cleaning + +Keyword Cleaning — assisted workflow, не ручная таблица с нуля. + +`keywordService` предлагает классификацию: + +- `use` — использовать на странице; +- `support` — поддерживающие формулировки; +- `article` — отложить в backlog будущих материалов, не пихать в текущую страницу; +- `risky` — можно использовать только аккуратно; +- `trash` — удалить. + +Codex классифицирует спорные запросы по правилам проекта. Пользователь утверждает решения галками, фильтрами и массовыми действиями. + +### 3.9. Keyword Map + +Keyword Map не должен быть ручной дрочней. + +Система предлагает: + +- какой ключ к какой секции относится; +- роль ключа: `primary`, `secondary`, `supporting`, `do_not_use_on_page`, `article_backlog`; +- `soft_forms`; +- лимиты точного вхождения; +- предупреждения о риске переспама. + +Пользователь редактирует и утверждает предложения. + +### 3.10. Optimization Plan + +Перед переписыванием система формирует план: + +- какие секции трогать; +- какие секции не трогать; +- какие ключи добавить; +- какие ключи сократить; +- какие media SEO задачи есть; +- где есть риск по длине; +- где есть риск по тону. + +Без подтверждения пользователя план не переходит в rewrite. + +### 3.11. Rewrite Workspace + +Codex получает структурированное задание: + +```text +Секция: ... +Текущий workingText: ... +Смысл: ... +Основные ключи: ... +Поддерживающие ключи: ... +Лимит длины: не длиннее текущего / максимум N строк +Тон: строгий B2B, без рекламной воды +Запрещено: ломать смысл, раздувать текст, делать SEO-портянку +Задача: предложить 3 варианта правки +``` + +Модель предлагает варианты. Пользователь выбирает, редактирует или просит переписать. Изменения попадают только в `workingText`. + +### 3.12. Media SEO: изображения, видео и alt-тексты + +Отдельный сценарий нужен для медиа: + +1. Приложение парсит страницу и находит: + - ``; + - ``; + - `srcset`; + - `