Skip to content

Base Orchestrator — Фундамент бизнес-логики

BaseBotOrchestrator — это "сердце" каждой фичи. Если Директор управляет навигацией между комнатами, то Оркестратор — это хозяин комнаты, который решает, что пользователь увидит внутри.


🏛 Архитектура без состояния (Stateless Singletons)

Во многих фреймворках объекты логики создаются под каждого пользователя. В codex-bot всё иначе: 1. Синглон: Оркестратор создается в единственном экземпляре при старте бота. 2. Stateless: Он не имеет права хранить self.user_data. Если вы запишете что-то в self одного оркестратора, это увидят все пользователи бота. 3. Context-Driven: Все данные, специфичные для запроса, приходят «снаружи» через объект Director.

Это делает систему экстремально производительной и легкой в отладке.


✍️ Анатомия методов (Сигнатуры)

Мы придерживаемся строгого стандарта: Контекст всегда важнее Данных. Поэтому во всех методах Director идет первым аргументом.

1. render_content (Абстрактный)

Это единственное место, где вы пишете код формирования сообщения. * director: Доступ к БД, API, ID пользователя. * payload: Очищенные данные (уже без метаданных навигации).

2. handle_entry

Точка входа, которую вызывает Директор. По умолчанию она просто вызывает render, но вы можете переопределить её, если при первом заходе в фичу нужно сделать что-то особенное (например, отправить аналитику или обнулить какой-то стейт).


🏗 Жизненный цикл данных

Процесс превращения "сырых данных" в сообщение в Telegram выглядит так:

  1. Оркестратор выполняет бизнес-логику (запросы к БД, расчеты).
  2. Оркестратор возвращает ViewResultDTO (только текст и кнопки).
  3. Базовый класс ловит этот DTO и оборачивает его в UnifiedViewDTO (добавляет пустые поля для меню).
  4. Director подхватывает этот конверт и заполняет технические поля: chat_id, session_key.
  5. ViewSender получает финальный, полностью укомплектованный UnifiedViewDTO и выполняет отрисовку.

💡 Типизация и Безопасность

Фреймворк использует Python Generics для защиты ваших данных. При создании оркестратора всегда указывайте тип данных, которые он ожидает:

class ProfileOrchestrator(BaseBotOrchestrator[UserProfileDTO]):
    async def render_content(self, director: Director, payload: UserProfileDTO | None = None):
        # IDE теперь знает, что у payload есть поля name, balance и т.д.
        return self.ui.show_card(payload)

Использование | None обязательно, так как фича может быть вызвана из главного меню вообще без данных. Фреймворк гарантирует, что вы об этом не забудете на этапе написания кода.