Registration
Регистрация пользователей: OTP, жизненный цикл временного аккаунта, cleanup jobs.
OTP¶
| Параметр | Default | Env-переменная |
|---|---|---|
| Длина кода | 6 цифр (Random.secure().nextInt(999999).padLeft(6, '0')) |
— |
| TTL кода | 10 минут | REGISTRATION_OTP_TTL_MINUTES |
| Максимум попыток ввода | 5 | REGISTRATION_OTP_MAX_ATTEMPTS |
| Rate limit | 3 запроса за 10 минут | REGISTRATION_OTP_RATE_LIMIT_PER_10MIN |
OTP и счётчики попыток хранятся в Redis:
- otp:{email} — код (TTL = otpTtlMinutes)
- otp:attempts:{email} — счётчик неверных попыток (TTL 10 мин)
- otp:ratelimit:{email} — счётчик запросов кодов (TTL 10 мин)
При превышении otpMaxAttempts неверных попыток — ключ otp:{email} удаляется, следующий код нужно запросить заново.
Создание пользователя¶
sequenceDiagram
App->>AC: register(email)
AC->>AC: createOrFindPendingUser(email)
Note over AC: status=registration_in_progress\nregistrationExpiresAt = now + 7 дней\naccount_type=consumer
AC->>SMTP: OTP код (HTML email)
App->>AC: verifyOtp(email, code)
AC->>AC: validateOTP() — Redis проверка
App->>AC: finishRegistration(registrationToken, password)
AC->>AC: linkAuthUser(email, authUserId)
Note over AC: status → kyc_pending\nauthUserId установлен\nlastActivityAt обновлён
App->>App: перейти к KYC
createOrFindPendingUser идемпотентен: если пользователь уже существует в статусе registration_in_progress, обновляет registrationExpiresAt.
Admin-created аккаунты (merchant, agent) создаются с status=active и пропускают kyc_pending: linkAuthUser сохраняет текущий статус, не переводит в kyc_pending.
Cleanup FutureCalls¶
Все jobs самоперепланируются после каждого выполнения.
| Job | Первый запуск | Расписание | Действие |
|---|---|---|---|
DeleteIncompleteRegistrationsFutureCall |
через 1 минуту после старта | каждые 6 часов | DELETE пользователей без user_profile, старше REGISTRATION_INCOMPLETE_TTL_HOURS (default 24 ч), в статусах registration_in_progress / registration_expired |
ArchiveExpiredRegistrationsFutureCall |
следующий день 02:00 UTC | ежедневно 02:00 UTC | UPDATE users SET isArchived=true, status=registration_expired где registrationExpiresAt < now |
SendRegistrationRemindersFutureCall |
следующий день 09:00 UTC | ежедневно 09:00 UTC | Выборка пользователей, у которых registrationExpiresAt <= now + reminderDays; отправка email [PLAN] (TODO Phase 3) |
HardDeleteArchivedUsersFutureCall |
через 7 дней после старта | каждые 7 дней | HARD DELETE через UserDeletionService.deleteWithDependencies() для isArchived=true и archivedAt < now - hardDeleteDays |
Удаление (DeleteIncomplete, HardDelete) выполняется через UserDeletionService.deleteWithDependencies() — каскадное удаление всех связанных данных.
Env-переменные¶
| Переменная | Default | Описание |
|---|---|---|
REGISTRATION_OTP_TTL_MINUTES |
10 |
Время жизни OTP в Redis (минуты) |
REGISTRATION_OTP_MAX_ATTEMPTS |
5 |
Максимум неверных вводов до инвалидации кода |
REGISTRATION_OTP_RATE_LIMIT_PER_10MIN |
3 |
Максимум запросов нового кода за 10 минут |
REGISTRATION_TEMP_USER_TTL_DAYS |
7 |
TTL временного аккаунта registration_in_progress |
REGISTRATION_HARD_DELETE_ARCHIVED_AFTER_DAYS |
30 |
Через сколько дней после архивации выполнять hard delete |
REGISTRATION_REMINDER_DAYS_BEFORE_EXPIRY |
2 |
За сколько дней до истечения регистрации слать напоминание |
REGISTRATION_INCOMPLETE_TTL_HOURS |
24 |
TTL для DeleteIncompleteRegistrations: удалять пользователей без профиля старше N часов |