From 7e10b4b8aa6e627de1c6f0b20a8266fef5da2869 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Tue, 23 Jun 2026 06:54:29 +0300 Subject: [PATCH] docs: update tasks and plan to reflect actual implementation progress Mark completed tasks across all 6 phases, document code-first router approach deviation, update Phase 6 plan with actual steps --- .../frontend-infrastructure-tooling/plan.md | 53 +++---- .../frontend-infrastructure-tooling/tasks.md | 140 +++++++++--------- 2 files changed, 88 insertions(+), 105 deletions(-) diff --git a/docs/features/frontend-infrastructure-tooling/plan.md b/docs/features/frontend-infrastructure-tooling/plan.md index 52b535b..f9fc584 100644 --- a/docs/features/frontend-infrastructure-tooling/plan.md +++ b/docs/features/frontend-infrastructure-tooling/plan.md @@ -70,48 +70,29 @@ ### Phase 6 — TanStack Router *Крупный, высокий риск* +> **Фактический подход: code-first вместо file-based.** +> В процессе реализации выяснилось, что `@tanstack/router-plugin` не генерирует `routeTree.gen.ts` корректно на данной версии Vite/плагина. Принято решение использовать code-first подход — все маршруты определяются вручную в `routeTree.tsx`. + 1. Установить зависимости: - `@tanstack/react-router` - `@tanstack/router-devtools` (devDependency) - - `@tanstack/router-plugin` (vite plugin) -2. Настроить Vite plugin в `vite.config.ts` -3. Создать файловую структуру роутов: - ``` - src/app/routes/ - __root.tsx — AppLayout + ErrorBoundary - index.tsx — HomePage - stocks.$secid.tsx — StockPage - bonds.$secid.tsx — BondPage - screener.tsx — ScreenerPage + Zod search params - login.tsx — LoginPage - register.tsx — RegisterPage - profile.tsx — ProfilePage (guard: beforeLoad) - portfolios.tsx — PortfoliosListPage (guard) - portfolios.$id.tsx — PortfolioDetailPage (guard) - broker/ - index.tsx — BrokerAccountsPage (guard) - $accountId/ - index.tsx — BrokerAccountOverviewPage (guard) - shares.tsx — BrokerPositionsPage (guard) - bonds.tsx — BrokerPositionsPage (guard) - operations.tsx — BrokerOperationsPage + Zod search params (guard) - events.tsx — BrokerEventsPage (guard) - ``` -4. Перенести каждый роут из `AppRoutes.tsx` — каждый файл создаёт lazy route -5. Создать роутер в `app/routing/router.ts`: - - `createRouter()` с Route Tree - - `beforeLoad` для guard'ов - - Loaders для предзагрузки (TanStack Query integration) -6. Заменить `` + `` → `` в `App.tsx` -7. Заменить все импорты `react-router-dom` по всему проекту: +2. Создать `src/app/routing/routeTree.tsx` — code-first дерево маршрутов: + - Все маршруты определены в одном файле через `createRootRoute`, `createRoute`, `createRouter` + - `beforeLoad` для guard'ов (`requireAuth`) + - Loaders для предзагрузки отложены +3. Создать `src/app/routing/router.ts`: + - `createRouter()` с Route Tree из `routeTree.tsx` +4. Заменить `` + `` → `` в `App.tsx` +5. Заменить все импорты `react-router-dom` по всему проекту: - `Link` → `Link` из `@tanstack/react-router` - - `useNavigate` → `useNavigate` + - `useNavigate` → `useNavigate({ to: '...' })` (объектный синтаксис) - `useParams` → `useParams` - - `useSearchParams` → `useSearch` + `useNavigate` + - `useSearchParams` → `useSearchParamsCompat` (временная обёртка, т.к. TanStack Router не экспортирует useSearchParams) - `useLocation` → `useLocation` -8. Заменить `MemoryRouter` в тестах на `createMemoryRouter` из TanStack Router -9. Настроить router-devtools в dev-режиме -10. Прогнать тесты +6. Заменить `MemoryRouter` в тестах на `createMemoryHistory` + `RouterProvider` +7. Обновить `test-utils.tsx` — рендер-обёртка на TanStack Router +8. Настроить router-devtools в dev-режиме +9. Прогнать тесты, проверить сборку ## Dependencies diff --git a/docs/features/frontend-infrastructure-tooling/tasks.md b/docs/features/frontend-infrastructure-tooling/tasks.md index 6b07edb..a5b80d3 100644 --- a/docs/features/frontend-infrastructure-tooling/tasks.md +++ b/docs/features/frontend-infrastructure-tooling/tasks.md @@ -2,104 +2,106 @@ ## Phase 1: ky Migration -- [ ] Доработать `shared/api/kyClient.ts`: добавить normalizeEnvelope в afterResponse hook -- [ ] Экспортировать `kyApi` (create экземпляр) и `configureKyAuth` из kyClient -- [ ] Перевести `entities/session/api/sessionApi.ts` на kyApi -- [ ] Перевести `entities/stock/api/stockApi.ts` на kyApi -- [ ] Перевести `entities/bond/api/bondApi.ts` на kyApi -- [ ] Перевести `entities/search/api/searchApi.ts` на kyApi -- [ ] Перевести `entities/portfolio/api/portfolioApi.ts` на kyApi -- [ ] Перевести `entities/broker-account/api/brokerAccountApi.ts` на kyApi -- [ ] Перевести `entities/broker-position/api/brokerPositionApi.ts` на kyApi -- [ ] Перевести `entities/broker-operation/api/brokerOperationApi.ts` на kyApi -- [ ] Перевести `entities/broker-event/api/brokerEventApi.ts` на kyApi -- [ ] Перевести `features/screener/api/screenerApi.ts` на kyApi -- [ ] Удалить `shared/api/client.ts` -- [ ] Заменить `configureAuth()` на `configureKyAuth()` в точке входа (AppProviders) -- [ ] `npm run test` — все тесты проходят -- [ ] `npm run build` — сборка проходит +- [x] Доработать `shared/api/kyClient.ts`: добавить normalizeEnvelope, request, kyApi, configureKyAuth +- [x] Экспортировать `kyApi` (create экземпляр) и `configureKyAuth` из kyClient +- [x] Перевести `entities/session/api/sessionApi.ts` на kyApi +- [x] Перевести `entities/stock/api/stockApi.ts` на kyApi +- [x] Перевести `entities/bond/api/bondApi.ts` на kyApi +- [x] Перевести `entities/search/api/searchApi.ts` на kyApi +- [x] Перевести `entities/portfolio/api/portfolioApi.ts` на kyApi +- [x] Перевести `entities/broker-account/api/brokerAccountApi.ts` на kyApi +- [x] Перевести `entities/broker-position/api/brokerPositionApi.ts` на kyApi +- [x] Перевести `entities/broker-operation/api/brokerOperationApi.ts` на kyApi +- [x] Перевести `entities/broker-event/api/brokerEventApi.ts` на kyApi +- [x] Перевести `features/screener/api/screenerApi.ts` на kyApi +- [x] Удалить `shared/api/client.ts` +- [x] Заменить `configureAuth()` на `configureKyAuth()` в SessionProvider +- [x] `npm run test` — все тесты проходят +- [x] `npm run build` — сборка проходит ## Phase 2: Biome Migration - [ ] Research: проверить Biome plugin system на поддержку FSD/import-no-restricted-paths -- [ ] Установить `@biomejs/biome` (devDependency) +- [x] Установить `@biomejs/biome` (devDependency) - [ ] Запустить `npx @biomejs/biome migrate eslint --write` -- [ ] Создать `biome.json` с донастройкой под проект -- [ ] Если FSD-правила не портируются — создать минимальный `.eslintrc.cjs` только для FSD -- [ ] Удалить зависимости: eslint, prettier, @typescript-eslint/*, eslint-plugin-* -- [ ] Удалить `.eslintrc.cjs` (если FSD не нужен) -- [ ] Обновить `package.json`: `lint` → `biome check src/` -- [ ] Обновить `.gitea/workflows/ci.yml`: заменить eslint на biome -- [ ] Обновить pre-commit hook (lint-staged → biome) -- [ ] Прогнать `biome check --write src/` -- [ ] `npm run test` — все тесты проходят +- [x] Создать и настроить `biome.json` под проект +- [x] ESLint оставлен только для FSD-правил (`.eslintrc.cjs`) +- [ ] Удалить зависимости: prettier, @typescript-eslint/*, eslint-plugin-* (ESLint core пока нужен для FSD) +- [ ] Удалить `.prettierrc` и `.prettierignore` — форматирование перешло к Biome +- [x] Обновить `package.json`: `lint` → `biome check src/` +- [ ] Обновить `.gitea/workflows/ci.yml`: заменить eslint на biome для frontend +- [x] Обновить pre-commit hook (lint-staged → biome + prettier) +- [x] Прогнать `biome check --write src/` +- [x] `npm run test` — все тесты проходят +- [x] `npm run build` — сборка проходит ## Phase 3: Unify API Types -- [ ] Проверить все импорты в entity API — должны быть из `types.ts` (codegen), не из `responses.ts` -- [ ] Если кто-то импортирует из `responses.ts` — переключить на `types.ts` -- [ ] Удалить `shared/api/responses.ts` -- [ ] Перенести normalizeEnvelope (ky-версия) в `shared/api/kyClient.ts` +- [ ] Аудит импортов: entity API используют `types.ts` (codegen) или `responses.ts`? +- [ ] Переключить все импорты с `responses.ts` на `types.ts` (если типы есть в codegen) +- [ ] Удалить `shared/api/responses.ts` (после переключения) +- [x] normalizeEnvelope перенесён в `shared/api/kyClient.ts` - [ ] `npm run build` — сборка проходит ## Phase 4: MSW Browser -- [ ] Создать `shared/lib/test/browser.ts` (setupWorker из msw/browser) -- [ ] Установить и прокинуть mockServiceWorker.js: `npx msw init public/` -- [ ] Создать `shared/config/env.ts` с чтением и экспортом VITE_API_MOCK -- [ ] В `main.tsx`: при `VITE_API_MOCK === 'true'` запускать `worker.start()` +- [x] Создать `shared/lib/test/browser.ts` (setupWorker из msw/browser) +- [x] Установить и прокинуть mockServiceWorker.js: `npx msw init public/` +- [x] Создать `shared/config/env.ts` с чтением и экспортом VITE_API_MOCK + VITE_API_URL +- [x] В `main.tsx`: при `VITE_API_MOCK === 'true'` запускать `worker.start()` - [ ] Проверить: `VITE_API_MOCK=true npm run dev` без бэкенда — приложение работает - [ ] Проверить: `VITE_API_MOCK=false npm run dev` — запросы идут на бэкенд ## Phase 5: Env Validation -- [ ] Разработать Zod-схему в `shared/config/env.ts` для всех VITE_* переменных -- [ ] Вызвать `validateEnv()` в `main.tsx` до `ReactDOM.createRoot` +- [x] Разработать Zod-схему в `shared/config/env.ts` для всех VITE_* переменных +- [x] Валидация env выполняется при импорте (safeParse в модуле env.ts) - [ ] Проверить: при отсутствии обязательной переменной — понятная ошибка ## Phase 6: TanStack Router ### Setup -- [ ] Установить `@tanstack/react-router`, `@tanstack/router-devtools`, `@tanstack/router-plugin` -- [ ] Настроить Vite plugin для генерации RouteTree в `vite.config.ts` +- [x] Установить `@tanstack/react-router`, `@tanstack/router-devtools` +- [ ] ~~Установить `@tanstack/router-plugin`~~ (решение: code-first, без плагина) ### Route files -- [ ] Создать `src/app/routes/__root.tsx` — AppLayout + ErrorBoundary -- [ ] Создать `src/app/routes/index.tsx` — HomePage -- [ ] Создать `src/app/routes/stocks.$secid.tsx` — StockPage -- [ ] Создать `src/app/routes/bonds.$secid.tsx` — BondPage -- [ ] Создать `src/app/routes/screener.tsx` — ScreenerPage + Zod search params -- [ ] Создать `src/app/routes/login.tsx` — LoginPage -- [ ] Создать `src/app/routes/register.tsx` — RegisterPage -- [ ] Создать `src/app/routes/profile.tsx` — ProfilePage (guard: beforeLoad) -- [ ] Создать `src/app/routes/portfolios.tsx` — PortfoliosListPage (guard) -- [ ] Создать `src/app/routes/portfolios.$id.tsx` — PortfolioDetailPage (guard) -- [ ] Создать `src/app/routes/broker/index.tsx` — BrokerAccountsPage (guard) -- [ ] Создать `src/app/routes/broker.$accountId/index.tsx` — BrokerAccountOverviewPage (guard) -- [ ] Создать `src/app/routes/broker.$accountId/shares.tsx` — BrokerPositionsPage (guard) -- [ ] Создать `src/app/routes/broker.$accountId/bonds.tsx` — BrokerPositionsPage (guard) -- [ ] Создать `src/app/routes/broker.$accountId/operations.tsx` — BrokerOperationsPage (guard) -- [ ] Создать `src/app/routes/broker.$accountId/events.tsx` — BrokerEventsPage (guard) +- [x] Создать `src/app/routing/routeTree.tsx` — все маршруты (code-first) + - [x] root route + AppLayout + - [x] index → HomePage + - [x] stocks/$secid → StockPage + - [x] bonds/$secid → BondPage + - [x] screener → ScreenerPage + - [x] login → LoginPage + - [x] register → RegisterPage + - [x] profile → ProfilePage (guard) + - [x] portfolios → PortfoliosListPage (guard) + - [x] portfolios/$id → PortfolioDetailPage (guard) + - [x] broker → BrokerAccountsPage (guard) + - [x] broker/$accountId → BrokerAccountOverviewPage (guard) + - [x] broker/$accountId/shares → BrokerPositionsPage (guard) + - [x] broker/$accountId/bonds → BrokerPositionsPage (guard) + - [x] broker/$accountId/operations → BrokerOperationsPage (guard) + - [x] broker/$accountId/events → BrokerEventsPage (guard) ### Router integration -- [ ] Создать `app/routing/router.ts`: `createRouter()` с Route Tree -- [ ] Настроить `beforeLoad` для guard'ов -- [ ] Настроить loaders для предзагрузки (TanStack Query) -- [ ] Заменить `` + `` → `` в `App.tsx` +- [x] Создать `app/routing/router.ts`: `createRouter()` с Route Tree +- [x] Настроить `beforeLoad` для guard'ов (requireAuth) +- [ ] Настроить loaders для предзагрузки (TanStack Query) — отложено +- [x] Заменить `` + `` → `` в `App.tsx` ### Replace imports -- [ ] Заменить `Link` → `@tanstack/react-router` Link по всему проекту -- [ ] Заменить `useNavigate` → `@tanstack/react-router` -- [ ] Заменить `useParams` → `@tanstack/react-router` -- [ ] Заменить `useSearchParams` → `useSearch` + `useNavigate` -- [ ] Заменить `useLocation` → `@tanstack/react-router` +- [x] Заменить `Link` → `@tanstack/react-router` Link по всему проекту +- [x] Заменить `useNavigate` → `@tanstack/react-router` +- [x] Заменить `useParams` → `@tanstack/react-router` +- [x] Заменить `useSearchParams` → `useSearchParamsCompat` (временная обёртка) +- [x] Заменить `useLocation` → `@tanstack/react-router` ### Tests -- [ ] Заменить `MemoryRouter` в тестах на `createMemoryRouter` из TanStack Router -- [ ] Обновить тестовые утилиты (`test-utils.tsx`) -- [ ] `npm run test` — все тесты проходят -- [ ] `npm run build` — сборка проходит +- [x] Заменить `MemoryRouter` в тестах на `createMemoryHistory` + `RouterProvider` +- [x] Обновить тестовые утилиты (`test-utils.tsx`) +- [x] `npm run test` — все тесты проходят (125) +- [x] `npm run build` — сборка проходит ### Devtools -- [ ] Настроить `@tanstack/router-devtools` в dev-режиме -- [ ] Проверить навигацию по всем страницам вручную +- [x] Настроить `@tanstack/router-devtools` в dev-режиме +- [ ] Проверить навигацию по всем страницам вручную — отложено