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`
подключают 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
```
`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 границы.
[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 читают
@@ -31,4 +63,20 @@ public API `shared/theme`. Storybook показывает synthetic presentation
Existing route-aware AppShell расположен в shared/ui; это legacy placement,
а не образец нового 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;
[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.
-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` проверяют
типы, изоляцию и сборку. Build не выполняет `play` как CI interaction suite;
для проверки interaction открой story в браузере, для regression используй
существующий [Testing](frontend-testing.md). Визуальное соответствие задаче,
существующий [Testing](testing.md). Визуальное соответствие задаче,
keyboard и узкий viewport проверяются отдельно от успешной сборки.
+4 -4
View File
@@ -27,7 +27,7 @@ Hooks вызываются без условий и ранних выходов
контракту стабильной identity; не добавляй их ко всем значениям/handlers.
React Compiler включён в Vite, но не доказывает выигрыш и не заменяет effect
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
@@ -39,15 +39,15 @@ Backend vocabulary бери из generated `paths`, не создавай руч
`ProblemDetailsDto.code` сейчас `string`. Не объявляй закрытый frontend error
enum и не превращай неизвестный code в известный через cast. Повторяющуюся
обработку своди у ответственного owner; [errors](frontend-data.md#errors).
обработку своди у ответственного owner; [errors](data.md#errors).
`noMagicNumbers` в Biome — error; fixtures/tests/stories исключены только
из этого правила. Policy получает имя и единицы; подавление допустимо для
incidental value с объяснением. Обычный UI-текст не превращай в constant:
его owner — [i18n](frontend-ui.md#строки-и-валидация).
его owner — [i18n](ui.md#строки-и-валидация).
Semantic magic strings и props profile требуют review.
## Проверка
`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 |
| Параметр навигации, который должен переживать переход/ссылку | Router/URL |
| Локальное открытие, 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/изменения тестов
используй [Testing](frontend-testing.md). UI: keyboard, narrow viewport,
используй [Testing](testing.md). UI: keyboard, narrow viewport,
loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога;
сверяй UI с задачей отдельно от build.
+23 -10
View File
@@ -2,21 +2,20 @@
Общие инструкции — [workspace AGENTS](../AGENTS.md). Объединяй triggers задачи,
путей и обнаруженных boundaries; читай только нужные темы до решения.
[Sources](.ai/SOURCES.md) выбирает факты/spec/ADR по возникшему вопросу.
Системные факты/spec/ADR выбирай в разделе [Источники](#источники) по вопросу.
| Решение / сигнал | Читать |
| --- | --- |
| Первое знакомство, data flow, общая архитектура | [Mental model](.ai/architecture.md) |
| Создать/перенести component/module/slice, owner/FSD, cross-slice imports | [FSD](.ai/conventions/frontend-architecture.md) |
| Устройство/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/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) |
| 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/frontend-testing.md) |
| Storybook/stories/play, theme/tokens/shared UI | [Storybook](.ai/conventions/storybook.md), UI; design facts — через Sources |
| 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) |
@@ -24,3 +23,17 @@
Testing и без production diff. Повтори routing по итоговому diff, включая новые
файлы. Migration backlog читается только при работе над соответствующим finding
через [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)
- [Выбор 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)