# Research: Альтернативные варианты организации чатов в Telegram ## Сравнительная таблица | Вариант | Friction для юзера | Техническая сложность | Ограничения | Статус | |---------|-------------------|----------------------|-------------|--------| | **1. Виртуальные чаты в DM** | Нет | Низкая | Нет | ✅ РЕКОМЕНДУЕТСЯ | | **2. Threads / Reply Threads** | Высокая | Средняя | Требует группу, бот не создаёт темы | ❌ | | **3. Multiple Bot Instances** | Высокая | Средняя | Нужно добавлять каждый | ❌ | | **4. Inline Mode** | Нет | Низкая | Stateless, не для диалогов | ❌ | | **5. Бот создаёт приватные группы** | Очень высокая | Очень высокая | Bot API не создаёт группы | ❌ | | **6. Telegram Web App (TWA)** | Нет | Высокая | Нужен web-сервер | ⚠️ Phase 2 | | **7. Forum Topics (исходный)** | Высокая | Средняя | Пользователь создаёт группу вручную | ⚠️ Оставить как опцию | --- ## Вариант 1: Виртуальные чаты в DM (РЕКОМЕНДУЕТСЯ) ### Как выглядит для пользователя ``` /start → [➕ Новый чат] [📋 Мои чаты] [⚙️ Настройки] Нажимает "Новый чат" → "✅ Чат #1 создан! Начните писать..." User: "Расскажи про Python" → "[Чат #1] Python — это язык программирования..." Нажимает "Мои чаты" → 1️⃣ Чат #1 (Python) 2️⃣ Чат #2 (Математика) — 2 часа назад 3️⃣ Исследование рынка — вчера Нажимает на "Чат #2" → "Вы в Чате #2. Последние сообщения: ..." → Продолжает разговор ``` ### Технические детали (aiogram 3.x) #### FSM состояния ```python from aiogram.fsm.state import State, StatesGroup class UserStates(StatesGroup): main_menu = State() in_chat = State() selecting_chat = State() ``` #### Хранение активного чата в StateData ```python # При создании чата await state.set_state(UserStates.in_chat) await state.update_data(active_chat_id=chat_id) # При получении сообщения data = await state.get_data() chat_id = data["active_chat_id"] ``` #### Список чатов с инлайн-кнопками ```python from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton @router.message(Command("list")) async def cmd_list(message: Message, state: FSMContext): chats = db.get_user_chats(message.from_user.id) buttons = [ [InlineKeyboardButton( text=f"📄 {chat.title or f'Чат #{chat.id[:6]}'}", callback_data=f"select:{chat.id}" )] for chat in chats ] await message.answer("📋 Ваши чаты:", reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)) @router.callback_query(F.data.startswith("select:")) async def switch_chat(callback: CallbackQuery, state: FSMContext): chat_id = callback.data.split(":")[1] await state.update_data(active_chat_id=chat_id) await state.set_state(UserStates.in_chat) await callback.message.edit_text(f"✅ Переключился в чат. Пишите...") ``` #### Схема БД ```sql CREATE TABLE chats ( chat_id TEXT PRIMARY KEY, -- UUID user_id INTEGER NOT NULL, title TEXT, created_at TIMESTAMP, updated_at TIMESTAMP ); CREATE TABLE messages ( id INTEGER PRIMARY KEY, chat_id TEXT NOT NULL, user_id INTEGER NOT NULL, direction TEXT, -- 'user' / 'bot' content TEXT NOT NULL, created_at TIMESTAMP, FOREIGN KEY(chat_id) REFERENCES chats(chat_id) ); ``` ### Ограничения - История только в нашей БД, не в Telegram нативно - Нет шаринга чата с другими пользователями ### Примеры в реальных ботах - **ChatGPT Telegram боты** — именно этот паттерн, `/new` → новый разговор, `/history` → список - **StudyGPT** — каждый урок = отдельный "чат" с контекстом - **Notion Bot** — список "проектов" с переключением ### Оценка ✅ Нулевое трение — ничего настраивать не нужно ✅ Работает в DM — приватно ✅ Стандартный паттерн — пользователи знакомы ✅ Полный контроль над UX ✅ Масштабируется без ограничений ❌ История только в нашей БД (но это нормально) --- ## Вариант 2: Threads / Reply Topics — ОТКЛОНЕНО ### Суть Telegram поддерживает `message_thread_id` в апдейтах — можно читать из какого треда пришло сообщение и отвечать в него. Но: - **Бот не может создавать треды** — Bot API этого не умеет - Работает только в Group/Supergroup, не в DM - Пользователь должен создавать каждый тред вручную - Не решает проблему friction — делает хуже ```python # Читать можно thread_id = message.message_thread_id # int или None # Отвечать можно await message.answer("ответ", message_thread_id=thread_id) # Создать тред НЕЛЬЗЯ — метода нет в Bot API ``` --- ## Вариант 3: Deep Linking — ОТКЛОНЕНО Каждый чат = отдельная ссылка вида `https://t.me/bot?start=chatid_xyz`. Пользователь переходит по ссылке, бот предвыбирает чат. **Проблема:** пользователь не знает что такие ссылки существуют, нет discovery, не масштабируется. ```python @router.message(Command("start")) async def cmd_start(message: Message): args = message.text.split() if len(args) > 1: chat_id = args[1] # из deep link # предвыбрать чат ``` --- ## Вариант 4: Inline Mode — ОТКЛОНЕНО Inline mode (`@botname query`) — fundamentally stateless. Один запрос → несколько результатов → пользователь выбирает. Нет истории, нет контекста. Категорически не подходит для многооборотного диалога с AI. --- ## Вариант 5: Бот создаёт приватные группы — ОТКЛОНЕНО **Telegram Bot API не умеет создавать группы.** Единственный workaround — заранее создать 100+ пустых групп и назначать их пользователям. 1000 пользователей = 1000 лишних групп. Абсурд. --- ## Вариант 6: Telegram Web App (TWA) — Phase 2 ### Суть Кнопка в боте открывает мини-приложение (веб). Там красивый интерфейс со списком чатов, историей, поиском. ### Технические детали ```python # В боте from aiogram.types import WebAppInfo, InlineKeyboardButton web_app_btn = InlineKeyboardButton( text="📱 Открыть приложение", web_app=WebAppInfo(url="https://lambda.example.com/app") ) ``` ```javascript // В TWA (JavaScript) const tg = window.Telegram.WebApp; const user_id = tg.initDataUnsafe.user.id; // Загрузить список чатов const chats = await fetch('/api/chats', { headers: { 'X-Telegram-Init-Data': tg.initData } }).then(r => r.json()); ``` ### Оценка ✅ Красивый интерфейс (история, поиск, форматирование) ✅ Мобильный-friendly ⚠️ Нужен HTTPS web-сервер ⚠️ Сложнее разрабатывать ⚠️ Усложняет деплой **Вывод: хороший вариант для v2, не для MVP.** --- ## Финальные рекомендации ### Сейчас (MVP) **Вариант 1 — Виртуальные чаты в DM.** Реализуется за 2-3 дня, нулевое friction, стандартный паттерн. ### Phase 2 **Вариант 6 — TWA** как дополнительный UI поверх той же логики. Бэкенд не меняется — просто добавляется web-интерфейс. ### Опционально (для пользователей которые хотят) **Forum Topics** — оставить как opt-in возможность. Пользователь сам создаёт группу, добавляет бота — получает "продвинутый режим" с нативными Telegram темами. --- ## Что это означает для архитектуры `ChatManager` в `core/chat.py` должен работать одинаково для обоих режимов — и виртуальных чатов в DM, и Forum Topics. Разница только в адаптере: | | Telegram DM (virtual) | Telegram Forum | Matrix | |-|-----------------------|----------------|--------| | `chat_id` | UUID | `message_thread_id` | `room_id` | | Создание | В БД | `create_forum_topic` | `room_create` | | Отправка | `send_message(chat_id=user_id)` + tag | `send_message(thread_id=...)` | `room_send` | | `core/` | Не знает разницы | Не знает разницы | Не знает разницы |