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

10 operator guide

Руководство оператора: KYC-проверка, управление пользователями, аудит.

Роли операторов

Роли определены в таблице admin_roles, назначаются пользователям через admin_user_roles.

Роль Доступные действия
superadmin Все операции: KYC (approve/reject/finalize/setKycTier), управление пользователями (block/unblock/lockProfile/unlockProfile/updateProfile), просмотр PII, управление NFC, создание мерчантов/агентов/потребителей
operator Те же права что у superadmin (в текущей реализации оба проходят одинаковые guards)
finance Определена в БД; guards для финансовых операций не реализованы в текущей версии
support Определена в БД; guards для операций поддержки не реализованы в текущей версии

Проверка выполняется через _requireRoles(session, ['superadmin', 'operator']) — SQL JOIN admin_user_roles + admin_roles.

KYC Review

sequenceDiagram
    participant Op as Оператор
    participant Admin as Admin Panel
    participant AC as Auth Center
    participant User as Пользователь

    Op->>Admin: открыть заявку KYC
    Admin->>AC: getKycVerification(id)
    Op->>Admin: просмотреть документы + OCR
    Admin->>AC: revealOcrResult(id, reason)
    Op->>Admin: одобрить заявку

    alt Одобрение
        Op->>Admin: approve()
        Admin->>AC: operatorApprove(kycId)
        Op->>Admin: finalize()
        Admin->>AC: finalizeVerification(kycId)
        Note over AC: user.status → active<br/>userProfile.isLocked = true
        AC->>User: push "Кошелёк активирован"
    else Отклонение
        Op->>Admin: reject(reason)
        Admin->>AC: operatorReject(kycId, reason)
        Note over AC: kyc.status → pending<br/>user может повторить
        AC->>User: push "KYC отклонена"
    end
Действие Метод эндпоинта Что происходит
Просмотр очереди getQueue() Возвращает все KYC в статусе pending_operator_review с masked-профилями
Просмотр карточки getDetail(userId) Полная KYC карточка + presigned URLs документов
Одобрить approve(userId) KycService.operatorApprove() → kyc.status обновляется; запись в audit_log
Отклонить reject(userId, reason) KycService.operatorReject() → kyc.status откатывается, пользователь может повторить; reason сохраняется в audit
Финализировать finalize(userId) KycService.finalizeVerification() → kyc.status = fully_verified, user.status = active, профиль блокируется, push-уведомление пользователю
Изменить tier setKycTier(userId, tier) UserProfile.accountTier = BASIC/STANDARD/PREMIUM/VIP; устанавливает флаг accountTierOverriddenByAdmin=true — автологика не перезапишет

Допустимые значения tier: BASIC, STANDARD, PREMIUM, VIP.

Просмотр PII

Профиль пользователя

AdminUserEndpoint.revealPii(userId, reason)
  • Роли: operator, superadmin
  • reason обязателен, минимум 10 символов
  • Расшифровывает encryptedPii и возвращает DecryptedProfile
  • Раскрываемые поля: phone, firstName, lastName, fullName, dateOfBirth, nationality, countryOfResidence, nationalIdNumber, address, dateOfIssue, dateOfExpiry, gender
  • Автоматически пишет в audit_log action=pii_revealed с reason, списком полей и traceId

OCR результат KYC

AdminKycEndpoint.revealOcrResult(kycId, reason)
  • Роли: operator, superadmin
  • reason обязателен, минимум 10 символов
  • Расшифровывает kyc_verification.ocrResult
  • Пишет в audit_log action=ocr_revealed с kycId, reason, traceId

Управление пользователями

Блокировка

AdminUserEndpoint.blockUser(userId, reason)
  • Роли: superadmin, operator
  • reason минимум 10 символов
  • Выполняет: AuthUser.blocked=true → Serverpod отклоняет refresh → клиент разлогинивается; User.status='blocked'; рассылает authenticationRevoked (активные streaming-соединения закрываются)
  • Сохраняет previousStatus в audit для последующего восстановления

Разблокировка

AdminUserEndpoint.unblockUser(userId, reason)
  • Роли: superadmin, operator
  • Восстанавливает User.status из поля previousStatus последней записи user_block в audit_log; fallback = 'active'
  • Снимает AuthUser.blocked=false

Профиль (PII-защита)

Метод Действие
lockProfile(userId, reason) UserProfile.isLocked=true — запрещает редактирование PII; если user.status='pending_operator_review' — дополнительно финализирует KYC
unlockProfile(userId, reason) UserProfile.isLocked=false — разрешает редактирование
updateProfile(userId, input) Обновляет PII-поля через PiiProfileWriter; только когда isLocked=false
setNfcEnabled(userId, bool, reason) Заморозка NFC: nfcEnabled=false → все NFC-операции отклоняются с NFC_DISABLED
setEncryptPiiMode(userId, bool, reason) Режим хранения имён: encryptPii=false — открытый текст (для мерчантов)

Создание аккаунтов через admin

Метод accountType Особенности
createMerchant(...) merchant Требует businessName, taxId, businessCategoryCode; encryptPii=false по умолчанию
createAgent(...) agent Требует businessName, taxId; encryptPii=false по умолчанию
createConsumer(...) consumer encryptPii=true по умолчанию; создаёт кошелёк THB через WalletCreationService

Все три метода: генерируют временный пароль → создают auth-аккаунт → отправляют invite-письмо.

Audit Log

Каждое чувствительное действие записывается в таблицу audit_log.

action Когда записывается
kyc_approve Оператор одобряет KYC
kyc_reject Оператор отклоняет KYC
kyc_finalize Финализация верификации
kyc_set_tier Ручное изменение KYC tier
ocr_revealed Просмотр расшифрованного OCR результата
pii_revealed Просмотр расшифрованного PII профиля
user_block Блокировка пользователя
user_unblock Разблокировка пользователя
profile_lock Блокировка редактирования профиля
profile_unlock Снятие блокировки редактирования
profile_update Изменение PII полей администратором
nfc_enabled_changed Изменение флага NFC
encrypt_pii_mode_changed Изменение режима шифрования PII
merchant_created Создание мерчанта через admin
agent_created Создание агента через admin
consumer_created Создание потребителя через admin

Каждая запись содержит: userId (кого затронуло), action, performedBy='operator', details (JSON с adminId + специфичные поля), createdAt.