План улучшения developer experience без визуальных изменений
Архив. Этот план заменён
docs/quality-gates-refactor-plan.mdкак единственным исполняемым документом для текущего цикла. Он сохранён только как исторический контекст и не должен использоваться как источник параллельных задач или критериев готовности.
1. Цель
Этот документ — исполняемый план для разработчика или AI-агента. Его задача — сделать кодовую базу BELF предсказуемой для чтения и безопасной для обновления, не меняя текущий интерфейс, тексты, маршруты и пользовательские сценарии.
Работа считается завершённой только после прохождения финального quality gate из раздела 14.
2. Текущее состояние
На момент составления плана проект уже имеет:
- React + TypeScript + Vite;
- отдельные страницы
/,/partners/,/careers/; - компонентный navbar с явными
NavThemeRegion; - тонкие композиционные CSS-файлы страниц;
- локально разнесённые CSS-файлы секций;
- Vitest, Testing Library, Playwright и visual regression;
- единый скрипт
npm run quality; - CI-зависимость deploy от quality и e2e.
Оставшиеся проблемы developer experience:
- CSS-файлы лежат рядом с компонентами, но классы остаются глобальными;
- часть секций представлена плоским списком файлов вместо компонентных папок;
- несколько внутренних preview-компонентов и их стили всё ещё объединены;
- зависимости страницы от стилей скрыты за композиционными CSS-import файлами;
- общие данные разделены между
src/dataиsrc/sharedбез окончательного правила владения; - отсутствуют path aliases и автоматически проверяемые границы слоёв;
- нет короткого
CONTRIBUTING.mdс инструкцией по добавлению новой секции; - часть повторяемых дизайн-значений ещё не выражена семантическими токенами.
3. Неприкосновенные ограничения
Во время выполнения запрещено:
- менять дизайн, тексты, размеры, цвета, отступы и анимации;
- менять DOM-порядок без технической необходимости;
- менять маршруты, hash-якоря, SEO и SSR/prerender-поведение;
- менять поведение navbar, форм и калькулятора;
- добавлять градиент в navbar или его overlay;
- менять прозрачность или фон header при открытии меню;
- обновлять visual snapshots до анализа причины расхождения;
- одновременно мигрировать несколько несвязанных секций;
- отключать ESLint, Stylelint, TypeScript или тесты ради зелёного результата;
- использовать
!importantдля компенсации проблем каскада; - добавлять новую библиотеку иконок: использовать установленный
react-icons; - удалять пользовательские изменения из грязного рабочего дерева;
- выполнять commit, push или deploy без отдельного указания владельца.
Допустимы только архитектурные изменения с нулевой визуальной дельтой.
4. Целевая структура
src/
app/
entrypoints/
main.tsx
partners.tsx
careers.tsx
mountApp.tsx
pages/
home/
HomePage.tsx
sections/
HeroSection/
HeroSection.tsx
HeroSection.module.css
DashboardPreview.tsx
DashboardPreview.module.css
PlatformSection/
PlatformSection.tsx
PlatformSection.module.css
ModulesSection/
ProctoringSection/
DeploymentSection/
ClosingSections/
partners/
PartnersPage.tsx
data.ts
sections/
PartnersHero/
CommissionSection/
TerritorySection/
ApplicationSection/
careers/
CareersPage.tsx
data.ts
sections/
CareersHero/
CandidateProfileSection/
ResponsibilitiesSection/
TrainingSection/
RequirementsSection/
ResumeSection/
features/
calculator/
components/
CalculatorSection/
CalculatorForm/
CalculatorQuote/
model/
calculator.ts
calculator.test.ts
components/
navigation/
SiteHeader/
NavigationOverlay/
NavigationGroups/
NavigationContact/
model/
layout/
SiteFooter/
shared/
data/
assets.ts
contacts.ts
navigation.ts
pricing.ts
ui/
utils/
types/
styles/
fonts.css
tokens.css
reset.css
global.css
Структура является ориентиром. Не следует создавать пустые директории или компоненты без самостоятельной ответственности.
5. Общая стратегия безопасной миграции
Каждая итерация должна затрагивать только один компонент или одну тесно связанную группу файлов.
Для каждого компонента:
- Зафиксировать его текущие DOM, computed styles и screenshots.
- Создать целевую директорию.
- Переместить компонент без изменения JSX.
- Переместить его CSS в
*.module.cssбез изменения деклараций. - Заменить строки
classNameна ссылки изstyles. - Сохранить исходные specificity, media queries и порядок правил.
- Запустить статические проверки и релевантный component test.
- Запустить Playwright только для затронутого маршрута на шести viewport.
- Сравнить screenshots с существующими baseline без
--update-snapshots. - Удалить старые правила только после зелёного сравнения.
Если screenshot отличается, итерация останавливается. Сначала определяется конкретное CSS-свойство, вызвавшее дельту. Snapshot не обновляется, поскольку цель этой работы — нулевая визуальная разница.
6. Этап 0 — зафиксировать baseline
Перед первой правкой:
git status --short
npm run quality
git diff --check
Дополнительно сохранить список текущих изменённых и неотслеживаемых файлов, не смешивая их с новыми изменениями.
Baseline должен включать:
- 3 маршрута;
- 6 viewport: 390×844, 430×932, 768×1024, 1024×768, 1440×900, 1920×1080;
- navbar в открытом и закрытом состоянии;
- header над светлой и зелёной секциями;
- главный экран, формы и калькулятор.
Gate 0
npm run quality— PASS;git diff --check— PASS;- все baseline snapshots существуют и проходят без обновления;
- список исходных пользовательских изменений сохранён.
При FAIL дальнейшая миграция не начинается.
7. Этап 1 — зафиксировать архитектурные правила
Создать:
docs/architecture.md;CONTRIBUTING.md;- краткую таблицу владения слоями;
- правило направления импортов
app → pages → features/components → shared.
Документация должна отвечать на вопросы:
- куда добавлять новую страницу;
- куда добавлять секцию;
- где хранить данные страницы;
- где хранить общие данные;
- как задавать тему header;
- как добавлять CSS Module;
- какие тесты запускать перед передачей работы.
На этом этапе код приложения не перемещается.
Gate 1
- документация совпадает с фактической структурой;
- в документации нет несуществующих команд;
npm run format:check— PASS;npm run lint— PASS.
8. Этап 2 — aliases и границы импортов
Добавить alias @/* → src/* одновременно в:
tsconfig.json;vite.config.ts;- при необходимости в Vitest/Playwright config.
Переводить импорты на alias небольшими партиями: сначала app, затем
navigation, features, pages.
В ESLint добавить проверяемые ограничения:
sharedне импортируетpages,featuresилиapp;components/navigationне импортирует CSS и данные страниц;features/calculatorне импортируетpages/home;- страницы не импортируют внутренние файлы чужой feature в обход публичного API.
Не добавлять отдельный dependency, если правила можно выразить текущим ESLint.
Gate 2
npm run typecheck— PASS;npm run lint— PASS;npm run test— PASS;npm run build— PASS;- прямые URL
/,/partners/,/careers/открываются.
9. Этап 3 — navigation и layout
Порядок миграции:
NavigationContact;NavigationGroups;NavigationOverlay;SiteHeader;SiteFooter.
Для каждого компонента создать собственную папку и CSS Module. Общую модель
navigation оставить в navigation/model.
Особые условия:
- не менять portal и z-index;
- не менять
position,inset,100dvhи scroll overlay; - не менять контраст logo/menu/close/CTA;
- не объединять
header.cssи overlay CSS в один файл; - не переносить стили navbar обратно в page CSS;
- сохранить focus trap, Escape, inert и восстановление scroll/focus.
Gate 3
- unit tests
SiteHeader— PASS; - navbar открывается и закрывается кнопкой;
Escapeзакрывает меню и возвращает фокус;- Tab/Shift+Tab не выходят из диалога;
- переход по ссылке закрывает меню;
- mobile overlay перекрывает viewport;
- desktop overlay остаётся компактным;
- computed
background-color,opacity,backdrop-filterheader совпадают до и после открытия; - в navigation CSS отсутствуют
linear-gradientи!important; - visual snapshots всех маршрутов и viewport — PASS без обновления.
10. Этап 4 — home и calculator
Мигрировать по очереди:
HeroSectionи отдельноDashboardPreview;PlatformSectionи его визуальные подкомпоненты;ModulesSection;ProctoringSectionи отдельноProctoringPreview;DeploymentSection;CalculatorSection,CalculatorForm,CalculatorQuote;- closing/contact sections.
После переноса каждого компонента:
- компонент импортирует собственный CSS Module;
- из
src/styles/pages/home.cssудаляется соответствующий import; - не меняются CSS declarations и media queries;
- повторяемые части JSX выносятся только при наличии собственной ответственности;
- состояние калькулятора и расчётная модель не меняются одновременно со стилями.
Когда последняя секция мигрирована, удалить композиционный home.css и его
import из entrypoint.
Gate 4
- unit tests калькулятора — PASS;
- значения расчёта до и после миграции совпадают;
- форма остаётся доступной с клавиатуры;
- anchors
#platform,#modules,#deployment,#calculator,#contactработают; - нет горизонтального overflow на шести viewport;
- home visual snapshots — PASS без обновления;
npm run check— PASS.
11. Этап 5 — partners и careers
Мигрировать строго по одной смысловой секции.
Для partners:
- hero и overview;
- типы и преимущества партнёров;
- client registry;
- commission;
- rules;
- territory;
- international;
- process;
- application form;
- footer.
Для careers:
- hero;
- candidate profile;
- responsibilities;
- training;
- requirements;
- resume form;
- footer.
Файлы данных страниц остаются рядом со страницей. Общие контакты не дублируются.
Gate 5
/partners/и/careers/открываются напрямую;- переходы из navbar работают;
- формы формируют те же mailto subject/body;
- client registry отображает те же данные;
- hash-якоря форм работают;
- visual snapshots обеих страниц — PASS на шести viewport;
npm run check— PASS.
12. Этап 6 — shared data, utilities и design tokens
Перенести действительно общие данные из src/data в src/shared/data:
- assets;
- contacts;
- navigation;
- общие pricing/module definitions, если они используются более чем одной feature или страницей.
Данные только одной страницы не переносить в shared.
Design tokens нормализовать в два прохода:
- Добавить семантический token с точно тем же исходным значением.
- В отдельной итерации заменить повторяемые literals на token.
Не создавать token для уникальных иллюстративных цветов. Не менять значения переменных во время замены ссылок.
Gate 6
- контакты имеют один источник истины;
- navigation data имеет один источник истины;
- отсутствуют циклические импорты;
- computed значения заменённых цветов, radius, shadow и spacing идентичны;
npm run check— PASS;- visual snapshots — PASS без обновления.
13. Этап 7 — очистка и финальная документация
После завершения миграции:
- удалить только доказанно неиспользуемые CSS и composition files;
- удалить неиспользуемые импорты и exports;
- удалить устаревшие visual snapshots, на которые больше нет тестов;
- проверить отсутствие пустых директорий;
- обновить
README.md,CONTRIBUTING.mdиdocs/architecture.md; - добавить пример создания новой секции;
- проверить, что
npm ciдостаточен для запуска проекта с чистого checkout.
Удаление должно выполняться только для точных проверенных путей. Несвязанные пользовательские файлы не трогать.
Gate 7
rgне находит импортов удалённых файлов;- каждый CSS Module импортируется владельцем;
- нет старых composition page CSS;
- README содержит актуальные команды;
- architecture docs соответствуют реальному дереву;
npm run quality— PASS.
14. Финальный quality gate
Работу можно объявить завершённой только при одновременном выполнении всех условий.
Статика и сборка
-
npm run format:checkзавершился с кодом0; -
npm run lintзавершился с кодом0; -
npm run lint:cssзавершился с кодом0; -
npm run typecheckзавершился с кодом0; -
npm run testзавершился с кодом0; -
npm run buildзавершился с кодом0; -
npm run qualityзавершился с кодом0; -
git diff --checkне нашёл проблем.
Архитектура
- page-компоненты являются тонкой композицией секций;
- каждая смысловая секция имеет собственную директорию;
- компонент импортирует собственный CSS Module;
- отсутствуют композиционные
home.css,partners.css,careers.css; - глобальные CSS содержат только fonts, tokens, reset и общие utilities;
- направление импортов соответствует документированной схеме;
- общие данные имеют один источник истины;
- page data не помещены в
sharedбез повторного использования; - крупные preview-компоненты отделены от page sections;
- public props имеют явные TypeScript-типы;
- нет отключённых линтеров и новых
!important.
Поведение
-
/,/partners/,/careers/открываются напрямую; - переходы между страницами работают;
- все hash-якоря работают;
- navbar проходит keyboard и focus-management tests;
- mobile overlay полностью перекрывает viewport и прокручивается;
- desktop overlay остаётся компактным;
- header сохраняет фон, opacity и backdrop-filter при открытии;
- logo, menu и close имеют правильный контраст;
- calculator выдаёт прежние результаты;
- forms формируют прежние mailto-ссылки;
- нет console errors, horizontal overflow и layout shift.
Визуальная идентичность
- 3 маршрута проверены на 6 viewport;
- закрытый и открытый navbar проверены для каждого сочетания;
- screenshots проходят с
maxDiffPixelRatio <= 0.003; - существующие baseline не обновлялись для сокрытия расхождений;
- репрезентативные mobile/tablet/desktop screenshots просмотрены вручную;
- тексты, цвета, spacing, размеры, typography и breakpoints не изменились.
Git и CI
- исходные пользовательские изменения сохранены;
- deploy по-прежнему зависит от успешных quality/e2e jobs;
- не выполнены commit, push или deploy без отдельного разрешения;
-
git status --shortвключён в итоговый отчёт.
Если хотя бы один пункт имеет FAIL или не проверен, запрещено писать, что
рефакторинг полностью завершён.
15. Обязательные команды после каждой итерации
Минимум:
npm run format:check
npm run lint
npm run lint:css
npm run typecheck
npm run test
npm run build
После изменения UI:
npm run test:e2e
Финал:
npm run quality
git diff --check
git status --short
Команда playwright test --update-snapshots не входит в обычный цикл этой
миграции. Её использование означает потенциальное визуальное изменение и требует
отдельного анализа и одобрения.
16. Формат отчёта после каждого этапа
Этап
- что мигрировано;
- какие файлы перемещены;
- какие обязанности разделены.
Проверки
- команда: PASS/FAIL;
- visual comparison: PASS/FAIL;
- проверенные маршруты и viewport.
Визуальная дельта
- отсутствует;
- либо точное описание причины и остановка этапа.
Риски
- оставшиеся зависимости или временные compatibility-слои.
Git
- затронутые файлы;
- commit/push status.
17. Стоп-условия
Работа немедленно останавливается внутри текущей итерации, если:
- изменился screenshot;
- появился console error;
- нарушилась клавиатурная навигация;
- перестал работать прямой маршрут или hash-якорь;
- CSS Module потребовал изменения визуальной декларации;
- обнаружено пересечение с неизвестными пользовательскими изменениями;
- тест можно сделать зелёным только ослаблением проверки.
После устранения причины повторяется весь gate текущего этапа. Переходить к следующему компоненту с красным gate запрещено.