12 KiB
Frontend FSD Market Pages Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Перевести market pages (home, stock, bond) и связанные market widgets в FSD-структуру без изменения пользовательского поведения и с сохранением совместимости через shim-файлы.
Architecture: Route params и orchestration загрузки данных остаются в pages/*, а UI-композиция переносится в widgets/* с явным public API. Search query-hook выделяется в отдельный entities/search slice, старые entrypoints в components/, hooks/ и плоских pages/ превращаются в re-export shims, чтобы маршруты и тесты можно было переключать постепенно.
Tech Stack: React 18, TypeScript, React Router v6, TanStack Query v5, lightweight-charts v4, Vitest, Testing Library, ESLint, Vite, Docusaurus.
Базовое состояние
- Feature branch:
codex/frontend-fsd-market-pages - Baseline verification:
npm test -w apps/frontend— PASS (36test files,198tests)npm run lint -w apps/frontend— PASSnpm run build -w apps/frontend— PASS
Карта файлов
Create
apps/frontend/src/entities/search/index.ts— public API search sliceapps/frontend/src/entities/search/model/useSearch.ts— query hook для поиска бумагapps/frontend/src/entities/search/model/useSearch.test.tsx— тесты query hook после переносаapps/frontend/src/widgets/search-bar/index.ts— public API search widgetapps/frontend/src/widgets/search-bar/ui/SearchBar.tsx— UI поиска с локальным state/dropdownapps/frontend/src/widgets/search-bar/ui/SearchBar.test.tsx— widget tests после переносаapps/frontend/src/widgets/price-chart/index.ts— public API chart widgetapps/frontend/src/widgets/price-chart/ui/PriceChart.tsx— chart widget implementationapps/frontend/src/widgets/price-chart/ui/PriceChart.test.tsx— chart tests после переносаapps/frontend/src/widgets/stock-details/index.ts— public API stock details widgetapps/frontend/src/widgets/stock-details/ui/StockDetails.tsx— stock details widgetapps/frontend/src/widgets/stock-details/ui/StockDetails.test.tsx— widget tests после переносаapps/frontend/src/widgets/bond-details/index.ts— public API bond details widgetapps/frontend/src/widgets/bond-details/ui/BondDetails.tsx— bond details widgetapps/frontend/src/widgets/bond-details/ui/BondDetails.test.tsx— widget tests после переносаapps/frontend/src/widgets/dividends-table/index.ts— public API dividends widgetapps/frontend/src/widgets/dividends-table/ui/DividendsTable.tsx— dividends table extracted from StockPageapps/frontend/src/pages/home/index.ts— public API home pageapps/frontend/src/pages/home/ui/HomePage.tsx— home page entrypointapps/frontend/src/pages/stock/index.ts— public API stock pageapps/frontend/src/pages/stock/ui/StockPage.tsx— stock page entrypoint/orchestrationapps/frontend/src/pages/bond/index.ts— public API bond pageapps/frontend/src/pages/bond/ui/BondPage.tsx— bond page entrypoint/orchestration
Modify
apps/frontend/src/app/routing/AppRoutes.tsx— переключить route imports на@/pages/home,@/pages/stock,@/pages/bondapps/frontend/src/app/layouts/AppLayout.tsx— переключить импорт SearchBar на@/widgets/search-barapps/frontend/src/components/SearchBar.tsx— re-export shimapps/frontend/src/components/SearchBar.test.tsx— перенести/обновить импорт под новый widget pathapps/frontend/src/components/PriceChart.tsx— re-export shimapps/frontend/src/components/PriceChart.test.tsx— перенести/обновить импорт под новый widget pathapps/frontend/src/components/StockDetails.tsx— re-export shimapps/frontend/src/components/StockDetails.test.tsx— перенести/обновить импорт под новый widget pathapps/frontend/src/components/BondDetails.tsx— re-export shimapps/frontend/src/components/BondDetails.test.tsx— перенести/обновить импорт под новый widget pathapps/frontend/src/hooks/useSearch.ts— re-export shimapps/frontend/src/hooks/useSearch.test.tsx— перенести/обновить импорт под новый entity pathapps/frontend/src/pages/HomePage.tsx— re-export shimapps/frontend/src/pages/HomePage.test.tsx— перенести/обновить импорт под новый page pathapps/frontend/src/pages/StockPage.tsx— re-export shimapps/frontend/src/pages/StockPage.test.tsx— перенести/обновить импорт под новый page pathapps/frontend/src/pages/BondPage.tsx— re-export shimapps/frontend/src/pages/BondPage.test.tsx— перенести/обновить импорт под новый page pathapps/docs/docs/frontend/overview.md— отразить FSD migration market pagesapps/docs/docs/frontend/components.md— обновить описание widget/component boundariesapps/docs/docs/frontend/hooks.md— убрать market search из legacy hooks как primary locationapps/docs/docs/adr/ADR-014-frontend-fsd-market-pages.md— зафиксировать стратегию второй market-итерации FSD
Целевая структура
apps/frontend/src/
├── entities/
│ └── search/
│ ├── index.ts
│ └── model/
│ ├── useSearch.ts
│ └── useSearch.test.tsx
├── widgets/
│ ├── search-bar/
│ │ ├── index.ts
│ │ └── ui/
│ │ ├── SearchBar.tsx
│ │ └── SearchBar.test.tsx
│ ├── price-chart/
│ ├── stock-details/
│ ├── bond-details/
│ └── dividends-table/
└── pages/
├── home/
│ ├── index.ts
│ └── ui/HomePage.tsx
├── stock/
│ ├── index.ts
│ └── ui/StockPage.tsx
└── bond/
├── index.ts
└── ui/BondPage.tsx
Потоки данных
Stock page
Route /stocks/:secid
→ pages/stock/ui/StockPage.tsx
→ useStock(secid) + useStockCandles(secid, interval, from, till) + useStockDividends(secid)
→ widgets/stock-details + widgets/price-chart + widgets/dividends-table
Bond page
Route /bonds/:secid
→ pages/bond/ui/BondPage.tsx
→ useBond(secid) + useBondCandles(secid, interval, from, till)
→ widgets/bond-details + widgets/price-chart
Search flow
AppLayout
→ widgets/search-bar/ui/SearchBar.tsx
→ entities/search/model/useSearch(debouncedQuery)
→ shared/api/client.searchSecurities(query)
→ navigate('/stocks/:secid' | '/bonds/:secid')
Этапы реализации
Phase 1: Search entity и SearchBar widget
- Создать
entities/search/model/useSearch.ts, перенеся текущий hook изsrc/hooks/useSearch.tsбез измененияqueryKey,enabled,staleTimeи response mapping. - Создать
entities/search/index.tsи экспортироватьuseSearchтолько через public API. - Перенести
SearchBar.tsxвwidgets/search-bar/ui/SearchBar.tsx, сохранив локальное состояниеquery,debounced,open, обработчик клика вне dropdown и navigate-логику. - Добавить
widgets/search-bar/index.ts. - Старые
src/hooks/useSearch.tsиsrc/components/SearchBar.tsxпревратить в re-export shims. - Переместить и адаптировать тесты
useSearch.test.tsxиSearchBar.test.tsxтак, чтобы они проверяли новые public entrypoints. - Переключить
app/layouts/AppLayout.tsxна импорт@/widgets/search-bar.
Phase 2: Market widgets
- Перенести
PriceChart.tsxвwidgets/price-chart/ui/PriceChart.tsxбез изменения работы сlightweight-charts. - Перенести
StockDetails.tsxиBondDetails.tsxвwidgets/stock-details/ui/StockDetails.tsxиwidgets/bond-details/ui/BondDetails.tsx. - Создать
widgets/dividends-table/ui/DividendsTable.tsx, выделив таблицу дивидендов изStockPage.tsxбез изменения разметки, заголовков и форматирования значений. - Добавить
index.tsдля каждого widget slice. - Старые
src/components/PriceChart.tsx,StockDetails.tsx,BondDetails.tsxпревратить в re-export shims. - Перенести widget tests рядом с новыми реализациями и оставить старые тестовые файлы либо как shim-import consumers, либо обновить их на новые public entrypoints без дублирования покрытия.
Phase 3: Market pages и route imports
- Создать
pages/home/ui/HomePage.tsxиpages/home/index.ts, сохранив текущее статическое содержимое главной страницы. - Создать
pages/stock/ui/StockPage.tsxиpages/stock/index.ts, оставив в page orchestration:- чтение
secidизuseParams - расчёт
from/till - вызовы
useStock,useStockCandles,useStockDividends - состояния loading/not-found
- передачу готовых props в widgets
- чтение
- Создать
pages/bond/ui/BondPage.tsxиpages/bond/index.tsпо той же схеме дляuseBondиuseBondCandles. - Переключить
app/routing/AppRoutes.tsxна новые page public entrypoints. - Старые
src/pages/HomePage.tsx,StockPage.tsx,BondPage.tsxпревратить в re-export shims. - Обновить page tests, чтобы они импортировали новые page entrypoints и подтверждали эквивалентность поведения.
Phase 4: Documentation, ADR и финальная verification
- Создать
apps/docs/docs/adr/ADR-014-frontend-fsd-market-pages.mdс секциями Context / Options / Decision / Consequences. - Обновить
apps/docs/docs/frontend/overview.md,components.md,hooks.md, чтобы опубликованная документация отражала market FSD slices и shim-стратегию coexistence. - Проверить, что новые public API не требуют deep imports из
model/илиui/во внешнем коде. - Выполнить финальную verification:
npm test -w apps/frontendnpm run lint -w apps/frontendnpm run build -w apps/frontendnpm run build -w apps/docs
Риски и контрольные точки
PriceChartчувствителен к ref/effect lifecycle. При переносе важно не менять cleanup и порядок инициализации chart series.SearchBarиспользуется вAppLayout, поэтому ошибки в импорт-пути сразу затронут почти все route-level tests.StockPage/BondPageвычисляют даты inline. В этой фиче это остаётся в page-layer и не выносится в shared util, чтобы не расширять scope.- Legacy shims должны оставаться тонкими re-export файлами без дополнительной логики.
Критерии завершения плана
- Все acceptance criteria из
spec.mdсопоставлены задачам реализации. - Новая market-структура использует только public API между
pages,widgetsиentities. - Frontend tests, lint и build проходят после миграции.
- ADR и frontend docs синхронизированы с новой структурой.