Budget Control & Luck Pool
1. Summary
Goal: Контроль экономики крафтов и поощрение активных игроков через систему буста вероятностей.
User Value: Активные игроки (50%+ прогресс крафта) получают × 3-13 увеличение шансов на материалы для целевых скинов через Boost.
2. Business Logic
Budget Periods
Экономика разбита на периоды для контроля расходов:
| Параметр | Значение |
|---|---|
| Длительность периода | 10 дней |
| Периодов в месяце | 3 |
| Бюджет периода | 3333₽ (333₽/день) |
- Внутри месяца: остаток переносится в следующий период
- В конце месяца: остаток сгорает
Luck Pool
Механика поощрения активных игроков через увеличение вероятностей.
Вкратце: Игроки с ≥50% прогрессом крафта получают буст × 3-13 к материалам.
См. Luck Pool для полного описания механики, seniority, anti-abuse, edge cases.
Budget Exhausted
Штрафной множитель: × 0.01 (99% снижение вероятности)
Применяется к FRAGMENT/BLUEPRINT для скинов в пуле. Остальные награды не затрагиваются.
Определение: available = baseBudget + carriedOver - spent <= 0
Уведомление: Админ получает alert только при переходе из "хватает" в "не хватает".
Игроки могут крафтить даже при исчерпанном бюджете. Система только логирует траты для администратора.
Admin Notifications (TG Alerts)
Budget Control отправляет уведомления администраторам через Telegram при критических событиях:
| Событие | Тип | Когда отправляется | Inline кнопки |
|---|---|---|---|
| Бюджет исчерпан | BUDGET_EXHAUSTED | При первом исчерпании бюджета периода | +500₽, +1000₽, +2000₽, +5000₽, Открыть админку |
| Подозрительная активность | SUSPICIOUS_CRAFTS | При >2 крафтах за 24ч одним пользователем | — |
| Смена периода | PERIOD_TRANSITION | При автоматическом переходе между периодами | — |
Формат уведомлений
BUDGET_EXHAUSTED:
⚠️ Бюджет периода исчерпан!
Сезон: {seasonNumber}
Период: {periodNumber}/9
День периода: {dayOfPeriod}/10
[+500₽] [+1000₽] [+2000₽] [+5000₽]
[Открыть админку]
SUSPICIOUS_CRAFTS:
🚨 Подозрительная активность!
Пользователь: {username || userId}
Крафтов за 24ч: {craftsIn24h}
Порог: {threshold}
[Открыть профиль]
PERIOD_TRANSITION:
📅 Смена периода бюджета
Сезон: {seasonNumber}
Переход: период {fromPeriod} → {toPeriod}
Перенесено: {budgetCarriedOver}₽
Сгорело: {budgetExpired}₽
Кнопки admin:budget_add_{amount} обрабатываются в backend/src/domains/telegram/handlers/admin-callback.handler.ts и вызывают BudgetAdminService.incrementBudget().
Edge Cases
| Ситуация | Поведение |
|---|---|
| Бюджет исчерпан | Штраф × 0.01 к материалам в пуле |
| Конец месяца | Остаток бюджета сгорает |
| Конец периода | Остаток переносится в следующий период |
| Крафт в сезоне A, вывод в сезоне B | spentRub учтён в сезоне A (по крафту). Withdrawal не привязан к сезону — это delivery, не commitment |
Edge cases связанные с пулом удачи (вход, выход, seniority) описаны в Luck Pool.
3. ADR (Architectural Decisions)
Архитектурные решения по Luck Pool (буст, seniority) описаны в Luck Pool ADR.
Почему Budget не блокирует крафты?
Проблема: При блокировке крафтов игроки потеряют прогресс.
Решение: Budget — инструмент мониторинга, а не ограничения.
Последствия:
- Админ контролирует экономику через отмену выводов
- Игроки не теряют прогресс из-за бюджета
Почему расход фиксируется при крафте, а не при выводе?
Проблема: Крафт и вывод могут произойти в разных сезонах. Игрок крафтит скин в последний день сезона A, но выводит уже в сезоне B.
Решение: Budget трекает commitment (обязательство платформы), а не delivery (фактическую доставку).
Аналогия: Бухгалтерский "accrued expense" — расход фиксируется когда возникает обязательство, а не когда деньги уходят.
Последствия:
spentRub= сумма обязательств платформы за периодWithdrawalне имеетperiodId— это operational detail- Админ контролирует реальные расходы через отмену выводов
- Скин в инвентаре = платформа уже "должна" его игроку
4. Architecture
Integration Overview
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| BudgetService | backend/src/domains/budget/services/budget.service.ts | Core: статус, запись расходов, проверки |
| BudgetAdminService | backend/src/domains/budget/services/budget-admin.service.ts | Admin: increment/decrement/reset бюджета |
| BudgetLifecycleService | backend/src/domains/budget/services/budget-lifecycle.service.ts | Lifecycle: создание периодов, transitions |
| LuckPoolService | backend/src/domains/luck-pool/services/luck-pool.service.ts | Управление пулом и бустом |
| BudgetRepository | backend/src/domains/budget/repositories/budget.repository.ts | CRUD для BudgetPeriod |
| Constants | shared/src/constants/budgetControl.ts | Все константы системы |
Константы системы
BUDGET_CONTROL = {
PERIOD_DAYS: 10,
PERIODS_PER_MONTH: 3,
DAILY_BUDGET_RUB: 333,
PERIOD_BUDGET_RUB: 3333,
MIN_PROGRESS_FOR_POOL: 0.5,
INACTIVE_DAYS_THRESHOLD: 14,
POOL_CHECK_INTERVAL_HOURS: 12,
BASE_BOOST_MULTIPLIER: 3.0,
SENIORITY: {
MULTIPLIER_PER_PERIOD: 1.2,
MAX_ACTIVE_PERIODS: 9,
},
BUDGET_EXHAUSTED_MULTIPLIER: 0.01,
}
5. Database Schema
Models
| Модель | Описание | Ключевые поля |
|---|---|---|
| BudgetPeriod | Период бюджета | baseBudgetRub, carriedOverRub, spentRub, isActive |
| LuckPoolEntry | Участник пула | activePeriods, boostMultiplier, isActive, blockedSkinIds |
| CraftBudgetLog | Лог крафтов | costRub, hadBoost, seniorityMultiplier, totalBoostMultiplier |
Relationships
6. API Endpoints
- Budget Admin
- Luck Pool Admin
| Метод | Эндпоинт | Описание |
|---|---|---|
| GET | /admin/budget/status | Статус текущего периода |
| GET | /admin/budget/periods | Все периоды сезона |
| POST | /admin/budget/periods/:id/increment | Увеличить бюджет |
| POST | /admin/budget/periods/:id/decrement | Уменьшить бюджет |
| GET | /admin/budget/craft-logs | Логи крафтов |
Luck Pool API описан в Luck Pool.
7. Related
- Luck Pool — полная документация по пулу удачи
- Cases — использует Luck Pool для буста материалов
- Daily Spins — использует Luck Pool для буста материалов
- Craft — триггерит выход из пула и записывает расходы
- Seasons — контекст для периодов и пула