D1+ push для юзеров начавших урок но не вернувшихся
Source: аналитика рекламной кампании 13 мая 2026 (~/repos/ai-hub/analytics/tralebot-2026-05-13-ad-campaign.md)
Goal: Из юзеров когорты 13 мая 53 человека прошли хотя бы один шаг урока, и 21% из них всё ещё активны на D6+. Это «живая» аудитория для удержания. Но из 39 «вернулись хотя бы раз» к D6+ доходит ~11 — половина теряется между D2 и D6. Цель эпика: отлавливать юзеров которые начали учиться но не вернулись на следующий день, и звать обратно через пуш в боте. КРИТИЧНО: пуш должен идти ТОЛЬКО тем, кто прошёл хотя бы один шаг урока — для незаведённых юзеров пуш бесполезен (D6+ retention 0% подтверждает).
Out of scope: push для юзеров не сделавших первый шаг (по данным они не возвращаются, нет смысла); push для трёхдневного отсутствия (V2 — пока только D1+); push для специфических модулей или контента (V2); адаптивные тексты под уровень (V2).
expected_impact: $30/мес (предположение: 10 lesson-starter-юзеров/неделя × +20% return rate × 5% paid × $1.50 = немного, но накопительный эффект через 3-6 месяцев — заметный).
Acceptance criteria (BDD)
-
Scenario 1 — пуш приходит когда юзер начал урок но не зашёл вчера
- Given: юзер X с CompletedLessonsJson != {} (прошёл хотя бы один шаг), LastPlayedAtUtc < вчера 06:00 UTC, IsActive = true, NotificationsEnabled = true
- When: Cron NotificationDispatcher срабатывает в 10:00 UTC (= 14:00 по Батуми, утро для большинства русскоязычных юзеров)
- Then: Telegram-сообщение от бота с текстом «Бомбора по тебе скучает 🐶 Продолжишь алфавит сегодня?» (имя модуля подставляется из последнего сыгранного), WebApp-кнопка ведёт прямо в следующий незавершённый урок этого модуля; в записи NotificationTrigger source=daily_return фиксируется LastSentAt
-
Scenario 2 — пуш не дублируется в тот же день
- Given: пуш уже был отправлен сегодня (LastSentAt = сегодня UTC)
- When: Cron срабатывает повторно в тот же день
- Then: второе сообщение НЕ отправляется
-
Scenario 3 — пуш НЕ идёт если юзер не сделал ни одного шага урока
- Given: юзер Y с CompletedLessonsJson = {} (только выбрал level), LastPlayedAtUtc < вчера, IsActive = true
- When: Cron срабатывает
- Then: сообщение НЕ отправляется этому юзеру; в коде явный гейт user.CompletedLessons != empty
-
Scenario 4 — кулдаун 3 дня для одного и того же юзера
- Given: юзеру X отправили пуш 3 дня назад, он не открывал мини-апп с тех пор
- When: Cron срабатывает на 4-й день
- Then: второй пуш не отправляется (3-дневный cooldown истёк, но фактический cooldown 7 дней чтобы не задалбывать неактивных); в payload в логе видно «skipped due to cooldown»
-
Scenario 5 — глубокая ссылка ведёт точно в нужный урок
- Given: юзер кликает WebApp-кнопку в пуш-сообщении
- When: мини-апп открывается
- Then: сразу показывается экран Practice или LessonTheory нужного урока (по deep-link параметру); не Dashboard, не модуль-выбор; trackEvent push_clicked фиксируется
-
Scenario 6 — opt-out через /notifications off уже работает
- Given: юзер ранее отключил уведомления (NotificationsEnabled = false)
- When: Cron срабатывает
- Then: пуш не отправляется; ничего не пишется в LastSentAt
-
Scenario 7 (negative) — pro юзер с активным sub не получает «come back» пушей (или получает с другим тоном)
- Given: Pro-юзер с активной подпиской не открывал мини-апп 2 дня
- When: Cron срабатывает
- Then: в V1 идёт тот же пуш (это не критично, не блокер); V2 — отдельный тон для Pro («твоя подписка работает, не теряй темп»)
-
Scenario 8 — A/B по двум текстам (опционально, если NotificationDispatcher уже поддерживает варианты)
- Given: два варианта текста A («Бомбора скучает») и B («Алфавит ждёт продолжения»)
- When: пуш отправляется юзеру
- Then: случайный выбор A/B, payload содержит variant; через 2 недели можно сравнить open rate (нужен event push_clicked из эпика A)
Technical constraints
- Зависит от наличия NotificationDispatcher (epic-894). Если этот сервис уже работает — расширяем новым типом триггера daily_return. Если нет — этот эпик включает в себя минимальную имплементацию.
- Cron-окно: один раз в день, 10:00 UTC (14:00 Батуми). Достаточно для V1.
- Deep-link в Practice: формат WebAppData с payload {moduleId, lessonId}; нужно расширить router в мини-аппе чтобы он принимал такой initial state.
- Кулдаун 7 дней на одного юзера — иначе риск превратить бот в спам и получить блок от Telegram.
Existing artefacts
- Notification infrastructure: ожидается из epic-894 (Контекстные пуш-нотификации). Если он не завершён — этот эпик блокируется или требует параллельной имплементации.
- StartCommand handles deep links:
src/Infrastructure/Telegram/BotCommands/StartCommand.cs
- analytics rationale:
~/repos/ai-hub/analytics/tralebot-2026-05-13-ad-campaign.md
Зависимости и порядок
- ЗАВИСИТ от эпика B (first-lesson UX fix). Без него у нас мало lesson-starters и пуш бесполезен.
- ЗАВИСИТ или соответствует epic-894 (если он уже даёт NotificationDispatcher — расширяем; если нет — делаем минимальную инфраструктуру здесь).
- Эпик A (event tracking) желателен для измерения, но не критичен.
D1+ push для юзеров начавших урок но не вернувшихся
Source: аналитика рекламной кампании 13 мая 2026 (
~/repos/ai-hub/analytics/tralebot-2026-05-13-ad-campaign.md)Goal: Из юзеров когорты 13 мая 53 человека прошли хотя бы один шаг урока, и 21% из них всё ещё активны на D6+. Это «живая» аудитория для удержания. Но из 39 «вернулись хотя бы раз» к D6+ доходит ~11 — половина теряется между D2 и D6. Цель эпика: отлавливать юзеров которые начали учиться но не вернулись на следующий день, и звать обратно через пуш в боте. КРИТИЧНО: пуш должен идти ТОЛЬКО тем, кто прошёл хотя бы один шаг урока — для незаведённых юзеров пуш бесполезен (D6+ retention 0% подтверждает).
Out of scope: push для юзеров не сделавших первый шаг (по данным они не возвращаются, нет смысла); push для трёхдневного отсутствия (V2 — пока только D1+); push для специфических модулей или контента (V2); адаптивные тексты под уровень (V2).
expected_impact: $30/мес (предположение: 10 lesson-starter-юзеров/неделя × +20% return rate × 5% paid × $1.50 = немного, но накопительный эффект через 3-6 месяцев — заметный).
Acceptance criteria (BDD)
Scenario 1 — пуш приходит когда юзер начал урок но не зашёл вчера
Scenario 2 — пуш не дублируется в тот же день
Scenario 3 — пуш НЕ идёт если юзер не сделал ни одного шага урока
Scenario 4 — кулдаун 3 дня для одного и того же юзера
Scenario 5 — глубокая ссылка ведёт точно в нужный урок
Scenario 6 — opt-out через /notifications off уже работает
Scenario 7 (negative) — pro юзер с активным sub не получает «come back» пушей (или получает с другим тоном)
Scenario 8 — A/B по двум текстам (опционально, если NotificationDispatcher уже поддерживает варианты)
Technical constraints
Existing artefacts
src/Infrastructure/Telegram/BotCommands/StartCommand.cs~/repos/ai-hub/analytics/tralebot-2026-05-13-ad-campaign.mdЗависимости и порядок