From 87bd4482a34f628240741f19269f2fb97e992580 Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Fri, 11 Sep 2026 05:57:47 +0500 Subject: [PATCH] docs: update plans, backlog and other docs --- AGENTS.md | 192 +++++++-------------------------- docs/{ => archive}/plan-c17.md | 12 ++- docs/archive/plan-tech-debt.md | 6 +- docs/backlog.md | 10 +- docs/plan-redesign.md | 62 +++++------ docs/plan-seo.md | 30 +++--- docs/roadmap.md | 14 +-- web/eslint-plugins/README.md | 148 +++++++++++++++++++++++++ web/src/lib/categories.ts | 7 +- 9 files changed, 265 insertions(+), 216 deletions(-) rename docs/{ => archive}/plan-c17.md (86%) create mode 100644 web/eslint-plugins/README.md diff --git a/AGENTS.md b/AGENTS.md index 6a3eb78..8c18b1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,68 +5,23 @@ ## Стек - **SvelteKit** (`web/`) — основное приложение, Svelte 5 (runes). -- Менеджер пакетов: **pnpm**. Запускать команды из `web/`, либо через - обёртки в корне: `pnpm build`, `pnpm dev` (это `pnpm --dir web ...`). - Не использовать npm. -- Сборка: `pnpm --dir web build`, проверка типов: `pnpm --dir web exec svelte-check --tsconfig ./tsconfig.json`, - тесты: `pnpm --dir web test` (Vitest), e2e: `pnpm --dir web test:e2e` (Playwright, - `web/e2e/`, свой webServer на `pnpm build` + `scripts/serve-static.mjs`, порт 4173). -- Форматирование: два независимых прогона. Корневой prettier форматирует - только markdown `docs/` (`.prettierrc` в корне, `pnpm format:docs`, проверка — - `pnpm check:docs`). Корневой `.prettierignore` — только точечные исключения - (node_modules, refs-html…), без `/*`-allowlist: он глушит формат-он-сейв - для всего `web/` (файлы резолвятся как ignored и дочерние конфиги не - применяются). Код `web/` форматируется - отдельно: `pnpm --dir web format` (Prettier + `prettier-plugin-svelte`, - конфиг `web/.prettierrc`, игнор `web/.prettierignore`). Проверка без записи: - `pnpm --dir web exec prettier --check .`. Оба прогона сразу: `pnpm format` - в корне. -- Линтинг: `pnpm --dir web lint` (ESLint, flat-конфиг `web/eslint.config.js`). - Устроен инкрементально: - - На **весь код** — парсинг TS/Svelte + правило - `@typescript-eslint/consistent-type-imports` (запрет инлайн-тип-импортов). - - Полные `recommended`-наборы (`eslint` + `typescript-eslint` + `eslint-plugin-svelte`) - навешены **только на новый код** (`src/lib/components/kit/**`, - `src/routes/preview/**`), чтобы старый код не засыпался предсуществующими - ошибками. Когда старый дизайн удалён (C19), scoped-блок убирается и - `recommended` включается на весь код. - - **Scoped-пути двигаются вместе с папками** (см. `plan-redesign.md` §10): - на C17 `src/routes/preview/**` → `src/routes/**` (preview переезжает на - реальные маршруты), на C19 при переименовании `kit/`→`ui/` — и компонентный - glob. Не оставлять устаревшие пути в `eslint.config.js`. - - Для `*.svelte` выключен `prefer-const` (пропсы в Svelte 5 пишутся через `let`). -- **Единый запуск всей дизайн-проверки: `pnpm --dir web lint:all`** - (`web/scripts/lint-all.mjs`) — гоняет по очереди: ESLint (все правила, - включая design-tokens), stylelint (`lint:css`) и токен-аудит - (`lint:tokens`). Каждый шаг выполняется, даже если предыдущий упал; выход - ненулевой, если хоть один не прошёл. Текущие «ожидаемые долги» (hardcoded - размеры в kit, не-Prefix токены в preview.css и т.п.) — техдолг: чинить +- Менеджер пакетов: **pnpm**. Запускать команды из `web/`, либо через обёртки в + корне: `pnpm build`, `pnpm dev` (это `pnpm --dir web ...`). Не использовать + npm. +- Сборка: `pnpm --dir web build`, проверка типов: + `pnpm --dir web exec svelte-check --tsconfig ./tsconfig.json`, тесты: + `pnpm --dir web test` (Vitest), e2e: `pnpm --dir web test:e2e` (Playwright, + `web/e2e/`, свой webServer на `pnpm build` + `scripts/serve-static.mjs`, порт + 4173). +- Форматирование: `pnpm format` в корне (оба прогона) или + `pnpm --dir web format` (только код web/). Проверка: `pnpm check:docs` + (docs) + `pnpm --dir web exec prettier --check .` (код). +- Линтинг: `pnpm --dir web lint` (ESLint). Полный прогон дизайн-проверок: + `pnpm --dir web lint:all` (ESLint + stylelint + токен-аудит). Каждый шаг + выполняется, даже если предыдущий упал. Текущие «ожидаемые долги» (hardcoded + размеры в kit до C19, не-Prefix токены в `app_v1.css`) — техдолг: чинить только по заведённым tasks, не игнорировать правилом. -### Тесты кастомных линт-правил - -Линт-правила в `web/eslint-plugins/` покрыты юнит-тестами (Vitest): - -- `web/eslint-plugins/__tests__/design-tokens.test.ts` — три чистых правила - (`no-hardcoded-in-svelte`, `no-category-mismatch`, - `no-token-definition-in-svelte`) через `RuleTester` со строковыми кейсами; - `no-undefined-in-svelte` — через `Linter` API, т.к. читает словарь токенов из - `__fixtures__/src/app.css` (не из реального `src/app.css`). -- `web/eslint-plugins/__tests__/no-mixed-imports.test.ts` — isolation-правило - через `Linter` API с `cwd` на `__fixtures__`: правило резолвит импорты по - реальным файлам, поэтому цели импортов обязаны существовать на диске. -- Хелпер `__tests__/helpers.ts` собирает `Linter` с `cwd = __fixtures__` — - `process.cwd()` не трогается, реальные `src/` не читаются. - -Запуск: `pnpm --dir web test:rules` (`vitest run eslint-plugins/__tests__`). -Полный `pnpm --dir web test` тоже их гоняет. - -Фикстуры живут в `web/eslint-plugins/__fixtures__/` и сами прогоняются линтом -(`eslint .`), поэтому добавление/правка стабов — тоже работа с валидным кодом. -Помнить: `allowDefaultProject` в `eslint.config.js` перечисляет test-файлы и -фикстуры точечно (glob'ы с `**` там запрещены tseslint) — при добавлении -файлов в `__tests__/`/`__fixtures__/` дописать их туда же. - ## Правила кода ### Svelte 5: типизация props через `interface Props` @@ -91,111 +46,44 @@ Не использовать инлайн-дженерик `$props<{ ... }>()` — он тяжело читается и разносит тип и деструктуризацию по разным местам. Также **не использовать инлайн-импорты в типах** (`children?: import('svelte').Snippet;`) — все -`import type` поднимаются наверх файла. Это правило **включено в ESLint** -(`@typescript-eslint/consistent-type-imports`, `prefer: 'type-imports'`). +`import type` поднимаются наверх файла. > Правило «всегда `interface Props` + `let {...}: Props = $props()`» стандартным -> ESLint-правилом не покрывается — остаётся конвенцией. Кастомное правило -> (eslint-plugin-svelte / свой visitor) — TODO, позже. +> ESLint-правилом не покрывается — остаётся конвенцией. ### Дизайн: новый визуальный язык -Переезд на новый дизайн описан в `docs/plan-redesign.md`. Ключевые -ограничения при работе с веткой `feat/redesign`: +Описание дизайна — в `docs/plan-redesign.md`. Общие правила: -- Глобальные стили старого и нового дизайна разнесены по layout без - наследования: старое в `web/src/app.css` (группа `(old)/`), новое в - `web/src/lib/styles/design2.css` (ветка `preview/*`). Префикс `.ds2` не - используется. +- Новый дизайн живёт в `web/src/app.css` (корневые маршруты), старый — в + `web/src/app_v1.css` (маршруты `/v1/*`). - Все повторяющиеся визуальные элементы — отдельные компоненты в - `web/src/lib/components/kit/`, даже «просто div с двумя стилями». + `web/src/lib/components/`, даже «просто div с двумя стилями». -### Линтинг дизайн-токенов («единая точка правды» дизайна) +### Линтинг дизайн-токенов Запрещено «захардкоживать» дизайн: цвета, размеры, длительности и z-index -обязаны приходить из CSS-переменных. Стек: **stylelint** прогоняется по всем -CSS-файлам (`web/stylelint.config.js`), **ESLint** лезет в `