17 KiB
Raw Blame History

Frontend FSD Shared Layer — 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: Создать FSD-слой shared/ с API-инфраструктурой и truly generic UI-компонентами, используя стратегию coexistence (re-export shims) как в broker pilot.

Architecture: Копирование файлов из api/shared/api/ и components/SkeletonBlock, components/TableSkeletonshared/ui/, превращение исходников в re-export shims, затем массовое переключение импортов на @/shared/.... Все изменения чисто структурные — поведение не меняется.

Tech Stack: React 18, TypeScript, Vite, Vitest


Карта файлов

Будут созданы

  • src/shared/api/index.ts — barrel для shared/api
  • src/shared/api/client.ts — базовый HTTP-клиент + доменные API-функции (копия api/client.ts)
  • src/shared/api/client.test.ts — тесты клиента (копия)
  • src/shared/api/responses.ts — все типы ответов (копия api/responses.ts)
  • src/shared/api/types.ts — generated OpenAPI types (копия api/types.ts)
  • src/shared/ui/index.ts — barrel для shared/ui
  • src/shared/ui/SkeletonBlock.tsx — скелетон (копия components/SkeletonBlock.tsx)
  • src/shared/ui/TableSkeleton.tsx — табличный скелетон (копия components/TableSkeleton.tsx)

Будут изменены (становятся re-export shims)

  • src/api/client.ts
  • src/api/responses.ts
  • src/api/types.ts
  • src/components/SkeletonBlock.tsx
  • src/components/TableSkeleton.tsx

Будут изменены (импорты → @/shared/)

~50 файлов в entities/, widgets/, pages/, hooks/, context/, components/, test/


Task 1: Создать shared/api/ + re-export shims

Файлы:

  • Create: src/shared/api/index.ts

  • Create: src/shared/api/client.ts

  • Create: src/shared/api/client.test.ts

  • Create: src/shared/api/responses.ts

  • Create: src/shared/api/types.ts

  • Modify: src/api/client.ts → re-export shim

  • Modify: src/api/responses.ts → re-export shim

  • Modify: src/api/types.ts → re-export shim

  • Step 1: Создать shared/api/ директорию

mkdir -p apps/frontend/src/shared/api
  • Step 2: Скопировать api/client.ts в shared/api/client.ts
cp apps/frontend/src/api/client.ts apps/frontend/src/shared/api/client.ts
cp apps/frontend/src/api/client.test.ts apps/frontend/src/shared/api/client.test.ts
  • Step 3: Скопировать api/responses.ts в shared/api/responses.ts
cp apps/frontend/src/api/responses.ts apps/frontend/src/shared/api/responses.ts
  • Step 4: Скопировать api/types.ts в shared/api/types.ts
cp apps/frontend/src/api/types.ts apps/frontend/src/shared/api/types.ts
  • Step 5: Создать shared/api/index.ts barrel
export { request, setAccessToken, getAccessToken, setOnUnauthorized, getHealth, searchSecurities, getShare, getShareMarketData, getShareDividends, getShareHistory, getBond, getBondMarketData, getBondHistory, getShareCandles, getBondCandles } from './client';
export type { ApiResponseMeta, ApiEnvelope, StockMarketData, ShareResponse, DividendItem, ShareHistoryItem, BondMarketData, BondResponse, BondHistoryItem, CandleItem, SearchResultItem, HealthResponse, UserResponse, AuthResponse, Portfolio, PositionWithPrice, PortfolioDetail, Position, PortfolioSummary, AnalyticsResponse, ScreenerItem, ScreenerResult, BrokerMoney, BrokerAccount, BrokerPosition, BrokerPortfolio, BrokerOperationCategory, BrokerOperation, BrokerOperationsPage, BrokerPositionsPage } from './responses';
  • Step 6: Превратить api/client.ts в re-export shim
