User Management
1. Summary
Goal: Полноценная админ-панель для управления пользователями goLoot — поиск, просмотр, модерация, управление балансами.
User Value: Администратор получает полный контроль над пользователями: от просмотра детальной статистики до управления банами и валютами.
2. Business Logic
Capabilities
- Search & Browse
- User Details
- Actions
- Game Stats
Таблица пользователей:
- Пагинация: 10/25/50/100 записей
- Поиск: по имени, username, Telegram ID
- Сортировка: дата регистрации, уровень, scrap, lastLoginDate, dailyLoginStreak
- Фильтры: level (min/max), premium, banned, active, lastActivityDays (любое целое число >= 1)
StatCards метрики:
- Всего пользователей
- Доступны для рассылки
- Premium пользователи
- Активные за 7 дней
- Новые за 24ч
- Забаненные
Детальная карточка (6 секций):
| Секция | Данные |
|---|---|
| Основное | ID, Telegram данные, статус регистрации, дата создания |
| Балансы | Scrap, XP, Level, Streak Points, Boost Points, breakdown по источникам |
| Статистика | Квесты, достижения, стрики, активность |
| Рефералы | Кто пригласил, кого пригласил, реферальный доход |
| Инвентарь | Предметы с изображениями, фильтр по tier |
| Выводы | История выводов скинов |
Модерация:
- Бан — с обязательной причиной (max 500 символов)
- Разбан — снятие бана
- Удаление — soft delete (
deletedAt+isActive = false), скрывает из списка админки
Управление валютами:
- Scrap — добавить/убрать (1..1,000,000)
- XP — добавить/убрать
- Streak Points — добавить/убрать
- Boost Points — добавить/убрать (per-season, требует активный сезон с Boost Pass)
- Каждая операция требует причину (опционально)
Управление инвентарём:
- Выдать предмет — с причиной (обязательно)
- Удалить предмет — с указанием количества и причины
Массовые операции:
- Bulk Currency — массовое начисление валюты группе пользователей
История с пагинацией:
- История открытия кейсов
- История спинов рулетки
- Активные и завершённые квесты
- Полученные достижения
- История выводов
- История крафта
- История salvage
- Промокоды
- Розыгрыши
- Сезонные награды
- Admin grants
- История баффов
Services
| Сервис | Методы | Описание |
|---|---|---|
| UserCRUDService | getAllUsers, getUserDetailed, getUserStats, deleteUser | Основной CRUD + статистика для StatCards |
| UserBanService | banUser, unbanUser, getBanInfo | Бан/разбан с Steam blacklist |
| UserCurrencyService | addScrap, removeScrap, addXP, removeXP, addStreakPoints, removeStreakPoints, addBoostPoints, removeBoostPoints, getUserBalances, getTargetUsersCount, bulkAddCurrency | Валюты + массовые операции |
| UserActionsService | grantItem, removeInventoryItem | Управление инвентарём |
| UserInventoryStatsService | getUserInventory, getWithdrawals | Инвентарь и выводы |
| UserActivityStatsService | getCasesList, getSpinsList, getCaseHistory, getSpinHistory, getAllQuests, getAllAchievements | Справочники и история активности |
| UserCraftStatsService | getCraftHistory, getSalvageHistory | История крафта и salvage |
| UserRewardsStatsService | getPromoCodeRedemptions, getRaffleHistory, getSeasonRewards, getAdminGrants, getBuffHistory | Награды и баффы |
| BulkOperationsService | getUsersWithFilter | Legacy bulk operations |
Constants
Backend константы
// backend/src/domains/admin/constants/admin-users.constants.ts
ADMIN_USERS_CONSTANTS = {
DEFAULT_PAGE_SIZE: 20,
MAX_PAGE_SIZE: 100,
MIN_PAGE_SIZE: 10,
MAX_LEVEL_RANGE: 100,
MIN_LEVEL: 1,
DEFAULT_ACTIVITY_DAYS: 7,
MAX_ACTIVITY_DAYS: 365,
MAX_BAN_REASON_LENGTH: 500,
MAX_CURRENCY_CHANGE: 1_000_000,
MIN_CURRENCY_CHANGE: 1,
MAX_SEARCH_LENGTH: 100,
MIN_SEARCH_LENGTH: 1,
}
USER_SORT_OPTIONS = {
CREATED_AT: 'createdAt',
LEVEL: 'level',
SCRAP: 'scrap',
LAST_LOGIN: 'lastLoginDate',
DAILY_STREAK: 'dailyLoginStreak',
}
BULK_OPERATIONS = {
MAX_BULK_CURRENCY_AMOUNT: 100_000,
MIN_BULK_CURRENCY_AMOUNT: 1,
BATCH_SIZE: 500,
}
Protection
| Действие | Rate Limit | Auth | Validation |
|---|---|---|---|
| list users | adminApiLimiter (50/min) | admin | AdminUsersListQueryValidation |
| get stats | adminApiLimiter | admin | — |
| get details | adminApiLimiter | admin | UserIdParamValidation |
| ban user | adminApiLimiter | admin | BanUserBodyValidation |
| unban user | adminApiLimiter | admin | UserIdParamValidation |
| delete user | adminApiLimiter | admin | DeleteUserBodyValidation |
| manage currency | adminApiLimiter | admin | UpdateCurrencyBodyValidation |
| get inventory | adminApiLimiter | admin | UserInventoryQueryValidation |
| get histories | adminApiLimiter | admin | *HistoryQueryValidation |
Edge Cases
| Ситуация | Поведение |
|---|---|
| Пользователь не найден | HTTP 404, Prisma error handling |
| Невалидный amount | HTTP 400, валидация 1..1,000,000 |
| Убавление > баланса | Проверка текущего баланса перед операцией |
| Admin scrap grant | addScrap/removeScrap используют interactive transaction с updateSeasonStats() — scrap source admin обновляет UserSeasonStats.scrapFromAdmin |
| Бан уже забаненного | Обновляется причина и дата |
| Удаление (soft delete) | deletedAt + isActive = false. Скрывается из списка админки, но продолжает иметь доступ к TMA (auth middleware не проверяет deletedAt) |
3. ADR (Architectural Decisions)
Почему adminId = username?
Проблема: Нужно логировать кто выполнил действие, но JWT payload содержит username, не id.
Решение: Использовать request.admin?.username как adminId в логах.
Последствия:
bannedByхранит username админа- При переименовании админа — старые логи не обновятся
Три уровня управления доступом
| Уровень | Поля | Блокирует доступ к TMA? | Удаляет данные? |
|---|---|---|---|
| Бан | isBanned = true | Да — auth middleware проверяет | Нет |
| Soft Delete | deletedAt, isActive = false | Нет — auth middleware не проверяет deletedAt | Нет |
Full Reset (/stop) | Удаление связанных записей | Нет (аккаунт остаётся) | Да (инвентарь, квесты, история) |
Soft delete через админку не блокирует доступ пользователя к TMA. Auth middleware (telegram-auth.middleware.ts) проверяет только isBanned, но не deletedAt. Soft-deleted пользователь продолжает пользоваться приложением как обычно.
Если нужно заблокировать доступ — используй Бан, а не удаление.
Почему soft delete?
Проблема: Полное удаление пользователя потеряет данные для аналитики.
Решение: Soft delete через deletedAt + isActive = false.
Что делает:
- Устанавливает
deletedAt = now()иisActive = false - Скрывает пользователя из списка в админке
- Данные сохраняются для аналитики
- Можно восстановить при необходимости
Чего НЕ делает:
- Не блокирует доступ к TMA (auth middleware не проверяет
deletedAt) - Не удаляет данные пользователя
- Не отвязывает Steam аккаунт
Почему UserGameStatsService разделён на 4 сервиса?
Проблема: UserGameStatsService вырос до 1,408 строк и 19 методов — God Object антипаттерн.
Решение: Разделение по доменам:
UserInventoryStatsService— инвентарь, выводыUserActivityStatsService— кейсы, спины, квесты, достиженияUserCraftStatsService— крафт, salvageUserRewardsStatsService— промокоды, розыгрыши, награды, баффы
Последствия:
- Каждый сервис ≤500 строк
- Чёткая ответственность по домену
- Проще тестировать (19 unit-тестов для критичных методов)
- API остаётся неизменным — рефакторинг прозрачен для фронтенда
Почему ban/currency/actions разделены на отдельные сервисы?
Проблема: UserActionsService изначально содержал ban, currency и inventory операции — нарушение SRP.
Решение: Разделение по ответственности:
UserBanService— бан/разбан с Steam blacklistUserCurrencyService— scrap, XP, streak points, boost points + bulk operationsUserActionsService— управление инвентарём (grantItem, removeInventoryItem)
4. Architecture
Services Overview
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| UserCRUDService | backend/src/domains/admin/services/user-crud.service.ts | CRUD операции + статистика |
| UserBanService | backend/src/domains/admin/services/user-ban.service.ts | Бан/разбан с Steam blacklist |
| UserCurrencyService | backend/src/domains/admin/services/user-currency.service.ts | Валюты (Scrap, XP, SP, BP) + bulk operations |
| UserActionsService | backend/src/domains/admin/services/user-actions.service.ts | Управление инвентарём |
| UserInventoryStatsService | backend/src/domains/admin/services/user-stats/user-inventory-stats.service.ts | Инвентарь, выводы |
| UserActivityStatsService | backend/src/domains/admin/services/user-stats/user-activity-stats.service.ts | Кейсы, спины, квесты, достижения |
| UserCraftStatsService | backend/src/domains/admin/services/user-stats/user-craft-stats.service.ts | Крафт, salvage |
| UserRewardsStatsService | backend/src/domains/admin/services/user-stats/user-rewards-stats.service.ts | Промокоды, розыгрыши, награды, баффы |
| BulkOperationsService | backend/src/domains/admin/services/bulk-operations.service.ts | Legacy bulk operations |
| Routes | backend/src/domains/admin/routes/admin-users.routes.ts | 31 API endpoints |
| Validation Schemas | backend/src/domains/admin/schemas/admin-users-validation.schemas.ts | JSON Schema валидация |
| Types | backend/src/domains/admin/types/admin-users.types.ts | TypeScript типы |
| Constants | backend/src/domains/admin/constants/admin-users.constants.ts | Лимиты, фильтры, sort options |
| Ban Check | backend/src/domains/telegram/middleware/telegram-auth.middleware.ts | Проверка бана в auth middleware |
Frontend Components
| Компонент | Путь | Описание |
|---|---|---|
| Users.tsx | admin/src/pages/Users.tsx | Главная страница |
| UsersTable | admin/src/components/users/UsersTable.tsx | Таблица с пагинацией |
| UserDetailsModal | admin/src/components/users/UserDetailsModal.tsx | Детальная карточка |
| BanUserModal | admin/src/components/users/modals/BanUserModal.tsx | Модалка бана |
| UnbanConfirmModal | admin/src/components/users/modals/UnbanConfirmModal.tsx | Подтверждение разбана |
| DeleteUserModal | admin/src/components/users/modals/DeleteUserModal.tsx | Удаление с подтверждением |
| ManageCurrencyModal | admin/src/components/users/modals/ManageCurrencyModal.tsx | Управление валютами |
5. Database Schema
Ban & Delete Fields on User
| Поле | Тип | Описание |
|---|---|---|
isBanned | Boolean | Флаг бана (default: false). Проверяется auth middleware |
bannedAt | DateTime? | Когда забанен |
banReason | String? | Причина бана (max 500 chars) |
bannedBy | String? | Username админа |
deletedAt | DateTime? | Когда удалён (soft delete). Не проверяется auth middleware |
isActive | Boolean | Флаг активности (default: true). Устанавливается в false при soft delete |
Indexes
@@index([isBanned])
@@index([bannedAt])
Related Models
| Модель | Использование |
|---|---|
| User | Основные данные + ban fields |
| UserInventory | Инвентарь пользователя |
| CaseOpening | История кейсов |
| SpinResult | История спинов |
| UserQuest | Квесты |
| UserAchievement | Достижения |
| Withdrawal | История выводов |
| Referral | Реферальные связи |
| AdminGrant | История admin операций |
| BannedSteamId | Steam blacklist для банов |
6. API Endpoints
Admin API (31 endpoints)
- Basic
- Actions
- Currency
- Inventory
- Game Stats
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/users | Список с фильтрами и пагинацией |
| GET | /admin/users/stats | Статистика для StatCards |
| GET | /admin/users/cases | Справочник кейсов (reference) |
| GET | /admin/users/spins | Справочник рулеток (reference) |
| GET | /admin/users/search | Поиск пользователей |
| GET | /admin/users/:userId | Детальная информация |
| Метод | Эндпоинт | Описание |
|---|---|---|
| POST | /admin/users/:userId/ban | Забанить пользователя |
| DELETE | /admin/users/:userId/ban | Разбанить пользователя |
| DELETE | /admin/users/:userId | Удалить (soft delete) |
| Метод | Эндпоинт | Описание |
|---|---|---|
| POST | /admin/users/:userId/scrap | Добавить/убрать Scrap |
| POST | /admin/users/:userId/xp | Добавить/убрать XP |
| POST | /admin/users/:userId/streak-points | Добавить/убрать SP |
| POST | /admin/users/:userId/boost-points | Добавить/убрать Boost Points (per-season) |
| GET | /admin/users/bulk-currency/count | Кол-во пользователей для bulk операции |
| POST | /admin/users/bulk-currency | Массовое начисление валюты |
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/users/:userId/inventory | Инвентарь с фильтром по tier |
| POST | /admin/users/:userId/inventory | Выдать предмет пользователю |
| POST | /admin/users/:userId/free-case-opens | Выдать бесплатные открытия кейсов |
| DELETE | /admin/users/:userId/inventory/:inventoryId | Удалить предмет из инвентаря |
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/users/:userId/case-history | История открытия кейсов |
| GET | /admin/users/:userId/spin-history | История спинов |
| GET | /admin/users/:userId/quests | Квесты (фильтр по status) |
| GET | /admin/users/:userId/achievements | Достижения (фильтр по status) |
| GET | /admin/users/:userId/withdrawals | История выводов |
| GET | /admin/users/:userId/craft-history | История крафта |
| GET | /admin/users/:userId/salvage-history | История salvage |
| GET | /admin/users/:userId/promo-codes | Активации промокодов |
| GET | /admin/users/:userId/raffle-history | История розыгрышей |
| GET | /admin/users/:userId/season-rewards | Сезонные награды |
| GET | /admin/users/:userId/admin-grants | История admin операций |
| GET | /admin/users/:userId/buff-history | История баффов |
Request/Response Examples
GET /admin/users
Query params:
- page: number (default 1)
- limit: number (default 20, max 100)
- sortBy: 'createdAt' | 'level' | 'scrap' | 'lastLoginDate' | 'dailyLoginStreak'
- sortOrder: 'asc' | 'desc'
- search: string (name, username, telegramId)
- levelMin, levelMax: number
- isPremium, isBanned, isActive: boolean
- lastActivityDays: integer (minimum 1)
POST /admin/users/:userId/ban
{
"reason": "Нарушение правил платформы"
}
POST /admin/users/:userId/scrap
{
"amount": 1000,
"reason": "Компенсация за баг"
}
// amount > 0 = добавить
// amount < 0 = убрать
7. Admin Guide
Доступ к панели пользователей
- Войти в Admin Panel
- Выбрать в меню раздел "Пользователи"
Просмотр списка
- Статистика отображается в StatCards над таблицей
- Поиск по имени, нику или Telegram ID
- Сортировка по колонкам таблицы
- Пагинация внизу таблицы
Детальная информация
- Нажать на строку пользователя
- Откроется модальное окно с секциями
Управление валютами
- Открыть детали пользователя
- Нажать кнопку "Scrap" / "XP" / "SP" / "BP"
- Выбрать операцию: добавить или убрать
- Указать сумму (1 - 1,000,000) и причину
- Подтвердить
Бан пользователя
- Открыть детали пользователя
- Нажать "Забанить"
- Указать причину (обязательно, max 500 символов)
- Подтвердить
Забаненный пользователь не сможет войти в TMA и получать уведомления от бота.
Разбан
- Открыть детали забаненного пользователя
- Нажать "Разбанить"
- Подтвердить
Удаление пользователя
- Открыть детали пользователя
- Нажать "Удалить"
- Поставить галочку подтверждения
- Подтвердить
Удаление устанавливает deletedAt и isActive = false. Пользователь скрывается из списка админки, данные сохраняются для аналитики.
Важно: Пользователь продолжит иметь доступ к TMA после soft delete. Для блокировки доступа используй Бан.
8. Dashboard & Analytics
Админ-панель включает дашборд с ключевыми метриками платформы.
Dashboard Stats
| Метрика | Описание | Сервис |
|---|---|---|
| Sent Withdrawals | Выводы, ожидающие принятия (статус SENT) | DashboardStatsService |
| Active Season Users | Пользователи с активностью в текущем сезоне | DashboardStatsService |
| Total Withdrawn (RUB) | Сумма всех выведенных скинов | DashboardStatsService |
| Scrap in Circulation | Общий баланс Scrap у всех пользователей | DashboardStatsService |
Charts & Analytics
| Компонент | Описание | Сервис |
|---|---|---|
| User Analytics | DAU, MAU, retention, когорты | UserAnalyticsService |
| UTM Analytics | Конверсии по источникам трафика | UniversalChartService |
| Revenue Charts | Графики экономики | UniversalChartService |
admin-charts.routes.ts существует, но не зарегистрирован в server.ts. Chart endpoints недоступны в runtime.
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| DashboardStatsService | backend/src/domains/admin/services/dashboard-stats.service.ts | Ключевые метрики |
| UserAnalyticsService | backend/src/domains/admin/services/user-analytics.service.ts | Аналитика пользователей |
| UniversalChartService | backend/src/domains/admin/services/universal-chart.service.ts | Универсальный движок графиков |
| Admin Analytics Routes | backend/src/domains/admin/routes/admin-analytics.routes.ts | API эндпоинты |
| Admin Charts Routes | backend/src/domains/admin/routes/admin-charts.routes.ts | API графиков (не зарегистрирован в server.ts) |
API Endpoints
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/analytics/dashboard | Метрики дашборда |
| GET | /admin/analytics/banners | Аналитика баннеров |
| GET | /admin/analytics/banners/metrics | Метрики баннеров |
| GET | /admin/analytics/push | Аналитика push-уведомлений |
| GET | /admin/analytics/referrals | Статистика рефералов |
| GET | /admin/analytics/referrals/admin | Детальная статистика рефералов |
| GET | /admin/analytics/export/referrals | Экспорт рефералов |
| GET | /admin/analytics/users/registration | Статистика регистраций |
| GET | /admin/analytics/bot-blocks | Блокировки бота |
| GET | /admin/charts/* | Универсальные графики (UTM, revenue, etc.) — не зарегистрирован |
9. Related
- Profile — профиль пользователя (User API)
- Settings — настройки пользователя
- Feedback — тикеты пользователей
- UTM Tracking — источники трафика
- Security Matrix — обзор защит