Skip to content

feat(mattermost): add Mattermost connector - #1466

Open
ad4mou wants to merge 11 commits into
mainfrom
feat/add-mattermost-connector/bot-1090
Open

feat(mattermost): add Mattermost connector#1466
ad4mou wants to merge 11 commits into
mainfrom
feat/add-mattermost-connector/bot-1090

Conversation

@ad4mou

@ad4mou ad4mou commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds Mattermost as a messaging connector, alongside Slack, Teams, Telegram and WhatsApp. Configure a server URL and bot token per project in Settings → Project → Mattermost; the bot holds an outbound connection per project, so no inbound webhook is needed.
  • Replies in the channel rather than a thread, matching Slack: one message in the channel, follow-up housekeeping in a thread. DMs stay unthreaded.
  • Answers mentions in channels, and everything in DMs. Follow-ups in an existing conversation don't need a repeat mention.
  • People are linked to their nao account automatically by their Mattermost email
  • Feedback is given by reacting 👍/👎 on an answer. Reactions arrive over the existing connection, so no network access back to nao is needed.
  • A Stop button appears while nao is answering. This needs Mattermost to reach nao over HTTP, so it's off by default with its own optional Callback URL setting, since the address Mattermost uses can differ from the one people use in a browser. Callbacks are verified with a signed token.

Out of scope

  • Slash commands, file uploads and modals.

Closes #1090

Review in cubic

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

URL https://pr-1466-3b62985.preview.getnao.io
Commit 3b62985

⚠️ No LLM API keys configured - you'll see the API key setup flow when trying to chat.


Preview will be automatically removed when this PR is closed.

@ad4mou
ad4mou marked this pull request as ready for review August 25, 2026 13:53

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 53 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread apps/backend/src/routes/mattermost.ts Outdated
Comment thread apps/backend/src/services/mattermost.ts Outdated
Comment thread apps/backend/src/queries/project-mattermost-config.queries.ts
Comment thread apps/backend/src/utils/mattermost-login.ts Outdated
Comment thread apps/backend/src/queries/chat.queries.ts Outdated
Comment thread apps/backend/src/utils/mattermost-user.ts Outdated
Comment thread apps/backend/src/utils/messaging-provider.ts Outdated
Comment thread apps/frontend/src/components/settings/mattermost-config-section.tsx
Comment thread apps/backend/src/queries/chat.queries.ts Outdated
Comment thread apps/backend/src/db/sqlite-schema.ts Outdated
supersededAt: integer('superseded_at', { mode: 'timestamp_ms' }),
versionGroupId: text('version_group_id'),
source: text('source', { enum: MESSAGE_SOURCES }),
mattermostPostId: text('mattermost_post_id'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this here?

@ad4mou ad4mou Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This links a Mattermost answer thumbs up/down to its nao message so reaction feedback is saved against the correct message.

Basically, buttons look bad on mattermost, so I wanted to avoid having 2 for thumbs up/down which is why I found a way to store feedback via reactions on the message

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should do an exception in the data model to put mattermost in the chatMessage table

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah fair enough, but so should we just not have reactions in Mattermost or use the very bad looking buttons?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did not see the bad looking buttons this morning :/

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/backend/src/services/mattermost-helpers.ts

@Bl3f Bl3f left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few comments

Comment thread apps/backend/src/app.ts

void pingLicensesServer();
void slackService.startSocketModeForAllProjects();
void mattermostService.startForAllProjects();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary? shouldn't it be a reactive route instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mattermost’s outgoing webhooks do not provide the full event flow we need, especially DMs, mentions, threads, and reactions.

So we use its WebSocket API. Unlike an HTTP route, that connection must be restored after every backend restart, which is why startForAllProjects() is necessary. Slack does the same for projects using Socket Mode.

return result;
};

export const deleteFeedbackVote = async (messageId: string, vote: 'up' | 'down'): Promise<void> => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it handle elsewhere? Why do we need a specific function for this here but not elsewhere in the code?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this is mainly because we used reactions instead of buttons for thumbs up/down.
I'll try to put it back as buttons

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread apps/backend/tests/mattermost-feedback-query.test.ts Outdated
@ad4mou

ad4mou commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

So I kept 👍/👎 as native Mattermost reactions.
the fix is:
Mattermost sends 👍/👎 reactions to nao through the existing WebSocket. Because each Mattermost post includes its corresponding nao message ID, nao can save the vote directly in the existing feedback table.
This removes the need for a new chat_message column or migration, while keeping the Stop button unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] Mattermost connector / bot

2 participants