← Проекты
2025-2026
PythonFastAPIPostgreSQLWebSocketRabbitMQmicroservices

SK Auto Messenger

Кросс-канальный мессенджер

О проекте

Внутренняя платформа для общения с клиентами. Трафик поступал сразу из нескольких источников: Авито, Telegram, WhatsApp, мессенджер Max. До мессенджера сотрудники работали в каждом приложении отдельно - легко было потерять сообщение или вовремя не ответить. Задача была объединить всё в одно окно браузера.

Готовые CRM-решения вроде Битрикса или amoCRM использовались, но подписка была слишком дорогой. И компания решила строить своё решение.

Архитектура

Каждый источник сообщений — отдельный микросервис. Telegram и WhatsApp требуют по одному активному приложению на аккаунт, поэтому под каждый аккаунт поднимается отдельный инстанс сервиса. Авито и Max в этом плане свободнее — там ограничений меньше.

Все сервисы общаются через RabbitMQ: входящее сообщение из любого канала попадает в очередь, основной бэкенд забирает его и доставляет в браузер сотрудников через WebSocket. Медиафайлы вынесены в MinIO — S3-совместимое объектное хранилище.

Фишка проекта

Новый источник сообщений можно подключить через стандартизированный HTTP-контракт — не нужно трогать основную кодовую базу. Любой адаптер — хоть Авито, хоть новая платформа — просто приводит входящее сообщение к единому формату и вызывает одну функцию:

def save_incoming_message(
    payload: dict,
    platform: str,
    user_url: str = None,
    ad_text: str = None,
    ad_price: str = None,
    ad_url: str = None,
) -> None:

payload — единый формат для всех платформ:

payload = {
    "message_id": str,
    "from_me": bool,
    "created_at": datetime,
    "message_type": str,
    "text": str,
    "replied_message_id": str | None,
    "media": {
        "file_name": str,
        "file_bucket": str,
    } | None,
    "chat_avatar": {
        "media_key": str,
        "bucket_name": str,
    } | None,
}

Сложности

Самым нетривиальным оказался RabbitMQ — не сам факт использования, а понимание его модели. Queue и exchange это не одно и то же, routing key работает не так как ожидаешь, а backpressure и ack нужно думать заранее, иначе сообщения теряются или дублируются. Это тот случай, когда документацию мало прочитать — нужно несколько раз ошибиться, чтобы понять как оно работает на самом деле.

Вторая сложность — нестабильность инстансов. Любой из инстансов мог отвалиться в любой момент: сессия протухла, сеть упала, платформа обновила API. Особенно страдал WhatsApp — там использовалась библиотека whatsapp-web.js, которая работает через headless-браузер и была очень нестабильна.

Пример интерфейса мессенджера