# 🔐 ПЛАН БЕЗОПАСНОЙ МИГРАЦИИ НА AuthContext

**Дата создания:** 2025-09-18  
**Автор:** Claude AI + Вероника Смирнова  
**Статус:** Готов к реализации

## 📊 Результаты глубокой диагностики

### Анализ текущей реализации useAuth

**Размер и сложность:**
- 657 строк кода
- 65 файлов используют useAuth()
- Сложная логика с rollback механизмами
- Интеграция с Apollo Client через localStorage

**Ключевые компоненты:**
1. **State Management**
   - `user: User | null` - данные пользователя
   - `isAuthenticated: boolean` - статус авторизации
   - `isLoading: boolean` - индикатор загрузки
   - `isCheckingAuth: boolean` - защита от дублирования

2. **Методы авторизации**
   - `sendSmsCode` - отправка SMS
   - `verifySmsCode` - проверка кода
   - `checkAuth` - проверка текущей сессии
   - `logout` - выход

3. **Методы регистрации**
   - `registerFulfillmentOrganization`
   - `registerSellerOrganization`
   - `registerOrganization` (универсальный)

4. **Интеграции**
   - Apollo Client для GraphQL
   - localStorage для токенов
   - refreshApolloClient для синхронизации

### Выявленные проблемы

1. **Множественные экземпляры состояния**
   ```
   AppShell → useAuth() → useState (копия 1)
   Sidebar → useAuth() → useState (копия 2)
   Component → useAuth() → useState (копия 3)
   ```

2. **Race conditions**
   - checkAuth вызывается параллельно из разных компонентов
   - isCheckingAuth защищает только локальный экземпляр

3. **Отсутствие синхронизации**
   - Обновления в одном компоненте не видны в других
   - GET_ME выполняется многократно

4. **Проблемы с SSR**
   - Прямое обращение к localStorage
   - window checks разбросаны по коду

## 🎯 Архитектура решения

### Новая структура с AuthContext

```
AuthProvider (глобальное состояние)
    ├── Apollo Provider
    │   └── Auth Link (токены из контекста)
    ├── State Management
    │   ├── user
    │   ├── isAuthenticated
    │   └── isLoading
    └── Methods
        ├── Authentication
        ├── Registration
        └── Session Management
```

### Преимущества

1. **Единое состояние** - все компоненты видят одни данные
2. **Оптимизация запросов** - GET_ME выполняется 1 раз
3. **Синхронизация** - изменения видны везде мгновенно
4. **SSR совместимость** - централизованные проверки
5. **Типобезопасность** - строгая типизация контекста

## 📋 Поэтапный план миграции

### ЭТАП 0: Подготовка [30 мин]

**Цель:** Создать безопасную среду для миграции

1. **Создать backup текущего состояния**
   ```bash
   git add .
   git commit -m "backup: перед миграцией на AuthContext"
   git branch backup-before-auth-context
   ```

2. **Создать feature branch**
   ```bash
   git checkout -b feature/auth-context-migration
   ```

3. **Подготовить структуру папок**
   ```
   src/
   ├── contexts/
   │   └── auth/
   │       ├── AuthContext.tsx       # Основной контекст
   │       ├── AuthProvider.tsx      # Provider компонент
   │       ├── types.ts             # TypeScript типы
   │       └── utils.ts             # Вспомогательные функции
   ```

### ЭТАП 1: Создание AuthContext с минимальной функциональностью [1 час]

**Цель:** Создать работающий контекст без нарушения существующего функционала

1. **Создать типы** (`src/contexts/auth/types.ts`)
   ```typescript
   export interface User {
     id: string
     phone: string
     avatar?: string
     managerName?: string
     organization?: Organization
   }

   export interface Organization {
     id: string
     inn: string
     type: 'FULFILLMENT' | 'SELLER' | 'LOGIST' | 'WHOLESALE'
     // ... остальные поля
   }

   export interface AuthState {
     user: User | null
     isAuthenticated: boolean
     isLoading: boolean
   }

   export interface AuthContextType extends AuthState {
     // Методы будем добавлять постепенно
     checkAuth: () => Promise<void>
     logout: () => void
   }
   ```

2. **Создать контекст** (`src/contexts/auth/AuthContext.tsx`)
   ```typescript
   import { createContext } from 'react'
   import type { AuthContextType } from './types'

   export const AuthContext = createContext<AuthContextType | null>(null)
   ```

