docs: update plans, backlog

This commit is contained in:
2026-09-27 11:11:13 +05:00
parent e703451474
commit 2fc7801162
14 changed files with 463 additions and 311 deletions
+100 -64
View File
@@ -1,38 +1,41 @@
# План: SEO + GEO — индексация и конкуренция в image tools
> **Статус (2026-09-11; уточнено 2026-09-27):** план к выполнению; маршруты
> инструментов — корневые (`/tools/[id]`). **`noindex` на страницах инструментов
> не выставляется** — снимать нечего, каталог открыт для индексации; запрет
> индексации держится только на служебных путях (`robots.txt`). Задачи S1
> разбиты на domain-free (можно делать параллельно с покупкой домена) и
> domain-required (после покупки и настройки домена).
> **Статус: active.** Адреса страниц инструментов — `/tools/<id>` (`crop-png` и
> подобные), каталог — `/list-tools`; отдельного поля `slug` в реестре пока нет,
> `id` и есть адрес.
>
> **Цель:** каждая страница инструмента — индексируемый лендинг под конкретный
> интент («crop png», «make png transparent», «jpg to png»…), конкуренция с
> onlinepngtools.com за ядро запросов + попадание в ответы генеративных систем
> (ChatGPT, Perplexity, AI Overviews) — GEO.
> **`noindex, nofollow` выставлен на каждой странице инструмента**
> (`web/src/routes/tools/[id]/+page.svelte`) — осознанно, до появления
> уникального контента (S2). Пока он стоит, сайт не индексируется вообще, и
> **S1b–S1e (sitemap, `robots.txt` с `Sitemap:`, canonical, OG) не дают
> эффекта**: их имеет смысл делать вместе со снятием `noindex`, а не вместо
> него. Условие снятия и порядок — §4, S1.
>
> Задача: «для каждого инструмента — своя страница, и можно реально
> конкурировать с onlinepngtools».
> **Цель:** страница каждого инструмента — индексируемый лендинг под конкретный
> интент («crop png», «make png transparent», «jpg to png»…) плюс попадание в
> ответы генеративных систем (ChatGPT, Perplexity, AI Overviews) — GEO.
>
> **Позиционирование (уточнено 2026-09-09):** сайт — не «PNG-инструменты», а
> **image tools с PNG-ядром**: любой инструмент работает с PNG/JPG/WebP/GIF/BMP
> на входе и отдаёт результат в PNG/JPG/WebP/BMP через селектор в кнопке
> Download. Дифференциатор — прозрачность/альфа/фон и no-upload-приватность.
> Референс-конкурент по ядру — onlinepngtools.com (см. §2). Долгосрочно ядро
> переезжает на wasm и обрастает API + PWA (оффлайн/установка) —
> `docs/roadmap.md` фазы 3–10, `docs/plan-platform.md`; для SEO это аргументы
> дистрибуции (S4c) и GEO-факты, схему сайта они не меняют.
> **Позиционирование:** не «PNG-инструменты», а **image tools с PNG-ядром** —
> любой инструмент принимает PNG/JPG/WebP/GIF/BMP и отдаёт результат в
> PNG/JPG/WebP/BMP через селектор в кнопке Download. Дифференциатор —
> прозрачность/альфа/фон и no-upload-приватность. Референс-конкурент по ядру —
> onlinepngtools.com (§2). Долгосрочно ядро переезжает на wasm и обрастает API +
> PWA (`docs/plan-platform.md`); для SEO это аргументы дистрибуции и GEO-факты,
> схему сайта они не меняют.
>
> **Слаги в этом документе:** `jpg-to-png`, `crop-jpeg` и подобное — интенты и
> URL конкурента, а не id наших инструментов. Наши id — в `docs/tools-map.md`; в
> тексте ниже реальные id инструментов приводятся в бэктиках.
## 0. Решения
- **Бренд: переименовать до индексации** (новое имя и домен сознательно не
записаны в этом репозитории — см. §6 и локальный план
`docs/plan-domain.local.md`, исключён из git: выбранное имя не должно утекать
в историю коммитов до покупки домена). Легенда честная: «started as PNG tools,
now all formats» — это контент-плюс, а не баг. Названия инструментов
(`crop-png`, …) и localStorage-ключи не переименовывать (см. решение про слаги
ниже). Точка истины по бренду: константа в i18n + README; хардкод в
записаны в этом репозитории — чек-лист в локальном файле
`plan-domain.local.md`, см. §6, он вне git: выбранное имя не должно утекать в
историю коммитов до покупки домена). Легенда честная: «started as PNG tools,
now all formats» — это контент-плюс, а не баг. Адреса страниц
(`/tools/crop-png`) и localStorage-ключи не переименовывать (см. решение про
`slug` ниже). Точка истины по бренду: константа в i18n + README; хардкод в
компонентах недопустим.
- **Форматы: формат = выбор в UI, не отдельные страницы.** Download-кнопка
каждого инструмента — с селектором PNG/JPG/WebP/BMP (+quality для lossy). Райз
@@ -40,10 +43,19 @@
есть (`ToolEntry.output`), нужна как продуктовая основа «image
tools»-позиционирования. В направлении «из формата в PNG» отдельных
инструментов нет (загрузка принимает любой формат) — см. §5.
- **Слаги инструментов `-png` сохраняются.** Они держат низкоконкурентные
png-интенты; широкие интенты («crop image online») переносятся теми же
страницами контентом: H1 «Crop image», текст «works with PNG, JPG, WebP».
URL-алиасы без `-png` не создаются (канонический беспорядок).
- **Адреса страниц `-png` сохраняются, внутренние имена — без.** Инструмент
работает с любым форматом, поэтому его `id` не должен врать (`crop`, а не
`crop-png`); png-интент держит адрес страницы и имя скачиваемого файла.
Требуется поле `slug` в `ToolEntry` + переход `routes/tools/[id]` → `[slug]`.
**Сейчас не реализовано:** в реестре `id: "crop-png"`, поля `slug` нет, роут —
`tools/[id]/`; текущее состояние описано в `docs/architecture.md`, раздел 3.
**Следствие для SEO: редиректы не нужны, canonical и sitemap не меняются,
адреса остаются теми же** — поэтому это безопасная правка, которую можно
делать до индексации, а не после. Побочная выгода: широкие интенты («crop
image online») переносятся теми же страницами контентом — H1 «Crop image»,
текст «works with PNG, JPG, WebP»; URL-алиасы без `-png` по-прежнему не
создаются (канонический беспорядок). Порядок работ — `docs/backlog.md`, задача
«Слаги инструментов (`*-png`) — развести `id` и адрес страницы».
- **Индексируемая локаль — EN** (базовая; конкурент англоязычный). RU-версия —
отдельно и позже: префикс `/ru/`, prerender обеих локалей, hreflang
(сознательно отложено). Пока язык переключается на клиенте (localStorage) —
@@ -53,10 +65,11 @@
canonical и «корневость» страниц. Свой домен + корень. Текущий деплой — GitHub
Pages (`.github/workflows/deploy.yml`); перенос на свой домен выполняется
сменой origin в CI и `PUBLIC_SITE_ORIGIN`.
- **URL-схема инструментов:** короткие плоские адреса. После C17 страницы
инструментов находятся в корне на `/tools/[id]`, каталог — на `/list-tools`;
текущую схему не менять без отдельного SEO-плана: после индексации
переименование URL означает 301 и потерю позиций.
- **URL-схема инструментов:** короткие плоские адреса — `/tools/<id>` для
инструмента, `/list-tools` для каталога, где `<id>` берётся из записи реестра.
Схему не менять без отдельного SEO-плана: после индексации переименование URL
означает 301 и потерю позиций. Разделение `id`/`slug` (решение выше) адресов
не меняет.
- **Без GA и рекламных скриптов:** аналитика — self-hosted Plausible/Umami или
Cloudflare Web Analytics. «No tracking» — часть позиционирования, её нельзя
подрывать собственными скриптами.
@@ -83,6 +96,7 @@
| Пробел | Где сейчас | Этап |
| -------------------------------------------------- | ----------------------------------- | ---- |
| `noindex` на страницах инструментов | стоит (`+page.svelte`) | S1 |
| `sitemap.xml` | нет | S1 |
| `robots.txt` без `Sitemap:` | allow-all (`web/static/robots.txt`) | S1 |
| `rel=canonical` | нет | S1 |
@@ -93,6 +107,10 @@
| `llms.txt`, хабы категорий с текстом | нет | S3 |
| GSC + приватная аналитика | нет | S4 |
Строка `noindex` — первая не потому, что её сложнее всего, а потому, что она
блокирует всё остальное: пока тег стоит, остальные строки таблицы не дают
трафика. Подробности и условие снятия — §4, S1.
## 2. Конкурент (onlinepngtools.com)
Снято с живого сайта (2026-09-09):
@@ -141,6 +159,15 @@
Разбито на две группы: **domain-free** (делаем параллельно с покупкой домена) и
**domain-required** (после покупки и DNS-настройки).
- [ ] **[S1h]** Снять `noindex, nofollow` со страниц инструментов
(`web/src/routes/tools/[id]/+page.svelte`) — заменить на
`<meta name="robots" content="index, follow" />`. **Это первым
обязательным шагом S1:** пока тег стоит, остальные задачи S1 готовят
инфраструктуру, но не приводят трафик. Порядок: S1h ставится после
S1b/S1c/S1d, иначе Google проиндексирует сайт без sitemap и canonical.
Снимать `noindex` до готовности S2-контента осознанно не стоит: в индекс
попадут тонкие страницы с одним title/description.
#### S1-free: без домена
- [ ] **[S1e]** OG-картинки per-tool: генерация PNG-карточек скриптом на
@@ -150,12 +177,12 @@
OG-картинки будут абсолютными и корректными.
- [ ] **[S1f]** Download-кнопка с селектором формата PNG/JPG/WebP/BMP (+quality
для lossy) для всех инструментов — механика `ToolEntry.output` уже есть
(backlog №7, райз «выбор формата/качества»). Продуктовая основа «image
tools»-позиционирования: без неё сайт остаётся PNG-сайтом. Вести
(`docs/backlog.md`, «Идеи» №6, UX-райз «Download»). Продуктовая основа
«image tools»-позиционирования: без неё сайт остаётся PNG-сайтом. Вести
параллельно с текущими quality-задачами.
- [ ] **[S1g]** Поведение конвертеров после S1f: не предлагать в меню форматов
формат исходника (disable) — чтобы `convert-png-to-jpg` не мог сохранить в
png. Существующие страницы не трогать: `jpg-to-png`, `convert-png-to-jpg`,
png. Существующие страницы не трогать: `convert-png-to-jpg`,
`convert-png-to-webp`, `png-to-bmp` остаются самостоятельными лендингами
со своим контентом (§5).
@@ -177,9 +204,14 @@
twitter:card. Подключить в root-layout. **Требует `PUBLIC_SITE_ORIGIN`**
для абсолютных URL в canonical и OG:url.
> **Порядок S1:** S1e/S1f/S1g → покупка домена → S1a+S1b+S1c+S1d. Гейты: build
> зелёный; в `build/` лежит корректный `sitemap.xml` со всеми инструментами;
> canonical/OG присутствуют на всех страницах; e2e зелёные.
> **Порядок S1:** S1e/S1f/S1g → покупка домена → S1a+S1b+S1c+S1d → **S1h**
> (снятие `noindex`) → S2-контент. Гейты: `pnpm --dir web build` зелёный; в
> `build/` лежит корректный `sitemap.xml` со всеми инструментами; canonical/OG
> присутствуют на всех страницах; `noindex` отсутствует в собранном HTML
> (`pnpm --dir web build` и проверка `build/tools/*/index.html`);
> `pnpm --dir web test:e2e` — по правилам `docs/quality-gates.md`, в CI job
> `e2e` non-blocking, поэтому его статус читается по отдельному job
> (`docs/decisions.md`, раздел 10).
### S2. Контентный слой (параллельно quality-плану, волнами по категориям)
@@ -278,11 +310,13 @@
Три возможных механики — важно не перепутать:
1. **301-редирект `/crop-jpeg` → `/crop-png`** — законно только для опечаток и
альтернативных написаний (`crop-jpg` → `crop-jpeg`) и переименований
существующих страниц. Для самостоятельного запроса редирект — это отказ от
страницы: Google перестаёт показывать редирект, ранжировать будет только
цель. Как посадочная под «crop jpeg» не работает вообще.
1. **301-редирект на существующую страницу** (`/crop-jpg` → `/crop-jpeg`, или
`/crop-png` → новый слаг после переименования) — законно **только** для
опечаток, альтернативных написаний и переименований **уже опубликованной**
страницы: URL, которого никогда не было в индексе, редиректом не закрывается.
Для самостоятельного запроса редирект — это отказ от страницы: Google
перестаёт показывать редирект, ранжировать будет только цель. Как посадочная
под «crop jpeg» не работает вообще.
2. **Зеркало с canonical на `/crop-png`** — технически легально, но бесполезно:
canonical-дубль в индекс не попадает, видимости не добавляет, а массовое
производство таких зеркал выглядит как накрутка площади и при ошибке в
@@ -307,9 +341,9 @@ with PNG, JPG, WebP» в тексте + селектор формата в Downl
- **«convert png to jpg»** — интент «страница-конвертер»: пользователь ищет
конкретную пару форматов (лучшее качество конверсии, меньше ошибок), это
готовые лендинги. Существующие (`jpg-to-png`, `png-to-jpg`, `png-to-webp`,
`png-to-bmp`, `svg-to-png`, …) **оставить и наполнить контентом как все**:
свой H1 («Convert PNG to JPG — free, no upload»), FAQ про
готовые лендинги. Существующие (`convert-png-to-jpg`, `convert-png-to-webp`,
`png-to-bmp`, `svg-to-png`, `base64-to-png`, …) **оставить и наполнить
контентом как все**: свой H1 («Convert PNG to JPG — free, no upload»), FAQ про
качество/прозрачность/фон, related. Селектор формата (S1f) их **не заменяет**
— он про «уже открыл инструмент и хочу другой формат на выходе».
- **«convert image» / «image converter»** — интент «швейцарский нож». Под него —
@@ -331,24 +365,25 @@ with PNG, JPG, WebP» в тексте + селектор формата в Downl
## 6. Переименование бренда и домен (сделать до S1-domain, дёшево сейчас)
Новое имя и конкретный домен **не записаны в этом репозитории** — детальный
чек-лист в `docs/plan-domain.local.md` (исключён из git через `.gitignore`),
чтобы выбранное имя не попало в историю коммитов до покупки домена.
Выбранное имя и домен **в этом репозитории не записаны**: детальный чек-лист
лежит в локальном файле `plan-domain.local.md` рядом с этим планом, он исключён
из git через `.gitignore`, чтобы имя не попало в историю коммитов до покупки
домена. Агент, работающий из клона, этого файла не увидит — при необходимости
попросить чек-лист у пользователя.
- [ ] **[R1]** Механический переезд бренда на новое имя по чек-листу из
локального плана: GitHub-репо + `git remote set-url`, README,
`package.json` (корень + `web/`), `TopBar.svelte` / `Footer.svelte`,
`favicon.svg` (title в SVG), i18n-строки (`en.ts`, `ru.ts`: defaultTitle,
pageTitle, metaDescription). НЕ трогать: слаги инструментов (`*-png`),
ключи localStorage (`easy-png-tools:*` — или мигрировать отдельной
мелочью), историю docs/archive.
- [ ] **[R1]** Механический переезд бренда на новое имя. Список файлов и строк с
хардкодом — в локальном плане (раздел «Где живёт бренд в коде»); здесь
только SEO-ограничения. **НЕ трогать:** адреса страниц инструментов
(`/tools/crop-png`), ключи localStorage (`easy-png-tools:*` — или
мигрировать отдельной мелочью), историю `docs/archive`. Бренд должен стать
i18n-константой, а не тремя независимыми хардкодами.
- [ ] **[R2]** Купить выбранный домен (кандидаты и пробы — в локальном плане) и
перевести прод на него без `BASE_PATH` (§0). Домен нужен до S1-domain:
canonical и sitemap генерятся от `PUBLIC_SITE_ORIGIN`.
- **Порядок:** R1+R2 можно делать параллельно с текущими quality-задачами (не
блокируют). R2 (домен) — блокер только для S1-domain (canonical + sitemap +
снятие `noindex`). После индексации переименование = переезд с 301, потеря
позиций и ссылок — не делать.
блокируют). R2 (домен) — блокер для S1-domain (canonical + sitemap), а
S1-domain — блокер для S1h (снятие `noindex`). После индексации переименование
= переезд с 301, потеря позиций и ссылок — не делать.
## 7. Что осознанно НЕ делаем
@@ -368,7 +403,8 @@ with PNG, JPG, WebP» в тексте + селектор формата в Downl
- `docs/tools-map.md` — карта «наш инструмент ↔ интент конкурента».
- `docs/backlog.md` — пункты SEO/GEO в общем бэклоге.
- `docs/roadmap.md` — фазы 2–8 (ядро TS→Rust/wasm, CLI); фазы 9–10 — API и PWA.
- `docs/roadmap.md` — фазы 2–8 (ядро TS→Rust/wasm, CLI), фаза 11 (пайплайн);
фазы 9–10 — API и PWA.
- `docs/plan-platform.md` — планы API и PWA (общее ядро, оффлайн-режим).
- `docs/plan-domain.local.md` — план переименования/домена; **в git не входит**
(`.gitignore`), лежит только локально.
- `plan-domain.local.md` — локальный чек-лист переименования и покупки домена;
**в git не входит** (`.gitignore`), в клоне отсутствует.