Знания компании — в переписке Mattermost
Сотрудник пишет боту в личных сообщениях — отвечает Query Engine под его доступами, со ссылками на источники. Всё, что умеет веб-чат, не выходя из мессенджера.
posted · WebSocket (исходящий)
ответ постом в тред
Mattermost — ещё одно тонкое окно в тот же диалог: думает и ищет Query Engine под личностью сотрудника, Mattermost лишь приносит реплику и уносит ответ. Близнец Slack на self-hosted сервере — беседу режет тред, а транспорт — исходящий WebSocket вместо вебхука. Одна модель диалога на все поверхности →
Admin заводит бот-аккаунт в System Console Mattermost
(Integrations → Bot Accounts) один раз — адрес сервера и bot-токен ложатся в
mattermost_settings, как SMTP у Email. Экран —
настройки платформы, один тумблер включает бота. Включение проверяет токен вживую
(GET /api/v4/users/me) и проставляет bot_user_id — так
слушатель отличает собственные посты бота.
В отличие от Telegram требования публичного HTTPS нет и webhook-секрета нет вовсе — слушатель подключается сам, наружу ничего не открыто. Адрес сервера в приватной сети — штатно (SSRF-защиты намеренно нет: у Telegram она защищала обратное направление, облако → нас).
Пишущего сводит к учётке
identity_mapping
(source='mattermost') — личность входа. Событие
posted доверенного email не несёт, поэтому авто-матча нет: только
код-привязка
— вошедший в веб получает код и возвращает его боту. Учётку заводит только админ
(приглашением) —
знание бота доступа не даёт.
Непривязанному — нейтральный отказ,
подбор кода ограничен.
Дальше везде только user_id → роль → ACL.
В личке Mattermost есть треды, поэтому граница — правило Slack:
тред — это беседа. Реплика в треде продолжает её, новое корневое сообщение открывает чистую — ни
команды /new, ни указателя активной беседы. Контекст усекается по
токенам — общий механизм движка.
Беседа живёт в conversations (ключ channel_id +
root_id в meta; вложенных тредов нет — реплика несёт id
настоящего корня). Группы · @mention · командные каналы — v2.
HTTP-push для DM у Mattermost нет, поэтому внутрь никто не стучится:
singleton-слушатель WebSocket в процессе планировщика
(единственный сервис в одну реплику) сам подключается к
{base_url}/api/v4/websocket, аутентифицируется bot-токеном и слушает
события posted. Он только транспортирует — фильтрует структурные DM
(не собственный пост бота, без системного subtype, не другой бот), обработка
уходит в очередь
interactive, ответ возвращается по REST постом в тред. Переживает рестарт и ретраи.
Повтор события отсекается по job id = id поста; окно по каналу — под rate-limit fail-closed. Здоровье слушателя — Redis-ключ с TTL, карточка админа показывает его тихой строкой «слушает / не подключён»; канал сигналов настройкам не нужен — слушатель перечитывает их каждые 30 с и разрывает соединение при смене своего конфига.
Какой статус релиза 4.2 и кто ведёт ajax-баг?
Релиз 4.2 в стадии регресс-тестов, выкатка плановая на пятницу. Ajax-баг ведёт Дина Сафина1.
Ответ под доступами Максима: что ему не видно — в ответ не попадёт. Реплика в треде продолжает беседу, новое корневое сообщение открывает чистую.
Первый контакт — привязка аккаунта кодом:
Привет! Какой статус релиза 4.2?
Чтобы продолжить, подтвердите аккаунт: войдите по ссылке — achilles.local/link — и пришлите код. После этого отвечу под вашими доступами.
K7P2-9XQ4
Готово — привязал к maxim@company.com. Спрашивайте
Бот отвечает одинаково всем — известному и встречному, существование инстанса не выдаёт. Код виден только во вошедшем браузере и возвращается в бот — пересланная ссылка угнать учётку не даёт. Экран привязки →
source='mattermost' → мост личности входа
channel_id + root_id
| id | BigInteger | PKCHECK | всегда 1 · singleton |
| base_url | Text | NULL |
адрес сервера (https://mattermost.company.com) · любая установка
с API v4, приватная сеть — штатно
|
| bot_token_enc | Text | NULL | токен бот-аккаунта из System Console, шифротекст AES-256-GCM |
| bot_user_id | Text | NULL |
из /users/me · проставляется только успешной проверкой ·
позволяет слушателю пропускать собственные посты бота
|
| bot_username | Text | NULL | @имя бота для UI · из /users/me |
| enabled | Boolean | NOT NULLDEFAULT | мастер-выключатель · DEFAULT false · off → бот молчит |
| last_test_ok | Boolean | NULL | итог последней проверки: токен ответил — здоровье доставки показывает флаг подключённости слушателя, отдельно |
| last_test_at | DateTime(tz) | NULL | когда проверяли · питает чип статуса на экране |
| created_at | DateTime(tz) | DEFAULT | server_default=now() |
| updated_at | DateTime(tz) | DEFAULT |
server_default=now() · триггер set_updated_at()
|
is_available() — свойство модели, не колонка:
enabled и заполнены base_url · bot_token_enc ·
bot_user_id. bot_user_id играет ту же роль «честно
подключено», что webhook_secret_enc у Telegram — появляется только
после того, как токен действительно ответил.
Честное включение. Включение бота атомарно: Achilles проверяет
токен вживую (GET /api/v4/users/me), и переключатель остаётся включённым
только если сервер ответил — отказ (отозванный токен, недостижимый адрес)
откатывает enabled и возвращает причину, а не зелёный тумблер без бота
за ним. Проверка заодно проставляет bot_user_id и
bot_username. «Проверить соединение» читает ту же правду — проверка
ручается за токен + сервер; за доставку ручается флаг подключённости слушателя.
Проверки: фильтр слушателя (свои посты · боты · системные)резолв личностидедуп по id постатред = беседаACL-проброснепривязанный пользовательлимит подбора кодачестное включение
Webhook-эндпоинта нет: единственный входящий путь — исходящий WebSocket, анонимного маршрута не существует вовсе.
identity_mapping → user_id, общий
link_tokens, защита кода привязки.
→ Auth / Security
/api/v1/admin/mattermost на общей карте поверхности.
→ HTTP API