# Frontend FSD — Portfolio Pages Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Migrate portfolio UI components from flat `components/portfolios/` to `widgets/` per FSD, following the broker domain pattern. **Architecture:** 6 widgets created under `widgets/`, each with `index.ts` barrel + `ui/Component.tsx`. Pages in `pages/portfolios/` switch imports to widgets. `components/portfolios/` deleted. `entities/portfolio/` unchanged. **Tech Stack:** React 18, TypeScript, Vite, Vitest --- ### Task 1: Create widget directory structure and barrel files **Files:** - Create: `apps/frontend/src/widgets/portfolio-card/index.ts` - Create: `apps/frontend/src/widgets/portfolio-form/index.ts` - Create: `apps/frontend/src/widgets/portfolio-summary/index.ts` - Create: `apps/frontend/src/widgets/portfolio-analytics/index.ts` - Create: `apps/frontend/src/widgets/share-positions-table/index.ts` - Create: `apps/frontend/src/widgets/bond-positions-table/index.ts` - Create: `apps/frontend/src/widgets/portfolio-card/ui/PortfolioCard.tsx` - Create: `apps/frontend/src/widgets/portfolio-form/ui/PortfolioForm.tsx` - Create: `apps/frontend/src/widgets/portfolio-summary/ui/PortfolioSummary.tsx` - Create: `apps/frontend/src/widgets/portfolio-summary/ui/AllocationChart.tsx` - Create: `apps/frontend/src/widgets/portfolio-analytics/ui/AnalyticsSummary.tsx` - Create: `apps/frontend/src/widgets/share-positions-table/ui/SharePositionTable.tsx` - Create: `apps/frontend/src/widgets/share-positions-table/ui/SharePositionRow.tsx` - Create: `apps/frontend/src/widgets/bond-positions-table/ui/BondPositionTable.tsx` - Create: `apps/frontend/src/widgets/bond-positions-table/ui/BondPositionRow.tsx` - [ ] **Step 1: Create all widget barrel files** ```ts // widgets/portfolio-card/index.ts export { PortfolioCard } from './ui/PortfolioCard'; ``` ```ts // widgets/portfolio-form/index.ts export { PortfolioForm } from './ui/PortfolioForm'; ``` ```ts // widgets/portfolio-summary/index.ts export { PortfolioSummary } from './ui/PortfolioSummary'; ``` ```ts // widgets/portfolio-analytics/index.ts export { AnalyticsSummary } from './ui/AnalyticsSummary'; ``` ```ts // widgets/share-positions-table/index.ts export { SharePositionTable } from './ui/SharePositionTable'; ``` ```ts // widgets/bond-positions-table/index.ts export { BondPositionTable } from './ui/BondPositionTable'; ``` - [ ] **Step 2: Copy and update imports for each component** For each component from `components/portfolios/`, copy to `widgets//ui/.tsx` and fix imports: **PortfolioCard.tsx** (copy from `components/portfolios/PortfolioCard.tsx`, no import changes needed): ```tsx // Same content as original — imports @/shared/api/responses which stays valid ``` **PortfolioForm.tsx** (copy from `components/portfolios/PortfolioForm.tsx`, no import changes): ```tsx // Same content — imports @/shared/api/responses ``` **PortfolioSummary.tsx** (copy from `components/portfolios/PortfolioSummary.tsx`, update import path): ```tsx import { AllocationChart } from './AllocationChart'; import type { PortfolioDetail } from '@/shared/api/responses'; // rest identical to original ``` **AllocationChart.tsx** (copy from `components/portfolios/AllocationChart.tsx`, no import changes): ```tsx // Same content — imports @/shared/api/responses ``` **AnalyticsSummary.tsx** (copy from `components/portfolios/AnalyticsSummary.tsx`, no import changes): ```tsx // Same content — imports @/shared/api/responses ``` **SharePositionRow.tsx** (copy from `components/portfolios/SharePositionRow.tsx`, no import changes): ```tsx // Same content — imports @/shared/api/responses ``` **SharePositionTable.tsx** (copy from `components/portfolios/SharePositionTable.tsx`, update import path): ```tsx import { SharePositionRow } from './SharePositionRow'; import type { PositionWithPrice } from '@/shared/api/responses'; // rest identical to original ``` **BondPositionRow.tsx** (copy from `components/portfolios/BondPositionRow.tsx`, no import changes): ```tsx // Same content — imports @/shared/api/responses ``` **BondPositionTable.tsx** (copy from `components/portfolios/BondPositionTable.tsx`, update import path): ```tsx import { BondPositionRow } from './BondPositionRow'; import type { PositionWithPrice } from '@/shared/api/responses'; // rest identical to original ``` - [ ] **Step 3: Verify build** Run: `npm run build -w apps/frontend` Expected: PASS - [ ] **Step 4: Run tests** Run: `npm test -w apps/frontend` Expected: PASS - [ ] **Step 5: Commit** ```bash git add apps/frontend/src/widgets/portfolio-card/ \ apps/frontend/src/widgets/portfolio-form/ \ apps/frontend/src/widgets/portfolio-summary/ \ apps/frontend/src/widgets/portfolio-analytics/ \ apps/frontend/src/widgets/share-positions-table/ \ apps/frontend/src/widgets/bond-positions-table/ git commit -m "feat(frontend): create portfolio widgets in FSD structure" ``` --- ### Task 2: Update pages to use widgets **Files:** - Modify: `apps/frontend/src/pages/portfolios/PortfoliosListPage.tsx` - Modify: `apps/frontend/src/pages/portfolios/PortfolioDetailPage.tsx` - [ ] **Step 1: Update PortfoliosListPage.tsx** ```tsx import { useState } from 'react'; import { usePortfolios, usePortfolioMutations } from '../../entities/portfolio'; import { PortfolioCard } from '../../widgets/portfolio-card'; import { PortfolioForm } from '../../widgets/portfolio-form'; ``` - [ ] **Step 2: Update PortfolioDetailPage.tsx** ```tsx import { useState } from 'react'; import { useParams, Link } from 'react-router-dom'; import { usePortfolio, usePortfolioMutations, usePositionMutations, } from '../../entities/portfolio'; import { PortfolioForm } from '../../widgets/portfolio-form'; import { PortfolioSummary } from '../../widgets/portfolio-summary'; import { AnalyticsSummary } from '../../widgets/portfolio-analytics'; import { SharePositionTable } from '../../widgets/share-positions-table'; import { BondPositionTable } from '../../widgets/bond-positions-table'; ``` - [ ] **Step 3: Verify build** Run: `npm run build -w apps/frontend` Expected: PASS - [ ] **Step 4: Run tests** Run: `npm test -w apps/frontend` Expected: PASS - [ ] **Step 5: Commit** ```bash git add apps/frontend/src/pages/portfolios/ git commit -m "refactor(frontend): switch pages/portfolios to widget imports" ``` --- ### Task 3: Remove flat components/portfolios/ **Files:** - Delete: `apps/frontend/src/components/portfolios/AllocationChart.tsx` - Delete: `apps/frontend/src/components/portfolios/AnalyticsSummary.tsx` - Delete: `apps/frontend/src/components/portfolios/BondPositionRow.tsx` - Delete: `apps/frontend/src/components/portfolios/BondPositionTable.tsx` - Delete: `apps/frontend/src/components/portfolios/PortfolioCard.tsx` - Delete: `apps/frontend/src/components/portfolios/PortfolioForm.tsx` - Delete: `apps/frontend/src/components/portfolios/PortfolioSummary.tsx` - Delete: `apps/frontend/src/components/portfolios/SharePositionRow.tsx` - Delete: `apps/frontend/src/components/portfolios/SharePositionTable.tsx` - [ ] **Step 1: Delete all files in components/portfolios/** Run: `rm apps/frontend/src/components/portfolios/*.tsx` - [ ] **Step 2: Check for remaining imports from components/portfolios** Run: `rg "components/portfolios" apps/frontend/src` Expected: no matches - [ ] **Step 3: Verify build** Run: `npm run build -w apps/frontend` Expected: PASS - [ ] **Step 4: Run tests** Run: `npm test -w apps/frontend` Expected: PASS - [ ] **Step 5: Lint check** Run: `npm run lint -w apps/frontend` Expected: PASS - [ ] **Step 6: Commit** ```bash git rm apps/frontend/src/components/portfolios/*.tsx git commit -m "refactor(frontend): remove flat components/portfolios" ``` --- ### Task 4: Update documentation **Files:** - Modify: `apps/docs/docs/frontend/hooks.md` - Modify: `apps/docs/docs/frontend/routes.md` - [ ] **Step 1: Update hooks.md** Remove any references to legacy `components/portfolios/` paths. Update import examples to use `@/widgets/portfolio-*` paths where applicable. - [ ] **Step 2: Update routes.md** Ensure portfolio route documentation reflects FSD structure. - [ ] **Step 3: Run doc build** Run: `npm run build -w apps/docs` Expected: PASS - [ ] **Step 4: Commit documentation** ```bash git add apps/docs/docs/frontend/ git commit -m "docs: update frontend docs for portfolio FSD structure" ``` --- ### Task 5: Final verification - [ ] **Step 1: Test** 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: Deep import check** Run: `rg "components/portfolios" apps/frontend/src` Expected: no matches - [ ] **Step 5: Docs build** Run: `npm run build -w apps/docs` Expected: PASS