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¶
Профиль пользователя¶
- Роли:
operator,superadmin reasonобязателен, минимум 10 символов- Расшифровывает
encryptedPiiи возвращаетDecryptedProfile - Раскрываемые поля:
phone,firstName,lastName,fullName,dateOfBirth,nationality,countryOfResidence,nationalIdNumber,address,dateOfIssue,dateOfExpiry,gender - Автоматически пишет в
audit_logaction=pii_revealedс reason, списком полей и traceId
OCR результат KYC¶
- Роли:
operator,superadmin reasonобязателен, минимум 10 символов- Расшифровывает
kyc_verification.ocrResult - Пишет в
audit_logaction=ocr_revealedс kycId, reason, traceId
Управление пользователями¶
Блокировка¶
- Роли:
superadmin,operator reasonминимум 10 символов- Выполняет:
AuthUser.blocked=true→ Serverpod отклоняет refresh → клиент разлогинивается;User.status='blocked'; рассылаетauthenticationRevoked(активные streaming-соединения закрываются) - Сохраняет
previousStatusв audit для последующего восстановления
Разблокировка¶
- Роли:
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.