Перейти к содержанию

OneWallet — Карта маршрутов

Переменные состояния (от провайдеров)

Переменная Источник Значение
isAuthenticated authProvider.status == authenticated Пользователь вошёл
userStatus authProvider.userStatus null / registration_in_progress / kyc_pending / pending_operator_review / fully_verified
kycStatus authProvider.kycStatus Статус KYC из таблицы kyc_verification (null / pending / in_review / pending_operator_review / approved / …)
needsKyc userStatus == 'kyc_pending' Нужно пройти KYC (не начат)
isPendingReview userStatus == 'pending_operator_review' или userStatus == 'registration_in_progress' && kycStatus != null && kycStatus != 'pending' KYC подан, ждёт проверки
isInitialized pinProvider.isInitialized SecureStorage прочитан
isPinSet pinProvider.isPinSet PIN задан
isLocked pinProvider.isLocked Приложение заблокировано (после 5 мин)

Все маршруты

/                    → SplashScreen        (начальный, ждёт инициализацию)
/welcome             → WelcomeScreen       (гость: выбор войти/регистрация)
/signin              → SignInScreen
/register/email      → RegisterEmailScreen
/register/otp        → RegisterOtpScreen
/register/referral   → RegisterReferralScreen
/register/password   → RegisterPasswordScreen
/forgot-password     → ForgotPasswordScreen
/forgot-password/otp → ForgotPasswordOtpScreen
/reset-password      → ResetPasswordScreen
/setup-pin           → SetupPinScreen      (первичная установка PIN)
/setup-biometric     → SetupBiometricScreen
/pin-unlock          → PinUnlockScreen     (разблокировка после auto-lock)
/kyc                 → KycIntroScreen
/kyc/upload          → KycDocumentScreen   (фото паспорта + селфи)
/kyc/processing      → KycProcessingScreen (ожидание OCR)
/kyc/review          → KycReviewScreen     (проверка данных)
/kyc/terms           → KycTermsScreen      (согласие)
/kyc/pending         → KycPendingScreen    ("Verification Status" — только по тапу на баннер)
/home                → HomeScreen          ┐
/history             → HistoryScreen       ├─ StatefulShellRoute
/profile             → ProfileScreen       │  (GlassNavigationBar)
/profile/activity    → ActivityScreen      ┘

Логика редиректов (выполняется при КАЖДОЙ навигации)

redirect(path) {

  ┌─ Block 1 ─────────────────────────────────────────────────────────────
  │ !isAuthenticated && !isAuthRoute && path ≠ '/'
  │ → /welcome
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 2 ─────────────────────────────────────────────────────────────
  │ isAuthenticated && isLocked && !isPinUnlockRoute
  │ → /pin-unlock
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 2b ─────────────────────────────────────────────────────────────
  │ isPinUnlockRoute && isAuthenticated && isInitialized && !isLocked
  │   needsKyc  → /kyc
  │   else      → /home   ← isPendingReview НЕ редиректит на /kyc/pending
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 3 ─────────────────────────────────────────────────────────────
  │ isAuthenticated && isInitialized && !isPinSet
  │           && !isPinSetupRoute && !isPinUnlockRoute
  │ → /setup-pin
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 4 ─────────────────────────────────────────────────────────────
  │ isAuthenticated && (isAuthRoute || path == '/')
  │   !isInitialized   → null  (остаёмся на сплэше)
  │   needsKyc         → /kyc
  │   else             → /home  ← isPendingReview НЕ редиректит на /kyc/pending
  │ ⚠️  isPendingReview НЕ вызывает авто-переход на /kyc/pending при холодном
  │     запуске. Статус виден через баннер на /home, переход — по тапу.
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 5 ─────────────────────────────────────────────────────────────
  │ isAuthenticated && needsKyc
  │       && !isKycRoute && !isPinSetupRoute && !isPinUnlockRoute
  │ → /kyc
  │ ⚠️  Без !isPinUnlockRoute: /pin-unlock→/kyc→/pin-unlock = redirect loop!
  └────────────────────────────────────────────────────────────────────────

  ┌─ Block 6 ─────────────────────────────────────────────────────────────
  │ isAuthenticated && isPendingReview
  │       && path ∈ [/kyc/upload, /kyc/processing, /kyc/review, /kyc/terms]
  │ → /kyc/pending
  │ Защищает от повторной подачи документов пока идёт проверка.
  └────────────────────────────────────────────────────────────────────────

  → null  (навигация разрешена)
}

isPendingReview — расширенная логика

bool get isPendingReview =>
    userStatus == 'pending_operator_review' ||
    (userStatus == 'registration_in_progress' &&
        kycStatus != null &&
        kycStatus != 'pending');
