Артефакт 7/10

Messenger Hub

Единое мобильное приложение для менеджеров: объединяет Telegram, WhatsApp, Signal, Matrix + локальная LLM для подсказок в реальном времени.

1 Архитектура: один бандл, не четыре

MessengerHub — единый домен "коммуникации менеджера", а не набор отдельных мессенджер-интеграций

Решение: Один бандл src/Bundles/MessengerHub/. Не per-messenger бандлы. Граница домена — "unified manager communications", а не "telegram integration". Adapter pattern внутри одного бандла проще поддерживать. Разбиение на 3 бандла (MessengerChannel, MessageStore, MessengerLLM) создало бы ненужные cross-bundle зависимости.
Mobile App (Flutter)
Unified Inbox
LLM Assist Panel
CRM View Panel
Push Handler
HTTPS / WSS | FCM / APNs
Backend (PHP 8.4 / RoadRunner)
ChannelAdapterManager
TelegramAdapter
WhatsAppAdapter
SignalAdapter
MatrixAdapter
ConversationService
EncryptedMessageStore
WebSocket Handler
LLMPipelineService
Существующие бандлы (переиспользуются):
TelegramBots
CRM
AiChat
Encryption
Acl
→ Ollama (qwen3:4b, localhost:11435/v1)

2 Четыре канала: сравнение и интеграция

Нажмите на канал для деталей подключения

Telegram

Bot API (webhook)
Низкая сложность
🔒

Signal

signal-cli daemon
Высокая сложность
🌐

Matrix

Synapse Appservice
Средняя сложность

Telegram — Bot API

Переиспользуем существующий TelegramBotEntity с новым полем is_messenger_hub. Webhook handler роутит MH-бот сообщения на ChannelAdapterManager::dispatch().

ПараметрЗначение
E2EEНет (bot chats)
Статусы доставкиЧастичные
Multi-tenancy1 бот / брокер
КодСуществует — расширяем

WhatsApp — Cloud API (Meta)

Официальный Cloud API. MTProto bridge отклонён (нарушение ToS, ненадёжно). Требуется WhatsApp Business Account на каждого брокера.

ПараметрЗначение
E2EEДа
Статусы доставкиДа
Multi-tenancy1 WABA / брокер
КодС нуля

Signal — signal-cli daemon

signal-cli daemon в Docker-контейнере, JSON-RPC через Unix socket. Один демон на брокера (1 номер = 1 демон). Нет статусов доставки.

ПараметрЗначение
E2EEДа
Статусы доставкиНет
Multi-tenancy1 номер / брокер
КодС нуля

Matrix — Synapse + Application Service

Synapse homeserver + Application Service (webhook-style, лучше long-poll). Один бот-пользователь на брокера.

ПараметрЗначение
E2EEДа (Megolm)
Статусы доставкиДа
Multi-tenancy1 bot-user / брокер
КодС нуля

3 UI: Unified Inbox и Thread View

Интерфейс мобильного приложения менеджера

9:41FastOTC Hub🔔
Все
TG
WA
Sig
Mx
TG
Иван Петров
Хочу купить 50k USDT
● привязан к сделке #847
12:34
3
+7 999 111 22 33
Фото чека отправил
○ не привязан к CRM
вчера
SIG
Alice_OTC
Нужно обменять 10k EUR срочно
⚠ [LLM] Высокий риск!
10:21
!
✈ Иван Петров
Сделка #847 · USDT 50k
Добрый день! Хочу купить 50,000 USDT. Ваш курс?
12:30 ✓✓
Здравствуйте! Текущий курс 98.5 RUB за USDT.
12:32
🤖 AI подсказка
Клиент покупает 3-й раз за месяц. Объём растёт (10k → 30k → 50k). Предложить VIP-тариф?
Реквизиты Текущий курс ОК, ждём
📎
UX-правило LLM-подсказок: "Не мешать". Подсказка появляется внизу над полем ввода, не перекрывает историю, убирается свайпом вниз. Не блокирует работу менеджера.

4 5 типов LLM-подсказок через qwen3:4b

Нажмите на тип для просмотра примера API-ответа

1

Quick Reply

3-5 вариантов быстрого ответа на сообщение клиента

2

Summary

Краткая сводка диалога + CRM-контекст

3

Risk Alert

AML-триггеры, подозрительные паттерны

4

Deal Suggest

Условия сделки на основе истории

5

Sentiment

Анализ настроения клиента

Quick Reply — Быстрые ответы

Запрос: POST /api/v2/messenger/conversations/{id}/assist

Request:  { "type": "quick_reply" }

Response: {
  "type": "quick_reply",
  "suggestions": [
    "Курс сейчас 92.5 за USDT, могу зафиксировать на 30 минут",
    "Минимальная сумма обмена 1000 USDT",
    "Могу предложить 92.3 при объёме от 10,000 USDT"
  ],
  "confidence": 0.85
}

Summary — Сводка диалога

