Три плагина для Mattermost за день: как мы закрыли боли мессенджера с помощью Cursor
- понедельник, 24 августа 2026 г. в 00:00:13
Очередная статья про то, как AI упрощает жизнь разработчикам, и параллельно отбирает у него куски работы, которые ещё недавно казались «только руками и с опытом». Долго можно было отмахиваться: «ну нет, это игрушка». Сейчас уже сложнее: случилось то, что отрицали. Описал задачу, получил рабочий код, осталось проверить на стенде и не накосячить в проде.
Cursor использую постоянно, но история не про «AI всё сделал за меня» (хотя в целом сделал но не с первого раза). Задачи от бизнеса не было: три мелочи в Mattermost нас задолбали, я решил допилить сам. Заодно опенсорс в копилку и немного кармы: порадовать коллег, с которыми каждый день в одних чатах. Раньше на это ушла бы неделя: docs, примеры, trial and error. Ушёл день. Вот что из этого вышло.
Кратко: self-hosted Mattermost, обычная лицензия. Три раздражителя в ежедневной работе:
ответ на сообщение в ленте
статус «прочитал или нет» (ну такое, но тоже полезно)
быстрый голосовой созвон.
Закрыл тремя плагинами, собрал за ~день в Cursor, выложил на GitHub. Ниже: зачем, что получилось и где не ждите чуда.

Почему бы вообще не переехать
Когда в Mattermost не хватает мелочи, мысль всплывает сама: «Может, на другое?»
Переезда не было, но думали. Решений на СНГ рынке много, как стартапов так и решений из Big Tech. Каждый раз упирались в одно: у вендора, за чей продукт начнёшь платить, что-то пойдёт не так. Падения, деньги кончатся, закроются, заблокируют. А ты уже мигрировал, уже заплатил. И снова искать, куда бежать.
Mattermost не идеальный из коробки, зато платформа с плагинами. Не хватает фичи: допилить. Не хочешь допиливать: Enterprise. Я пошёл третьим путём, своими силами, без тикета в бэклог.
Ответ на конкретное сообщение в ленте канала, не только в треде.
Галочки «доставлено / прочитано» на своих сообщениях.
Постоянные голосовые комнаты в сайдбаре, без отдельного сервиса.
Вспомним один из принципов SRP (Single Responsibility Principle).
Я решил что каждый плагин должен закрывать свою проблему и есть риск одним плагином заблокировать работу других, а так можно отключить конкретный и продолжать работать с остальными.
В Mattermost есть треды. Нажал Reply, ответ ушёл в боковую панель. Для длинных веток норм.
Но часто нужно другое: ответ в потоке канала с цитатой, чтобы все видели контекст, а не копировали текст руками и не писали «+1 к сообщению @ivan выше».
Что сделал:
кнопка Reply на сообщении;
превью цитаты над полем ввода;
ответ отдельным постом с кликабельной цитатой (переход к оригиналу);
встроенную кнопку MM переименовал в Thread, чтобы не путать;


Мобилка: UI плагина там не работает. Но в текст поста зашита markdown-цитата, прочитать ответ с контекстом можно. Красивый блок с кликом только в вебе.
Классическая рабочая ситуация: написал коллеге, ждёшь. Тишина. Он занят? Не заходил? Прочитал и забыл ответить? В Mattermost на Team Edition ты этого не знаешь. В Enterprise read receipts есть, но мы не на Enterprise.
Зачем галочки:
- ✓ серая: сообщение дошло до сервера, доставлено;
- ✓✓ зелёные: собеседник увидел сообщение в клиенте (прокрутил в зону видимости);
- при наведении: кто именно прочитал.
Плагин рисует галочки только на своих сообщениях. Обновления в реальном времени.

