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

07 merchant scenarios

Сценарии для мерчантов и агентов: инвойсы, NFC, пополнения.

Мерчант и агент — отдельные accountType. Каждый endpoint защищён guard requireAccountType(session, [...]). Все финансовые операции создаются через POST /intents Payment Manager с HMAC-подписью.

Метод Кто вызывает Тип операции
createInvoice merchant INVOICE_PAYMENT
cancelInvoice merchant — (отмена)
chargeByNfc merchant NFC_CHARGE
createTopup agent TOPUP
requestSettlement merchant WITHDRAWAL

Создание QR-инвойса

Мерчант выставляет счёт; покупатель сканирует QR и платит из своего кошелька.

sequenceDiagram
    participant MerchApp as Merchant App
    participant AC as Auth Center
    participant PM as Payment Manager

    MerchApp->>AC: createInvoice(amount, currency, idempotencyKey, note?, ttlSeconds?)
    AC->>AC: requireAccountType([merchant])
    AC->>AC: resolve merchantWallet из v_user_tb_accounts
    AC->>PM: POST /intents (HMAC, operationType=INVOICE_PAYMENT, toTbAccountId=merchant)
    PM-->>AC: IntentDto { intentId, status: CREATED, qrSignature, expiresAt }
    AC->>AC: encodeInvoiceQr(intentId, merchantTbAccountId, amount, expiresAt, signature)
    AC-->>MerchApp: InvoiceQrPayload { qrPayload, intentId, expiresAt, merchantDisplayName }

    MerchApp->>MerchApp: отображает QR покупателю

Детали:

  • merchantDisplayNamebusinessName из профиля, fallback firstName, fallback email.
  • QR содержит HMAC-подпись PM; Auth Center верифицирует её при previewInvoice на стороне покупателя.
  • ttlSeconds задаёт время жизни QR; PM вернёт INVOICE_EXPIRED после истечения.
  • Мерчант может отменить невыкупленный инвойс через cancelInvoice(intentId).

Приём NFC-платежа

Покупатель прикладывает NFC-карту к устройству мерчанта; деньги списываются автоматически.

sequenceDiagram
    participant ConsCard as NFC Chip (покупатель)
    participant MerchApp as Merchant App
    participant AC as Auth Center
    participant PM as Payment Manager
    participant TB as TigerBeetle

    MerchApp->>ConsCard: READ_CNT + NDEF read
    ConsCard-->>MerchApp: token (base64url) + counter

    MerchApp->>AC: chargeByNfc(token, counter, amount, currency, idempotencyKey, lat?, lon?)
    AC->>AC: requireAccountType([merchant])
    AC->>AC: resolveAndConsume → верифицирует token, атомарно продвигает счётчик
    AC->>AC: assertNfcEnabled(customerUserId)
    AC->>AC: checkTagLimits(tag, amount) — perTapLimit, dailyLimit
    AC->>PM: POST /intents (HMAC auth-center-merchant, NFC_CHARGE)
    PM->>TB: consumer wallet → merchant wallet
    TB-->>PM: SETTLED
    PM-->>AC: IntentDto { status: COMPLETED }
    AC-->>MerchApp: NfcChargeResult

chargeByNfc подписывается привилегированным HMAC-ключом auth-center-merchant — отдельная пара serviceId / secret от стандартного auth-center. Это позволяет PM применять особые правила авторизации для pull-charge операций.

Проверки до PM (порядок важен):

  1. Токен найден в реестре → статус active → TTL не истёк.
  2. Счётчик строго вырос (counter > lastCounter) — защита от replay/клона.
  3. NFC включён глобально и для владельца метки.
  4. perTapLimit и dailyLimit не превышены.

Пополнение клиента (Topup)

Агент принимает наличные и зачисляет деньги на кошелёк клиента.

sequenceDiagram
    participant AgentApp as Agent App
    participant AC as Auth Center
    participant PM as Payment Manager
    participant TB as TigerBeetle

    AgentApp->>AC: createTopup(consumerPhone, amount, currency, idempotencyKey, comment?)
    AC->>AC: requireAccountType([agent])
    AC->>AC: hashPhone(consumerPhone) → lookup UserProfile
    AC->>AC: проверить accountType == consumer
    AC->>PM: POST /intents (HMAC, operationType=TOPUP, recipientUserId=consumer)
    PM->>TB: agent liquidity pool → consumer wallet
    TB-->>PM: SETTLED
    PM-->>AC: IntentDto { status: COMPLETED }
    AC-->>AgentApp: IntentDto

Детали:

  • Только agent-аккаунты вправе вызывать createTopup; consumer и merchant получают 403.
  • Телефон клиента хешируется через PII-сервис перед поиском — в запрос PM номер не попадает.
  • Операция синхронная: PM возвращает COMPLETED сразу после записи в TigerBeetle.

Settlement [PLAN]

Функциональность не реализована. Endpoint requestSettlement присутствует в коде (operationType=WITHDRAWAL), но PM-сага вывода средств находится в разработке.

Предполагаемый сценарий: мерчант запрашивает вывод накопленного баланса через агента-партнёра. Агент физически передаёт наличные, PM списывает средства с кошелька мерчанта на кошелёк агента. Подтверждение агентом — отдельный шаг (двухфазный трансфер в TigerBeetle).