Skip to content

Бот MAX ​

Обзор ​

Бот работает внутри процесса бэкенда параллельно с Fastify REST API. Использует библиотеку @maxhub/max-bot-api для взаимодействия с мессенджером MAX через long polling. Бот отвечает на команды пользователей и отправляет уведомления о мероприятиях по расписанию.


Структура ​

back/src/bot/
├── index.ts                     # Инициализация бота, регистрация команд, запуск
├── utils.ts                     # Утилиты: форматирование дат в МСК
├── handlers/
│   ├── index.ts                 # Регистрация всех обработчиков
│   ├── start.ts                 # /start и bot_started — приветствие
│   └── events.ts               # /events — список мероприятий пользователя
└── scheduler/
    └── notifications.ts         # Cron-планировщик уведомлений

Запуск ​

Бот запускается в back/src/index.ts после инициализации базы данных и загрузки модулей API:

typescript
await initializeDatabase();
await loadModules();

const { startBot } = await import('./bot/index.js');
await startBot();

await server.listen({ ... });

startBot() выполняет:

  1. Создаёт экземпляр Bot с токеном из BOT_TOKEN
  2. Устанавливает подсказки команд через setMyCommands
  3. Регистрирует обработчики команд
  4. Запускает cron-планировщик уведомлений
  5. Запускает long polling через bot.start()

Бот и Fastify работают асинхронно в одном Node.js процессе на одном event loop.


Команды ​

/start ​

Отправляется при первом запуске бота или по команде. Приветственное сообщение с описанием приложения и списком доступных команд.

Также обрабатывается событие bot_started — когда пользователь впервые открывает диалог с ботом.

/events ​

Показывает список предстоящих мероприятий пользователя.

Логика:

  1. Получает user_id из контекста MAX (идентификатор пользователя в мессенджере)
  2. Ищет пользователя в БД по xamId
  3. Если не найден — сообщает что нужно зарегистрироваться через приложение
  4. Загружает регистрации пользователя с populate событий и их типов
  5. Фильтрует только будущие мероприятия
  6. Форматирует список с эмодзи-статусами: ✅ посещено, ⏳ ожидается

Пример ответа:

Ваши предстоящие мероприятия (2):

1. ⏳ Научная конференция
   📅 15.05.2026 в 10:00
   📍 Главный корпус, ауд. 301
   🏷 Конференция, Наука

2. ⏳ Спортивный день
   📅 20.05.2026 в 09:00
   📍 Стадион СКФУ
   🏷 Спорт

Планировщик уведомлений ​

Реализован на node-cron. Два cron-задания:

Утреннее уведомление — 0 4 * * * (7:00 МСК) ​

Каждый день в 7:00 по московскому времени (4:00 UTC):

  1. Находит все мероприятия, запланированные на сегодня
  2. Для каждого мероприятия получает зарегистрированных пользователей
  3. Фильтрует тех, у кого notifications = true и xamId не null
  4. Отправляет каждому сообщение в личный чат с ботом

Пример:

🌅 Сегодня состоится мероприятие!

Научная конференция
⏰ Начало в 10:00
📍 Главный корпус, ауд. 301

Напоминание за 30 минут — * * * * * (каждую минуту) ​

Каждую минуту проверяет, есть ли мероприятия начинающиеся через 29-31 минуту (окно в 2 минуты для надёжности):

  1. Запрашивает мероприятия в этом временном окне
  2. Отправляет напоминание зарегистрированным участникам

Пример:

⏰ Мероприятие начнётся через 30 минут!

Научная конференция
📍 Главный корпус, ауд. 301

Уведомление об обновлении мероприятия ​

Не привязано к cron — вызывается синхронно при обновлении мероприятия через API (POST /webapp/v1/events/update). Отправляет всем зарегистрированным участникам актуальные данные мероприятия.

Пример:

📝 Мероприятие обновлено!

Научная конференция
📅 16.05.2026 в 11:00
📍 Корпус 2, ауд. 205
👥 Вместимость: 150
🏷 Конференция, Наука

Описание мероприятия...

Часовой пояс ​

Все даты в БД хранятся в UTC (Docker-контейнер по умолчанию в UTC). Для отображения пользователям используется конвертация в МСК (UTC+3) через утилиты в bot/utils.ts:

  • toMsk(date) — добавляет 3 часа к UTC
  • formatDateRu(date) — формат ДД.ММ.ГГГГ в ЧЧ:ММ в МСК
  • formatTimeRu(date) — формат ЧЧ:ММ в МСК

Обработка ошибок ​

  • bot.catch() — перехватывает все ошибки бота и логирует их без завершения процесса
  • Каждая отправка уведомления обёрнута в try/catch — если не удалось отправить одному пользователю, остальные всё равно получат
  • Cron-задания оборачивают вызовы в .catch() для логирования ошибок планировщика

Переменные окружения ​

ПеременнаяОписание
BOT_TOKENТокен бота MAX (из настроек Master Bot)
WEBAPP_URLURL фронтенда (используется в конфиге, не в боте напрямую)

NCFU Events Documentation