Response: {
  "type": "summary",
  "text": "Клиент Ivan Petrov (VIP, Москва) хочет обменять
           5000 USDT на рубли. Предыдущие 3 сделки:
           суммы 2000-8000 USDT, средний курс 91.8.
           Клиент лоялен, но чувствителен к курсу."
}

Risk Alert — Предупреждение

Response: {
  "type": "risk_alert",
  "alerts": [{
    "level": "medium",
    "text": "Клиент упоминает третье лицо как получателя
             — возможный structuring (дробление операций)"
  }]
}

AML red flags: дробление крупных сделок, срочность без объяснений + отказ от KYC, несоответствие суммы профилю, "анонимность" / "без документов" / "серые схемы", страны из FATF black/grey list.

Deal Suggest — Предложение сделки

Response: {
  "type": "deal_suggest",
  "suggestion": {
    "instrument": "USDT-TRC20",
    "amount": 50000,
    "rate": 92.5,
    "reason": "Клиент регулярный (3 сделки/мес),
               объём растёт. Рекомендуемая скидка 0.3%"
  }
}

Sentiment — Настроение

Response: {
  "type": "sentiment",
  "sentiment": "neutral_to_positive",
  "signals": ["вежливый тон", "конкретные суммы",
               "не торгуется агрессивно"],
  "recommendation": "Клиент настроен на сделку,
                     не затягивайте с ответом"
}

Бюджет контекстного окна (qwen3:4b, 32K)

System 500t
CRM 1000t
Messages (20 последних) 2000t
Output 500t
Итого ~4000 токенов = 12% от лимита. Latency: 1.5-3 секунды (inference)

5 Путь входящего сообщения

От клиента в Telegram до подсказки на экране менеджера

1. Клиент (Telegram) Telegram API Webhook RoadRunner
2. ChannelAdapterManager::dispatch()
3. TelegramInboundAdapter::normalize() UnifiedMessage DTO
4. ConversationService::handleInbound(UnifiedMessage)
5. EncryptedMessageStore::persist() (AES-256-GCM)
6. WebSocketBroadcast экран менеджера (мгновенно)
7. LLMPipelineService::analyzeAsync() (в очередь)
8. NotificationService::pushToManager() (FCM/APNs)
Ключевые решения:
- WebSocket (RoadRunner), не SSE — бидирекционный realtime. SSE отклонён (требует отдельный POST-канал).
- At-rest encryption (AES-256-GCM), не E2EE — иначе LLM-анализ невозможен.
- Ollama локально (localhost:11435) — данные НЕ покидают сервер. Внешние LLM API запрещены для переписок.
- Per-broker DB для сообщений — изоляция данных. Мастер-БД только для channel accounts.

6 Flutter: архитектура мобильного приложения

Flutter + Riverpod + SQLCipher. Offline-First: локальная БД = источник правды для UI

Почему Flutter, а не React Native / Native / PWA?
- Один кодбаз для iOS + Android (маленькая команда FastOTC)
- Рендерит через Skia/Impeller напрямую, нет JS bridge (критично для скролла тысяч сообщений)
- Dart Isolates — реальная многопоточность для SQLite декрипции и WebSocket обработки
- React Native отклонён: JS bridge создаёт задержки в потоке WebSocket
- PWA отклонён: ненадёжные push-уведомления на iOS, нет Secure Enclave
Presentation Layer Screens / Widgets / GoRouter
State Layer Riverpod Providers / Notifiers
Domain Layer UseCases / Repository Interfaces / Entities
Data Layer Remote DS (REST + WS) | Local DS (SQLCipher)
Core Layer DI (Riverpod) / Crypto / SecureStorage / Logger
// Riverpod: стрим сообщений чата
@riverpod
Stream<List<Message>> chatMessages(Ref ref, String chatId) async* {
  // 1. Сначала из локальной БД — мгновенно
  yield await ref.read(localDbProvider).getMessages(chatId, limit: 50);
  // 2. Затем подписка на WebSocket дельты
  yield* ref.read(wsProvider).messageStream(chatId);
}

// Offline-First алгоритм отправки:
// 1. Сохранить в SQLCipher со статусом PENDING
// 2. UI показывает с индикатором "отправляется"
// 3. Отправить в очередь (dart:isolate)
// 4. Успех → статус SENT / Ошибка → статус ERROR + кнопка "повтор"

7 Интеграция с существующим кодом

Какие бандлы переиспользуем и что расширяем

БандлКак используетсяЧто расширяем
TelegramBots TelegramAdapter использует TelegramBotCredentialsService, TelegramHttpClient TelegramBotEntity + поле is_messenger_hub; webhook — новая ветка для MH-ботов
CRM PartnerEntity в LLM-контексте; привязка чата к сделке Только чтение, не расширяем
AiChat AiChatOpenAiClient + OpenAiFactory для Ollama Как есть, BASE_URL = localhost:11435/v1
Encryption EncryptionRepository для шифрованных сообщений Не расширяем
Notification NotificationEntity для in-app; новый PushNotificationService для FCM/APNs + мобильные push-уведомления
Acl Права доступа менеджеров к чатам Новые ACL-ресурсы: MessengerHub.View/.Send/.Assist/.Admin