3. **Создать базовый Provider** (`src/contexts/auth/AuthProvider.tsx`)
   ```typescript
   import { useState, useCallback, useEffect } from 'react'
   import { AuthContext } from './AuthContext'
   import { getAuthToken, removeAuthToken } from '@/lib/apollo-client'
   
   export function AuthProvider({ children }: { children: React.ReactNode }) {
     const [user, setUser] = useState<User | null>(null)
     const [isAuthenticated, setIsAuthenticated] = useState(false)
     const [isLoading, setIsLoading] = useState(true)
     
     // Минимальная реализация checkAuth
     const checkAuth = useCallback(async () => {
       const token = getAuthToken()
       if (!token) {
         setIsAuthenticated(false)
         setUser(null)
         setIsLoading(false)
         return
       }
       
       // TODO: Добавить GET_ME запрос
       setIsLoading(false)
     }, [])
     
     // Минимальная реализация logout
     const logout = useCallback(() => {
       removeAuthToken()
       setUser(null)
       setIsAuthenticated(false)
       window.location.href = '/'
     }, [])
     
     useEffect(() => {
       checkAuth()
     }, [checkAuth])
     
     const value = {
       user,
       isAuthenticated,
       isLoading,
       checkAuth,
       logout
     }
     
     return (
       <AuthContext.Provider value={value}>
         {children}
       </AuthContext.Provider>
     )
   }
   ```

4. **Создать временный хук-обертку** (`src/hooks/useAuth.ts`)
   ```typescript
   // В начале файла добавляем
   import { useContext } from 'react'
   import { AuthContext } from '@/contexts/auth/AuthContext'
   
   // Временный флаг для постепенной миграции
   const USE_AUTH_CONTEXT = false
   
   export const useAuth = (): UseAuthReturn => {
     if (USE_AUTH_CONTEXT) {
       const context = useContext(AuthContext)
       if (!context) {
         throw new Error('useAuth must be used within AuthProvider')
       }
       
       // Адаптер для совместимости API
       return {
         ...context,
         // Методы-заглушки для совместимости
         sendSmsCode: async () => ({ success: false, message: 'Not implemented' }),
         verifySmsCode: async () => ({ success: false, message: 'Not implemented' }),
         registerFulfillmentOrganization: async () => ({ success: false, message: 'Not implemented' }),
         registerSellerOrganization: async () => ({ success: false, message: 'Not implemented' }),
         registerOrganization: async () => ({ success: false, message: 'Not implemented' }),
         updateUser: () => {}
       }
     }
     
     // Существующая реализация остается без изменений
     // ... весь текущий код
   }
   ```

### ЭТАП 2: Тестирование базовой интеграции [30 мин]

**Цель:** Убедиться что ничего не сломалось

1. **Добавить AuthProvider в providers.tsx**
   ```typescript
   import { AuthProvider } from '@/contexts/auth/AuthProvider'
   
   export function Providers({ children }: { children: React.ReactNode }) {
     return (
       <ApolloProvider client={apolloClient}>
         <AuthProvider>
           <SidebarProvider>
             {children}
           </SidebarProvider>
         </AuthProvider>
       </ApolloProvider>
     )
   }
   ```

2. **Включить USE_AUTH_CONTEXT для одного компонента**
   - Начать с простого компонента (например, UserProfile в sidebar)
   - Проверить что компонент рендерится
   - Проверить что нет ошибок в консоли

3. **Rollback план**
   - Если есть ошибки - установить USE_AUTH_CONTEXT = false
   - Исправить проблемы
   - Повторить тестирование

### ЭТАП 3: Миграция основного функционала [2 часа]

**Цель:** Перенести всю логику в AuthContext

1. **Перенести checkAuth с GET_ME**
   ```typescript
   const checkAuth = useCallback(async () => {
     if (isCheckingAuth.current) return
     
     const token = getAuthToken()
     if (!token) {
       setIsAuthenticated(false)
       setUser(null)
       setIsLoading(false)
       return
     }
     
     isCheckingAuth.current = true
     setIsLoading(true)
     
     try {
       const { data } = await apolloClient.query({
         query: GET_ME,
         errorPolicy: 'all',
         fetchPolicy: 'network-only'
       })
       
       if (data?.me) {
         setUser(data.me)
         setIsAuthenticated(true)
         setUserData(data.me)
       }
     } catch (error) {
       // Обработка ошибок
     } finally {
       isCheckingAuth.current = false
       setIsLoading(false)
     }
   }, [])
   ```

2. **Перенести SMS методы**
   - sendSmsCode
   - verifySmsCode
   - Сохранить всю логику с логированием

3. **Перенести методы регистрации**
   - registerFulfillmentOrganization
   - registerSellerOrganization
   - registerOrganization
   - Сохранить rollback механизмы

4. **Добавить updateUser**
   ```typescript
   const updateUser = useCallback((updatedUser: Partial<User>) => {
     setUser(current => {
       if (!current) return current
       const updated = { ...current, ...updatedUser }
       setUserData(updated) // Синхронизация с localStorage
       return updated
     })
   }, [])
   ```

