# FSD Frontend Refactor ## Цель Довести фронтенд-архитектуру до эталонного Feature-Sliced Design (FSD) — устранить существующие нарушения, вынести жирные страницы в виджеты/фичи, внедрить автоматический контроль FSD-правил. Текущее состояние: 4.2/5 по FSD-зрелости. Цель: 5/5. ## Задачи ### 1. Исправить нарушение слоёв в shared/lib/test - `shared/lib/test/test-utils.tsx` импортирует `SessionProvider` из `@/app/providers` - Это единственное нарушение FSD (shared → app) - Решение: вынести `TestSessionProvider` в `shared/lib/test/` и переключить `test-utils.tsx` на него - Тесты не должны сломаться: `TestSessionProvider` предоставляет те же значения контекста (замоканые) ### 2. Вынести BrokerPositionTable из страницы в виджет - `pages/broker-positions/ui/BrokerPositionsPage.tsx` (310 строк) содержит внутренние компоненты: - `BrokerPositionTable` (~190 строк) — таблица с пагинацией, skeleton, inline-стилями - `PositionTicker` (~20 строк) — ссылка на инструмент - `formatQuantity` — хелпер - Решение: создать `widgets/broker-positions-table/` с: - `ui/BrokerPositionTable.tsx` - `ui/PositionTicker.tsx` - `index.ts` - Страница сокращается до ~100 строк (только cursor-логика + композиция) ### 3. Вынести BrokerSummary, BrokerAssetCards, BrokerOverviewSkeleton в виджет - `pages/broker-account/ui/BrokerAccountOverviewPage.tsx` (160 строк) содержит: - `BrokerSummary` — сводка портфеля (карточки стоимости и денег) - `BrokerAssetCards` — карточки классов активов (акции/облигации) - `BrokerOverviewSkeleton` — скелетон загрузки - `allocationPercent`, `formatAllocationPercent` — хелперы - Решение: создать `widgets/broker-overview/` с: - `ui/BrokerSummary.tsx` - `ui/BrokerAssetCards.tsx` - `ui/BrokerOverviewSkeleton.tsx` - `index.ts` - Страница сокращается до ~40 строк (только loading/error guard + композиция) ### 4. Вынести AddPositionForm в фичу - `pages/portfolios/ui/PortfolioDetailPage.tsx` (290 строк) содержит inline-форму добавления позиции: - 4 state-переменные (newSecid, newQty, newPrice, newDate) - 4 input-поля с inline-стилями - Валидация и submit - Это полноценная бизнес-фича, не место в странице - Решение: создать `features/add-position/` с: - `api/useAddPosition.ts` — мутация (обёртка над usePositionMutations) - `model/useAddPositionForm.ts` — управление формой - `ui/AddPositionForm.tsx` — UI формы - `index.ts` - Страница сокращается до ~140 строк (showAddForm toggle + ``) ### 5. Вынести cursor-пагинацию в shared-хук - 25 строк cursor-логики дублируются в: - `pages/broker-positions/ui/BrokerPositionsPage.tsx` - `pages/broker-operations/ui/BrokerOperationsPage.tsx` - Решение: создать `shared/lib/useCursorPagination.ts` ```ts function useCursorPagination() { // cursor, pageNumber, handleNext(cursor), handlePrevious, reset } ``` ### 6. Добавить ESLint-плагин FSD - Текущий `import/no-restricted-paths` проверяет только межслойные границы - Плагин `@conarti/eslint-plugin-feature-sliced` добавит: - Проверки public API (запрет импорта из внутренних модулей в обход index.ts) - Проверки сегментов (api/ui/model не импортируют друг друга напрямую) - Решение: установить плагин и включить recommended rules ## Критерии приёмки (Acceptance Criteria) - [ ] AC1: `test-utils.tsx` не импортирует из `@/app/*` - [ ] AC2: `widgets/broker-positions-table` создан, страница использует его - [ ] AC3: `widgets/broker-overview` создан, страница использует его - [ ] AC4: `features/add-position` создана, страница использует её - [ ] AC5: `shared/lib/useCursorPagination.ts` создан, обе страницы используют его - [ ] AC6: `@conarti/eslint-plugin-feature-sliced` установлен и настроен - [ ] AC7: `npm run lint` проходит без ошибок - [ ] AC8: `npm run build` проходит без ошибок - [ ] AC9: Все существующие тесты проходят (включая тесты рефакторимых компонентов) - [ ] AC10: Визуально поведение страниц не изменилось ## Ограничения - Не менять API-контракты компонентов (пропсы, типы). Только перемещение кода. - Не добавлять новую функциональность — только рефакторинг. - inline-стили переносятся вместе с компонентами; централизация UI-кита — отдельная задача.