export { request, setAccessToken, getAccessToken, setOnUnauthorized, getHealth, searchSecurities, getShare, getShareMarketData, getShareDividends, getShareHistory, getBond, getBondMarketData, getBondHistory, getShareCandles, getBondCandles } from '../shared/api/client';
  • Step 7: Превратить api/responses.ts в re-export shim
export type { ApiResponseMeta, ApiEnvelope, StockMarketData, ShareResponse, DividendItem, ShareHistoryItem, BondMarketData, BondResponse, BondHistoryItem, CandleItem, SearchResultItem, HealthResponse, UserResponse, AuthResponse, Portfolio, PositionWithPrice, PortfolioDetail, Position, PortfolioSummary, AnalyticsResponse, ScreenerItem, ScreenerResult, BrokerMoney, BrokerAccount, BrokerPosition, BrokerPortfolio, BrokerOperationCategory, BrokerOperation, BrokerOperationsPage, BrokerPositionsPage } from '../shared/api/responses';
  • Step 8: Превратить api/types.ts в re-export shim
export * from '../shared/api/types';
  • Step 9: Проверить, что тесты проходят

Run: npm test -w apps/frontend Expected: PASS

  • Step 10: Закоммитить
git add apps/frontend/src/shared/api apps/frontend/src/api/client.ts apps/frontend/src/api/responses.ts apps/frontend/src/api/types.ts
git commit -m "refactor(frontend): create shared/api layer with re-export shims"

Task 2: Создать shared/ui/ + re-export shims

Файлы:

  • Create: src/shared/ui/index.ts

  • Create: src/shared/ui/SkeletonBlock.tsx

  • Create: src/shared/ui/TableSkeleton.tsx

  • Modify: src/components/SkeletonBlock.tsx → re-export shim

  • Modify: src/components/TableSkeleton.tsx → re-export shim

  • Step 1: Создать shared/ui/ директорию

mkdir -p apps/frontend/src/shared/ui
  • Step 2: Скопировать SkeletonBlock и TableSkeleton в shared/ui/
cp apps/frontend/src/components/SkeletonBlock.tsx apps/frontend/src/shared/ui/SkeletonBlock.tsx
cp apps/frontend/src/components/TableSkeleton.tsx apps/frontend/src/shared/ui/TableSkeleton.tsx
  • Step 3: Обновить shared/ui/TableSkeleton.tsx — импорт SkeletonBlock из shared/ui
// replace: import { SkeletonBlock } from './SkeletonBlock';
// with:    import { SkeletonBlock } from '@/shared/ui/SkeletonBlock';

Edit apps/frontend/src/shared/ui/TableSkeleton.tsx line 1:

import { SkeletonBlock } from './SkeletonBlock';  →  import { SkeletonBlock } from '@/shared/ui/SkeletonBlock';
  • Step 4: Создать shared/ui/index.ts barrel
export { SkeletonBlock } from './SkeletonBlock';
export { TableSkeleton } from './TableSkeleton';
  • Step 5: Превратить components/SkeletonBlock.tsx в re-export shim
export { SkeletonBlock } from '../shared/ui/SkeletonBlock';
  • Step 6: Превратить components/TableSkeleton.tsx в re-export shim
export { TableSkeleton } from '../shared/ui/TableSkeleton';
  • Step 7: Проверить, что тесты проходят

Run: npm test -w apps/frontend Expected: PASS

  • Step 8: Закоммитить
git add apps/frontend/src/shared/ui apps/frontend/src/components/SkeletonBlock.tsx apps/frontend/src/components/TableSkeleton.tsx
git commit -m "refactor(frontend): create shared/ui layer with skeleton components"

Task 3: Переключить импорты FSD entities/widgets/pages на @/shared/

Файлы: Все файлы в entities/, widgets/, pages/ (FSD-части), которые импортируют из api/client, api/responses, components/SkeletonBlock, components/TableSkeleton.

