Перейти к содержимому

ZenAi: от кода до продакшна — деплой, React Admin, TG-авторизация и live-синхронизация

Эта статья — результат рабочей сессии с AI-агентом. Агент фиксирует процесс, я редактирую и дополняю.

ZenAi: от кода до продакшна — деплой, React Admin, TG-авторизация и live-синхронизация

Date: 2026-02-27 Project: ZenAi — ИИ-менеджер для Telegram (C:\Tools\ZenAi) Duration context: длинная сессия (вторая половина дня — деплой, админка, авторизация, синхронизация)

Что было сделано

Деплой на продакшн

React Admin (Этап 6)

TG-авторизация по телефону

TG-авторизация по QR-коду

KB: файлы и entries

Persistent Telegram pool + live handlers

Синхронизация диалогов

Логирование и мониторинг

Проблемы и решения

Проблема: Alembic не видит VECTOR-тип в контейнере

Симптомы: alembic revision --autogenerate генерирует миграцию, но VECTOR-колонки пропущены.

Решение: import pgvector.sqlalchemy.vector в alembic/env.py — без явного импорта SQLAlchemy не регистрирует кастомный тип.

Проблема: React Admin не получает total count для пагинации

Симптомы: список показывает 0 записей, хотя данные есть.

Решение: кастомный paginated_response() хелпер на бэкенде — явно ставит X-Total-Count и Content-Range в headers + expose_headers в CORS.

Проблема: QR-авторизация и 2FA

Симптомы: при QR-логине с включённой двухфакторной Telethon бросает SessionPasswordNeededError, но её перехватывали как “QR expired” и регенерировали QR.

Решение: Отдельный except SessionPasswordNeededError перед генеральным except, запись статуса needs_2fa в Redis, отдельный фронтенд-шаг для ввода пароля.

Проблема: ValueError на load-history — float duration

Симптомы: 503 на эндпоинте загрузки истории из Telegram.

Решение: Telethon возвращает duration медиа как float, а формат :02d ожидает int. Добавлен int() cast.

Ключевые решения

  1. Кастомный dataProvider вместо готового — React Admin не имеет официального провайдера для FastAPI. Написан свой с маппингом offset/limit, кастомными путями и X-Total-Count.
  2. Module-level dict для QR-клиентовqr_login.wait() требует живой TelegramClient, его нельзя сериализовать в Redis. Поэтому dict в памяти процесса + результат polling через Redis.
  3. Lazy load историиsync_dialogs() тянет только метаданные + последнее сообщение. Полная история — по запросу админа через load-history. Экономит трафик и время при первичной синхронизации.
  4. Persistent pool с fallback — если аккаунт подключён в persistent pool → используем его. Если нет → создаём temp pool на время запроса. Покрывает оба кейса без дублирования кода.

Источники и ссылки

Из сессии

Дополнительный контекст

Что дальше

Все записи