userStatus kycStatus isPendingReview Результат
registration_in_progress null false Нужно пройти KYC → баннер _KycBanner (если needsKyc)
registration_in_progress pending false Нужно пройти KYC
registration_in_progress in_review / pending_operator_review / … true KYC подан → баннер _KycReviewBanner, переход по тапу
pending_operator_review любой true KYC подан → баннер _KycReviewBanner
fully_verified любой false Полный доступ, нет баннеров

Баннеры на /home

Условие Баннер Действие по тапу
needsKyc _KycBanner — "Complete identity verification" context.go('/kyc')
isPendingReview _KycReviewBanner — "Documents under review" context.go('/kyc/pending')
иначе нет баннера

/kyc/pending открывается только по тапу на баннер. Автоматической навигации на этот экран при холодном запуске нет.


Схема переходов

Router Map

Исходник: docs/diagrams/router-map.puml


Сценарии пользователей

A. Новый пользователь (регистрация → KYC)

RegisterPassword → context.go('/home')
  └─ redirect Block3: !isPinSet         → /setup-pin
       └─ redirect Block5: needsKyc     → /kyc  ← пользователь здесь
            └─ redirect: null (isKycRoute) → /kyc рендерится

B. Возврат в приложение (PIN заблокирован, needsKyc)

App start → / (SplashScreen)
  └─ _init() completes: isLocked=true
       └─ redirect Block2: isLocked     → /pin-unlock
            └─ User verifies PIN
                 └─ redirect Block2b: needsKyc → /kyc

C. Возврат в приложение (PIN разблокирован, KYC пройден)

App start → / (SplashScreen)
  └─ _init() completes: isLocked=true
       └─ redirect Block2                → /pin-unlock
            └─ User verifies PIN
                 └─ redirect Block2b: !needsKyc → /home

D. KYC submitter (ждёт оператора) — холодный запуск

App start → / (SplashScreen)
  └─ isAuthenticated + isInitialized + !needsKyc
       └─ Block4 → /home
            └─ _KycReviewBanner отображается на /home
                 └─ Пользователь тапает → context.go('/kyc/pending')

⚠️ До изменения (v1): Block 4/2b перенаправляли isPendingReview → /kyc/pending автоматически. Теперь /kyc/pending открывается только явным тапом.

E. registration_in_progress + kycStatus активный

userStatus='registration_in_progress', kycStatus='in_review'
  isPendingReview = true
  → Block4: !needsKyc → /home
  → _KycReviewBanner отображается
  → Block6: если попытка зайти в /kyc/upload → /kyc/pending (защита)

F. Перелогон (pending_operator_review) — через /setup-biometric

signIn()
  └─ clearPin()                          → isPinSet=false
       └─ status: authenticated           → Block3: !isPinSet → /setup-pin
            └─ loadUserStatus()           → userStatus='pending_operator_review'
                 └─ Пользователь ставит PIN → /setup-biometric
                      └─ Skip / Enable / Unavailable
                           └─ _postSetupRoute: !needsKyc → /home  ✅
                                └─ _KycReviewBanner отображается на /home

⚠️ До исправления (issue #5): SetupBiometricScreen всегда делал context.go('/kyc'), из-за чего пользователь с pending_operator_review видел экран "Start Verification".


Навигация внутри экранов (не GoRouter redirect)

Ряд экранов сами управляют навигацией после завершения действия. Это не покрывается логикой redirect — GoRouter проверяет маршрут только при переходе.

Экран Действие Переход
SetupPinScreen PIN подтверждён context.go('/setup-biometric')
SetupBiometricScreen Enable / Skip / Unavailable context.go(_postSetupRoute)/kyc если needsKyc, иначе /home
HomeScreen_KycBanner Тап context.go('/kyc')
HomeScreen_KycReviewBanner Тап context.go('/kyc/pending')
KycIntroScreen "Start Verification" context.go('/kyc/upload')

Известные проблемы

# Статус Проблема Блок Симптом
1 ✅ fixed Block5 не исключал /pin-unlock Block 5 /pin-unlock↔/kyc redirect loop → "Route not found"
2 ✅ fixed Block5 не исключал /setup-pin, /setup-biometric Block 5 Пользователь не попадает на PIN setup при needsKyc=true
3 ✅ fixed Block4/2b авто-редиректили isPendingReview/kyc/pending при холодном запуске Block 4, 2b "Verification Status" показывался при каждом открытии для registration_in_progress пользователей
4 debugLogDiagnostics: true в production Лишние логи → теперь kDebugMode
5 ✅ fixed SetupBiometricScreen жёстко вёл на /kyc после PIN setup Screen-level nav Пользователь с pending_operator_review после перелогона видел "Start Verification" вместо /home