Activation
1. Summary
Goal: Трекинг и активация пользователей, пришедших по приглашающим ссылкам (UTM или Referral). Связывание источника привлечения с зарегистрированным пользователем.
User Value: Прозрачная система вознаграждений за приглашение друзей. Награды (XP для referrer, Scrap для referred) начисляются отложенно через claim modal.
2. Business Logic
Session Types
- UTM Session
- Referral Session
Описание: Сессия для пользователей, пришедших по UTM-ссылке (блогеры, рекламные кампании).
Metadata:
campaignId— ID UTM-кампанииsource,medium,campaign— UTM параметрыadType,influencer— дополнительные параметры
При активации:
- Обновляется счётчик конверсий кампании
- Награды выдаются только через промокоды (если кампания привязана к промокоду)
Описание: Сессия для пользователей, приглашённых другим пользователем.
Metadata:
referralCodeId— ID реферального кодаreferrerUserId— ID пригласившего пользователяinviterTelegramId(optional) — Telegram ID пригласившего
При активации:
- Создаётся запись Referral
- Награды (XP для referrer, Scrap для referred) откладываются до claim modal
- Обновляется прогресс квестов/достижений
- Создаётся событие в Feed
- Отправляется Telegram уведомление
Session Lifecycle
Core Mechanics
1. Создание сессии (при клике)
- Проверка на USER_RESET (блокирует создание)
- Проверка на существующую PENDING сессию (дедупликация)
- Создание InviteSession + инкремент clicksCount в транзакции
2. Активация сессии (после онбординга)
- Поиск всех PENDING сессий по telegramId
- Активация каждой (UTM → конверсия, REFERRAL → награды)
- Обновление state → ACTIVATED
Если у пользователя уже есть PENDING сессия любого типа, новая сессия НЕ создаётся. Возвращается существующая.
Если у пользователя была сессия со статусом USER_RESET (сброс аккаунта), создание новых сессий заблокировано. Это защита от абьюза наград через пересоздание аккаунта.
Deduplication Logic
| Состояние | При попытке создать UTM | При попытке создать Referral |
|---|---|---|
| USER_RESET существует | Возврат USER_RESET | Возврат USER_RESET |
| PENDING UTM существует | Возврат существующей | Возврат существующей |
| PENDING REFERRAL существует | Возврат существующей | Возврат существующей |
| ACTIVATED существует (same type) | Возврат существующей | Возврат существующей (нет повторного referral) |
| EXPIRED существует | Создание новой | Ошибка unique constraint (EXPIRED referral не обработан явно) |
| Нет сессий | Создание новой | Создание новой |
Кросс-типовая дедупликация (UTM блокирует Referral и наоборот) работает только для PENDING сессий. Если у пользователя есть ACTIVATED сессия одного типа, создание сессии другого типа не будет заблокировано.
Edge Cases
| Ситуация | Поведение | Код |
|---|---|---|
| USER_RESET блокировка | Возврат существующей сессии | — |
| PENDING дедупликация | Возврат существующей сессии | — |
| Referral creation fails | Сессия активируется, награды не начисляются | — |
| Quest/Achievement error | Non-blocking, сессия активируется | — |
| Missing referrerUserId | Сессия активируется, Referral не создаётся | — |
3. ADR (Architectural Decisions)
Почему разделены InviteSessionService и ActivationRewardService?
Проблема: Изначально всё было в одном сервисе (583 строк). Нарушался SRP: создание сессий смешано с логикой наград.
Решение: Разделение на два сервиса:
InviteSessionService— создание и поиск сессий (CRUD)ActivationRewardService— активация и распределение наград
Альтернативы (отклонены):
- Один большой сервис — сложнее тестировать, нарушает SRP
Последствия:
- Чистая архитектура
- Проще unit-тесты (26 тестов для двух сервисов)
- Каждый сервис < 320 строк
Почему дедупликация кросс-типов?
Проблема: Пользователь может кликнуть сначала по UTM, потом по Referral. Какую сессию считать основной?
Решение: Первая PENDING сессия побеждает. Если пользователь пришёл по UTM, а потом по Referral — UTM сессия сохраняется.
Последствия:
- Честная атрибуция (first touch wins)
- Защита от манипуляций с referral после UTM
Почему non-blocking errors для quest/achievement?
Проблема: Если обновление прогресса квестов падает, должна ли активация отменяться?
Решение: Non-blocking. Активация критична, прогресс — нет. Ошибки логируются, но не прерывают flow.
Последствия:
- Надёжная активация
- Возможна рассинхронизация прогресса (редко, исправляется ретраем)
Почему UTM не даёт автоматический scrap-бонус?
Проблема: Ранее UTM-переход автоматически начислял 200 scrap (BONUS_SCRAP_UTM). Это было заменено на промокодный flow — маркетолог привязывает промокод к UTM-кампании, пользователь вводит его после онбординга.
Решение: UTM-активация фиксирует только конверсию (PENDING → ACTIVATED). Награды выдаются исключительно через промокоды (/api/promo-codes/redeem).
Последствия:
- Полный контроль маркетолога над наградами через промокоды
- Нет скрытого начисления scrap при переходе по ссылке
- UTM-аналитика конверсий работает независимо от наград
4. Architecture
Services Overview
Key Components
| Компонент | Путь | Описание |
|---|---|---|
| InviteSessionService | backend/src/domains/activation/services/invite-session.service.ts | Создание и поиск сессий |
| ActivationRewardService | backend/src/domains/activation/services/activation-reward.service.ts | Активация и награды |
| InviteSessionAdapter | backend/src/domains/activation/utils/invite-session.adapter.ts | Форматирование для аналитики |
| Constants | backend/src/domains/activation/constants/activation.constants.ts | TTL, таймауты, конфигурация |
| Types | backend/src/domains/activation/types/activation.types.ts | Типы домена |
Method Details
InviteSessionService Methods
createUTMSession(data: UTMSessionData)
- Создаёт UTM сессию при клике по ссылке
- Транзакция: InviteSession + UTMCampaign.clicksCount++
- Дедупликация: возврат существующей при USER_RESET или PENDING
createReferralSession(data: ReferralSessionData)
- Создаёт Referral сессию при клике по ссылке
- Транзакция: InviteSession + ReferralCode.appOpensCount++ + ReferralClickAnalytics
- Дедупликация: возврат существующей при USER_RESET, PENDING, или ACTIVATED referral
findByTelegramId(telegramId: string)
- Поиск PENDING сессии для активации
- Возвращает null при ошибке (graceful)
getAnalyticsForChart(filters)
- Данные для графиков аналитики
- Лимит 5000 записей для производительности
ActivationRewardService Methods
activateSession(telegramId: string, userId: string)
- Находит все PENDING сессии
- Активирует UTM: обновляет state, считает конверсию
- Активирует REFERRAL: создаёт Referral, начисляет награды
- Non-blocking errors для quest/achievement progress
- Возвращает:
{ utmActivated?, referralActivated? }
5. Database Schema
Models
| Модель | Описание | Ключевые поля |
|---|---|---|
| InviteSession | Сессия приглашения | type, state, telegramId, metadata, expiresAt |
| ReferralClickAnalytics | Аналитика кликов по referral | referralCodeId, telegramHash |
InviteSession Fields
| Поле | Тип | Описание |
|---|---|---|
type | InviteType | UTM или REFERRAL |
state | InviteSessionState | PENDING, ACTIVATED, EXPIRED, USER_RESET |
telegramId | String | Telegram ID пользователя |
userId | String? | User ID после активации |
metadata | Json | UTMMetadata или ReferralMetadata |
expiresAt | DateTime | Время истечения (24 часа) |
activatedAt | DateTime? | Время активации |
activationSource | InviteActivationSource? | Источник активации (REF_DEEPLINK, UTM_DEEPLINK, PROMO_CODE) |
Relationships
6. API Endpoints
- User API
- Internal Usage
Activation домен не имеет собственных HTTP endpoints. Вся логика вызывается через Telegram Bot Routes при онбординге.
Большинство функциональности activation домена используется внутренними вызовами, а не через HTTP API.
| Consumer | Method | Description |
|---|---|---|
| Telegram Bot Routes | InviteSessionService.createUTMSession() | При клике по UTM ссылке |
| Telegram Bot Routes | InviteSessionService.createReferralSession() | При клике по Referral ссылке |
| Telegram Bot | ActivationRewardService.activateSession() | После успешного онбординга |
| Admin Analytics | InviteSessionService.getAnalyticsForChart() | Данные для графиков |
7. Related
- Onboarding — проверка подписок перед активацией
- Referrals — реферальная система
- UTM Tracking — UTM кампании и аналитика
- Telegram Bot — бот, вызывающий активацию
- Promo Codes — промокоды для UTM-кампаний