15 KiB
Подключение будущего бота MAX
Серверная часть готова к подключению. Сам бот ещё не создан, секреты не заполнены, реальная отправка не включена. Изменений интерфейса сайта в этой поставке нет. Интеграция уведомляет самого пациента; врачебные оповещения остаются в существующем канале проекта.
Что реализовано
- Одноразовая ссылка для привязки аккаунта MAX к текущему пациенту сайта, срок по умолчанию 10 минут.
- Подтверждение подключения,
/help,/stop, отключение при остановке или удалении бота в MAX. - Нейтральные напоминания из существующего планировщика сайта: тесты, дневник, приём лекарств и другие события outbox.
- Уведомление о завершении теста: сервер каждые примерно 30 секунд находит новые завершённые
QuestionnaireRecordиScaleResult, начиная с момента подключения MAX. Незавершённые и старые тесты не отправляются. - Постоянная очередь, восстановление после перезапуска, ограниченные повторы при сетевых ошибках и ответах 429/5xx.
- В сообщении только короткий текст и кнопка на сайт. Ответы, оценки, диагнозы, назначения и ключ входа на сайт в MAX не передаются. Переписка с ботом не сохраняется и не отправляется в LLM.
1. Создать бота — будущему владельцу
- Открыть MAX для партнёров и пройти регистрацию/проверку профиля. Условия допуска зависят от типа владельца; актуальный порядок — в официальной инструкции подключения.
- Создать чат-бота, оформить описание и пройти требуемую MAX модерацию.
- В настройках бота получить токен и скопировать имя из его публичной ссылки
https://max.ru/ИМЯ. - Передать администратору сервера имя бота, а токен — через защищённое хранилище секретов. Токен не нужен в переписке, MR или репозитории.
2. Заполнить настройки сервера
Нужны доступная identity/clinical БД проекта, публичный HTTPS-адрес сайта и HTTPS-адрес API на порту 443.
Входящие POST от MAX должны доходить до API без браузерной CAPTCHA или страницы авторизации.
Прокси должен передавать заголовок X-Max-Bot-Api-Secret и не журналировать тело webhook/Authorization.
Дополнительные таблицы identity создаются существующим init_db() при запуске приложения.
В .env сервера (вне Git) заполнить:
MAX_ENABLED=false
MAX_BOT_TOKEN=
MAX_BOT_USERNAME=
MAX_WEBHOOK_SECRET=
MAX_WEBHOOK_URL=https://api.example.org/api/v1/webhooks/max
MAX_SITE_URL=https://patient.example.org/
MAX_LINK_TTL_SECONDS=600
# При необходимости — PEM-файл доверенного CA, доступный внутри контейнера:
MAX_CA_BUNDLE=
DEMO_CLOCK=false
MAX_BOT_USERNAME— только имя, без@, домена или параметров ссылки.MAX_WEBHOOK_SECRET— отдельная случайная строка, не токен бота: 32–256 символов изA–Z a–z 0–9 _ -. Сгенерировать локально, напримерpython -c 'import secrets; print(secrets.token_urlsafe(32))', сохранить в секреты.MAX_SITE_URLведёт в обычный личный кабинет; не добавлять в адрес ключи доступа или данные пациента.- Исходящие запросы идут на
https://platform-api2.max.ru, токен передаётся заголовкомAuthorization. Верификация TLS всегда включена. Если системе нужен корневой сертификат Минцифры, установить его по официальной инструкции MAX и указать PEM-путь вMAX_CA_BUNDLE; не отключать проверку TLS. - Переменные должны попасть именно в окружение API-контейнера/процесса, а не только панели сайта.
В текущем Compose сервис
appуже получает.envчерезenv_file. После изменения окружения пересоздать процесс/контейнер API. Новые зависимости не требуются.
3. Проверить и включить
В каталоге проекта, в том же окружении, где работает API:
uv run python -m app.channels.max_setup check
Команда проверит токен и совпадение имени бота. Сообщений пользователям она не отправляет.
Затем установить MAX_ENABLED=true, перезапустить API и выполнить:
uv run python -m app.channels.max_setup subscribe
uv run python -m app.channels.max_setup status
subscribe регистрирует только заданный webhook с секретом и событиями
bot_started, message_created, bot_stopped, dialog_removed. Старые чужие подписки автоматически
не удаляются: при переносе сервера владелец должен проверить их отдельно через MAX API.
status проверяет регистрацию адреса; это ещё не проверка доступности сервера из MAX.
Команды не печатают токены, секрет webhook или сырые ответы платформы.
При запуске через Compose вместо uv run python ... использовать
docker compose exec app python -m app.channels.max_setup check (также subscribe и status).
После изменения .env пересоздать API: docker compose up -d --build --force-recreate app.
Запускать один процесс API с MAX на один токен бота: его worker отправляет до одного сообщения в секунду.
БД защищает очередь от параллельного захвата, но общий лимит скорости нескольких процессов не координируется.
Планировщик и MAX worker запускаются вместе с FastAPI, отдельный процесс бота не нужен.
При MAX_ENABLED=false сетевых вызовов MAX и фонового worker нет; сайт продолжает обычную работу.
API для разработчика сайта
В проекте используется ключ текущего пациента, полученный при входе. Для этих ручек передавать его
как Authorization: Bearer <patient_token>; это существующая авторизация прототипа, не новая система SSO.
Не брать token другого пациента и не публиковать демонстрационные учётные записи для реального использования.
| Метод и путь | Запрос | Ответ |
|---|---|---|
GET /api/v1/me/notifications/max |
Authorization | available, connected, last_delivery |
POST /api/v1/me/notifications/max/link |
Authorization; JSON {"consent": true} |
url, expires_at |
DELETE /api/v1/me/notifications/max |
Authorization | состояние с connected: false |
POST /api/v1/webhooks/max |
MAX JSON + X-Max-Bot-Api-Secret |
{"success": true} после записи события |
Поток подключения: пациент явно соглашается на уведомления → сайт получает url → открывает ссылку MAX →
пользователь запускает бота → webhook подтверждает привязку → повторный GET показывает connected: true.
Ссылка одноразовая; новая ссылка отменяет предыдущую. Изначальный ключ пациента не входит в URL MAX.
Для привязки и доставки дополнительно нужны действующее согласие и подтверждение совершеннолетия в состоянии пациента.
Активную привязку нельзя молча переназначить другому аккаунту: сначала отключить её.
Коды ошибок: 401 — неизвестный/отсутствующий ключ пациента; 403 — нет согласия или неверный секрет webhook; 422 — неверный запрос; 413 — webhook больше 64 КиБ; 503 — MAX выключен или хранилище события недоступно. Повтор webhook с тем же идентификатором события не создаёт новых отправок. Групповые чаты игнорируются.
last_delivery: queued, sending, sent, failed, cancelled или null.
sent означает принятие сообщения API MAX, а не прочтение человеком.
Пробное подключение после создания бота
- Войти на сайте синтетическим пациентом и дать необходимые согласия.
- Получить ссылку через POST выше (Swagger
/docsили будущий интерфейс сайта), перейти в MAX и запустить бота. - Убедиться, что GET показывает
connected: trueи приходит подтверждение. - Завершить тест на сайте; примерно через 30 секунд плюс очередь должно прийти сообщение без результатов.
- Дождаться события планировщика и проверить нейтральное напоминание с кнопкой на сайт.
- Отправить
/stop: GET должен показатьconnected: false, ожидающие уведомления отменяются. - Повторить подключение новой ссылкой, проверить DELETE через API и остановку бота через интерфейс MAX.
При недоставке проверить настройки и подписку, доступность HTTPS, состояние очереди и коды ошибок в логах.
http_401/http_403 требуют проверки токена/прав; http_429 — ожидания; transport — сети/TLS;
failed после шести попыток требует вмешательства администратора. Детали ответов и идентификаторы в логи не выводятся.
Отключение отменяет очередь; уже принятый MAX запрос отозвать невозможно.
Гарантии и ограничения
Очередь и подтверждения событий сохраняются в identity БД. Клинические записи остаются в clinical БД.
Для событий завершения тестов БД повторно просматривается после перезапуска; ключи уведомлений предотвращают
повторную постановку. Напоминания используют существующий механизм outbox/повторов планировщика.
При временных ошибках — до 6 попыток с увеличением задержки и учётом Retry-After; зависшая отправка получает
новую аренду через 60 секунд. Потеря процесса между принятием сообщения MAX и записью успеха в БД может
привести к повторному сообщению: MAX не предоставляет ключ идемпотентности отправки.
Не удалять строки дедупликации/очереди без согласованной политики хранения. При большом количестве пациентов
нужны пакетное сканирование завершённых тестов и общий ограничитель скорости; текущая реализация рассчитана на MVP.
Проверки разработчика: make lint test; тесты MAX работают с синтетикой и подменённым HTTP-транспортом.
Реальную доставку подтвердит только пробное подключение после выдачи токена и настройки публичного сервера.
Официальные контракты: отправка сообщений, подписка webhook, события, ссылки запуска бота.