docs: simplify conventions layout
Frontend security / security (pull_request) Successful in 8s
Frontend verify / verify (pull_request) Successful in 3m53s
Conventional commits / commits (pull_request) Successful in 19s
Frontend security / security (push) Successful in 8s
Frontend verify / verify (push) Successful in 3m53s

This commit was merged in pull request #14.
This commit is contained in:
2026-09-15 05:58:31 +03:00
parent 718365cd5a
commit 9f7e342333
11 changed files with 93 additions and 114 deletions
-9
View File
@@ -1,9 +0,0 @@
# Frontend conventions: вход
Актуальный routing по задаче, пути и boundary находится в [AGENTS](../AGENTS.md).
Выбирай только активированные темы; при новой границе повтори routing.
[Architecture](architecture.md) объясняет mental model, [SOURCES](SOURCES.md)
ведёт к системным фактам, specifications и ADR по конкретному вопросу.
Этот адрес сохранён для существующих входящих ссылок; второй копии правил
и таблицы маршрутов здесь нет.
-18
View File
@@ -1,18 +0,0 @@
# Источники frontend
| Что нужно установить | Владелец |
| --- | --- |
| Какое 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) |
| Значение 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 по догадке.
+57 -9
View File
@@ -1,4 +1,6 @@
# Frontend mental model # Frontend architecture
## Устройство и data flow
React + TypeScript + Vite SPA. Router задаёт navigation; providers в `app` React + TypeScript + Vite SPA. Router задаёт navigation; providers в `app`
подключают auth, TanStack Query, i18n и Mantine. Vite использует React Compiler; подключают auth, TanStack Query, i18n и Mantine. Vite использует React Compiler;
@@ -12,17 +14,47 @@ page container → page VM → entity/feature query → shared/api → backend /
props → state/section views 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 собирает данные Server state и lifecycle запроса принадлежат TanStack Query; VM собирает данные
для view. Transport — `openapi-fetch`/`openapi-react-query`, типизированные из для view. Transport — `openapi-fetch`/`openapi-react-query`, типизированные из
предоставленного snapshot через `openapi-typescript`. Backend владеет wire предоставленного snapshot через `openapi-typescript`. Backend владеет wire
contract; frontend не читает его checkout для генерации и не вызывает T-Bank. contract; frontend не читает его checkout для генерации и не вызывает T-Bank.
[Data convention](conventions/frontend-data.md) задаёт auth/cache границы. [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` `shared/theme/tokens.json` — переносимый source design tokens; `theme.ts`
адаптирует доверенный JSON к Mantine без runtime schema. App и Storybook читают адаптирует доверенный JSON к Mantine без runtime schema. App и Storybook читают
@@ -31,4 +63,20 @@ public API `shared/theme`. Storybook показывает synthetic presentation
Existing route-aware AppShell расположен в shared/ui; это legacy placement, Existing route-aware AppShell расположен в shared/ui; это legacy placement,
а не образец нового shared primitive. Общий план улучшений читается только а не образец нового shared primitive. Общий план улучшений читается только
при migration через [router](CONVENTIONS.md). при 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 не доказывает
правильный выбор слоя.
@@ -74,7 +74,7 @@ Network/unknown error получает безопасное локальное
[usePortfolio](../../src/entities/portfolio/api/usePortfolio.ts) — entity query; [usePortfolio](../../src/entities/portfolio/api/usePortfolio.ts) — entity query;
[shared client](../../src/shared/api/client.ts) — transport/auth boundary. [shared client](../../src/shared/api/client.ts) — transport/auth boundary.
Изменяя header/retry/invalidation, проверяй наблюдаемое поведение через MSW и Изменяя header/retry/invalidation, проверяй наблюдаемое поведение через MSW и
[Testing](frontend-testing.md); не обращайся к реальному T-Bank. [Testing](testing.md); не обращайся к реальному T-Bank.
`npm run openapi:check`, `npm run typecheck` и targeted tests проверяют разные `npm run openapi:check`, `npm run typecheck` и targeted tests проверяют разные
части решения. Для API semantics нужны exact docs и проверки наблюдаемого части решения. Для API semantics нужны exact docs и проверки наблюдаемого
HTTP-поведения на стороне backend. HTTP-поведения на стороне backend.
-55
View File
@@ -1,55 +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 не
импортирует внутренний файл напрямую. Slices `pages`, `features`, `entities` не зависят от соседнего slice своего слоя;
композиция принадлежит вышележащему owner. Existing меж-slice исключения
не являются разрешением добавлять новые.
Направление зависимостей и public imports частично проверяет
`npm run deps`; Knip проверяет использование exports, а не смысл placement.
## UI foundation
Mental model, theme и data flow — в [architecture](../architecture.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 не доказывает
правильный выбор слоя.
+1 -1
View File
@@ -29,5 +29,5 @@ RTL suite и не тестируй внутренности Mantine. Сущес
`npm run typecheck`, `npm run deps:storybook`, `npm run build:catalog` проверяют `npm run typecheck`, `npm run deps:storybook`, `npm run build:catalog` проверяют
типы, изоляцию и сборку. Build не выполняет `play` как CI interaction suite; типы, изоляцию и сборку. Build не выполняет `play` как CI interaction suite;
для проверки interaction открой story в браузере, для regression используй для проверки interaction открой story в браузере, для regression используй
существующий [Testing](frontend-testing.md). Визуальное соответствие задаче, существующий [Testing](testing.md). Визуальное соответствие задаче,
keyboard и узкий viewport проверяются отдельно от успешной сборки. keyboard и узкий viewport проверяются отдельно от успешной сборки.
+4 -4
View File
@@ -27,7 +27,7 @@ Hooks вызываются без условий и ранних выходов
контракту стабильной identity; не добавляй их ко всем значениям/handlers. контракту стабильной identity; не добавляй их ко всем значениям/handlers.
React Compiler включён в Vite, но не доказывает выигрыш и не заменяет effect React Compiler включён в Vite, но не доказывает выигрыш и не заменяет effect
correctness. Не удаляй существующую memoization без понимания её consumers. correctness. Не удаляй существующую memoization без понимания её consumers.
Container/VM/view и state owners — в [UI](frontend-ui.md). Container/VM/view и state owners — в [UI](ui.md).
## Domain literals and magic values ## Domain literals and magic values
@@ -39,15 +39,15 @@ Backend vocabulary бери из generated `paths`, не создавай руч
`ProblemDetailsDto.code` сейчас `string`. Не объявляй закрытый frontend error `ProblemDetailsDto.code` сейчас `string`. Не объявляй закрытый frontend error
enum и не превращай неизвестный code в известный через cast. Повторяющуюся enum и не превращай неизвестный code в известный через cast. Повторяющуюся
обработку своди у ответственного owner; [errors](frontend-data.md#errors). обработку своди у ответственного owner; [errors](data.md#errors).
`noMagicNumbers` в Biome — error; fixtures/tests/stories исключены только `noMagicNumbers` в Biome — error; fixtures/tests/stories исключены только
из этого правила. Policy получает имя и единицы; подавление допустимо для из этого правила. Policy получает имя и единицы; подавление допустимо для
incidental value с объяснением. Обычный UI-текст не превращай в constant: incidental value с объяснением. Обычный UI-текст не превращай в constant:
его owner — [i18n](frontend-ui.md#строки-и-валидация). его owner — [i18n](ui.md#строки-и-валидация).
Semantic magic strings и props profile требуют review. Semantic magic strings и props profile требуют review.
## Проверка ## Проверка
`npm run typecheck` и `npm run lint`; behavior проверяй по `npm run typecheck` и `npm run lint`; behavior проверяй по
[Testing](frontend-testing.md), placement — по [FSD](frontend-architecture.md). [Testing](testing.md), placement — по [FSD](../architecture.md).
@@ -22,7 +22,7 @@ Wrapper нужен для проектной ответственности, а
| Состояние | Владелец | | Состояние | Владелец |
| --- | --- | | --- | --- |
| Ответ сервера / query lifecycle | TanStack Query, [data rules](frontend-data.md) | | Ответ сервера / query lifecycle | TanStack Query, [data rules](data.md) |
| Ввод и ошибки формы | React Hook Form + Zod, container/VM | | Ввод и ошибки формы | React Hook Form + Zod, container/VM |
| Параметр навигации, который должен переживать переход/ссылку | Router/URL | | Параметр навигации, который должен переживать переход/ссылку | Router/URL |
| Локальное открытие, focus, rendering fallback | React UI state | | Локальное открытие, focus, rendering fallback | React UI state |
@@ -101,6 +101,6 @@ Types, props, hooks и memoization — в [TypeScript/React](typescript-react.md
## Проверка ## Проверка
Type/style: `npm run typecheck`, `npm run lint`. Для risk behavior/изменения тестов Type/style: `npm run typecheck`, `npm run lint`. Для risk behavior/изменения тестов
используй [Testing](frontend-testing.md). UI: keyboard, narrow viewport, используй [Testing](testing.md). UI: keyboard, narrow viewport,
loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога; loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога;
сверяй UI с задачей отдельно от build. сверяй UI с задачей отдельно от build.
+23 -10
View File
@@ -2,21 +2,20 @@
Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи, Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи,
путей и обнаруженных boundaries; читай только нужные темы до решения. путей и обнаруженных boundaries; читай только нужные темы до решения.
[Sources](.ai/SOURCES.md) выбирает факты/spec/ADR по возникшему вопросу. Системные факты/spec/ADR выбирай в разделе [Источники](#источники) по вопросу.
| Решение / сигнал | Читать | | Решение / сигнал | Читать |
| --- | --- | | --- | --- |
| Первое знакомство, data flow, общая архитектура | [Mental model](.ai/architecture.md) | | Устройство/data flow, component/module/slice, owner/FSD, cross-slice imports | [Architecture](.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) | | 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) | | UI/Mantine, form, container/VM/view, state owner, loading/error/recovery | [UI](.ai/conventions/ui.md) |
| Только продуктовая строка / Zod message | [Строки](.ai/conventions/frontend-ui.md#строки-и-валидация) | | Только продуктовая строка / Zod message | [Строки](.ai/conventions/ui.md#строки-и-валидация) |
| Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/frontend-data.md) | | Query/mutation, server cache, shared/api, generated types | [Data](.ai/conventions/data.md) |
| API/network/application errors, codes и сообщения | [Errors](.ai/conventions/frontend-data.md#errors) | | 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/frontend-testing.md) | | 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#источник-контракта) | | 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) | | Tests или behavior с regression risk | [Testing](.ai/conventions/testing.md) |
| Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — через Sources | | 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) | | Helper/dependency/новый pattern, refactor/scope | [Code health](../.ai/conventions/code-health.md), для пакета — [Dependencies](../.ai/conventions/dependencies.md) |
| Выбор gate, tooling, завершение | [Guardrails](../.ai/conventions/guardrails.md) | | Выбор gate, tooling, завершение | [Guardrails](../.ai/conventions/guardrails.md) |
@@ -24,3 +23,17 @@
Testing и без production diff. Повтори routing по итоговому diff, включая новые Testing и без production diff. Повтори routing по итоговому diff, включая новые
файлы. Migration backlog читается только при работе над соответствующим finding файлы. Migration backlog читается только при работе над соответствующим finding
через [plan](../.ai/migrations/conventions-v1/plan.md). через [plan](../.ai/migrations/conventions-v1/plan.md).
## Источники
Открывай только источник по возникшему вопросу; примеры кода не переопределяют
контракт. Specs задают behavior, а editable OpenAPI принадлежит backend.
| Вопрос | Источник |
| --- | --- |
| 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) - [AGENTS: правила и источники](AGENTS.md)
- [Выбор owner/FSD](.ai/conventions/frontend-architecture.md) - [Выбор owner/FSD](.ai/architecture.md)
- [UI, state, формы и компоненты](.ai/conventions/frontend-ui.md) - [UI, state, формы и компоненты](.ai/conventions/ui.md)
- [Data/API/cache](.ai/conventions/frontend-data.md) - [Data/API/cache](.ai/conventions/data.md)
- [Testing](.ai/conventions/frontend-testing.md) - [Testing](.ai/conventions/testing.md)
- [UI-каталог Storybook](#ui-каталог-storybook) - [UI-каталог Storybook](#ui-каталог-storybook)
- [Обзор поставленной системы](../docs/overview.md) - [Обзор поставленной системы](../docs/overview.md)
- [Карта проектных фактов](../docs/README.md) - [Карта проектных фактов](../docs/README.md)