docs: refine frontend conventions and routing #14

Merged
ksv741 merged 2 commits from codex/engineering-conventions into develop 2026-09-15 06:08:38 +03:00
11 changed files with 250 additions and 203 deletions
-23
View File
@@ -1,23 +0,0 @@
# Frontend router
Читай строки, которые активирует задача, затронутый путь **или** обнаруженная
граница. Объединяй совпадения; якорь разрешает чтение только нужного раздела.
Не загружай все conventions из-за одного frontend-файла.
| Решение / сигнал | Читать до решения |
| --- | --- |
| Создать/перенести 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.
-18
View File
@@ -1,18 +0,0 @@
# Источники frontend
| Что нужно установить | Владелец |
| --- | --- |
| Какое implementation-решение принять | [CONVENTIONS](CONVENTIONS.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) |
| Значение Money, cached snapshot, account/position/income | [docs: Domain](../../docs/glossary.md) |
| Mantine/theme/tokens и существующие stories | [Дизайн-система](../../docs/design/overview.md), [UI-каталог](../README.md#ui-каталог-storybook) |
| As-built behavior нужной feature | [docs: Features](../../docs/README.md#предметные-области) |
| Существующие behavioral requirements, если нужны по задаче | [specs index](../../specs/AI_INDEX.md) |
| Действующие versions/scripts/check scope | package.json, lockfile, Biome/TS/dependency configs |
Открывай точный source только по возникшему вопросу. Code examples показывают
pattern, но не переопределяют контракт. Specs не являются editable OpenAPI;
SDD-процедура для обычной работы не нужна. При конфликте источников сначала
установи факты, не меняй generated types или security policy по догадке.
+82
View File
@@ -0,0 +1,82 @@
# Frontend architecture
## Устройство и data flow
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
```
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/data.md) задаёт auth/cache границы.
## Выбор владельца
Сначала найди владельца поведения и ближайший пример. Расширяй existing slice,
если ответственность остаётся связной. Размер файла или возможный будущий reuse
не создают новую архитектурную границу.
| Ответственность | Размещение |
| --- | --- |
| Bootstrap, глобальные providers, routes | `app` |
| Композиция маршрута и поведение, нужное только этому экрану | `pages/<page>` |
| Самостоятельная пользовательская возможность с собственным смыслом | `features/<capability>` |
| Представление/поведение бизнес-сущности | `entities/<entity>` |
| Переиспользуемый код без WealthLedger domain meaning | `shared` |
Локальный FSD profile: `app → pages → features → entities → shared`, без `widgets`.
Крупный уникальный блок остаётся в своей page. Form, mutation или click handler
сами по себе не требуют feature. Два callers не делают domain helper generic shared.
Slice именуется по ответственности, а не `helpers`, `hooks` или `types`.
**Безопасный путь:** при сомнении оставь код у ближайшего допустимого owner.
Извлекай его, когда появилась самостоятельная ответственность или реальный reuse.
Не вводи новый layer и не обходи public API, чтобы устранить неудобный import.
## Imports и public API
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
`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](../AGENTS.md).
При изменении foundation прочитай [design system](../../docs/design/overview.md).
## Примеры
- Общая busy-область: существующий [LoadingSkeleton](../src/shared/ui/LoadingSkeleton.tsx), а не domain widget в shared.
- Account-income state views: [страница](../src/pages/account-income/ui/AccountIncomePage.tsx) и её flat `components/*.view.tsx`; новый page-local filter остаётся здесь.
- Portfolio query: [entity public API](../src/entities/portfolio/index.ts); новая UI-сводка с бизнес-смыслом не становится shared только из-за нескольких экранов.
## Проверка
После placement/import change: `npm run deps`, `npm run typecheck`, `npm run knip`;
после собственного behavior — применимые tests. Финальный gate указан в AGENTS.
Existing dependency config не запрещает все same-layer imports: их и смысл
owner проверяет review. Не объявляй Steiger установленным; graph проверяет
текущий dependency-cruiser. Review отдельно проверяет смысл owner: разрешённый dependency graph не доказывает
правильный выбор слоя.
@@ -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,17 +46,35 @@ 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;
[shared client](../../src/shared/api/client.ts) — transport/auth boundary.
Изменяя header/retry/invalidation, проверяй наблюдаемое поведение через MSW и
[Testing](frontend-testing.md); не обращайся к реальному T-Bank.
[Testing](testing.md); не обращайся к реальному T-Bank.
`npm run openapi:check`, `npm run typecheck` и targeted tests проверяют разные
части решения. Для API semantics нужны exact docs и проверки наблюдаемого
HTTP-поведения на стороне backend.
-56
View File
@@ -1,56 +0,0 @@
# Frontend architecture
## Выбор владельца
Сначала найди владельца поведения и ближайший пример. Расширяй existing slice,
если ответственность остаётся связной. Размер файла или возможный будущий reuse
не создают новую архитектурную границу.
| Ответственность | Размещение |
| --- | --- |
| Bootstrap, глобальные providers, routes | `app` |
| Композиция маршрута и поведение, нужное только этому экрану | `pages/<page>` |
| Самостоятельная пользовательская возможность с собственным смыслом | `features/<capability>` |
| Представление/поведение бизнес-сущности | `entities/<entity>` |
| Переиспользуемый код без WealthLedger domain meaning | `shared` |
Локальный FSD profile: `app → pages → features → entities → shared`, без `widgets`.
Крупный уникальный блок остаётся в своей page. Form, mutation или click handler
сами по себе не требуют feature. Два callers не делают domain helper generic shared.
Slice именуется по ответственности, а не `helpers`, `hooks` или `types`.
**Безопасный путь:** при сомнении оставь код у ближайшего допустимого owner.
Извлекай его, когда появилась самостоятельная ответственность или реальный reuse.
Не вводи новый layer и не обходи public API, чтобы устранить неудобный import.
## Imports и public API
Cross-slice consumer использует `@/` и `index.ts` владельца, например
`@/entities/portfolio`. Alias Vite и TypeScript согласован. Другой slice не
импортирует внутренний файл напрямую. Направление зависимостей проверяет
`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).
## Примеры
- Общая busy-область: существующий [LoadingSkeleton](../../src/shared/ui/LoadingSkeleton.tsx), а не domain widget в shared.
- Account-income state views: [страница](../../src/pages/account-income/ui/AccountIncomePage.tsx) и её flat `components/*.view.tsx`; новый page-local filter остаётся здесь.
- Portfolio query: [entity public API](../../src/entities/portfolio/index.ts); новая UI-сводка с бизнес-смыслом не становится shared только из-за нескольких экранов.
## Проверка
После placement/import change: `npm run deps`, `npm run typecheck`, `npm run knip`;
после собственного behavior — применимые tests. Финальный gate указан в AGENTS.
Review отдельно проверяет смысл owner: разрешённый dependency graph не доказывает
правильный выбор слоя.
+33
View File
@@ -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](testing.md). Визуальное соответствие задаче,
keyboard и узкий viewport проверяются отдельно от успешной сборки.
@@ -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).
+53
View File
@@ -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<Props>`; named props находятся рядом или
в types-файле. Принимай `props`, destructure в body, без inline props typing.
Только children — `FC<PropsWithChildren>`; дополнительные 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](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](data.md#errors).
`noMagicNumbers` в Biome — error; fixtures/tests/stories исключены только
из этого правила. Policy получает имя и единицы; подавление допустимо для
incidental value с объяснением. Обычный UI-текст не превращай в constant:
его owner — [i18n](ui.md#строки-и-валидация).
Semantic magic strings и props profile требуют review.
## Проверка
`npm run typecheck` и `npm run lint`; behavior проверяй по
[Testing](testing.md), placement — по [FSD](../architecture.md).
@@ -11,21 +11,28 @@ 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).
| Состояние | Владелец |
| --- | --- |
| Ответ сервера / query lifecycle | TanStack Query, [data rules](frontend-data.md) |
| Ответ сервера / query lifecycle | TanStack Query, [data rules](data.md) |
| Ввод и ошибки формы | React Hook Form + Zod, container/VM |
| Параметр навигации, который должен переживать переход/ссылку | Router/URL |
| Локальное открытие, 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<Props>` и named props рядом/в types-файле; без inline
props typing и destructuring в параметрах. Принимай `props`, destructure в body.
Только children — `FC<PropsWithChildren>`; дополнительные 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).
## Строки и валидация
@@ -153,6 +101,6 @@ 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.
используй [Testing](testing.md). UI: keyboard, narrow viewport,
loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога;
сверяй UI с задачей отдельно от build.
+33 -30
View File
@@ -1,36 +1,39 @@
# Frontend
# Frontend router
React/Vite-клиент; общие правила работы — в root `AGENTS.md`.
До frontend-решения прочитай [router](.ai/CONVENTIONS.md) и
[sources](.ai/SOURCES.md), затем только применимые документы/разделы.
Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи,
путей и обнаруженных boundaries; читай только нужные темы до решения.
Системные факты/spec/ADR выбирай в разделе [Источники](#источники) по вопросу.
## Проверка
| Решение / сигнал | Читать |
| --- | --- |
| Устройство/data flow, component/module/slice, owner/FSD, cross-slice imports | [Architecture](.ai/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/ui.md) |
| Только продуктовая строка / Zod message | [Строки](.ai/conventions/ui.md#строки-и-валидация) |
| Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/data.md) |
| API/network/application errors, codes и сообщения | [Errors](.ai/conventions/data.md#errors) |
| Login/refresh/logout, token/cookie, session ownership | Data + [Security](../backend/.ai/conventions/security-auth.md) + [Testing](.ai/conventions/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/testing.md) |
| Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — в разделе Источники |
| 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.
Показ query state не означает изменение fetching. Изменение тестов активирует
Testing и без production diff. Повтори routing по итоговому diff, включая новые
файлы. Migration backlog читается только при работе над соответствующим finding
через [plan](../.ai/migrations/conventions-v1/plan.md).
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 и его состояния определяет
задача, а визуальное соответствие проверяется отдельно от сборки.
Открывай только источник по возникшему вопросу; примеры кода не переопределяют
контракт. Specs задают behavior, а editable OpenAPI принадлежит backend.
## Ветки и релизы
Работа — в отдельной ветке от `develop`, затем PR в `develop`; в `main` напрямую
не пушить. Release/hotfix и синхронизация веток — по [root README](../README.md#релизы-и-ветки).
Commits и заголовки PR — Conventional Commits; для спецификаций допустим `spec:`.
Перед подготовкой релиза прочитай root README; версии вручную не повышать.
| Вопрос | Источник |
| --- | --- |
| HTTP contract, validation/error codes | [HTTP API](../docs/architecture/http-api.md) |
| Auth/session/refresh, подключение брокера | [Authentication](../docs/domains/authentication/overview.md), [T-Bank](../docs/integrations/tbank.md) |
| Money, account/position/income/cache meanings | [Глоссарий](../docs/glossary.md) |
| Theme/tokens, UI-каталог | [Дизайн-система](../docs/design/overview.md), [Storybook](README.md#ui-каталог-storybook) |
| Поведение области / требования | [Области docs](../docs/README.md#предметные-области), [Specs index](../specs/AI_INDEX.md) |
| Versions/scripts/check scope | Manifest/lockfile, Biome/TypeScript/dependency configs |
+5 -5
View File
@@ -59,11 +59,11 @@ document и затем выполните `npm run openapi:generate`.
## Документация
- [Router conventions](.ai/CONVENTIONS.md) и [источники](.ai/SOURCES.md)
- [Выбор owner/FSD](.ai/conventions/frontend-architecture.md)
- [UI, state, формы и компоненты](.ai/conventions/frontend-ui.md)
- [Data/API/cache](.ai/conventions/frontend-data.md)
- [Testing](.ai/conventions/frontend-testing.md)
- [AGENTS: правила и источники](AGENTS.md)
- [Выбор owner/FSD](.ai/architecture.md)
- [UI, state, формы и компоненты](.ai/conventions/ui.md)
- [Data/API/cache](.ai/conventions/data.md)
- [Testing](.ai/conventions/testing.md)
- [UI-каталог Storybook](#ui-каталог-storybook)
- [Обзор поставленной системы](../docs/overview.md)
- [Карта проектных фактов](../docs/README.md)