Замена:

  • from '../../../api/responses'from '@/shared/api/responses'

  • from '../../../api/client'from '@/shared/api/client'

  • from '../../api/responses'from '@/shared/api/responses'

  • from '../../api/client'from '@/shared/api/client'

  • from '../../../components/SkeletonBlock'from '@/shared/ui/SkeletonBlock'

  • from '../../../components/TableSkeleton'from '@/shared/ui/TableSkeleton'

  • from '../../components/SkeletonBlock'from '@/shared/ui/SkeletonBlock'

  • from '../../components/TableSkeleton'from '@/shared/ui/TableSkeleton'

  • Step 1: Заменить импорты в entities/

cd apps/frontend/src/entities
# api/responses → @/shared/api/responses (relative depth 3: ../../../)
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./api/responses'|from '@/shared/api/responses'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./api/client'|from '@/shared/api/client'|g"
  • Step 2: Заменить импорты в widgets/
cd apps/frontend/src/widgets
# api/responses → @/shared/api/responses (relative depth 3: ../../../)
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./api/responses'|from '@/shared/api/responses'|g"
# components/SkeletonBlock → @/shared/ui/SkeletonBlock (relative depth 3)
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./components/SkeletonBlock'|from '@/shared/ui/SkeletonBlock'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./components/TableSkeleton'|from '@/shared/ui/TableSkeleton'|g"
  • Step 3: Заменить импорты в pages/ (FSD-страницы)
cd apps/frontend/src/pages
# api/responses → @/shared/api/responses (from pages/broker-*/ and pages/broker-positions/)
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./api/responses'|from '@/shared/api/responses'|g"
# components/SkeletonBlock → @/shared/ui/SkeletonBlock
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./components/SkeletonBlock'|from '@/shared/ui/SkeletonBlock'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./\.\./components/TableSkeleton'|from '@/shared/ui/TableSkeleton'|g"

Files matched and updated:

  • entities/broker-account/api/brokerAccountApi.ts — 2 импорта

  • entities/broker-account/model/brokerAccountsOverview.ts — 1 импорт

  • entities/broker-account/model/brokerAccountsOverview.test.ts — 1 импорт

  • entities/broker-account/model/useBrokerAccounts.ts — 1 импорт

  • entities/broker-account/model/useBrokerAccountPortfolios.ts — 1 импорт

  • entities/broker-account/model/useBrokerPortfolio.ts — 1 импорт

  • entities/broker-position/model/useBrokerPositions.ts — 1 импорт

  • entities/broker-position/model/brokerDisplay.ts — 1 импорт

  • entities/broker-position/model/brokerDisplay.test.ts — 1 импорт

  • entities/broker-position/model/brokerAllocation.ts — 1 импорт

  • entities/broker-position/model/brokerAllocation.test.ts — 1 импорт

  • entities/broker-operation/model/useBrokerOperations.ts — 1 импорт

  • entities/broker-operation/model/operationFilters.ts — 1 импорт

  • widgets/broker-account-card/ui/BrokerAccountCard.tsx — 1 импорт + SkeletonBlock

  • widgets/broker-accounts-summary/ui/BrokerAccountsSummary.tsx — SkeletonBlock

  • widgets/broker-allocation-chart/ui/BrokerAllocationChart.tsx — 1 импорт

  • widgets/broker-operations-table/ui/BrokerOperationsTable.tsx — 1 импорт + TableSkeleton

  • pages/broker-account/ui/BrokerAccountOverviewPage.tsx — 1 импорт + SkeletonBlock

  • pages/broker-positions/ui/BrokerPositionsPage.tsx — 1 импорт + TableSkeleton

  • Step 4: Проверить, что заменилось корректно

cd apps/frontend/src
rg "from '\.\./\.\./\.\./api/(responses|client)'" --include '*.ts' --include '*.tsx' entities widgets pages
rg "from '\.\./\.\./\.\./components/(SkeletonBlock|TableSkeleton)'" --include '*.ts' --include '*.tsx' entities widgets pages

