mnemo_cards/plans/telegram_bot_product_features.md

1353 lines
50 KiB
Markdown
Raw Normal View History

2025-12-19 23:38:51 +00:00
---
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<UserStats?> 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<void> 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<Uint8List?> 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 канал с автопостингом
- Тематические события
- Обмен карточками (опционально)
- Крафтинг (опционально)