--- name: Telegram Bot Product Features overview: Добавление продуктовых фич в Telegram бот для повышения вовлеченности пользователей и создания привычки ежедневного обучения. Фокус на простых, но эффективных механиках для MVP стадии. todos: - id: daily-command content: Реализовать команду /daily для карточки дня с изображением status: pending - id: stats-command content: Реализовать команду /stats и backend endpoint для статистики status: pending - id: streaks-tracking content: Добавить tracking стриков в PostgreSQL (таблица user_streaks) status: pending - id: quiz-command content: Реализовать мини-квиз /quiz с inline keyboard status: pending - id: reminders-command content: Реализовать настройку напоминаний /reminders и cron job для отправки status: pending - id: achievements content: Добавить автоматические поздравления с достижениями status: pending - id: collectible-cards-system content: Реализовать систему коллекционных карточек с редкостью (Common/Rare/Legendary) status: pending - id: collection-command content: Реализовать команду /collection для просмотра коллекции status: pending - id: card-variants-generation content: Добавить генерацию изображений с разными рамками для редкостей status: pending - id: tests content: Написать unit и integration тесты для новых фич status: pending --- # План продуктовых фич для Telegram бота Mnemo Cards ## Обзор Текущий бот выполняет технические функции (бэкап, авторизация, админ-панель) и имеет базовую команду `/share`. Предлагается добавить **продуктовые фичи для вовлечения и контента**, которые помогут: - Создать привычку ежедневного использования - Повысить удержание пользователей - Предоставить дополнительную ценность помимо основного приложения - Собрать аналитику вовлеченности ## Приоритетные фичи (MVP) ### 1. 🎴 Карточка дня (`/daily` команда) **Описание:** Пользователь получает случайную карточку для изучения **UX Flow:** ``` Пользователь: /daily Бот: [Красивое изображение карточки] 🇪🇸 el perro 🇷🇺 собака 💡 Мнемоника: [mnemo text] 🔊 Транскрипция: [transcription] Хочешь проверить себя? Нажми /quiz ``` **Реализация:** - Новая команда в [`bin/main.dart`](mnemo_cards_telegram_bot/bin/main.dart) → `teledart.onCommand('daily')` - Использовать существующий `BackendClient.getRandomCard()` - Повторно использовать `ImageGenerator` из `/share` команды - Отправлять фото + caption с информацией о карточке **Backend изменения:** - Endpoint уже есть: `/api/v2/telegram-bot/random-card` - Добавить опциональный параметр `?userId=` для персонализации (учитывать уже изученные карточки) --- ### 2. 📊 Статистика и стрики (`/stats` команда) **Описание:** Показать пользователю его прогресс и мотивационные метрики **UX Flow:** ``` Пользователь: /stats Бот: 📈 Твоя статистика 🔥 Стрик: 7 дней 📚 Изучено карточек: 42 ✅ Завершено тестов: 5 ⏱ Последняя активность: 2 часа назад Так держать! Продолжай в том же духе! 💪 ``` **Реализация:** - Новая команда `/stats` в [`bin/main.dart`](mnemo_cards_telegram_bot/bin/main.dart) - Новый метод в [`lib/backend_client.dart`](mnemo_cards_telegram_bot/lib/backend_client.dart): ```dart Future getUserStats(String telegramUserId) ``` **Backend изменения:** - Новый endpoint: `GET /api/v2/telegram-bot/users/:telegramUserId/stats` - Использовать существующую логику из [`lib/statistics/statistics_calculator.dart`](mnemo_cards_backend/lib/statistics/statistics_calculator.dart) - Добавить tracking стриков (consecutive days of activity) - Новая таблица `user_streaks` в PostgreSQL: ```sql CREATE TABLE user_streaks ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), telegram_user_id TEXT, current_streak INTEGER DEFAULT 0, longest_streak INTEGER DEFAULT 0, last_activity_date DATE, created_at TIMESTAMP DEFAULT NOW() ); ``` --- ### 3. ⏰ Ежедневные напоминания **Описание:** Бот отправляет напоминание о занятиях в выбранное время **UX Flow:** ``` Пользователь: /reminders Бот: ⏰ Настрой напоминания [Inline keyboard:] - 09:00 утра - 12:00 день - 18:00 вечер - 21:00 ночь - 🚫 Отключить После выбора: Бот: ✅ Буду напоминать тебе каждый день в 18:00! --- В выбранное время: Бот: 👋 Время изучать новые слова! Попробуй карточку дня → /daily Или пройди быстрый квиз → /quiz ``` **Реализация:** - Новая команда `/reminders` с inline keyboard (используя `teledart.sendMessage` с `replyMarkup`) - Хранение настроек в БД (новая таблица `user_reminder_settings`) - **Cron job** в [`lib/cron/`](mnemo_cards_backend/lib/cron/) для отправки напоминаний: ```dart // lib/cron/send_reminders.dart class SendRemindersTask extends Task { @override String get name => 'Send Reminders'; @override Duration get interval => const Duration(minutes: 30); @override Future run() async { // Проверять каждые 30 минут, кому нужно отправить // Отправлять через Telegram Bot API } } ``` **Backend изменения:** - Новый endpoint: `POST /api/v2/telegram-bot/reminders/set` - Новый endpoint: `GET /api/v2/telegram-bot/reminders/pending` - Новая таблица: ```sql CREATE TABLE user_reminder_settings ( id SERIAL PRIMARY KEY, telegram_user_id TEXT UNIQUE, reminder_time TIME, -- время в UTC timezone TEXT, -- часовой пояс пользователя enabled BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW() ); ``` --- ### 4. 🎯 Мини-квиз (`/quiz` команда) **Описание:** Быстрая проверка знаний из 3-5 вопросов прямо в боте **UX Flow:** ``` Пользователь: /quiz Бот: 🎯 Быстрый квиз Вопрос 1/3 Как переводится "el perro"? [Inline keyboard:] A) кошка B) собака ✅ C) птица D) рыба После ответа: Бот: ✅ Правильно! (или ❌ Неправильно, правильный ответ: собака) [Следующий вопрос...] После завершения: Бот: 🎉 Квиз завершен! Правильных ответов: 2/3 Твой результат: 67% Продолжай практиковаться → /daily ``` **Реализация:** - Новая команда `/quiz` с inline keyboard - Состояние квиза хранить в памяти (Map с ключом chat_id) - Использовать `teledart.onCallbackQuery` для обработки нажатий кнопок - Генерировать вопросы на бэкенде: - Правильный ответ - 3 неправильных варианта из других карточек **Backend изменения:** - Новый endpoint: `POST /api/v2/telegram-bot/quiz/generate` - Параметр: `userId` (опционально, для персонализации) - Параметр: `count` (количество вопросов, default: 3) - Endpoint возвращает: ```json { "quizId": "uuid", "questions": [ { "questionId": "uuid", "question": "Как переводится 'el perro'?", "options": ["кошка", "собака", "птица", "рыба"], "correctIndex": 1 } ] } ``` - Новый endpoint: `POST /api/v2/telegram-bot/quiz/submit` - Записывать результаты квиза для статистики --- ### 5. 🎊 Мотивационные события (автоматические) **Описание:** Бот автоматически поздравляет с достижениями **События:** - 🔥 Стрик 3 дня: "Отличное начало! Продолжай в том же духе!" - 🔥 Стрик 7 дней: "Целая неделя! Ты молодец! 🎉" - 🔥 Стрик 14 дней: "Две недели ежедневных занятий! Потрясающе!" - 🔥 Стрик 30 дней: "Месяц без перерывов! Ты легенда! 🏆" - 📚 Изучено 10/50/100 карточек - ✅ Завершено 5/10/20 тестов **Реализация:** - **Webhook или cron job** для проверки достижений - Новый cron task: `CheckAchievementsTask` каждый час - При достижении milestone → отправить сообщение пользователю **Backend изменения:** - Новая таблица `user_achievements`: ```sql CREATE TABLE user_achievements ( id SERIAL PRIMARY KEY, telegram_user_id TEXT, achievement_type TEXT, -- 'streak_3', 'streak_7', 'cards_10', etc. achieved_at TIMESTAMP DEFAULT NOW(), notified BOOLEAN DEFAULT false ); ``` - Endpoint для получения новых достижений: `GET /api/v2/telegram-bot/achievements/pending` --- ### 6. 🃏 Коллекционные карточки (Collectible Cards System) **Описание:** Система коллекционирования карточек с разными уровнями редкости. Одно и то же слово может иметь несколько вариантов карточек с разными изображениями и редкостью. #### Концепция редкости **Три уровня редкости:** 1. **🟢 Common (Обычная)** - Базовое изображение карточки - Серая рамка - Получение: автоматически при изучении слова или через `/daily` 2. **🔵 Rare (Редкая)** - Улучшенное/детальное изображение - Синяя рамка с эффектом свечения - Получение: за достижения (стрик 7 дней, квиз 100%, и т.д.) 3. **🟣 Legendary (Легендарная)** - Уникальное артовое изображение - Золотая рамка с блеском и эффектами - Получение: за высокие достижения (стрик 30+ дней, особые награды) #### Пример: слово "el perro" ``` el perro (собака) ├─ 🟢 Common ✅ Получена 15.12.2024 ├─ 🔵 Rare ✅ Получена 20.12.2024 (стрик 7 дней) └─ 🟣 Legendary 🔒 Требуется: стрик 30 дней (текущий: 12) ``` #### UX Flow **Команда `/collection` - просмотр коллекции:** ``` Пользователь: /collection Бот: 📚 Твоя коллекция 📊 Общий прогресс: 45/450 карточек (10%) 🟢 Common: 15/150 слов (10%) 🔵 Rare: 8/150 слов (5%) 🟣 Legendary: 2/150 слов (1%) [Inline keyboard:] - 📖 По словам - 🎨 По редкости - 📦 По пакам - 🔍 Поиск слова При выборе "По словам": 🇪🇸 Испанский (15 слов) 📝 el perro (собака) ✅🟢 ✅🔵 🔒🟣 📝 el gato (кот) ✅🟢 🔒🔵 🔒🟣 📝 la casa (дом) ✅🟢 🔒🔵 🔒🟣 [Кнопка: Показать детали] ``` **Команда `/showcase [слово]` - детали карточки:** ``` Пользователь: /showcase el perro Бот: [Отправляет изображение Common версии с серой рамкой] 🟢 COMMON 🇪🇸 el perro 🇷🇺 собака ✅ В коллекции с 15.12.2024 [Отправляет изображение Rare версии с синей рамкой] 🔵 RARE 🇪🇸 el perro 🇷🇺 собака ✅ Получена за стрик 7 дней (20.12.2024) [Placeholder для Legendary] 🟣 LEGENDARY 🇪🇸 el perro 🇷🇺 собака 🔒 Как получить: стрик 30 дней 📊 Твой прогресс: 12/30 дней (осталось 18) ``` **Обновленная команда `/daily` с коллекционированием:** ``` Пользователь: /daily Бот: [Красивое изображение карточки с рамкой редкости] 🎴 Карточка дня 🇪🇸 el perro 🇷🇺 собака 💡 Мнемоника: [текст] 🔊 Транскрипция: [текст] 📦 Коллекция: ✅ 🟢 Common - уже в коллекции 🔒 🔵 Rare - пройди квиз на 100% 🔒 🟣 Legendary - стрик 30 дней Хочешь проверить себя? → /quiz Посмотреть коллекцию → /collection ``` **Получение редкой карточки (событие):** ``` [После достижения стрика 7 дней] Бот: 🎉 ПОЗДРАВЛЯЕМ! 🔥 Ты держишь стрик 7 дней подряд! 🎁 Награда: случайная RARE карточка! [Анимация/эффект открытия "пака"] [Задержка 1-2 секунды] [Отправляет изображение с синей рамкой и блеском] ✨ 🔵 RARE CARD! ✨ 🇪🇸 el perro 🇷🇺 собака Это улучшенная версия карточки! Теперь у тебя 2/3 версии этого слова! Посмотри свою коллекцию → /collection ``` **Обновленная команда `/stats` с коллекцией:** ``` Пользователь: /stats Бот: 📈 Твоя статистика 🔥 Стрик: 12 дней 📚 Изучено слов: 42 ✅ Завершено тестов: 5 📦 Коллекция карточек: 🟢 Common: 42/150 (28%) 🔵 Rare: 8/150 (5%) 🟣 Legendary: 2/150 (1%) 🏆 Ближайшие награды: - 🔥 Стрик 14 дней → 1 Rare карточка (через 2 дня) - 🔥 Стрик 30 дней → 1 Legendary! (через 18 дней) - 🎯 Квиз 100% → Rare версия карточки из квиза Продолжай в том же духе! 💪 ``` #### Условия получения карточек **🟢 Common (автоматически):** - Изучил слово в основном приложении - Получил через `/daily` (первый раз) - Прошел тест, где встретилось слово **🔵 Rare (за активность):** - 🔥 Стрик 7 дней → 1 случайная Rare - 🔥 Стрик 14 дней → 2 случайные Rare - 🎯 Квиз 100% правильных → Rare версия одной карточки из квиза - 📅 Использовал `/daily` 10 раз → выбери любую Rare - ⭐ Завершил пак полностью → все карточки пака в Rare версии - 📚 Изучил 50 карточек → 3 Rare на выбор **🟣 Legendary (за высокие достижения):** - 🔥 Стрик 30 дней → 1 случайная Legendary - 🔥 Стрик 60 дней → 2 случайные Legendary - 🔥 Стрик 100 дней → 5 Legendary на выбор - 🎯 Прошел 50 квизов → 1 Legendary на выбор - 🎯 10 квизов подряд на 100% → 2 Legendary - 📚 Завершил 5 паков → 3 Legendary на выбор - 🏆 Топ-10 в месячном рейтинге активности → 2 Legendary #### Визуальные отличия **Генерация изображений с разными рамками:** ```dart // Обновленный ImageGenerator class ImageGenerator { Future generateCardImage({ required GameCardModel card, required CardRarity rarity, }) async { final baseImage = await _loadCardImage(card.image); final frame = _getFrameForRarity(rarity); final effects = _getEffectsForRarity(rarity); return _composeImage(baseImage, frame, effects); } FrameStyle _getFrameForRarity(CardRarity rarity) { switch (rarity) { case CardRarity.common: return FrameStyle( color: 0xFF808080, // Серый width: 40, glowIntensity: 0, ); case CardRarity.rare: return FrameStyle( color: 0xFF4169E1, // Синий width: 50, glowIntensity: 0.3, glowColor: 0xFF6495ED, ); case CardRarity.legendary: return FrameStyle( color: 0xFFFFD700, // Золотой width: 60, glowIntensity: 0.6, glowColor: 0xFFFFA500, sparkles: true, gradient: true, ); } } } ``` **Цветовая схема:** - 🟢 Common: #808080 (серый) - 🔵 Rare: #4169E1 (royal blue) + свечение - 🟣 Legendary: #FFD700 (золотой) + градиент + блестки #### Социальный аспект **Команда `/share_card [слово]` - поделиться карточкой:** ``` Пользователь: /share_card el perro Бот: Какую версию карточки хочешь показать? [Inline keyboard:] - 🟢 Common - 🔵 Rare ✅ - 🟣 Legendary 🔒 После выбора Rare: [Генерирует красивое изображение с синей рамкой] Вот твоя RARE карточка! 🔵 Ты можешь поделиться ей: - Отправь друзьям в Telegram - Опубликуй в соц. сетях 💬 Сообщение для друзей: "Смотри какую редкую карточку я собрал в Mnemo Cards! 🔵 Присоединяйся и собери свою коллекцию! [ссылка на бота]" ``` #### Техническая реализация **Новые таблицы PostgreSQL:** ```sql -- Варианты карточек (все возможные collectibles) CREATE TABLE card_variants ( id SERIAL PRIMARY KEY, card_id TEXT NOT NULL, -- ID основной карточки rarity TEXT NOT NULL, -- 'common', 'rare', 'legendary' image_variant TEXT, -- Путь к альтернативному изображению -- Если NULL, используется базовое с рамкой frame_color TEXT NOT NULL, -- HEX цвет рамки frame_width INTEGER DEFAULT 40, -- Ширина рамки в px has_glow BOOLEAN DEFAULT false, -- Эффект свечения has_sparkles BOOLEAN DEFAULT false, -- Эффект блесток unlock_condition TEXT, -- Условие получения description TEXT, -- Описание варианта created_at TIMESTAMP DEFAULT NOW(), UNIQUE(card_id, rarity) ); CREATE INDEX idx_variants_card_id ON card_variants(card_id); CREATE INDEX idx_variants_rarity ON card_variants(rarity); -- Коллекция пользователя CREATE TABLE user_card_collection ( id SERIAL PRIMARY KEY, telegram_user_id TEXT NOT NULL, card_variant_id INTEGER REFERENCES card_variants(id), obtained_at TIMESTAMP DEFAULT NOW(), obtained_via TEXT, -- 'daily', 'quiz', 'streak_7', 'achievement', etc. UNIQUE(telegram_user_id, card_variant_id) ); CREATE INDEX idx_collection_user ON user_card_collection(telegram_user_id); CREATE INDEX idx_collection_obtained ON user_card_collection(obtained_at); -- Прогресс коллекции (кэш для быстрого доступа) CREATE TABLE user_collection_progress ( id SERIAL PRIMARY KEY, telegram_user_id TEXT UNIQUE NOT NULL, total_cards INTEGER DEFAULT 0, common_count INTEGER DEFAULT 0, rare_count INTEGER DEFAULT 0, legendary_count INTEGER DEFAULT 0, updated_at TIMESTAMP DEFAULT NOW() ); ``` **Backend endpoints:** ``` GET /api/v2/telegram-bot/collection/:telegramUserId - Получить коллекцию пользователя - Query params: ?rarity=common|rare|legendary, ?pack_id=X POST /api/v2/telegram-bot/collection/add - Добавить карточку в коллекцию - Body: { telegramUserId, cardId, rarity, obtainedVia } GET /api/v2/telegram-bot/card-variants/:cardId - Получить все варианты карточки (common, rare, legendary) GET /api/v2/telegram-bot/collection/:telegramUserId/progress - Получить статистику коллекции POST /api/v2/telegram-bot/collection/award-rare - Наградить случайной rare карточкой - Body: { telegramUserId, reason } POST /api/v2/telegram-bot/collection/award-legendary - Наградить legendary карточкой - Body: { telegramUserId, cardId (optional), reason } ``` **Изменения в боте:** ``` mnemo_cards_telegram_bot/ ├── lib/ │ ├── backend_client.dart [ОБНОВИТЬ] │ │ + getCollection() │ │ + getCardVariants() │ │ + addToCollection() │ │ + getCollectionProgress() │ │ + awardRareCard() │ │ + awardLegendaryCard() │ │ │ ├── image_generator.dart [ОБНОВИТЬ] │ │ + generateCardImage(card, rarity) │ │ + _getFrameForRarity() │ │ + _addGlowEffect() │ │ + _addSparkles() │ │ │ └── models/ │ ├── card_rarity.dart [НОВЫЙ] │ ├── card_variant.dart [НОВЫЙ] │ └── user_collection.dart [НОВЫЙ] │ └── bin/ └── main.dart [ОБНОВИТЬ] + onCommand('collection') + onCommand('showcase') + onCommand('share_card') + обновить onCommand('daily') - показывать прогресс коллекции + обновить onCommand('stats') - добавить статистику коллекции ``` **Изменения в бэкенде:** ``` mnemo_cards_backend/ ├── lib/ │ ├── api/v2/ │ │ └── telegram_bot_api_v2.dart [ОБНОВИТЬ] │ │ + GET /telegram-bot/collection/:id │ │ + POST /telegram-bot/collection/add │ │ + GET /telegram-bot/card-variants/:cardId │ │ + POST /telegram-bot/collection/award-rare │ │ + POST /telegram-bot/collection/award-legendary │ │ │ ├── database/tables/ │ │ ├── card_variants.dart [НОВЫЙ] │ │ ├── user_card_collection.dart [НОВЫЙ] │ │ └── user_collection_progress.dart [НОВЫЙ] │ │ │ ├── collection/ │ │ ├── collection_manager.dart [НОВЫЙ] │ │ │ - Логика добавления карточек │ │ │ - Проверка условий unlock │ │ │ - Награждение карточками │ │ │ │ │ └── rarity_calculator.dart [НОВЫЙ] │ │ - Определение редкости при награждении │ │ - Случайный выбор карточек для наград │ │ │ └── cron/ │ └── collection_rewards.dart [НОВЫЙ] - Автоматическое награждение за стрики/достижения - Интеграция с системой достижений ``` #### Геймификация и мотивация **Прогресс-системы:** 1. **Коллекционирование по пакам:** - "Собери все Common карточки пака 'Животные'" → награда: 1 Rare любой карточки пака - "Собери все Rare карточки пака" → награда: 1 Legendary из пака 2. **Коллекционирование по редкости:** - "Собери 10 Rare карточек" → награда: 1 Legendary на выбор - "Собери первую Legendary" → достижение + особая награда 3. **Тематические коллекции:** - "Собери все карточки с животными" → награда - "Собери все карточки с едой" → награда **Лидерборд коллекционеров (опционально):** ``` Команда: /leaderboard collection Бот: 🏆 Топ коллекционеров 🥇 @username1 - 145/450 (32%) 🟣 15 Legendary 🥈 @username2 - 132/450 (29%) 🟣 12 Legendary 🥉 @username3 - 128/450 (28%) 🟣 10 Legendary ... 🔹 Ты - #15 - 45/450 (10%) 🟣 2 Legendary ``` #### Канал (если будет) **Еженедельный пост "Карточка недели":** ``` 🌟 КАРТОЧКА НЕДЕЛИ [Изображение Legendary карточки с золотой рамкой] 🟣 LEGENDARY 🇪🇸 el perro (собака) Это одна из самых популярных легендарных карточек! 💎 Как получить: - 🔥 Стрик 30 дней - 🎯 Завершить 3 пака подряд 📊 Статистика: - У 5% пользователей есть эта карточка - Средний срок получения: 45 дней Сколько Legendary карточек у тебя? 👇 ``` **Событие "Редкие выходные":** ``` 🎉 СОБЫТИЕ: РЕДКИЕ ВЫХОДНЫЕ! В эти выходные (23-24 декабря): - 🔵 Шанс получить Rare увеличен вдвое! - 🎁 Каждый квиз на 80%+ даёт Rare карточку - 🎯 /daily даёт Rare вместо Common Не упусти шанс! Время ограничено! ⏰ ``` #### Дальнейшее развитие (Phase 3) **Обмен карточками между пользователями:** ``` /trade @username - Предложить обмен: 2 твои Rare на 1 его Rare - Система подтверждения обмена - История обменов ``` **Крафтинг (объединение карточек):** ``` /craft el perro - 3 Common → 1 Rare (того же слова) - 3 Rare → 1 Legendary - Требует "пыль" (dust) - получаешь за дубликаты ``` **Сезонные/тематические карточки:** ``` - Новогодние версии (декабрь) - Летние версии (июль-август) - Halloween версии (октябрь) - Ограниченное время получения ``` --- ## Дополнительные фичи (Phase 2) ### 7. 📢 Telegram канал (опционально) Если канал будет создан, можно автоматизировать: **Карточка дня в канале:** - Автопостинг красивого изображения с карточкой в канал каждый день в 9:00 - Использовать `ImageGenerator` + `Telegram.sendPhoto` - Реализация: новый cron task `PostDailyCardTask` **Еженедельные итоги:** - Каждое воскресенье пост с статистикой: - Количество активных пользователей за неделю - Самые популярные карточки - Мотивационное сообщение --- ## Технические детали ### Структура проекта **Изменения в боте:** ``` mnemo_cards_telegram_bot/ ├── lib/ │ ├── backend_client.dart [ОБНОВИТЬ] │ │ + getUserStats() │ │ + generateQuiz() │ │ + submitQuiz() │ │ + setReminder() │ │ + getPendingReminders() │ │ + getPendingAchievements() │ │ + getCollection() [НОВЫЙ - для коллекционных карточек] │ │ + getCardVariants() [НОВЫЙ] │ │ + addToCollection() [НОВЫЙ] │ │ + getCollectionProgress() [НОВЫЙ] │ │ + getPendingCardRewards() [НОВЫЙ] │ │ │ ├── bot_config.dart [БЕЗ ИЗМЕНЕНИЙ] │ │ │ ├── image_generator.dart [ОБНОВИТЬ] │ │ + generateCardImage(card, rarity) [НОВЫЙ] │ │ + _getFrameForRarity() [НОВЫЙ] │ │ + _addGlowEffect() [НОВЫЙ] │ │ + _addSparklesEffect() [НОВЫЙ] │ │ │ ├── quiz_manager.dart [НОВЫЙ] │ │ - In-memory state для активных квизов │ │ - Логика генерации inline keyboards │ │ │ └── models/ [НОВАЯ ПАПКА] │ ├── card_rarity.dart [НОВЫЙ] │ ├── card_variant.dart [НОВЫЙ] │ └── user_collection.dart [НОВЫЙ] │ └── bin/ └── main.dart [ОБНОВИТЬ] + onCommand('daily') + onCommand('stats') + onCommand('reminders') + onCommand('quiz') + onCommand('collection') [НОВЫЙ] + onCommand('showcase') [НОВЫЙ] + onCommand('share_card') [НОВЫЙ] + onCallbackQuery (для квизов, напоминаний, коллекции) ``` **Изменения в бэкенде:** ``` mnemo_cards_backend/ ├── lib/ │ ├── api/v2/ │ │ └── telegram_bot_api_v2.dart [НОВЫЙ] │ │ + GET /telegram-bot/users/:id/stats │ │ + POST /telegram-bot/quiz/generate │ │ + POST /telegram-bot/quiz/submit │ │ + POST /telegram-bot/reminders/set │ │ + GET /telegram-bot/reminders/pending │ │ + GET /telegram-bot/achievements/pending │ │ + GET /telegram-bot/collection/:id [НОВЫЙ] │ │ + POST /telegram-bot/collection/add [НОВЫЙ] │ │ + GET /telegram-bot/card-variants/:cardId [НОВЫЙ] │ │ + GET /telegram-bot/collection/:id/progress [НОВЫЙ] │ │ + POST /telegram-bot/collection/award-rare [НОВЫЙ] │ │ + POST /telegram-bot/collection/award-legendary [НОВЫЙ] │ │ + GET /telegram-bot/rewards/pending [НОВЫЙ] │ │ │ ├── database/tables/ │ │ ├── user_streaks.dart [НОВЫЙ] │ │ ├── user_reminder_settings.dart [НОВЫЙ] │ │ ├── user_achievements.dart [НОВЫЙ] │ │ ├── quiz_results.dart [НОВЫЙ] │ │ ├── card_variants.dart [НОВЫЙ - коллекционные карточки] │ │ ├── user_card_collection.dart [НОВЫЙ] │ │ ├── user_collection_progress.dart [НОВЫЙ] │ │ └── pending_card_rewards.dart [НОВЫЙ] │ │ │ ├── collection/ [НОВАЯ ПАПКА] │ │ ├── collection_manager.dart [НОВЫЙ] │ │ │ - Добавление карточек в коллекцию │ │ │ - Проверка unlock conditions │ │ │ - Награждение карточками │ │ │ - Обновление прогресса │ │ │ │ │ ├── rarity_calculator.dart [НОВЫЙ] │ │ │ - Определение редкости для наград │ │ │ - Случайный выбор карточек │ │ │ - Весовые коэффициенты │ │ │ │ │ └── variant_generator.dart [НОВЫЙ] │ │ - Генерация вариантов карточек при инициализации │ │ - Создание Common/Rare/Legendary версий │ │ │ ├── cron/ │ │ ├── send_reminders.dart [НОВЫЙ] │ │ ├── check_achievements.dart [НОВЫЙ] │ │ ├── collection_rewards.dart [НОВЫЙ - награды за коллекцию] │ │ └── post_daily_card.dart [НОВЫЙ, опционально для канала] │ │ │ └── statistics/ │ └── streak_calculator.dart [НОВЫЙ] ``` --- ## Миграции базы данных ### Новые таблицы PostgreSQL ```sql -- User streaks tracking CREATE TABLE user_streaks ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id), telegram_user_id TEXT UNIQUE, current_streak INTEGER DEFAULT 0, longest_streak INTEGER DEFAULT 0, last_activity_date DATE, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_user_streaks_telegram_user_id ON user_streaks(telegram_user_id); CREATE INDEX idx_user_streaks_last_activity ON user_streaks(last_activity_date); -- Reminder settings CREATE TABLE user_reminder_settings ( id SERIAL PRIMARY KEY, telegram_user_id TEXT UNIQUE, reminder_time TIME NOT NULL, timezone TEXT DEFAULT 'UTC', enabled BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_reminder_settings_time ON user_reminder_settings(reminder_time, enabled); -- Achievements CREATE TABLE user_achievements ( id SERIAL PRIMARY KEY, telegram_user_id TEXT NOT NULL, achievement_type TEXT NOT NULL, achieved_at TIMESTAMP DEFAULT NOW(), notified BOOLEAN DEFAULT false ); CREATE INDEX idx_achievements_notified ON user_achievements(notified); CREATE INDEX idx_achievements_telegram_user ON user_achievements(telegram_user_id); -- Quiz results CREATE TABLE quiz_results ( id SERIAL PRIMARY KEY, telegram_user_id TEXT NOT NULL, quiz_id TEXT NOT NULL, total_questions INTEGER NOT NULL, correct_answers INTEGER NOT NULL, completed_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_quiz_results_telegram_user ON quiz_results(telegram_user_id); -- ================================================== -- COLLECTIBLE CARDS SYSTEM -- ================================================== -- Card variants (all possible collectible versions) CREATE TABLE card_variants ( id SERIAL PRIMARY KEY, card_id TEXT NOT NULL, -- ID основной карточки (game_card.id) rarity TEXT NOT NULL, -- 'common', 'rare', 'legendary' image_variant TEXT, -- Путь к альтернативному изображению -- NULL = использовать базовое изображение с рамкой frame_color TEXT NOT NULL, -- HEX цвет рамки (например: '#808080') frame_width INTEGER DEFAULT 40, -- Ширина рамки в пикселях has_glow BOOLEAN DEFAULT false, -- Эффект свечения вокруг рамки has_sparkles BOOLEAN DEFAULT false, -- Эффект блесток/искр unlock_condition TEXT, -- Текстовое описание условия получения description TEXT, -- Описание варианта карточки created_at TIMESTAMP DEFAULT NOW(), UNIQUE(card_id, rarity), CHECK (rarity IN ('common', 'rare', 'legendary')) ); CREATE INDEX idx_variants_card_id ON card_variants(card_id); CREATE INDEX idx_variants_rarity ON card_variants(rarity); -- User card collection (что собрал пользователь) CREATE TABLE user_card_collection ( id SERIAL PRIMARY KEY, telegram_user_id TEXT NOT NULL, card_variant_id INTEGER NOT NULL REFERENCES card_variants(id) ON DELETE CASCADE, obtained_at TIMESTAMP DEFAULT NOW(), obtained_via TEXT, -- 'daily', 'quiz_perfect', 'streak_7', 'streak_30', 'achievement', etc. UNIQUE(telegram_user_id, card_variant_id) ); CREATE INDEX idx_collection_user ON user_card_collection(telegram_user_id); CREATE INDEX idx_collection_obtained ON user_card_collection(obtained_at); CREATE INDEX idx_collection_obtained_via ON user_card_collection(obtained_via); -- User collection progress (кэш для быстрого доступа к статистике) CREATE TABLE user_collection_progress ( id SERIAL PRIMARY KEY, telegram_user_id TEXT UNIQUE NOT NULL, total_unique_words INTEGER DEFAULT 0, -- Количество уникальных слов в коллекции total_cards INTEGER DEFAULT 0, -- Общее количество карточек (с учетом редкостей) common_count INTEGER DEFAULT 0, rare_count INTEGER DEFAULT 0, legendary_count INTEGER DEFAULT 0, completion_percentage DECIMAL(5,2) DEFAULT 0.0, updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_collection_progress_user ON user_collection_progress(telegram_user_id); -- Pending card rewards (очередь наград, которые нужно выдать) CREATE TABLE pending_card_rewards ( id SERIAL PRIMARY KEY, telegram_user_id TEXT NOT NULL, reward_type TEXT NOT NULL, -- 'rare_random', 'legendary_random', 'rare_choice', 'legendary_choice' quantity INTEGER DEFAULT 1, reason TEXT, -- 'streak_7', 'streak_30', 'quiz_perfect', etc. card_choices TEXT[], -- Массив card_id для выбора (если reward_type содержит 'choice') claimed BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT NOW(), claimed_at TIMESTAMP ); CREATE INDEX idx_pending_rewards_user ON pending_card_rewards(telegram_user_id, claimed); CREATE INDEX idx_pending_rewards_claimed ON pending_card_rewards(claimed); ``` --- ## Аналитика и метрики После реализации фич, отслеживать: **Вовлеченность:** - DAU (Daily Active Users) через команды - Частота использования команд `/daily`, `/quiz`, `/stats` - Retention rate (возвращаются ли пользователи на следующий день) **Эффективность:** - Средняя длина стрика - Процент пользователей с настроенными напоминаниями - Процент прохождения квизов (completion rate) - Средний результат в квизах **Endpoints для админа:** ``` GET /api/v2/admin/telegram-bot/analytics - Количество активных пользователей бота - Популярные команды - Средняя длина стриков - Retention metrics ``` --- ## Приоритеты реализации ### MVP (Iteration 1) - 2-3 недели 1. ✅ `/daily` - Карточка дня (базовая версия без коллекционирования) 2. ✅ `/stats` - Базовая статистика 3. ✅ Backend: Endpoints для карточек и статистики 4. ✅ Backend: Таблица user_streaks ### Iteration 2 - 1-2 недели 5. ✅ `/quiz` - Мини-квизы 6. ✅ Backend: Quiz generation и results tracking ### Iteration 3 (Коллекционные карточки) - 2-3 недели 7. ✅ Система коллекционных карточек: - Backend: таблицы card_variants, user_card_collection, user_collection_progress - Backend: endpoints для коллекции - Генерация вариантов карточек с разными рамками (Common/Rare/Legendary) 8. ✅ Команда `/collection` - просмотр коллекции 9. ✅ Команда `/showcase [слово]` - детали карточки 10. ✅ Обновление `/daily` - интеграция с коллекцией 11. ✅ Обновление `/stats` - статистика коллекции 12. ✅ Система награждения карточками за достижения ### Iteration 4 - 1-2 недели 13. ✅ `/reminders` - Напоминания 14. ✅ Cron job для отправки напоминаний ### Iteration 5 - 1 неделя 15. ✅ Автоматические достижения 16. ✅ Cron job для проверки achievements 17. ✅ Интеграция достижений с наградами коллекционных карточек ### Iteration 6 (Социальные фичи) - 1-2 недели 18. ✅ `/share_card` - поделиться карточкой 19. ✅ `/leaderboard collection` - топ коллекционеров (опционально) 20. ✅ Тематические события для коллекции (опционально) ### Optional (если канал появится) 21. 📢 Автопостинг в канал 22. 📊 Еженедельные итоги в канале 23. 🌟 "Карточка недели" в канале 24. 🎉 События "Редкие выходные" --- ## Риски и митигация ### Технические риски **Проблема:** Telegram API rate limits - **Митигация:** Использовать батчинг сообщений, queue для напоминаний **Проблема:** Сложность state management для квизов - **Митигация:** Простой in-memory Map, ограничить время жизни квиза (15 минут) **Проблема:** Часовые пояса для напоминаний - **Митигация:** Начать с UTC, потом добавить определение timezone через location ### Продуктовые риски **Проблема:** Низкая активация (пользователи не используют команды) - **Митигация:** - Добавить onboarding после авторизации - Welcome message с перечислением команд - Push notification после регистрации **Проблема:** Спам напоминаниями - **Митигация:** - Максимум 1 напоминание в день - Легкое отключение через `/reminders` - Автоматическое отключение после 7 дней неактивности --- ## Дизайн сообщений ### Единый стиль Использовать эмодзи для визуальной привлекательности: - 🎴 Карточки - 📊 Статистика - 🔥 Стрики - 🎯 Квизы - ⏰ Напоминания - 🎉 Достижения - ✅ Успех - ❌ Ошибка **Тон общения:** - Дружелюбный, мотивирующий - Короткие сообщения (2-4 строки) - Призывы к действию (CTA) --- ## Пример onboarding flow После первой авторизации через `/start` или `/login`: ``` Бот: Привет! 👋 Я бот Mnemo Cards. Помогу тебе учить языки каждый день! Что я умею: 🎴 /daily - карточка дня для изучения 🎯 /quiz - быстрый квиз для проверки знаний 📊 /stats - твоя статистика и стрики ⏰ /reminders - настрой напоминания Начнем с карточки дня? → /daily ``` --- ## Тестирование ### Unit тесты - `BackendClient.getUserStats()` → проверить парсинг response - `BackendClient.generateQuiz()` → проверить структуру квиза - `QuizManager` → state management для активных квизов - `StreakCalculator` → логика подсчета стриков ### Integration тесты - End-to-end flow: `/daily` → получить карточку → отправить изображение - End-to-end flow: `/quiz` → ответить на вопросы → получить результат - Cron job: `SendRemindersTask` → отправка напоминаний в нужное время ### Manual QA - Тестирование команд в реальном Telegram - Проверка inline keyboards - Проверка таймингов напоминаний - Проверка корректности стриков при активности в разные дни --- ## Документация После реализации обновить: - [`mnemo_cards_telegram_bot/README.md`](mnemo_cards_telegram_bot/README.md) - описание новых команд - [`mnemo_cards_backend/README.md`](mnemo_cards_backend/README.md) - новые API endpoints - Создать `mnemo_cards_telegram_bot/COMMANDS.md` - справочник команд для пользователей --- ## Заключение Предложенные фичи создают **полноценную продуктовую экосистему** вокруг Telegram бота: ✅ **Привычка** - ежедневные напоминания и карточка дня ✅ **Мотивация** - стрики, достижения и коллекционирование ✅ **Практика** - квизы для закрепления знаний ✅ **Прогресс** - видимая статистика успехов и коллекции ✅ **Удобство** - обучение прямо в Telegram без открытия приложения ✅ **Геймификация** - система коллекционных карточек с редкостью создает долгосрочную цель ✅ **Социальный аспект** - возможность делиться своими достижениями и редкими карточками ### Почему коллекционные карточки важны для retention: 1. **Долгосрочная мотивация** - собрать все Legendary карточки может занять месяцы 2. **Визуальная награда** - красивые изображения с разными рамками создают эмоциональную связь 3. **Прогресс виден** - пользователь всегда видит, сколько ещё осталось собрать 4. **FOMO эффект** - ограниченные/сезонные карточки заставляют возвращаться 5. **Гордость достижениями** - возможность похвастаться редкими карточками Это создает дополнительную ценность для пользователей и значительно повышает retention, что критично для MVP стадии проекта. --- ## Roadmap Summary **Минимальный MVP (4-5 недель):** - Базовые команды: /daily, /stats, /quiz - Система стриков - Простая коллекция (только Common карточки) **Полноценный MVP (8-10 недель):** - Все базовые команды - Полная система коллекционных карточек (Common/Rare/Legendary) - Напоминания - Достижения с наградами в виде карточек - Команды /collection, /showcase **Phase 2 (12+ недель):** - Социальные фичи (/share_card, /leaderboard) - Telegram канал с автопостингом - Тематические события - Обмен карточками (опционально) - Крафтинг (опционально)