Expected: no matches (все импорты заменены)

  • Step 5: Проверить, что тесты проходят

Run: npm test -w apps/frontend Expected: PASS

  • Step 6: Закоммитить
git add -u apps/frontend/src/entities apps/frontend/src/widgets apps/frontend/src/pages
git commit -m "refactor(frontend): update fsd entities imports to use @/shared/"

Task 4: Переключить legacy импорты на @/shared/

Файлы: hooks/, context/, components/ (legacy каталоги), pages/ (legacy страницы), test/, которые импортируют из api/client, api/responses, api/types с относительными путями ../ или ../../.

Замена:

  • from '../api/responses'from '@/shared/api/responses'

  • from '../api/client'from '@/shared/api/client'

  • from '../api/types'from '@/shared/api/types'

  • from '../../api/responses'from '@/shared/api/responses'

  • from '../../api/client'from '@/shared/api/client'

  • Step 1: Заменить импорты в hooks/

cd apps/frontend/src/hooks
# ../api/ → @/shared/api/
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/responses'|from '@/shared/api/responses'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/client'|from '@/shared/api/client'|g"
  • Step 2: Заменить импорты в context/
cd apps/frontend/src/context
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/responses'|from '@/shared/api/responses'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/client'|from '@/shared/api/client'|g"
  • Step 3: Заменить импорты в components/ (кроме shims)
cd apps/frontend/src/components
# api/responses может быть на глубине ../ или ../../
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/responses'|from '@/shared/api/responses'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./api/responses'|from '@/shared/api/responses'|g"
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./api/client'|from '@/shared/api/client'|g"
  • Step 4: Заменить импорты в pages/ (legacy страницы, не FSD)

Legacy страницы на глубине ../../ от pages/broker/ и ../../ от pages/portfolios/:

cd apps/frontend/src/pages/broker
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./\.\./api/responses'|from '@/shared/api/responses'|g"
  • Step 5: Заменить импорты в test/
cd apps/frontend/src/test
find . -name '*.ts' -o -name '*.tsx' | xargs sed -i '' "s|from '\.\./api/responses'|from '@/shared/api/responses'|g"
  • Step 6: Проверить, что не осталось относительных импортов из api/client или api/responses
cd apps/frontend/src
rg "from '\.\./api/(responses|client|types)'" --include '*.ts' --include '*.tsx'
rg "from '\.\./\.\./api/(responses|client|types)'" --include '*.ts' --include '*.tsx'
rg "from '\.\./\.\./\.\./api/(responses|client|types)'" --include '*.ts' --include '*.tsx'

Expected: only shim files in api/ itself may still have ../shared/api/ — that's correct.

  • Step 7: Проверить, что тесты проходят

Run: npm test -w apps/frontend Expected: PASS

  • Step 8: Закоммитить
git add -u apps/frontend/src/hooks apps/frontend/src/context apps/frontend/src/components apps/frontend/src/pages apps/frontend/src/test
git commit -m "refactor(frontend): update legacy imports to use @/shared/"

Task 5: Финальная верификация

  • Step 1: Полный прогон тестов

Run: npm test -w apps/frontend Expected: PASS

  • Step 2: Проверить lint

Run: npm run lint -w apps/frontend Expected: PASS

  • Step 3: Проверить build

Run: npm run build -w apps/frontend Expected: PASS

  • Step 4: Проверить, что все импорты корректны
cd apps/frontend/src
# Должны остаться ТОЛЬКО импорты из api/auth, api/broker, api/portfolio, api/screener (не moved)
rg "from '\.\./(\.\./)*api/(responses|client|types)'" --include '*.ts' --include '*.tsx'

Expected: 0 matches (кроме shim-файлов в api/)

  • Step 5: Обновить tasks.md

  • Step 6: Финальный коммит

git add -A apps/frontend
git commit -m "refactor(frontend): complete shared layer migration"