8 Безопасность: что исправить до запуска

Найденные уязвимости в существующем коде, влияющие на Messenger Hub

CRITICAL

credentials.txt в репо

Файл app/credentials.txt с plaintext admin-паролем в репозитории

CRITICAL

MySQL root/pass hardcoded

root/pass во всех docker-compose файлах

HIGH

SQL Injection

UserRoleRepository.php (getRawList) — прямая конкатенация строк

HIGH

TG webhook без secret_token

Любой может отправить фейковые updates — критично для Messenger Hub

HIGH

Redis без tenant isolation

AiChat Redis Storage — брокер A может видеть чаты брокера B

HIGH

LLM Prompt Injection

Нет санитизации ввода перед отправкой в LLM. Клиент может инъецировать промпт через сообщение

Правило: Ollama только локально

Данные переписок НЕ уходят на внешние API (OpenAI, Anthropic). Только localhost:11435. Это снимает основные GDPR-проблемы cross-border transfer.

Правило: Rate limiting

Не более 10 LLM-запросов в минуту на пользователя. Redis counter. Все запросы логируются (без контента) для аудита.

Правило: MiCA / AMLD6

Хранить все коммуникации 5 лет. Retention policy. AML-мониторинг в чатах через risk_alert. SAR-процедура.

9 Фазы реализации Messenger Hub

Параллельный поток разработки, не блокирует основную архитектуру

0

Security Hardening

2 недели — ОБЯЗАТЕЛЬНО ПЕРВЫМ
  • Fix 2 CRITICAL + 14 HIGH уязвимостей
  • Audit log для AI-операций
  • JWT expiry + refresh tokens
1

MVP — Telegram + LLM

4-6 недель
  • MessengerHub bundle (Entity, Service, API)
  • Telegram adapter (на базе TelegramBots)
  • REST API для inbox + messages
  • At-rest шифрование сообщений
  • Базовый LLM assist (quick_reply, summary)
  • Flutter MVP (inbox, chat, basic offline)
2

Realtime + WhatsApp

6-8 недель
  • WebSocket (RoadRunner)
  • Push notifications (FCM/APNs)
  • WhatsApp Business API adapter
  • LLM: risk_alert, deal_suggest, sentiment
  • Offline sync + media
3

Federation

8-10 недель
  • Matrix (Synapse + Appservice)
  • Signal (signal-cli daemon)
  • Retention policies (GDPR/MiCA)
  • Admin UI для управления каналами
  • AML-мониторинг в чатах

10 Полная структура бандла MessengerHub

Всё в одном месте: Entity, Adapter, Service, LLM, Api, Queue

src/Bundles/MessengerHub/
  MessengerHubComponent.php
  Routes.php
  adminMenu.php

  Entity/
    ConversationEntity.php         // Чат (channel + contact + status)
    MessageEntity.php              // Сообщение (encrypted content)
    ChannelAccountEntity.php       // Подключённый канал брокера
    MessageAttachmentEntity.php    // Медиа-файлы

  Enum/
    ChannelType.php                // Telegram | WhatsApp | Signal | Matrix
    MessageDirection.php           // Inbound | Outbound
    MessageStatus.php              // Sent | Delivered | Read | Failed
    ConversationStatus.php         // Active | Archived | Blocked

  Adapter/
    ChannelAdapterInterface.php    // connect, disconnect, sendMessage, handleWebhook
    ChannelAdapterManager.php      // Роутинг по ChannelType
    Telegram/TelegramChannelAdapter.php
    WhatsApp/WhatsAppChannelAdapter.php
    Signal/SignalChannelAdapter.php
    Matrix/MatrixChannelAdapter.php

  Service/
    ConversationService.php        // handleInbound, создание/архивация чатов
    MessageService.php             // отправка через адаптер
    EncryptedMessageStore.php      // AES-256-GCM at rest
    WebSocketBroadcastService.php  // push к менеджеру
    PushNotificationService.php    // FCM / APNs

  LLM/
    LLMPipelineService.php         // Оркестратор 5 типов подсказок
    ContextBuilder.php             // Сборка контекста: messages + CRM data
    PromptTemplates.php            // System prompts для каждого типа

  Api/
    ConversationsEndpoint.php      // GET /api/v2/messenger/conversations
    MessagesEndpoint.php           // GET/POST /api/v2/messenger/messages
    AssistEndpoint.php             // POST /api/v2/messenger/.../assist
    ChannelsEndpoint.php           // CRUD каналов
    SyncEndpoint.php               // Delta sync для мобильного

  Queue/Handler/
    InboundMessageHandler.php      // Обработка входящих
    OutboundMessageHandler.php     // Очередь исходящих
    LLMAnalysisHandler.php         // Async LLM inference

  DTO/
    UnifiedMessage.php             // Универсальный формат
    SendMessageRequest.php
    ConversationListItem.php
    LLMAssistResponse.php

  WebSocket/
    MessengerHubWsHandler.php      // RoadRunner WS plugin