### Task 4: Telegram-действия поиска (методы TelegramManager) **Files:** - Modify: `backend/app/services/telegram.py` (класс `TelegramManager`) **Interfaces:** - Consumes: `self.client`, `ban_guard`. - Produces (async-методы): - `async def discovery_search(q: str, limit: int = 30) -> list[dict]` — `client(functions.contacts.SearchRequest(q=q, limit=limit))`; вернуть `[{id(str), name, username, kind, hue}]` (kind через `_kind_of`, hue через `dialog_hue`); между вызовами — `await asyncio.sleep(ban_guard.search_pause())`. - `async def discovery_info(dialog_id: str) -> dict` — `{id, name, username, kind, hue, participants: int | None, is_forum: bool}` (participants из `full_chat` где возможно; иначе None). - `async def discovery_read(dialog_id: str, limit: int) -> dict` — последние сообщения: `{"ok": bool, "error": str | None, "messages": [{"id", "text", "date_ms", "topic_id"}]}`; `topic_id` — `getattr(getattr(m,'reply_to',None),'reply_to_top_id',None)`. История недоступна → `{"ok": False, "error": "no_history", "messages": []}`. - `async def discovery_join(username: str) -> None` — `client(functions.channels.JoinChannelRequest(...))`; ПЕРЕД вызовом `await ban_guard.wait_join_delay()`; `FloodWaitError` → `ban_guard.note_flood()` и проброс. - `async def discovery_leave(dialog_id: str) -> None` — `channels.LeaveChannelRequest`. - `def add_dialog_monitored(dialog_id, name, username, kind, hue) -> None` — INSERT/UPDATE `dialogs` с `monitor=TRUE, backfilled=FALSE` (как в `set_monitor`, но без авто-join-логики). - [ ] **Step 1: Реализовать методы** (импорт `telethon.tl.functions`, `telethon.errors.rpcerrorlist.FloodWaitError`). - [ ] **Step 2: Проверить компиляцию** `py_compile`. Полная проверка — после Task 6/7 на живом аккаунте (ручные шаги в Task 10). ---