9.0 KiB
Raw Permalink Blame History

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'ов после полной миграции