Activation
1. Summary
Goal: Трекинг и активация пользователей, пришедших по приглашающим ссылкам (UTM или Referral). Связывание источника привлечения с зарегистрированным пользователем.
User Value: Прозрачная система вознаграждений за приглашение друзей. Referrer получает XP, referred — Scrap.
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— Telegram ID пригласившего
При активации:
- Создаётся запись Referral
- Referrer получает XP
- Referred получает Scrap
- Обновляется прогресс квестов/достижений
- Создаётся событие в 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/EXPIRED существует | Создание новой | Возврат существующей (нет повторного referral) |
| Нет сессий | Создание новой | Создание новой |
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-тесты (28 тестов для двух сервисов)
- Каждый сервис < 320 строк
Почему дедупликация кросс-типов?
Проблема: Пользователь может кликнуть сначала по UTM, потом по Referral. Какую сессию считать основной?
Решение: Первая PENDING сессия побеждает. Если пользователь пришёл по UTM, а потом по Referral — UTM сессия сохраняется.
Последствия:
- Честная атрибуция (first touch wins)
- Защита от манипуляций с referral после UTM
Почему non-blocking errors для quest/achievement?
Проблема: Если обновление прогресса квестов падает, должна ли активация отменяться?
Решение: Non-blocking. Активация критична, прогресс — нет. Ошибки логируются, но не прерывают flow.
Последствия:
- Надёжная активация
- Возможна рассинхронизация прогресса (редко, исправляется ретраем)
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 | Форматирование для аналитики |
| 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.clicksCount++ + 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 | Время истечения (72 часа) |
activatedAt | DateTime? | Время активации |
Relationships
6. API Endpoints
Activation — внутренний домен без публичных API. Используется другими доменами:
utm— создание UTM сессийreferrals— создание Referral сессийtelegram— активация при онбординге
Internal Usage
| Consumer | Method | Description |
|---|---|---|
| UTM Routes | InviteSessionService.createUTMSession() | При клике по UTM ссылке |
| Referral Routes | InviteSessionService.createReferralSession() | При клике по Referral ссылке |
| Telegram Bot | ActivationRewardService.activateSession() | После успешного онбординга |
| Admin Analytics | InviteSessionService.getAnalyticsForChart() | Данные для графиков |
7. Related
- Onboarding — проверка подписок перед активацией
- Referrals — реферальная система
- UTM Tracking — UTM кампании
- Telegram Bot — бот, вызывающий активацию