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

03 auth lifecycle

Машина состояний пользователя: от регистрации до удаления.

Диаграмма состояний

stateDiagram-v2
    [*] --> registration_in_progress: createOrFindPendingUser()
    registration_in_progress --> kyc_pending: linkAuthUser()
    registration_in_progress --> registration_expired: TTL истёк (REGISTRATION_TEMP_USER_TTL_DAYS)
    kyc_pending --> pending_operator_review: confirmKycData()
    pending_operator_review --> kyc_pending: operatorReject()
    pending_operator_review --> active: finalizeVerification()
    active --> blocked: blockUser()
    blocked --> active: unblockUser()
    registration_expired --> [*]: ArchiveExpiredRegistrations job (isArchived=true)

Описание статусов

Статус Описание Блокирует вход? Триггер перехода
registration_in_progress Временный пользователь создан, OTP выслан, email не подтверждён Нет (вход невозможен — auth user не привязан) createOrFindPendingUser()
kyc_pending Email подтверждён, auth user привязан; документы ещё не загружены Нет linkAuthUser()
pending_operator_review KYC-данные отправлены, ждут проверки оператором или auto-verify Нет confirmKycData()
active Полноправный аккаунт; кошелёк создан, KYC fully_verified Нет finalizeVerification()
blocked Заблокирован оператором; вход запрещён Да → 403 blockUser()
registration_expired Регистрация не завершена за TTL; isArchived флаг не выставлен немедленно Да → 403 ArchiveExpiredRegistrations job

isArchived = true выставляется job'ом ArchiveExpiredRegistrations. После этого пользователь не находится ни одним query (where: t.isArchived.equals(false)).

AuthValidateEndpoint

Вызывается при каждом token refresh и endpoint-запросе через Serverpod middleware.

Статусы, блокирующие доступ (→ NotAuthorizedException / insufficientAccess):

Статус Поведение
registration_expired 403, логируется warning
blocked 403, логируется warning
isArchived = true user не найден → 401 (unauthenticated)

Возвращаемый объект ValidateResult:

Поле Тип Источник
userId int users.id
status String users.status
kycStatus String? kyc_verifications.status
email String? users.email
displayName String? Расшифровка PII: fullNamefirstName lastName
roles List<String> admin_roles JOIN admin_user_roles

Также обновляет users.lastActivityAt при каждом успешном validate.
Файл: lib/src/endpoints/auth/auth_validate_endpoint.dart

Cleanup FutureCalls

Все jobs регистрируются и планируются в lib/server.dart при старте — идемпотентно (cancel + reschedule).

Job Расписание Действие
DeleteIncompleteRegistrationsFutureCall Через 1 мин после старта, затем само перепланируется каждые 6 ч Удаляет registration_in_progress записи старше OTP TTL без привязанного auth user
ArchiveExpiredRegistrationsFutureCall Ежедневно в 02:00 UTC Ставит isArchived=true на пользователей со статусом registration_expired (TTL истёк)
SendRegistrationRemindersFutureCall Ежедневно в 09:00 UTC Push/email напоминание не завершившим KYC за REGISTRATION_REMINDER_DAYS_BEFORE_EXPIRY дней до экспирации
HardDeleteArchivedUsersFutureCall Раз в 7 дней Hard delete строк с isArchived=true старше REGISTRATION_HARD_DELETE_ARCHIVED_AFTER_DAYS дней

Env vars

Переменная Умолчание Назначение
REGISTRATION_OTP_TTL_MINUTES 10 Время жизни OTP-кода в минутах
REGISTRATION_OTP_MAX_ATTEMPTS 5 Максимум попыток ввода OTP
REGISTRATION_OTP_RATE_LIMIT_PER_10MIN 3 Максимум запросов OTP за 10 минут
REGISTRATION_TEMP_USER_TTL_DAYS 7 Дней до экспирации незавершённой регистрации
REGISTRATION_HARD_DELETE_ARCHIVED_AFTER_DAYS 30 Дней до hard-delete после архивации
REGISTRATION_REMINDER_DAYS_BEFORE_EXPIRY 2 За сколько дней до экспирации слать напоминание

Все значения читаются в RegistrationConfig.initialize() при старте сервера.
Файл: lib/src/services/registration_service.dart