Хитрость, которую стоит знать: «прочитано» фиксируется, когда человек смотрит сообщение в вебе или desktop (там крутится webapp плагина). Открыл чат в нативном приложении, галочки у отправителя не зеленеют. Можно читать «тихо» :)
Галочки сами по себе тоже видны только в web/desktop, в телефоне их UI нет.
Нужен был быстрый голос без ссылки на Jitsi, который мы обычно использовали (там была отдельная авторизация, что ещё больше раздражало, но отдадим должное, работал стабильно). Комнаты в сайдбаре: зашёл, поговорил, вышел. Всё на своём сервере.
Что сделал: WebRTC + Pion на Go, аудио живёт прямо в server-плагине, без отдельного медиа-хоста. Комнаты под Threads, список участников, mute, плавающий виджет. Настройки STUN/TURN и NAT для прода за Docker.
Почему не LiveKit, MediaSoup и прочие SFU «на отдельной машине»: нужно было быстрое базовое решение, а не второй сервис с деплоем, мониторингом и ещё одним местом, где что-то упадёт. Pion внутри плагина проще для нашего масштаба.

Важно: нужно пробросить UDP-порты (20000-20010) и указать публичный IP. Без этого плагин самый капризный из трёх. Зато завёлся, удобно.
Еще момент, что вариант с медиасервером а не P2P выбран для дальнейшего внедрения записей встреч и отправкой ссылки на неё ботом в канал, но это как руки дойдут.
Я не Mattermost-разработчик, зато работаю с медиа (WebRTC, стриминг, аудио/видео). С Mattermost plugin API до этого особо не пересекался: CRT, registerPostActionComponent, всё новое.
AI не в вакууме. Для Cursor заранее заложил правила: что использовать, как собирать, как отлаживать, особенно для плагина со звонками. Явно прописал: медиа через Pion в Go-плагине, без разворачивания LiveKit/MediaSoup на отдельном хосте. Без этого Cursor любезно предложил бы «поднимите SFU-кластер», красиво, но не за день.
Но в целом можно сделать так, чтобы медиасервер не лежал прямо внутри а был отдельно развернут указав адрес где он живет, полезно чтобы не уронить звонками весь мессенджер, но нас не очень много в компании, поэтому должно справиться.
Работало так:
1. Описал боль и ограничения: «reply как в Slack», «галочки на своих сообщениях», «голосовые комнаты, Pion, один бинарник плагина.
2. AI набросал каркас: plugin.json, Makefile, webapp, server hooks.
3. Итерации по скриншотам и логам: «кнопка не там», «renegotiation ломается», «NAT без 1:1 IP», правка, make dist, стенд.
4. Документацию MM читал точечно; по WebRTC/Pion опирался на свой бэкграунд и подсказывал AI, где он уходит не туда.
~один рабочий день до рабочих прототипов. Поставил на стенд, коллеги начали пользоваться, без презентаций и «официального релиза». Для меня это и был успех: перестало бесить, плюс три репозитория на GitHub.
AI хорош для каркаса и незнакомого API, если ты задаёшь рамки. Без опыта в медиа и без правил для Cursor он бы утонул в over-engineering. Staging, NAT, mobile, всё равно на вас.
Запомнить одно:
Web, Desktop | ✅ всё работает
приложения iOS, Android | ❌ UI плагинов нет
Нативные приложения не грузят ваш main.js. Server-side (Go) работает везде. Кнопки, галочки, комнаты только там, где webapp.
На практике:
- Reply: создавать с телефона нельзя, читать (как цитату) можно.
- Галочки: видны и обновляются в web/desktop; в приложении, «тихое чтение».
- Голос: только web/desktop. (но вполне можно вытащить в отдельный веб чтобы и с телефона заходить на крайний случай)
Можно собрать самому.
make dist
Либо из релиза взять готовую сборку и загрузить её.
→ .tar.gz в System Console → Plugins → Upload. Mattermost 9.0+, после установки Ctrl+F5.
Риски: major-апдейт MM может потребовать правок; support на вас; перед продом, staging.
Mattermost на обычной лицензии не тупик, если готовы допилить узкие боли плагинами. Три штуки за день с AI: личная инициатива, не проект от бизнеса. Trade-off один: мобилка урезана, у нас большинство с ПК и ноутбука, терпимо.
Ссылки:
Channel Reply - https://github.com/Azario16/mattermost-plugin-channel-reply
Message Status- https://github.com/Azario16/mattermost-plugin-message-status
Voice Channels - https://github.com/Azario16/mattermost-plugin-voice-channel
MIT. Берите, форкайте, критикуйте. Я сначала починил своё, потом выложил наружу.
Пишите почаще руками.
Всем удачи!