9.0 KiB
9.0 KiB
Frontend FSD App + Auth — План реализации
Стратегия миграции
Поэтапный рефакторинг без big-bang. Каждый legacy-файл сначала превращается в re-export shim после переноса кода. Все изменения — только перегруппировка, поведение не меняется.
Целевая структура
src/
├── app/
│ ├── App.tsx # BrowserRouter + AppRoutes
│ ├── index.ts # barrel (export { default as App } from './App')
│ ├── providers/
│ │ ├── AppProviders.tsx # QueryClientProvider + SessionProvider
│ │ ├── SessionProvider.tsx # Auth orchestration (из context/AuthContext)
│ │ └── index.ts # barrel
│ ├── routing/
│ │ ├── AppRoutes.tsx # Route definitions (из routes.tsx)
│ │ ├── ProtectedRoute.tsx # Auth guard (из components/ProtectedRoute)
│ │ └── index.ts # barrel
│ └── layouts/
│ ├── AppLayout.tsx # Header + nav + Outlet (из components/Layout)
│ └── index.ts # barrel
│
├── entities/
│ └── session/
│ ├── index.ts # barrel
│ ├── api/
│ │ ├── sessionApi.ts # login, register, refresh, logout, getMe, updateProfile
│ │ └── sessionApi.test.ts # перенос из api/auth.test.ts
│ └── model/
│ ├── sessionContext.ts # SessionContext + SessionContextValue
│ ├── useSession.ts # хук (из hooks/useAuth.ts)
│ └── useSession.test.tsx # перенос из hooks/useAuth.test.tsx
│
├── pages/
│ ├── LoginPage.tsx # обновлён импорт на @/entities/session
│ ├── RegisterPage.tsx # обновлён импорт
│ └── ProfilePage.tsx # обновлён импорт
│
├── api/
│ ├── auth.ts → SHIM для entities/session/api/sessionApi
│ ├── client.ts → SHIM (уже есть)
│ ├── responses.ts → SHIM (уже есть)
│ └── ... (остальные файлы без изменений)
│
├── hooks/
│ ├── useAuth.ts → SHIM для entities/session/model/useSession
│ └── ... (остальные shim'ы уже есть)
│
├── context/
│ └── AuthContext.tsx → SHIM (реэкспорт SessionProvider + sessionContext)
│
├── components/
│ ├── Layout.tsx → SHIM для app/layouts/AppLayout
│ ├── ProtectedRoute.tsx → SHIM для app/routing/ProtectedRoute
│ └── ... (остальные без изменений)
│
└── main.tsx → обновлён: использует AppProviders
Потоки данных
Auth flow (без изменений в runtime)
User action → Page (LoginPage)
→ useSession().login(email, password)
→ sessionApi.login(email, password) [entities/session/api]
→ request() [shared/api/client]
→ SessionProvider.updateSession(result) [app/providers]
→ setUser + setAccessToken
→ SessionContext.Provider value update
Session restore на старте
main.tsx
→ AppProviders
→ SessionProvider (mount)
→ sessionApi.refresh()
→ if ok: updateSession(result)
→ if fail: keep anonymous
→ App → AppRoutes → ProtectedRoute → page
Этапы реализации
Phase 1: entities/session/
- Создать
entities/session/api/sessionApi.ts— скопировать 6 функций изapi/auth.ts, заменить импорт./clientна@/shared/api/client, импорт./responsesна@/shared/api/responses - Создать
entities/session/api/sessionApi.test.ts— скопировать изapi/auth.test.ts, заменить импорты - Создать
entities/session/model/sessionContext.ts— SessionContext + SessionContextValue (без Provider-логики, только тип и createContext) - Создать
entities/session/model/useSession.ts— хук useContext с guard - Создать
entities/session/model/useSession.test.tsx— скопировать изhooks/useAuth.test.tsx, заменить импорты (тест пока оборачивает AuthProvider — будет работать через шим) - Создать
entities/session/index.ts— barrel - Превратить
api/auth.tsв shim - Превратить
hooks/useAuth.tsв shim
Phase 2: app/providers/
- Создать
app/providers/SessionProvider.tsx— перенести логику изcontext/AuthContext.tsx:- Импортирует sessionApi из entities/session
- Использует SessionContext из entities/session
- Весь lifecycle (refresh on mount, updateSession, clearSession) остаётся здесь
- Создать
app/providers/AppProviders.tsx— композиция QueryClientProvider + SessionProvider (вынести QueryClient config из main.tsx) - Создать
app/providers/SessionProvider.test.tsx— скопировать изcontext/AuthContext.test.tsx, заменить импорты - Создать
app/providers/index.ts— barrel - Превратить
context/AuthContext.tsxв shim (реэкспорт SessionProvider и sessionContext)
Phase 3: app/routing/
- Создать
app/routing/ProtectedRoute.tsx— скопировать изcomponents/ProtectedRoute.tsx, заменить импорт useAuth на useSession из entities/session - Создать
app/routing/AppRoutes.tsx— скопировать изroutes.tsx:- Заменить импорт Layout на AppLayout из app/layouts
- Заменить импорт ProtectedRoute на app/routing/ProtectedRoute
- Broker page импорты остаются без изменений
- Создать
app/routing/index.ts— barrel - Превратить
routes.tsxв shim - Превратить
components/ProtectedRoute.tsxв shim
Phase 4: app/layouts/
- Создать
app/layouts/AppLayout.tsx— скопировать изcomponents/Layout.tsx:- Заменить импорт useAuth на useSession из entities/session
- Заменить импорт SearchBar на @/components/SearchBar (SearchBar пока не мигрируется)
- Создать
app/layouts/index.ts— barrel - Превратить
components/Layout.tsxв shim
Phase 5: app/App.tsx
- Создать
app/App.tsx— изApp.tsx, BrowserRouter + AppRoutes из app/routing - Создать
app/index.ts— barrel - Превратить
App.tsxв shim
Phase 6: main.tsx
- Обновить
main.tsx— импортировать AppProviders из app/providers - Убрать прямой импорт QueryClientProvider и AuthProvider
Phase 7: update pages
pages/LoginPage.tsx— заменить../hooks/useAuthна@/entities/sessionpages/RegisterPage.tsx— аналогичноpages/ProfilePage.tsx— аналогично- Запустить тесты, lint, build
Ключевые решения
Почему entities/session, а не features/auth
- User session — это бизнес-сущность (текущий пользователь, токен, статус аутентификации)
- Auth actions (login/register/logout) — это операции над сессией
- Provider-оркестрация вынесена в
app/providers/, так как это инфраструктурный код
Почему context не в entities, а в app/providers
- React-провайдер — это механизм связывания (DI/Infrastructure), а не бизнес-логика
SessionProviderидёт вapp/, где размещается вся корневая инфраструктура приложения- SessionContext (тип + createContext) остаётся в
entities/session/model/, чтобы entities могли определять свой контракт
Coexistence
Все legacy файлы остаются как re-export шимы, чтобы:
- Не ломать импорты в ещё не мигрированных файлах
- Позволить поэтапный переход
- Упростить удаление shim'ов после полной миграции