179 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/
1. Создать `entities/session/api/sessionApi.ts` — скопировать 6 функций из `api/auth.ts`,
заменить импорт `./client` на `@/shared/api/client`, импорт `./responses` на `@/shared/api/responses`
2. Создать `entities/session/api/sessionApi.test.ts` — скопировать из `api/auth.test.ts`,
заменить импорты
3. Создать `entities/session/model/sessionContext.ts` — SessionContext + SessionContextValue
(без Provider-логики, только тип и createContext)
4. Создать `entities/session/model/useSession.ts` — хук useContext с guard
5. Создать `entities/session/model/useSession.test.tsx` — скопировать из `hooks/useAuth.test.tsx`,
заменить импорты (тест пока оборачивает AuthProvider — будет работать через шим)
6. Создать `entities/session/index.ts` — barrel
7. Превратить `api/auth.ts` в shim
8. Превратить `hooks/useAuth.ts` в shim
### Phase 2: app/providers/
1. Создать `app/providers/SessionProvider.tsx` — перенести логику из `context/AuthContext.tsx`:
- Импортирует sessionApi из entities/session
- Использует SessionContext из entities/session
- Весь lifecycle (refresh on mount, updateSession, clearSession) остаётся здесь
2. Создать `app/providers/AppProviders.tsx` — композиция QueryClientProvider + SessionProvider
(вынести QueryClient config из main.tsx)
3. Создать `app/providers/SessionProvider.test.tsx` — скопировать из `context/AuthContext.test.tsx`,
заменить импорты
4. Создать `app/providers/index.ts` — barrel
5. Превратить `context/AuthContext.tsx` в shim (реэкспорт SessionProvider и sessionContext)
### Phase 3: app/routing/
1. Создать `app/routing/ProtectedRoute.tsx` — скопировать из `components/ProtectedRoute.tsx`,
заменить импорт useAuth на useSession из entities/session
2. Создать `app/routing/AppRoutes.tsx` — скопировать из `routes.tsx`:
- Заменить импорт Layout на AppLayout из app/layouts
- Заменить импорт ProtectedRoute на app/routing/ProtectedRoute
- Broker page импорты остаются без изменений
3. Создать `app/routing/index.ts` — barrel
4. Превратить `routes.tsx` в shim
5. Превратить `components/ProtectedRoute.tsx` в shim
### Phase 4: app/layouts/
1. Создать `app/layouts/AppLayout.tsx` — скопировать из `components/Layout.tsx`:
- Заменить импорт useAuth на useSession из entities/session
- Заменить импорт SearchBar на @/components/SearchBar (SearchBar пока не мигрируется)
2. Создать `app/layouts/index.ts` — barrel
3. Превратить `components/Layout.tsx` в shim
### Phase 5: app/App.tsx
1. Создать `app/App.tsx` — из `App.tsx`, BrowserRouter + AppRoutes из app/routing
2. Создать `app/index.ts` — barrel
3. Превратить `App.tsx` в shim
### Phase 6: main.tsx
1. Обновить `main.tsx` — импортировать AppProviders из app/providers
2. Убрать прямой импорт QueryClientProvider и AuthProvider
### Phase 7: update pages
1. `pages/LoginPage.tsx` — заменить `../hooks/useAuth` на `@/entities/session`
2. `pages/RegisterPage.tsx` — аналогично
3. `pages/ProfilePage.tsx` — аналогично
4. Запустить тесты, 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'ов после полной миграции