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>
This commit is contained in:
Veronika Smirnova
2025-09-19 17:21:52 +03:00
parent d19530a985
commit 24a6ff74b5
91 changed files with 3626 additions and 7296 deletions

View File

@ -0,0 +1,250 @@
# 🔍 ПЛАН ИСПРАВЛЕНИЯ SMS РЕГИСТРАЦИИ - ДЕТАЛЬНЫЙ АНАЛИЗ ПРОБЛЕМЫ
> **Дата:** 2025-09-18
> **Проблема:** После SMS верификации пользователь перебрасывается на `/` вместо продолжения регистрации
---
## 🚨 ОПИСАНИЕ ПРОБЛЕМЫ
### 📱 Что должно происходить (правильная логика SFERA):
**ЕДИНЫЙ FLOW авторизации/регистрации:**
1. Пользователь вводит номер телефона → SMS отправляется
2. Пользователь вводит SMS код → код верифицируется
3. **Определяется сценарий:**
- **СЦЕНАРИЙ A:** Пользователь существует + есть организация → **Dashboard**
- **СЦЕНАРИЙ B:** Пользователь существует + НЕТ организации → **Cabinet-select** (выбор типа кабинета)
- **СЦЕНАРИЙ C:** Новый пользователь → **Cabinet-select** (выбор типа кабинета)
### ❌ Что происходит сейчас (баг):
```
1. Пользователь вводит телефон → ✅ SMS отправляется
2. Пользователь вводит SMS код → ✅ код верифицируется успешно
3. ❌ Пользователь перебрасывается на главную страницу `/`
4. ❌ AuthFlow сбрасывается на step: "phone"
5. ❌ Пользователь вынужден начинать регистрацию заново
```
### 🔍 Логи ошибки:
```javascript
// SMS verification прошла успешно:
🌐 GraphQL REQUEST: { operationName: 'VerifySmsCode', variables: { phone: '76657584949', code: '1234' } }
POST /api/graphql 200 in 1295ms
// Но после этого:
AppShell state: { pathname: '/', isAuthenticated: false, hasUser: false }
🎢 AuthFlow - useEffect triggered with: { isAuthenticated: false, hasUser: false, currentStep: "phone" }
🎢 AuthFlow - User not authenticated, setting step to phone
```
**КЛЮЧЕВАЯ ПРОБЛЕМА:** `isAuthenticated: false` после успешной SMS верификации!
---
## 🔍 КОРНЕВАЯ ПРИЧИНА
### 🎯 Диагноз:
**AuthContext не обновляется после SMS верификации**, поэтому:
1. SMS верификация успешна → токен сохраняется в localStorage
2. НО AuthContext остается `isAuthenticated: false, user: null`
3. app/page.tsx видит неавторизованного пользователя → redirect на `/login`
4. AuthFlow инициализируется заново → step: "phone"
### 🔧 Предполагаемые причины:
**1. Timing issue в AuthContext:**
- SMS-step сохраняет токен через `verifySmsCode()`
- AuthContext не успевает обновить состояние
- useEffect в AuthFlow срабатывает с устаревшими данными
**2. Конфликт между экземплярами AuthFlow:**
- AuthGuard на `/dashboard` может создавать второй AuthFlow
- Два AuthFlow конфликтуют между собой
**3. Проблема в app/page.tsx:**
- Слишком быстро перенаправляет до обновления AuthContext
- Не учитывает `isLoading` состояние
---
## 📋 ПЛАН ИСПРАВЛЕНИЯ
### **PHASE 1: ДИАГНОСТИКА И ЛОГИРОВАНИЕ**
#### 1.1 Добавить детальное логирование в AuthContext
```typescript
// В verifySmsCode после успешной верификации:
console.warn('🔑 AuthContext - BEFORE setState:', {
isAuthenticated: this.isAuthenticated,
hasUser: !!this.user
})
setUser(result.user)
setIsAuthenticated(true)
console.warn('🔑 AuthContext - AFTER setState:', {
isAuthenticated: true,
hasUser: !!result.user,
userOrganization: result.user.organization
})
```
#### 1.2 Добавить логирование в AuthFlow useEffect
```typescript
useEffect(() => {
console.warn('🎢 AuthFlow - useEffect DETAILED:', {
isAuthenticated,
hasUser: !!user,
hasOrganization: !!user?.organization,
userFromContext: user,
currentStep: step,
timestamp: new Date().toISOString()
})
// Существующая логика...
}, [isAuthenticated, user])
```
#### 1.3 Добавить логирование в app/page.tsx
```typescript
useEffect(() => {
console.warn('📍 app/page.tsx - routing decision:', {
isLoading,
hasUser: !!user,
hasOrganization: !!user?.organization,
currentPath: window.location.pathname
})
// Существующая логика...
}, [router, user, isLoading])
```
### **PHASE 2: ИСПРАВЛЕНИЕ TIMING ISSUES**
#### 2.1 Исправить AuthContext - добавить промисы
```typescript
const verifySmsCode = async (phone: string, code: string) => {
// ... существующий код ...
if (result.success && result.token && result.user) {
setAuthToken(result.token)
setUserData(result.user)
// Синхронно обновляем состояние
setUser(result.user)
setIsAuthenticated(true)
// ЖДЕМ обновления Apollo Client
await refreshApolloClient()
// Возвращаем промис когда все готово
return new Promise(resolve => {
setTimeout(() => {
resolve({ success: true, message: result.message, user: result.user })
}, 100) // Небольшая задержка для обновления состояния
})
}
}
```
#### 2.2 Добавить isLoading в app/page.tsx
```typescript
const { user, isLoading, isAuthenticated } = useAuthContext()
useEffect(() => {
// КРИТИЧНО: ждем завершения всех проверок
if (isLoading) {
console.warn('📍 app/page.tsx - still loading, waiting...')
return
}
// Только после isLoading: false делаем redirect
if (user?.organization) {
router.replace('/dashboard')
} else if (isAuthenticated) {
router.replace('/login') // Продолжить на странице регистрации
} else {
router.replace('/login')
}
}, [router, user, isLoading, isAuthenticated])
```
### **PHASE 3: УСТРАНЕНИЕ КОНФЛИКТОВ**
#### 3.1 Исправить AuthGuard
```typescript
// НЕ создавать новый AuthFlow на dashboard
if (!isAuthenticated || (isAuthenticated && user && !user.organization)) {
// Перенаправить вместо показа AuthFlow
const router = useRouter()
useEffect(() => {
router.replace('/login')
}, [])
return <div>Перенаправление...</div>
}
```
#### 3.2 Убрать window.location.href из AuthFlow
```typescript
// ЗАМЕНИТЬ:
window.location.href = '/dashboard'
// НА:
router.push('/dashboard')
```
### **PHASE 4: ТЕСТИРОВАНИЕ**
#### 4.1 Тест-сценарии:
1. **Новый пользователь:** phone → sms → cabinet-select → inn/api → complete → dashboard
2. **Существующий без организации:** phone → sms → cabinet-select → inn/api → complete → dashboard
3. **Существующий с организацией:** phone → sms → dashboard
4. **Партнерские коды:** все сценарии с параметрами
#### 4.2 Проверки:
- ✅ Нет перебросов на `/`
- ✅ AuthFlow не сбрасывается на phone
- ✅ Состояние AuthContext корректное
- ✅ Нет создания второго AuthFlow
---
## 🎯 ОЖИДАЕМЫЙ РЕЗУЛЬТАТ
### ✅ После исправления:
```
1. Пользователь вводит телефон → SMS отправляется
2. Пользователь вводит SMS код → код верифицируется
3. AuthContext обновляется → isAuthenticated: true, user: {...}
4. AuthFlow определяет сценарий:
- СЦЕНАРИЙ A: user.organization есть → step: 'complete' → dashboard
- СЦЕНАРИЙ B/C: user.organization нет → step: 'cabinet-select'
5. Пользователь продолжает регистрацию БЕЗ сброса
```
### 📊 Логи после исправления:
```javascript
🔑 AuthContext - SMS verification successful
🔑 AuthContext - State updated: isAuthenticated=true, user=...
🎢 AuthFlow - useEffect: { isAuthenticated: true, hasUser: true, hasOrganization: false }
🎢 AuthFlow - Setting step to cabinet-select
Пользователь видит страницу выбора типа кабинета
```
---
## 🚀 ГОТОВНОСТЬ К РЕАЛИЗАЦИИ
**✅ Проблема диагностирована:** Timing issue в AuthContext + конфликт AuthFlow экземпляров
**✅ План пошаговый:** 4 фазы с детальным логированием и тестированием
**✅ Минимальные изменения:** Фокус на исправлении, а не переписывании архитектуры
**🎯 Следующий шаг:** Начать PHASE 1 - добавить детальное логирование для подтверждения диагноза