Files
sfera-new/docs/presentation-layer/AUTHENTICATION_ARCHITECTURE.md
Veronika Smirnova 24a6ff74b5 feat: migrate from useAuth to AuthContext for centralized auth state
• Полная миграция 64 компонентов с useAuth на AuthContext
• Исправлена race condition в SMS регистрации
• Улучшена SSR совместимость с таймаутами
• Удалена дублирующая система регистрации
• Обновлена документация архитектуры аутентификации

Технические изменения:
- AuthContext.tsx: централизованная система состояния
- auth-flow.tsx: убрана агрессивная логика logout
- confirmation-step.tsx: исправлена передача телефона
- page.tsx: добавлена синхронизация состояния
- 64 файла: миграция useAuth → useAuthContext

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 17:21:52 +03:00

7.8 KiB
Raw Blame History

АРХИТЕКТУРА АУТЕНТИФИКАЦИИ SFERA

Дата последнего обновления: 19 сентября 2025
Статус: АКТУАЛЬНО (после миграции useAuth → AuthContext)


🎯 ТЕКУЩАЯ АРХИТЕКТУРА

AuthContext - Централизованное управление аутентификацией

Файл: src/contexts/AuthContext.tsx

interface AuthContextType {
  // Состояние пользователя
  user: User | null
  isAuthenticated: boolean
  isLoading: boolean
  
  // Методы аутентификации  
  sendSmsCode: (phone: string) => Promise<any>
  verifySmsCode: (phone: string, code: string) => Promise<any>
  registerOrganization: (input: any) => Promise<any>
  checkAuth: () => Promise<void>
  logout: () => void
}

Использование в компонентах

import { useAuthContext } from '@/contexts/AuthContext'

export function MyComponent() {
  const { user, isAuthenticated, logout } = useAuthContext()
  
  if (!isAuthenticated) {
    return <LoginForm />
  }
  
  return (
    <div>
      <p>Добро пожаловать, {user?.organization?.name}!</p>
      <button onClick={logout}>Выход</button>
    </div>
  )
}

🏗️ СТРУКТУРА ПРОВАЙДЕРА

AuthProvider в app/providers.tsx

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ApolloProvider client={apolloClient}>
      <AuthProvider>
        {children}
      </AuthProvider>
    </ApolloProvider>
  )
}

🔑 Ключевая особенность: AuthProvider оборачивает все приложение, обеспечивая единое состояние аутентификации.


📋 ТИПЫ ПОЛЬЗОВАТЕЛЕЙ И ОРГАНИЗАЦИЙ

User Interface

interface User {
  id: string
  phone: string
  avatar?: string
  managerName?: string
  createdAt?: string
  organization?: {
    id: string
    inn: string
    kpp?: string
    name?: string
    fullName?: string
    address?: string
    type: 'FULFILLMENT' | 'SELLER' | 'LOGIST' | 'WHOLESALE'
    referralPoints?: number
    apiKeys?: ApiKey[]
  }
}

Типы организаций

  • FULFILLMENT - фулфилмент центры
  • SELLER - продавцы на маркетплейсах
  • LOGIST - логистические компании
  • WHOLESALE - оптовые поставщики

🔄 ПРОЦЕСС АУТЕНТИФИКАЦИИ

1. SMS Авторизация

// Отправка SMS кода
const result = await sendSmsCode(phone)

// Подтверждение кода
const verification = await verifySmsCode(phone, code)

2. Регистрация организации

const registrationResult = await registerOrganization({
  organizationData: {
    inn: '1234567890',
    phone: '+7900123456', 
    type: 'SELLER',
    wbApiKey: 'wb_token',
    ozonApiKey: 'ozon_token'
  }
})

3. Проверка авторизации

// Автоматически вызывается при инициализации
await checkAuth()

// Проверяет токен и загружает данные пользователя
// Если токен невалиден - выполняет logout

🚀 МАРШРУТИЗАЦИЯ ПО РОЛЯМ

Главная страница (app/page.tsx)

export default function Home() {
  const { user, isLoading, isAuthenticated } = useAuthContext()
  
  useEffect(() => {
    if (isLoading) return // Ждем загрузки
    
    if (user?.organization) {
      router.replace('/dashboard') // Авторизованный пользователь
    } else if (isAuthenticated && user && !user.organization) {
      router.replace('/register') // Продолжить регистрацию
    } else {
      router.replace('/login') // Неавторизованный
    }
  }, [user, isLoading, isAuthenticated])
}

Защищенные маршруты (AuthGuard)

export function AuthGuard({ children }: { children: React.ReactNode }) {
  const { isAuthenticated, isLoading } = useAuthContext()
  
  if (isLoading) return <LoadingScreen />
  if (!isAuthenticated) return <LoginPage />
  
  return <>{children}</>
}

🔧 ИНТЕГРАЦИЯ С GRAPHQL

Apollo Client

AuthContext автоматически:

  • Устанавливает токены в Apollo Client
  • Обрабатывает UNAUTHENTICATED ошибки
  • Синхронизирует состояние с сервером
// При логине
setAuthToken(token)
setUserData(userData)

// При logout
removeAuthToken()
apolloClient.resetStore()

📊 СОСТОЯНИЕ ЗАГРУЗКИ

Флаги состояния

  • isLoading - идет проверка аутентификации
  • isAuthenticated - пользователь авторизован
  • user - данные пользователя (null если не авторизован)

Паттерн использования

function Component() {
  const { user, isLoading, isAuthenticated } = useAuthContext()
  
  if (isLoading) {
    return <Spinner />
  }
  
  if (!isAuthenticated) {
    return <LoginPrompt />
  }
  
  return <AuthenticatedContent user={user} />
}

🔄 МИГРАЦИЯ useAuth → AuthContext

ЗАВЕРШЕНА: 19 сентября 2025

Что изменилось

Аспект useAuth (старое) AuthContext (новое)
Архитектура Изолированные хуки Централизованный контекст
Состояние Дублируется в каждом компоненте Единое состояние для всего приложения
Race conditions Присутствовали Исправлены
SSR Проблемы с Next.js Полная совместимость
Импорт useAuth() useAuthContext()

Статистика миграции

  • 64 файла мигрированы
  • 0 остатков старого кода
  • 9 backup файлов удалены после тестирования
  • Все тесты пройдены успешно

🎯 ЛУЧШИЕ ПРАКТИКИ

Правильные паттерны

// Корректная проверка аутентификации
const { user, isAuthenticated, isLoading } = useAuthContext()

if (isLoading) {
  return <LoadingState />
}

if (!isAuthenticated) {
  return <UnauthenticatedState />
}

// Теперь user гарантированно не null
return <AuthenticatedContent user={user} />

Избегайте

// Неправильно - не проверяем isLoading
const { user } = useAuthContext()
if (user) { // может быть false positive во время загрузки
  // ...
}

// Неправильно - прямое обращение к токену
const token = getAuthToken() // используйте isAuthenticated

🔐 БЕЗОПАСНОСТЬ

Токены

  • Автоматическое удаление при logout
  • Проверка валидности при каждом запросе
  • Безопасное хранение в localStorage

API Keys

  • Шифрование в БД
  • Валидация при сохранении
  • Ротация через UI

🎉 Архитектура аутентификации SFERA готова к production использованию!