Files
frontend/.ai/architecture.md
T
codex-bot e2d143df46
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 12s
Frontend verify / verify (push) Failing after 7m51s
refactor: move portfolio structure into account page, drop widgets (WealthLedger/frontend#139) (#140)
2026-11-04 18:01:00 +03:00

6.9 KiB
Raw Blame History

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, реализация — source of truth.

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 задаёт 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 остаются у 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 и запрет соседних slices в pages, features, entities проверяет npm run deps. Внутренние imports одного slice и связи shared segments этот запрет не ограничивает. Knip проверяет использование exports, а не смысл placement.

UI foundation

Private workspace packages/tokens экспортирует переносимый source design tokens как @wealthledger/tokens/tokens.json. Private workspace packages/ui адаптирует доверенный JSON к Mantine без runtime schema. App и Storybook читают @wealthledger/ui/theme и явно подключают @wealthledger/ui/styles.css после Mantine CSS. Потребители используют public exports пакетов напрямую. Storybook показывает synthetic presentation states, не использует application API. RTL/MSW проверяют поведение приложения отдельно.

Route-aware AppShell и его navigation styles принадлежат app/ui; ProtectedLayout использует public API этого владельца. При изменении foundation прочитай UI и Storybook.

Все SVG, их геометрия и анимации принадлежат private packages/icons. Приложение импортирует компоненты из @wealthledger/icons и подключает @wealthledger/icons/styles.css. В src нет SVG-файлов и компонентов, единственная задача которых — рисовать иконку. Domain mapping категории в параметры OperationIcon остаётся в entities/bank-card/model.

Примеры

  • Общая busy-область: существующий LoadingSkeleton, а не domain widget в shared.
  • Account-income state views: страница и её components/; новый page-local filter остаётся здесь. Комплекты файлов группируются по UI convention.
  • Portfolio query: entity public API; новая UI-сводка с бизнес-смыслом не становится shared только из-за нескольких экранов.

Проверка

После placement/import change: npm run deps, npm run typecheck, npm run knip; после собственного behavior — применимые tests. Финальный gate указан в AGENTS. Graph src и packages проверяет текущий dependency-cruiser; зависимости из packages в код приложения src запрещены. Generated packages/*/dist не анализируется как исходник; все package sources остаются в graph. Review отдельно проверяет смысл owner: разрешённый dependency graph не доказывает правильный выбор слоя.