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

305 lines
7.8 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.

# АРХИТЕКТУРА АУТЕНТИФИКАЦИИ SFERA
**Дата последнего обновления:** 19 сентября 2025
**Статус:** ✅ АКТУАЛЬНО (после миграции useAuth → AuthContext)
---
## 🎯 ТЕКУЩАЯ АРХИТЕКТУРА
### AuthContext - Централизованное управление аутентификацией
**Файл:** `src/contexts/AuthContext.tsx`
```typescript
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
}
```
### Использование в компонентах
```typescript
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
```typescript
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ApolloProvider client={apolloClient}>
<AuthProvider>
{children}
</AuthProvider>
</ApolloProvider>
)
}
```
**🔑 Ключевая особенность:** AuthProvider оборачивает все приложение, обеспечивая единое состояние аутентификации.
---
## 📋 ТИПЫ ПОЛЬЗОВАТЕЛЕЙ И ОРГАНИЗАЦИЙ
### User Interface
```typescript
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 Авторизация
```typescript
// Отправка SMS кода
const result = await sendSmsCode(phone)
// Подтверждение кода
const verification = await verifySmsCode(phone, code)
```
### 2. Регистрация организации
```typescript
const registrationResult = await registerOrganization({
organizationData: {
inn: '1234567890',
phone: '+7900123456',
type: 'SELLER',
wbApiKey: 'wb_token',
ozonApiKey: 'ozon_token'
}
})
```
### 3. Проверка авторизации
```typescript
// Автоматически вызывается при инициализации
await checkAuth()
// Проверяет токен и загружает данные пользователя
// Если токен невалиден - выполняет logout
```
---
## 🚀 МАРШРУТИЗАЦИЯ ПО РОЛЯМ
### Главная страница (app/page.tsx)
```typescript
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)
```typescript
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 ошибки
- Синхронизирует состояние с сервером
```typescript
// При логине
setAuthToken(token)
setUserData(userData)
// При logout
removeAuthToken()
apolloClient.resetStore()
```
---
## 📊 СОСТОЯНИЕ ЗАГРУЗКИ
### Флаги состояния
- **isLoading** - идет проверка аутентификации
- **isAuthenticated** - пользователь авторизован
- **user** - данные пользователя (null если не авторизован)
### Паттерн использования
```typescript
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 файлов** удалены после тестирования
- **Все тесты** пройдены успешно
---
## 🎯 ЛУЧШИЕ ПРАКТИКИ
### ✅ Правильные паттерны
```typescript
// Корректная проверка аутентификации
const { user, isAuthenticated, isLoading } = useAuthContext()
if (isLoading) {
return <LoadingState />
}
if (!isAuthenticated) {
return <UnauthenticatedState />
}
// Теперь user гарантированно не null
return <AuthenticatedContent user={user} />
```
### ❌ Избегайте
```typescript
// Неправильно - не проверяем isLoading
const { user } = useAuthContext()
if (user) { // может быть false positive во время загрузки
// ...
}
// Неправильно - прямое обращение к токену
const token = getAuthToken() // используйте isAuthenticated
```
---
## 🔐 БЕЗОПАСНОСТЬ
### Токены
- **Автоматическое удаление** при logout
- **Проверка валидности** при каждом запросе
- **Безопасное хранение** в localStorage
### API Keys
- **Шифрование** в БД
- **Валидация** при сохранении
- **Ротация** через UI
---
**🎉 Архитектура аутентификации SFERA готова к production использованию!**