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

04 user journeys

Пользовательские сценарии в OneWallet — от регистрации до платежа.

Регистрация нового пользователя

Самостоятельная регистрация через email OTP. После успешного подтверждения пользователь переходит к KYC.

sequenceDiagram
  participant U as Пользователь
  participant App as onewallet_app
  participant AC as Auth Center
  participant Redis as Redis (OTP)
  participant Email as SMTP

  U->>App: ввести email
  App->>AC: startRegistration(email)
  AC->>Redis: createOrFindPendingUser → status=registration_in_progress
  AC->>Email: OTP (6 цифр, TTL 10 мин)
  U->>App: ввести OTP
  App->>AC: verifyOtp(email, code)
  AC->>Redis: validateOTP → del otp:email
  U->>App: задать пароль + PIN (6 цифр)
  App->>AC: finishRegistration(password, pin)
  AC->>AC: linkAuthUser → status=kyc_pending
  App->>App: перейти на KYC-онбординг

Шаги: 1. Приложение отправляет email в startRegistration — создаётся запись User со статусом registration_in_progress. 2. Auth Center генерирует 6-значный OTP, сохраняет в Redis (TTL — env REGISTRATION_OTP_TTL_MINUTES, по умолчанию 10 мин), отправляет SMTP-письмо. 3. Пользователь вводит OTP в приложении; попытки ограничены (REGISTRATION_OTP_MAX_ATTEMPTS). 4. После подтверждения OTP пользователь задаёт пароль и 6-значный PIN (требование NatBank). 5. linkAuthUser связывает Serverpod-запись с authUserId и переводит статус в kyc_pending. 6. Приложение открывает экран KYC-онбординга.

Поле Значение после регистрации
user.status kyc_pending
user.accountType consumer (по умолчанию)
user.authUserId заполнен (UUID Serverpod Auth)

P2P-перевод (phone flow)

Перевод с кошелька на кошелёк по номеру телефона. Перевод выполняется синхронно через PM (channel=INTERNAL).

sequenceDiagram
  participant U as Отправитель
  participant App as onewallet_app
  participant AC as Auth Center
  participant PM as Payment Manager

  U->>App: ввести номер телефона получателя
  App->>AC: resolveRecipientByPhone(phone)
  AC-->>App: PhoneResolveResult (имя, tbAccountId)
  U->>App: ввести сумму
  App->>AC: previewIntent(amount, currency, recipientUserId)
  AC->>PM: POST /intents/preview (HMAC)
  PM-->>AC: IntentQuoteResponse (fee, итого)
  AC-->>App: комиссия и итоговая сумма
  U->>App: подтвердить PIN / биометрию
  App->>AC: createIntent(idempotencyKey, P2P_TRANSFER, amount, ...)
  AC->>PM: POST /intents (HMAC, channel=INTERNAL)
  PM->>PM: settleSync() → TigerBeetle
  PM-->>AC: IntentDto (status=COMPLETED)
  AC-->>App: IntentDto
  App->>AC: getIntent(intentId) — поллинг при необходимости
  App-->>U: экран успеха

Шаги: 1. resolveRecipientByPhone — ищет активного пользователя по телефону, возвращает имя и tbAccountId для отображения. 2. previewIntent — запрашивает у PM расчёт комиссии без создания интента. 3. Пользователь подтверждает через PIN (6 цифр) или биометрию. 4. createIntent с flow='phone' и recipientUserId — PM выполняет синхронный расчёт (INTERNAL channel, без PSP-адаптера). 5. Поллинг через getIntent нужен только при возвращении статуса PENDING; в норме COMPLETED приходит сразу.


Пополнение через агента (TOPUP)

Агент (кассир) создаёт пополнение для потребителя через merchant_app. Перевод из агентского кошелька в кошелёк потребителя.

sequenceDiagram
  participant A as Агент
  participant MApp as merchant_app
  participant AC as Auth Center
  participant PM as Payment Manager
  participant C as Потребитель

  A->>MApp: ввести телефон потребителя и сумму
  MApp->>AC: createTopup(consumerPhone, amount, currency)
  AC->>AC: requireAccountType → merchant | agent
  AC->>PM: POST /intents (HMAC, operationType=TOPUP)
  PM->>PM: settleSync() → TigerBeetle
  PM-->>AC: IntentDto (COMPLETED)
  AC-->>MApp: IntentDto
  MApp-->>A: экран успеха
  C-->>C: получает push-уведомление о зачислении

Шаги: 1. createTopup доступен только аккаунтам с accountType = merchant | agent. 2. Auth Center передаёт в PM operationType=TOPUP с HMAC-подписью (X-Service-Id, X-Timestamp, X-Signature). 3. PM выполняет списание с агентского кошелька и зачисление на кошелёк потребителя через TigerBeetle. 4. Потребитель получает push-уведомление через Notifications Service.


Оплата QR-инвойса

Потребитель сканирует QR мерчанта и оплачивает инвойс. Мерчант создаёт инвойс заранее через createInvoice.

sequenceDiagram
  participant U as Потребитель
  participant App as onewallet_app
  participant AC as Auth Center
  participant PM as Payment Manager
  participant M as Мерчант

  M->>AC: createInvoice(amount, currency, ref)
  AC-->>M: InvoiceQrPayload (QR с tbAccountId + invoiceId)
  U->>App: сканировать QR
  App->>AC: previewInvoice(qrRawPayload, appId)
  AC->>AC: requireAccountType → consumer | wallet
  AC->>AC: InvoiceQrDecoder.decode(qrRawPayload)
  AC->>PM: POST /intents/preview (HMAC)
  PM-->>AC: fee breakdown
  AC-->>App: InvoicePreviewResponse (сумма, комиссия, мерчант)
  U->>App: подтвердить PIN / биометрию
  App->>AC: confirmInvoice(invoiceId, appId, idempotencyKey)
  AC->>PM: POST /intents (HMAC, operationType=INVOICE_PAYMENT)
  PM->>PM: settleSync() → TigerBeetle
  PM-->>AC: IntentDto (COMPLETED)
  AC-->>App: IntentDto
  App-->>U: экран успеха
  M-->>M: получает push о поступлении оплаты

Шаги: 1. Мерчант заранее создаёт инвойс (createInvoice); результат — QR-payload с tbAccountId и invoiceId. 2. previewInvoice декодирует QR, проверяет срок действия инвойса и запрашивает комиссию у PM без создания интента. 3. Потребитель подтверждает через PIN или биометрию. 4. confirmInvoice создаёт и сразу исполняет интент; invoiceId связывает платёж с записью инвойса. 5. Оба участника получают push-уведомления через Notifications Service.