Вопрос по некромагии: миграция с Mattermost

Вопрос

Хотел бы узнать о текущих лучших рекомендациях по миграции данных из экземпляра Mattermost Team Edition в экземпляр Discourse (я администрирую оба).

Я уже ознакомился с советами по координации перехода, поэтому сейчас ищу технические ресурсы и рекомендации именно по миграции данных.

Контекст

Сейчас октябрь 2025 года, и я оказался в ситуации, похожей на тот вопрос 2018 года[1]:

Однако в моём случае давление более определённое — Mattermost фактически прекращает поддержку своей Team Edition[2] (технически это не совсем так, но я рассматриваю эти изменения как нарушение их обязательств по открытому исходному коду).

Исходное обсуждение здесь началось с рекомендации объединить обе платформы, а затем было закрыто заявлением о том, что у Discourse теперь вполне приемлемый чат (что действительно так, особенно с учётом предстоящего поиска по чату). Однако в нём не было никаких советов по миграции.


  1. обсуждение завершилось заявлением участника команды Discourse о том, что Discourse использует Mattermost ↩︎

  2. иронично, что объявление опубликовано с помощью Discourse ↩︎

Привет, Антон!

Миграция с Mattermost на Discourse вполне возможна, но потребует написания собственного скрипта импорта, так как готового скрипта пока нет (см. доступные скрипты импорта здесь). Вы можете изучить существующие скрипты для справки, но обязательно проверьте даты их последнего обновления и адаптируйте их соответствующим образом, так как некоторые из них могут содержать устаревшие ссылки на таблицы Discourse.

Команда с радостью примет pull request со скриптом импорта из Mattermost!

Отображение каналов и данных

Вы можете импортировать всё как каналы чата, но также можете сопоставить их с другими типами:

  • Каналы как категории: Импортируйте каждый канал Mattermost как категорию Discourse. Треды внутри каналов могут стать темами, где каждое сообщение — это пост. Альтернативно, отдельные посты могут стать первыми сообщениями (OP) тем.
  • Каналы как темы: Другой подход — сделать каждый канал Mattermost единой темой, где сообщения будут ответами. В этом случае треды будут отображаться последовательно.
  • Личные сообщения (DM): Их также можно импортировать как личные сообщения. Это хороший вариант для обсуждений, требующих архивирования.

Внимательно подумайте, какой подход лучше всего подходит для вашего сообщества и объёма контента.

Заголовки тем

При отображении чата в темы и посты вам нужно создавать заголовки для каждой темы. Один отличный способ сделать это — использовать Discourse AI для генерации заголовков с учётом реального контекста темы.

Генерация заголовков тем с помощью ИИ

TL;DR используйте этот метод:

def gen_title(llm, system_prompt, topic)
  begin
  content = topic.posts.map(&:cooked).join("\n").slice(0..10_000)
  message = [{type: :user, content: content}]
  prompt = DiscourseAi::Completions::Prompt.new(system_prompt, messages: message)

  title = llm.generate(
      prompt,
      user: Discourse.system_user,
      temperature: 0.3,
      feature_name: "ai_helper"
  )

  topic.title = title
  topic.save!
  puts "Topic: #{topic.id}, changed sucessfully."
  rescue ActiveRecord::RecordInvalid
    puts "validation error"
  end
end

Вам понадобится LLM и мастер-промпт:

llm = DiscourseAi::Completions::Llm.proxy(SiteSetting.ai_helper_model)

system_prompt = <<-PROMPT
  Я хочу, чтобы вы выступили в роли генератора заголовков для текстовых материалов. Я предоставлю вам текст,\nа вы сгенерируете заголовок. Пожалуйста, держите заголовок кратким и не более 20 слов,\nи убедитесь, что смысл сохраняется. Заголовок должен использовать язык темы.\nЯ хочу, чтобы вы ответили только предложенным заголовком и ничего больше, не пишите объяснений.\nНикогда не используйте двоеточия в заголовке. Всегда используйте регистр предложения, начиная заголовок с заглавной буквы, никогда не начинайте заголовок со строчной буквы. Собственные имена в заголовке\nмогут иметь заглавную букву, а аббревиатуры, такие как LLM, могут использовать заглавные буквы. Оформляйте некоторые заголовки\nкак вопросы, некоторые как утверждения. Убедитесь, что используете вопросительные знаки, если заголовок является вопросом."
PROMPT

Затем вы можете перебрать список тем так, как вам удобно:

# сгенерировать всё
Topic
  .joins(:_custom_fields)
  .where('topic_custom_fields.name = ?', 'import_id')
  .find_each { |topic| gen_title(llm, system_prompt, topic) }

# отфильтровать личные сообщения
Topic
  .joins(:_custom_fields)
  .where('topic_custom_fields.name = ?', 'import_id')
  .where.not(archetype: "private_message")
  .find_each { |topic| gen_title(llm, system_prompt, topic) }

Важные соображения

  • Реакции: Mattermost поддерживает несколько реакций на один пост. При импорте как посты Discourse вам придётся ограничиться одной реакцией, если только вы не отображаете их в Discourse Chat (который нативно поддерживает несколько реакций).
  • Пользовательские эмодзи: Вы можете перенести пользовательские эмодзи, см. документацию плагина Discourse Reactions.
  • Команды и права доступа: «Команды» Mattermost не имеют прямого аналога в Discourse, но вы можете настроить категории/каналы с соответствующим контролем доступа на основе групп.
  • Вложения: Вложения в Mattermost (изображения и документы) не встраиваются в контент, как в Discourse. При импорте вам нужно будет добавить ссылки на вложения (в формате Markdown) или встроить их в тела постов.

Справочные материалы


У нас есть опыт миграции с платформ чата. Если вы хотите получить помощь от нашей команды, посетите нашу страницу услуг по миграции на Discourse.

Если у вас возникнут конкретные вопросы в процессе разработки скрипта или принятия решений по отображению данных, не стесняйтесь задавать их на Meta для получения рекомендаций!

Спасибо за это отличное резюме! Я изучу это, когда наступит время миграции. Если я напишу скрипт, то обязательно поделюсь им с сообществом.

В данный момент я склоняюсь к импорту чата в каналы чата. Помимо отсутствия поиска, который скоро будет реализован, есть ли ещё какие-либо важные соображения?

В этом случае большая часть работы будет связана с парсингом сообщений. Вот несколько важных моментов:

  • Упоминания потребуют записи в базе данных. Проверьте: mention.rb и group_mention.rb.
  • Вложения также должны быть импортированы как upload и ссылаться в markdown-сообщении. Альтернативно, вы можете загрузить изображения на временный сервер по вашему выбору, добавить к ним ссылку в посте и включить настройку: download_remote_images_to_local.
  • Вам всё равно нужно создать категории для каналов, чтобы можно было настроить разрешения.
  • Если вы используете SSO, вы можете импортировать пользователей напрямую из вашего провайдера идентификации. Проверьте: Sync DiscourseConnect user data with the sync_sso route.