### ЭТАП 4: Постепенная миграция компонентов [1 день]

**Цель:** Безопасно перевести все компоненты на новую систему

1. **Приоритетные компоненты** (первая очередь)
   - AppShell
   - Sidebar и все его варианты
   - AuthGuard

2. **Критические компоненты** (вторая очередь)
   - Страницы авторизации (login, register)
   - DashboardHome
   - useRoleGuard

3. **Остальные компоненты** (третья очередь)
   - Разбить на группы по 10-15 файлов
   - Мигрировать группами
   - Тестировать после каждой группы

**Процесс для каждого компонента:**
1. Включить USE_AUTH_CONTEXT локально
2. Проверить функциональность
3. Если работает - коммит
4. Если нет - откат и исправление

### ЭТАП 5: Оптимизация и очистка [1 час]

**Цель:** Удалить старый код и оптимизировать

1. **Удалить старую реализацию из useAuth**
   - Оставить только обертку для контекста
   - Удалить локальные useState
   - Удалить дублированную логику

2. **Оптимизировать рендеринг**
   ```typescript
   // Мемоизация значения контекста
   const value = useMemo(() => ({
     user,
     isAuthenticated,
     isLoading,
     checkAuth,
     logout,
     // ... другие методы
   }), [user, isAuthenticated, isLoading])
   ```

3. **Добавить DevTools**
   ```typescript
   if (process.env.NODE_ENV === 'development') {
     (window as any).__AUTH_STATE__ = { user, isAuthenticated }
   }
   ```

### ЭТАП 6: Финальное тестирование [1 час]

**Цель:** Убедиться что все работает

1. **Функциональные тесты**
   - [ ] Авторизация по SMS
   - [ ] Регистрация всех типов организаций
   - [ ] Отображение sidebar
   - [ ] Переходы между страницами
   - [ ] Выход из системы
   - [ ] Обновление страницы (F5)

2. **Тесты производительности**
   - [ ] Нет множественных GET_ME запросов
   - [ ] Нет лишних ре-рендеров
   - [ ] Быстрая загрузка после F5

3. **Регрессионные тесты**
   - [ ] Все 65 компонентов работают
   - [ ] API ключи сохраняются
   - [ ] Роутинг по типам организаций

## 🚨 Риски и митигация

### Риск 1: Поломка авторизации
**Митигация:**
- Постепенная миграция через флаг USE_AUTH_CONTEXT
- Возможность быстрого отката
- Тестирование на каждом этапе

### Риск 2: Потеря состояния
**Митигация:**
- Сохранение в localStorage остается
- Rollback механизмы сохраняются
- Логирование всех изменений

### Риск 3: Проблемы с SSR
**Митигация:**
- Все проверки window в одном месте
- useEffect для клиентских операций
- Правильная инициализация состояния

### Риск 4: Race conditions
**Митигация:**
- useRef для флагов загрузки
- Отмена дублированных запросов
- Правильная очередность операций

## 📊 Метрики успеха

1. **Функциональность**
   - ✅ Все 65 компонентов работают
   - ✅ Sidebar отображается корректно
   - ✅ Авторизация стабильна

2. **Производительность**
   - ✅ GET_ME вызывается 1 раз
   - ✅ Нет задержек при навигации
   - ✅ Быстрая загрузка после F5

3. **Качество кода**
   - ✅ Единое место управления состоянием
   - ✅ Типобезопасность
   - ✅ Отсутствие дублирования

## 🔄 Rollback план

Если что-то пойдет не так на любом этапе:

1. **Быстрый откат**
   ```bash
   git checkout backup-before-auth-context
   ```

2. **Частичный откат**
   - Установить USE_AUTH_CONTEXT = false
   - Вернуть проблемные компоненты на старую версию
   - Исправить проблемы в изолированной ветке

3. **Восстановление данных**
   - localStorage сохраняется
   - Токены остаются валидными
   - Пользователи не заметят проблем

## 📝 Чек-лист готовности

Перед началом миграции убедитесь:

- [ ] Создан backup текущего состояния
- [ ] Команда предупреждена о работах
- [ ] Подготовлен план коммуникации при проблемах
- [ ] Есть доступ к логам и мониторингу
- [ ] Определено время для миграции (лучше в период низкой активности)

## 🎯 Ожидаемый результат

После завершения миграции:

1. **Немедленные улучшения**
   - Sidebar работает стабильно
   - Состояние синхронизировано между компонентами
   - Уменьшено количество запросов к API

2. **Долгосрочные преимущества**
   - Готовность к добавлению новых функций
   - Упрощенная отладка
   - Лучшая производительность
   - Возможность добавления продвинутых функций (персистентность, refresh tokens)

---

*Документ будет обновляться по ходу выполнения миграции*