diff --git a/.ai/CONVENTIONS.md b/.ai/CONVENTIONS.md index 5b5becd..8dec1c0 100644 --- a/.ai/CONVENTIONS.md +++ b/.ai/CONVENTIONS.md @@ -1,23 +1,9 @@ -# Frontend router +# Frontend conventions: вход -Читай строки, которые активирует задача, затронутый путь **или** обнаруженная -граница. Объединяй совпадения; якорь разрешает чтение только нужного раздела. -Не загружай все conventions из-за одного frontend-файла. +Актуальный routing по задаче, пути и boundary находится в [AGENTS](../AGENTS.md). +Выбирай только активированные темы; при новой границе повтори routing. +[Architecture](architecture.md) объясняет mental model, [SOURCES](SOURCES.md) +ведёт к системным фактам, specifications и ADR по конкретному вопросу. -| Решение / сигнал | Читать до решения | -| --- | --- | -| Создать/перенести module/component/slice; выбрать page/entity/feature/shared; cross-slice imports | [Architecture](conventions/frontend-architecture.md) | -| Component/props, container/VM/view, form, local state/effect, loading/error/retry, Mantine/UI | [UI](conventions/frontend-ui.md) | -| Только продуктовая строка или Zod message | [Строки](conventions/frontend-ui.md#строки-и-валидация) | -| TS declaration/import/export, domain literals, magic values | [Код](conventions/frontend-ui.md#код-и-components) + [Domain literals](conventions/frontend-ui.md#domain-literals-and-magic-values) | -| query/mutation, shared/api, server state/cache, generated types, Bearer/refresh | [Data](conventions/frontend-data.md) | -| Тесты или behavior с testing risk | [Testing](conventions/frontend-testing.md) | -| Новый abstraction/dependency, refactor или неоднозначный scope | [Общий выбор реализации](../../AGENTS.md) | -| Request/response field, route/status/error shape, OpenAPI snapshot/generated type | [Источник HTTP-контракта](../../docs/architecture/http-api.md#источник-контракта) | -| Login/refresh/logout, token/cookie, auth ownership | Data + [security](../../backend/.ai/conventions/security-auth.md) + Testing | -| Storybook/theme/tokens/shared UI | UI + точные [источники](SOURCES.md) дизайн-системы/каталога | - -UI-only props/presentation требуют UI, без API/structure/testing при отсутствии -их triggers. Показ query state не означает изменение data fetching. -Изменение тестов активирует Testing и без production diff. Нужные project facts -выбирай через SOURCES. Повтори routing при новой границе и по итоговому diff. +Этот адрес сохранён для существующих входящих ссылок; второй копии правил +и таблицы маршрутов здесь нет. diff --git a/.ai/SOURCES.md b/.ai/SOURCES.md index 916b004..63570fd 100644 --- a/.ai/SOURCES.md +++ b/.ai/SOURCES.md @@ -2,7 +2,7 @@ | Что нужно установить | Владелец | | --- | --- | -| Какое implementation-решение принять | [CONVENTIONS](CONVENTIONS.md) | +| Какое implementation-решение принять | [AGENTS](../AGENTS.md) | | HTTP wire contract и направление генерации | Backend-owned contract → provided snapshot → [Источник HTTP-контракта](../../docs/architecture/http-api.md#источник-контракта) | | Error codes/validation/error envelope | [docs: HTTP API](../../docs/architecture/http-api.md) | | Auth/session, token storage и refresh | [Аутентификация](../../docs/domains/authentication/overview.md), [подключение брокера](../../docs/integrations/tbank.md) | diff --git a/.ai/architecture.md b/.ai/architecture.md new file mode 100644 index 0000000..12bb7b3 --- /dev/null +++ b/.ai/architecture.md @@ -0,0 +1,34 @@ +# Frontend mental model + +React + TypeScript + Vite SPA. Router задаёт navigation; providers в `app` +подключают auth, TanStack Query, i18n и Mantine. Vite использует React Compiler; +Vitest — отдельную JSDOM конфигурацию. Точные versions/scripts — в +[package.json](../package.json), реализация — source of truth. + +```text +app → pages → features → entities → shared +page container → page VM → entity/feature query → shared/api → backend /api/v1 + ↓ + props → state/section views +``` + +`widgets` не используется. Pages владеют route composition и локальным поведением; +features — самостоятельными возможностями пользователя; entities — устойчивыми +доменными понятиями; shared — техническими primitives без domain responsibility. +Правила выделения owner и public `index.ts` — в +[FSD convention](conventions/frontend-architecture.md). + +Server state и lifecycle запроса принадлежат TanStack Query; VM собирает данные +для view. Transport — `openapi-fetch`/`openapi-react-query`, типизированные из +предоставленного snapshot через `openapi-typescript`. Backend владеет wire +contract; frontend не читает его checkout для генерации и не вызывает T-Bank. +[Data convention](conventions/frontend-data.md) задаёт auth/cache границы. + +`shared/theme/tokens.json` — переносимый source design tokens; `theme.ts` +адаптирует доверенный JSON к Mantine без runtime schema. App и Storybook читают +public API `shared/theme`. Storybook показывает synthetic presentation states, +не использует application API. RTL/MSW проверяют поведение приложения отдельно. + +Existing route-aware AppShell расположен в shared/ui; это legacy placement, +а не образец нового shared primitive. Общий план улучшений читается только +при migration через [router](CONVENTIONS.md). diff --git a/.ai/conventions/frontend-architecture.md b/.ai/conventions/frontend-architecture.md index ec83d4a..5983689 100644 --- a/.ai/conventions/frontend-architecture.md +++ b/.ai/conventions/frontend-architecture.md @@ -27,20 +27,17 @@ Slice именуется по ответственности, а не `helpers`, Cross-slice consumer использует `@/` и `index.ts` владельца, например `@/entities/portfolio`. Alias Vite и TypeScript согласован. Другой slice не -импортирует внутренний файл напрямую. Направление зависимостей проверяет +импортирует внутренний файл напрямую. Slices `pages`, `features`, `entities` не зависят от соседнего slice своего слоя; +композиция принадлежит вышележащему owner. Existing меж-slice исключения +не являются разрешением добавлять новые. + +Направление зависимостей и public imports частично проверяет `npm run deps`; Knip проверяет использование exports, а не смысл placement. ## UI foundation -Общий visual foundation принадлежит `shared/theme`. `tokens.json` — переносимый -WealthLedger v1 source; `theme.ts` адаптирует доверенный JSON в Mantine без runtime -schema. App и Storybook используют public API `shared/theme/index.ts`: theme, -designTokens, color roles, CSSVariablesResolver и base styles. Внешний consumer -читает JSON напрямую. Mantine defaults и локальные domain styles остаются у владельцев. -`shared/ui` содержит StateView/LoadingSkeleton. Existing route-aware AppShell также -лежит в shared/ui, но не является общим catalog primitive; его расположение не -служит основанием переносить новую domain/navigation логику в shared. -Изменяя foundation, прочитай [design system](../../../docs/design/overview.md). +Mental model, theme и data flow — в [architecture](../architecture.md). +При изменении foundation прочитай [design system](../../../docs/design/overview.md). ## Примеры @@ -52,5 +49,7 @@ designTokens, color roles, CSSVariablesResolver и base styles. Внешний c После placement/import change: `npm run deps`, `npm run typecheck`, `npm run knip`; после собственного behavior — применимые tests. Финальный gate указан в AGENTS. -Review отдельно проверяет смысл owner: разрешённый dependency graph не доказывает +Existing dependency config не запрещает все same-layer imports: их и смысл +owner проверяет review. Не объявляй Steiger установленным; graph проверяет +текущий dependency-cruiser. Review отдельно проверяет смысл owner: разрешённый dependency graph не доказывает правильный выбор слоя. diff --git a/.ai/conventions/frontend-data.md b/.ai/conventions/frontend-data.md index 1b1428b..1764a00 100644 --- a/.ai/conventions/frontend-data.md +++ b/.ai/conventions/frontend-data.md @@ -23,7 +23,9 @@ type User = paths["/api/v1/auth/me"]["get"]["responses"][200]["content"]["applic ``` Domain/UI type допустим, когда он отличается по смыслу, а не копирует transport DTO. -Generated TS вручную не исправляется. Frontend-команды не читают соседний +Generated TS вручную не исправляется. Не добавляй параллельный fetch/axios +client, runtime schema, hash/checksum registry или дополнительный drift checker +без отдельной текущей потребности; existing OpenAPI flow уже владеет генерацией. Frontend-команды не читают соседний backend checkout и не проверяют backend runtime OpenAPI; изменение wire shape/status/route сохраняет [границу HTTP-контракта](../../../docs/architecture/http-api.md#источник-контракта). @@ -44,11 +46,29 @@ session-scoped cache. При auth/token change читай [security](../../../ba GET subtree; ошибка mutation не меняет generation/cache. Это отдельная граница от обычного фонового refetch: [connection policy](../../../docs/integrations/tbank.md#граница-финансового-кэша). +Mutations используют существующий generated client и query-key owner; +после успеха обновляй/invalidируй только связанные данные. Optimistic update +нужен конкретному UX и обязан иметь rollback/error behavior. + Default focus refetch выключен; freshness и retry определяются существующей [query policy](../../../docs/adr/007-react-query-fetch-policy.md) и feature source. При обычном refetch сохраняй Client Cached Snapshot, при session/connection смене не показывай данные прежнего владельца. UI presentation — в UI convention. +## Errors + +Извлекай code через existing `apiErrorCode` из shared/api. Backend Problem +Details code задаёт machine behavior; user-facing текст принадлежит i18n. +Network/unknown error получает безопасное локальное сообщение и retry, +не raw exception text. Input/domain failure сохраняет ввод и показывает +ошибку у ответственного form/section owner; не маскируй её успешным результатом. + +Если одна группа API codes требует одинакового recovery в нескольких views, +сведи классификацию у ближайшего общего owner. Не размножай magic comparisons +и не объявляй закрытый frontend error enum: generated `code` пока `string`. +Неизвестный новый code должен сохранять fallback. Рефакторинг существующих +разных recovery paths требует behavior proof, а не общей обработки всех ошибок. + ## Примеры и проверка [usePortfolio](../../src/entities/portfolio/api/usePortfolio.ts) — entity query; diff --git a/.ai/conventions/frontend-testing.md b/.ai/conventions/frontend-testing.md index 143be13..8b3513a 100644 --- a/.ai/conventions/frontend-testing.md +++ b/.ai/conventions/frontend-testing.md @@ -1,5 +1,9 @@ # Frontend testing +Перед нетривиальными тестами сформулируй +[общий Test Intent](../../../.ai/conventions/testing.md); отдельный документ +не требуется. Trivial low-risk изменения обходятся без него. + ## Выбор проверки Читай при изменении тестов, доступа, денежных расчётов, восстановления @@ -11,6 +15,7 @@ | Чистое domain преобразование/денежный расчёт | Unit case с граничными значениями | | Форма, route access, recovery, UI-state selection | RTL component/route test через видимое поведение | | Headers, refresh/retry, query invalidation | MSW на transport boundary | +| Критический browser flow, который JSDOM не доказывает | Browser/e2e proof существующими доступными средствами; отдельный frontend e2e runner пока не принят | | Только declarative props/Storybook fixture | Type/build + semantic/visual review; unit test без собственной логики не нужен | Tests colocated с source (`*.test.tsx` для UI, существующий `*.test.ts` для pure code). diff --git a/.ai/conventions/frontend-ui.md b/.ai/conventions/frontend-ui.md index c211935..f1c13f4 100644 --- a/.ai/conventions/frontend-ui.md +++ b/.ai/conventions/frontend-ui.md @@ -11,6 +11,11 @@ Mantine component и общую тему. Для выпадающего выбо ограничения JSDOM решай в test setup, сохраняя production UI. Семантический HTML для структуры страницы остаётся уместным. +Icons ищи у существующего owner (например, +[BankOperationIcon](../../src/entities/bank-card/ui/BankOperationIcon.tsx)); +общая icon library сейчас не принята. Не добавляй пакет ради одного символа. Business/domain +components живут у feature/entity/page, даже при повторном использовании. + Wrapper нужен для проектной ответственности, а не ради нового имени для Button. Локальный CSS module принадлежит component; общий token вводи для реально общей роли через [design system](../../../docs/design/overview.md). @@ -23,9 +28,11 @@ Wrapper нужен для проектной ответственности, а | Локальное открытие, focus, rendering fallback | React UI state | | Значение, вычисляемое из уже доступных inputs | Вычисление при render/в VM, без копирования через effect в state | -Effect нужен для синхронизации с внешней системой; действие пользователя -обрабатывай в handler. Не добавляй store, memoization или abstraction без текущей -потребности. Inspect ближайший component до создания нового pattern. +State, который нужен в ссылке, back/forward или после navigation, хранится в URL +через existing router search params. Остальной UI state остаётся у ближайшего +owner. Shared client store нужен только нескольким consumers без подходящего +общего owner; наличие двух компонентов само по себе его не требует. +Hooks/effects/derived state — по [TypeScript/React](typescript-react.md#hooks-и-derived-state). ## Container, VM и view @@ -76,71 +83,12 @@ Button loading при mutation и компактный cached-snapshot progress ## Код и components -Style/type automation задают configs. Используй `import type`; `enum` и -`namespace` в frontend не применяются. Named components — const-valued; Biome -проверяет declarations, no-default-export и exports-last в своём scope. - -Обязательный review: `FC` и named props рядом/в types-файле; без inline -props typing и destructuring в параметрах. Принимай `props`, destructure в body. -Только children — `FC`; дополнительные props — named type -на основе `PropsWithChildren<{ ... }>`. Без props — `FC`. -Своди обычные exports к читаемому нижнему named block; barrel делает прямой -re-export без промежуточного import. - -CSF `*.stories.tsx` сохраняют default meta и прямые story exports для indexer. -Vite/Vitest configs и `.storybook/main.ts`/`preview.tsx` имеют только -конфигурационное default-export exception. Scope исключений принадлежит biome.json. +Types, props, hooks и memoization — в [TypeScript/React](typescript-react.md). ## Domain literals and magic values -Finite business vocabulary must be modeled explicitly; incidental implementation -literals stay inline. Это относится к error codes, statuses, operation/account/ -instrument/transaction types, permissions, roles, feature states и бизнес-режимам. - -Перед новым определением найди existing owner/type/value. В branching и comparisons -используй символическое значение владельца; не повторяй raw domain literals. -Храни словарь у domain/module/entity с соблюдением границ слоёв, без глобальной -свалки `constants.ts`. Сохраняй принятый pattern; для нового project-owned словаря -без подходящего аналога используй `as const` с derived union: - -```ts -const BankErrorCode = { - InvalidDate: "BANK_INVALID_DATE", - ImmutableOperation: "BANK_IMMUTABLE_OPERATION", -} as const; -type BankErrorCode = (typeof BankErrorCode)[keyof typeof BankErrorCode]; - -// Вместо code === "BANK_INVALID_DATE": -if (code === BankErrorCode.InvalidDate) { /* existing handling */ } -``` - -Значимые numeric policies (timeout, retry, page size, threshold, coefficient) -называй по смыслу и единицам: `REQUEST_TIMEOUT_MS`, `CACHE_TTL_SECONDS`, -`MAX_RETRY_COUNT`, `PAGE_SIZE`. Оставляй inline UI labels в принятом месте, -log messages, индексы, `index + 1`, `Math.max(value, 0)`, `page ?? 1`, -`percentage * 100` и очевидные локальные детали без semantic benefit. -При неясном owner/смысле оставь значение и укажи ограничение в review. - -Не мигрируй корректные existing enum/union styles массово. Не добавляй ради -правила factories, registries, schemas, loaders, abstraction layers, dependencies, -custom lint/AST rules, generation/validation scripts или тесты существования -констант. Semantic review проверяет ownership, единое написание и неизменность -wire values; обычные behavior tests проверяют поведение. - -Backend API vocabulary бери из generated OpenAPI types/client, runtime values — -когда генератор их предоставляет. Не создавай ручную копию backend enum/object. -Текущий `schema.d.ts` предоставляет только types: используй indexed-access type -из `paths`; typed literals в запросах/сравнениях допустимы при отсутствии -runtime values. `ProblemDetailsDto.code` сейчас `string`: не выдумывай закрытый -frontend error enum. Развитие API source — отдельное contract-решение. -Frontend `enum` по-прежнему запрещён локальным TS/style profile. - -`noMagicNumbers` включён как error в Biome. Fixtures, tests и stories исключены -из этого правила; остальные проверки для них сохраняются. Используй имена -политик/единиц и existing values. Точечное подавление допустимо для очевидного -incidental значения с объяснением, например перевода доли в проценты; не подавляй -скрытые бизнес-лимиты. Semantic magic strings проверяются conventions/review: в -установленном Biome нет такого встроенного правила, новый инструмент не добавляем. +Правило и generated API exception — в +[TypeScript/React](typescript-react.md#domain-literals-and-magic-values). ## Строки и валидация @@ -154,5 +102,5 @@ incidental значения с объяснением, например пере Type/style: `npm run typecheck`, `npm run lint`. Для risk behavior/изменения тестов используй [Testing](frontend-testing.md). UI: keyboard, narrow viewport, -loading/error/empty/loaded и recovery по применимости. [Storybook](../../README.md#ui-каталог-storybook) -уже установлен; используй его как reference, но сверяй UI с задачей отдельно от build. +loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога; +сверяй UI с задачей отдельно от build. diff --git a/.ai/conventions/storybook.md b/.ai/conventions/storybook.md new file mode 100644 index 0000000..c82e9d0 --- /dev/null +++ b/.ai/conventions/storybook.md @@ -0,0 +1,33 @@ +# Storybook + +## Когда нужна story + +- Shared UI/theme: показывай принятые visual roles и переиспользуемое поведение. +- Domain/page presentation: добавляй story, когда независимый visual state + нужен для разработки/review или является устойчивым UI pattern. +- Выбирай значимые состояния: default, loading, disabled, error, empty, + длинный контент и смысловые variants по применимости. Не строй декартово + произведение props и story для каждого trivial wrapper/helper. +- Fetch/auth/router container и VM проверяй application tests; story получает + synthetic props presentation component. Каталог не нужен каждому файлу. + +## Изоляция и interaction + +Используй CSF, `Meta`/`StoryObj`, `satisfies Meta`, локальные fixtures и actions. +Общие Mantine/theme/i18n/Dates providers уже есть в +[preview](../../.storybook/preview.tsx); не создавай второй theme source. +Stories не достигают application API, auth, VM и query providers даже транзитивно; +границу проверяет `deps:storybook`. Не добавляй MSW worker ради каталога. + +`play` через `storybook/test` нужен, когда interaction иллюстрирует собственный +контракт: keyboard activation, доступность действия, local callback. Не повторяй +RTL suite и не тестируй внутренности Mantine. Существующий +[Button](../../src/shared/ui/Button.stories.tsx) показывает themed control +без production wrapper; [LoadingSkeleton](../../src/shared/ui/LoadingSkeleton.stories.tsx) +— значимые busy states. + +`npm run typecheck`, `npm run deps:storybook`, `npm run build:catalog` проверяют +типы, изоляцию и сборку. Build не выполняет `play` как CI interaction suite; +для проверки interaction открой story в браузере, для regression используй +существующий [Testing](frontend-testing.md). Визуальное соответствие задаче, +keyboard и узкий viewport проверяются отдельно от успешной сборки. diff --git a/.ai/conventions/typescript-react.md b/.ai/conventions/typescript-react.md new file mode 100644 index 0000000..fee0393 --- /dev/null +++ b/.ai/conventions/typescript-react.md @@ -0,0 +1,53 @@ +# TypeScript и React + +## Types и components + +- Сохраняй strict TS profile и `import type`. Для недоверенного значения используй + `unknown` с narrowing; `any` не заменяет DTO/validation. Локальное исключение + на нетипизированной boundary должно быть узким и объяснённым. +- `enum` и `namespace` не используются: frontend имеет `erasableSyntaxOnly`. + Для состояния с разными payload выбирай discriminated union; не добавляй + необязательные поля, допускающие невозможные комбинации. +- Named components — const-valued `FC`; named props находятся рядом или + в types-файле. Принимай `props`, destructure в body, без inline props typing. + Только children — `FC`; дополнительные props — named type + на основе `PropsWithChildren<{ … }>`; без props — `FC`. +- Обычные exports — нижний named block; barrel делает прямой re-export. + CSF сохраняет default meta и прямые story exports; configuration exceptions + заданы в [Biome](../../biome.json). Не распространяй их на application code. + +## Hooks и derived state + +Hooks вызываются без условий и ранних выходов перед ними; custom hook нужен +связному поведению, а не новому имени над одним вызовом. Derived value вычисляй +при render/в VM. Пользовательское действие обрабатывай handler; `useEffect` +оставляй синхронизации с внешней системой с корректным cleanup/dependencies. + +`useMemo`, `useCallback`, `memo` нужны измеренной стоимости или конкретному +контракту стабильной identity; не добавляй их ко всем значениям/handlers. +React Compiler включён в Vite, но не доказывает выигрыш и не заменяет effect +correctness. Не удаляй существующую memoization без понимания её consumers. +Container/VM/view и state owners — в [UI](frontend-ui.md). + +## Domain literals and magic values + +Общее правило ownership и символических значений — +[Domain values](../../../.ai/conventions/code-health.md#domain-values). +Backend vocabulary бери из generated `paths`, не создавай ручную копию enum. +Текущий `schema.d.ts` содержит только types: typed wire literals допустимы, +когда generator не предоставляет runtime values. + +`ProblemDetailsDto.code` сейчас `string`. Не объявляй закрытый frontend error +enum и не превращай неизвестный code в известный через cast. Повторяющуюся +обработку своди у ответственного owner; [errors](frontend-data.md#errors). + +`noMagicNumbers` в Biome — error; fixtures/tests/stories исключены только +из этого правила. Policy получает имя и единицы; подавление допустимо для +incidental value с объяснением. Обычный UI-текст не превращай в constant: +его owner — [i18n](frontend-ui.md#строки-и-валидация). +Semantic magic strings и props profile требуют review. + +## Проверка + +`npm run typecheck` и `npm run lint`; behavior проверяй по +[Testing](frontend-testing.md), placement — по [FSD](frontend-architecture.md). diff --git a/AGENTS.md b/AGENTS.md index f215523..3d9dff9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,36 +1,26 @@ -# Frontend +# Frontend router -React/Vite-клиент; общие правила работы — в root `AGENTS.md`. -До frontend-решения прочитай [router](.ai/CONVENTIONS.md) и -[sources](.ai/SOURCES.md), затем только применимые документы/разделы. +Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи, +путей и обнаруженных boundaries; читай только нужные темы до решения. +[Sources](.ai/SOURCES.md) выбирает факты/spec/ADR по возникшему вопросу. -## Проверка +| Решение / сигнал | Читать | +| --- | --- | +| Первое знакомство, data flow, общая архитектура | [Mental model](.ai/architecture.md) | +| Создать/перенести component/module/slice, owner/FSD, cross-slice imports | [FSD](.ai/conventions/frontend-architecture.md) | +| TS types/props/imports/exports, hooks/effects, derived state, memoization, domain literals | [TypeScript/React](.ai/conventions/typescript-react.md) | +| UI/Mantine, form, container/VM/view, state owner, loading/error/recovery | [UI](.ai/conventions/frontend-ui.md) | +| Только продуктовая строка / Zod message | [Строки](.ai/conventions/frontend-ui.md#строки-и-валидация) | +| Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/frontend-data.md) | +| API/network/application errors, codes и сообщения | [Errors](.ai/conventions/frontend-data.md#errors) | +| Login/refresh/logout, token/cookie, session ownership | Data + [Security](../backend/.ai/conventions/security-auth.md) + [Testing](.ai/conventions/frontend-testing.md) | +| Request/response field, route/status/error shape, OpenAPI | Data + [HTTP contract source](../docs/architecture/http-api.md#источник-контракта) | +| Tests или behavior с regression risk | [Testing](.ai/conventions/frontend-testing.md) | +| Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — через Sources | +| Helper/dependency/новый pattern, refactor/scope | [Code health](../.ai/conventions/code-health.md), для пакета — [Dependencies](../.ai/conventions/dependencies.md) | +| Выбор gate, tooling, завершение | [Guardrails](../.ai/conventions/guardrails.md) | -Перед Node-командами: `nvm use --silent` по `.nvmrc`. -После lockfile install `npm ci` полный gate — `npm run verify`. -Он проверяет OpenAPI drift, TypeScript, Biome, Vitest/coverage, Knip, -dependency boundaries и сборки приложения/Storybook без backend. -Точные scripts принадлежат `package.json`; targeted checks — у выбранного convention. - -HTTP contract changes используют предоставленный OpenAPI snapshot; frontend -локально проверяет только соответствие generated types этому snapshot: -[Источник HTTP-контракта](../docs/architecture/http-api.md#источник-контракта). -Generated types редактируются через их source; T-Bank доступен только через backend. -Frontend dependencies используют exact versions. Pre-commit запускает staged -formatting и FSD checks; сообщения commits — Conventional Commits. -Если у задачи есть связанная issue этого репозитория, добавляй её номер -в конец заголовка: `ci: run full frontend verification #1`. -Без связанной issue номер необязателен: `chore(deps): update non-major dependencies`. -Формат Conventional Commits проверяет `commitlint.config.cjs`. - -Code/style checks автоматические только в scope конфигурации. i18n, props, -semantic placement и выбор полезных тестов обязательны при review. -Storybook уже доступен как reference; ожидаемый UI и его состояния определяет -задача, а визуальное соответствие проверяется отдельно от сборки. - -## Ветки и релизы - -Работа — в отдельной ветке от `develop`, затем PR в `develop`; в `main` напрямую -не пушить. Release/hotfix и синхронизация веток — по [root README](../README.md#релизы-и-ветки). -Commits и заголовки PR — Conventional Commits; для спецификаций допустим `spec:`. -Перед подготовкой релиза прочитай root README; версии вручную не повышать. +Показ query state не означает изменение fetching. Изменение тестов активирует +Testing и без production diff. Повтори routing по итоговому diff, включая новые +файлы. Migration backlog читается только при работе над соответствующим finding +через [plan](../.ai/migrations/conventions-v1/plan.md).