# 🔐 ПЛАН БЕЗОПАСНОЙ МИГРАЦИИ НА 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 logout: () => void } ``` 2. **Создать контекст** (`src/contexts/auth/AuthContext.tsx`) ```typescript import { createContext } from 'react' import type { AuthContextType } from './types' export const AuthContext = createContext(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(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 ( {children} ) } ``` 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 ( {children} ) } ``` 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) => { 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) --- *Документ будет обновляться по ходу выполнения миграции*