Files
sfera-new/2025-09-18/SMS_REGISTRATION_DEBUG_PLAN.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

9.5 KiB
Raw Blame History

🔍 ПЛАН ИСПРАВЛЕНИЯ 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. ❌ Пользователь вынужден начинать регистрацию заново

🔍 Логи ошибки:

// 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

// В 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

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

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 - добавить промисы

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

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

// НЕ создавать новый 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

// ЗАМЕНИТЬ:
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. Пользователь продолжает регистрацию БЕЗ сброса

📊 Логи после исправления:

🔑 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 - добавить детальное логирование для подтверждения диагноза