# План приведения фронтенда к стандарту кода Дата аудита: 2026-10-03 Репозиторий: `evening_detective_frontend` ## Результат проверки - `npm run type-check` — успешно. - `npx eslint .` — успешно. - `npx stylelint 'src/**/*.{css,scss,vue}'` — успешно. - Проверки запускались без `--fix`, исходный код аудитом не изменён. - `src/api/generated/**` и `dist/**` в план исправлений не включены. Автоматические проверки подтверждают синтаксическую и базовую lint-корректность, но не проверяют все обязательные правила `docs/FRONTEND_CODE_STANDARD.md`. ## Приоритетный план ### 1. Ошибки, загрузка и повторные действия — P0 Цель: ни один API-вызов не должен терять ошибку или оставлять UI в неясном состоянии. - Обработать `getPermissions()` в `src/components/HeaderMenu.vue:24` и `src/components/OfficePage.vue:17`: показать русское сообщение через `useMessage()` и добавить состояние загрузки/ошибки, если оно влияет на UI. - Обернуть начальные вызовы `getStory()` и `getAnswers()` в `src/components/TeamStoryPage.vue:115` в единый flow с отображением ошибки. - Проверить мутации `src/components/GamePage.vue:287-655` и `src/components/ScenariosEditorPage.vue:85-529`: для каждого действия оставить `try/catch/finally`, пользовательское сообщение и блокировку повторной отправки. - Проверить `src/components/LoginPage.vue:40-76`: во время всех операций формы кнопки должны быть недоступны, а ошибка должна обрабатываться в том же flow. - Для каждого экрана явно сохранить состояния loading, empty и error в template. Готово, когда ручной API-ошибкой можно проверить, что пользователь получает сообщение, кнопка разблокируется после `finally`, а частично изменённые данные не перезаписываются фоновым обновлением. ### 2. Доступность интерактивных элементов и изображений — P0 - Заменить кликабельные `div`/`span` или дать им полноценную клавиатурную семантику в `src/components/HeaderMenu.vue`, `GamePage.vue`, `PlaceBlock.vue`, `IntroBlock.vue` и `ScenariosPage.vue`. - Восстановить видимый focus: в частности, не оставлять `outline: none` в `src/components/GameInputForm.vue:186-189` без равноценной замены. - Добавить осмысленные `alt` к изображениям в `src/components/PlaceBlock.vue` (строки 268, 298, 345, 355, 368, 453, 504), а также проверить остальные `` через поиск по `src`. - Для модальных окон в `OfficePage.vue:261` и `UsersPage.vue:114` добавить `n-card` с `role="dialog"` и `aria-modal="true"` либо эквивалентную доступную структуру; проверить остальные модальные окна на единообразие. - Добавить доступные названия/`title` там, где действие выражено только иконкой или символом `x`. Готово, когда все действия доступны Tab/Enter/Space, focus виден, изображения озвучиваются понятно, а модальные окна имеют корректную семантику. ### 3. Границы компонентов и типизация — P1 - Оставить `*View.vue` маршрутными прокси. Перенести содержимое и стили `src/views/HomeView.vue` в `src/components/HomePage.vue`; стиль сделать `scoped`. Вьюхи документов с `DocsPage` и `HeaderMenu` отдельно проверить на соответствие этому правилу. - Перевести runtime-описания props на typed `defineProps` там, где нет причины сохранять `PropType`: `HeaderMenu.vue`, `PlaceBlock.vue`, `GameInputForm.vue`, `IntroBlock.vue`, `QuestionBlock.vue`. - В `PlaceBlock.vue` и `TeamStoryPage.vue` проверить типы режимов и callback-ов: заменить широкие `string`/необязательные утверждения на существующие типы, не дублируя generated API. - Не выделять новые composable или универсальные обёртки: выносить только реально повторяющийся flow после исправления конкретных callers. Готово, когда маршрутные страницы не содержат экранной логики, props/emits типизированы, а `any` и необоснованные `as` отсутствуют. ### 4. Формы и единообразие UI — P1 - Проверить обязательные поля и сообщения ошибок в формах `LoginPage.vue`, `GameInputForm.vue`, `TeamStoryPage.vue` и `ScenariosEditorPage.vue`. - Использовать Naive UI для обычных UI-контролов. Нативные контролы в `GameInputForm.vue:96-117` и `TeamStoryPage.vue:272,321` оставлять только там, где они нужны бумажному визуальному стилю; в таком случае сохранить доступную семантику и focus. - Проверить, что кнопки с мутациями имеют `loading`/`disabled`, а пустые и ошибочные ответы явно видны пользователю. ### 5. CSS-токены и локальность стилей — P2 - Сгруппировать повторяющиеся цвета из компонентов в уже существующую палитру `src/assets/base.css`; новые токены добавлять только с семантическими именами. - Не расширять глобальные стили. После переноса `HomeView.vue` проверить, что одноразовые классы не попали в `main.css`. - Сохранять алфавитный порядок CSS-свойств и существующие mobile-first брейкпоинты. ## Порядок выполнения 1. Исправить ошибки/loading и доступность в общих и часто используемых компонентах (`HeaderMenu`, `PlaceBlock`, `GameInputForm`). 2. Исправить `GamePage`, `TeamStoryPage`, `ScenariosEditorPage` по месту, не расширяя diff несвязанным рефакторингом. 3. Перенести `HomeView` в page-компонент и типизировать props. 4. Выполнить точечную миграцию цветов и стилей только затронутых файлов. 5. Запустить обязательные проверки: ```bash npm run type-check npm run lint npm run lint:css npm run build ``` 6. Выполнить ручной smoke-check: вход/регистрация, меню с клавиатуры, загрузка и ошибка API, создание/редактирование сценария, игровой ход, модальные окна, просмотр изображений и мобильная ширина. ## Не входит в исправление - Переписывание всего существующего кода только ради косметического соответствия. - Изменение `src/api/generated/**`, protobuf-контрактов и продуктового поведения. - Новые зависимости, новый state manager, общие абстракции «на будущее». - Редизайн и массовая замена бумажного визуального языка.