Skip to content

feat(notifications): add Mattermost integration for notifications#3751

Closed
hosseinmoghaddam wants to merge 1 commit intoDokploy:canaryfrom
hosseinmoghaddam:feat/add-mattermost-notification-provider
Closed

feat(notifications): add Mattermost integration for notifications#3751
hosseinmoghaddam wants to merge 1 commit intoDokploy:canaryfrom
hosseinmoghaddam:feat/add-mattermost-notification-provider

Conversation

@hosseinmoghaddam
Copy link
Copy Markdown

@hosseinmoghaddam hosseinmoghaddam commented Feb 19, 2026

  • Introduced support for Mattermost notifications, including the ability to create, update, and test connections for Mattermost notifications.
  • Updated the notification schema to include Mattermost as a notification type.
  • Added Mattermost icon and UI components for handling Mattermost notifications in the dashboard.
  • Implemented backend logic for creating and updating Mattermost notifications, along with necessary database schema changes.
  • Enhanced existing notification functionalities to support Mattermost notifications across various events (e.g., build success, failure, database backups).

What is this PR about?

Add Mattermost integration for notifications

Checklist

Before submitting this PR, please make sure that:

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file https://github.com/Dokploy/dokploy/blob/canary/CONTRIBUTING.md#pull-request
  • You have tested this PR in your local instance. If you have not tested it yet, please do so before submitting. This helps avoid wasting maintainers' time reviewing code that has not been verified by you.

Screenshots (if applicable)

image image

Greptile Summary

Adds Mattermost as a new notification provider with comprehensive integration across all notification types. Implementation follows existing patterns for other notification providers (Slack, Teams, Discord, etc.) and includes database schema, API endpoints, UI components, and notification handlers for all event types (build success/error, database backup, volume backup, Docker cleanup, Dokploy restart, server threshold).

  • Added mattermost table with webhookUrl and channel fields
  • Created CRUD operations (createMattermost, updateMattermost, testMattermostConnection)
  • Integrated Mattermost notifications across 8 different event handlers
  • Added UI components with form fields for webhook URL and optional channel override
  • Used attachment-based message formatting with color-coded alerts
  • Minor inconsistency in schema validation compared to similar providers

Confidence Score: 4/5

  • Safe to merge with minor style inconsistency
  • Implementation correctly follows established patterns from other notification providers. All database operations use transactions, error handling is consistent, and the integration is complete across all notification types. The only issue is a minor validation inconsistency that doesn't affect functionality.
  • No files require special attention - the validation inconsistency in packages/server/src/db/schema/notification.ts is a style issue rather than a functional problem

Last reviewed commit: 4c61819

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

- Introduced support for Mattermost notifications, including the ability to create, update, and test connections for Mattermost notifications.
- Updated the notification schema to include Mattermost as a notification type.
- Added Mattermost icon and UI components for handling Mattermost notifications in the dashboard.
- Implemented backend logic for creating and updating Mattermost notifications, along with necessary database schema changes.
- Enhanced existing notification functionalities to support Mattermost notifications across various events (e.g., build success, failure, database backups).
Copilot AI review requested due to automatic review settings February 19, 2026 07:45
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile


export const apiUpdateMattermost = apiCreateMattermost.partial().extend({
notificationId: z.string().min(1),
mattermostId: z.string(),
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.

inconsistent validation - teamsId uses .min(1) but mattermostId doesn't

Suggested change
mattermostId: z.string(),
mattermostId: z.string().min(1),

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds comprehensive Mattermost integration to the Dokploy notification system, enabling users to receive notifications about build events, backups, server alerts, and system events through Mattermost webhooks.

Changes:

  • Added Mattermost as a new notification type with database schema, backend services, and API endpoints
  • Integrated Mattermost notifications across all notification event types (builds, backups, server thresholds, system events)
  • Updated the dashboard UI to include Mattermost configuration forms and icon display

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
packages/server/src/db/schema/notification.ts Added mattermost table schema, notification type enum value, foreign key relationship, and Zod validation schemas for create/update/test operations
packages/server/src/services/notification.ts Implemented createMattermostNotification and updateMattermostNotification service functions with transaction handling
packages/server/src/utils/notifications/utils.ts Added sendMattermostNotification utility function for sending webhook-based notifications with attachment formatting
packages/server/src/utils/notifications/volume-backup.ts Integrated Mattermost notifications for volume backup success/failure events
packages/server/src/utils/notifications/server-threshold.ts Added Mattermost notifications for server resource threshold alerts
packages/server/src/utils/notifications/dokploy-restart.ts Integrated Mattermost notifications for Dokploy server restart events
packages/server/src/utils/notifications/docker-cleanup.ts Added Mattermost notifications for Docker cleanup operations
packages/server/src/utils/notifications/database-backup.ts Integrated Mattermost notifications for database backup success/failure events
packages/server/src/utils/notifications/build-success.ts Added Mattermost notifications for successful build deployments with action buttons
packages/server/src/utils/notifications/build-error.ts Integrated Mattermost notifications for build failures with truncated error messages
apps/dokploy/server/api/routers/notification.ts Added three new tRPC endpoints: createMattermost, updateMattermost, and testMattermostConnection
apps/dokploy/components/icons/notification-icons.tsx Added MattermostIcon SVG component for UI display
apps/dokploy/components/dashboard/settings/notifications/show-notifications.tsx Updated notification list display to show Mattermost icon for Mattermost notification types
apps/dokploy/components/dashboard/settings/notifications/handle-notifications.tsx Added Mattermost form fields, validation schema, mutation handlers, and test connection logic

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +300 to +302
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The channel field extraction and inclusion in the payload is redundant. The sendMattermostNotification function already handles the channel field from the connection object if it exists (line 160-162 in utils.ts). Passing channel separately in the message object and then spreading the connection will result in the channel being included twice in the payload, which is unnecessary.

Suggested change
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
await sendMattermostNotification(mattermost, {

Copilot uses AI. Check for mistakes.
Comment on lines +272 to +274
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The channel field extraction and inclusion in the payload is redundant. The sendMattermostNotification function already handles the channel field from the connection object if it exists (line 160-162 in utils.ts). Passing channel separately in the message object and then spreading the connection will result in the channel being included twice in the payload, which is unnecessary.

Suggested change
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
await sendMattermostNotification(mattermost, {

Copilot uses AI. Check for mistakes.
Comment on lines +283 to +285
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The channel field extraction and inclusion in the payload is redundant. The sendMattermostNotification function already handles the channel field from the connection object if it exists (line 160-162 in utils.ts). Passing channel separately in the message object and then spreading the connection will result in the channel being included twice in the payload, which is unnecessary.

Suggested change
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
await sendMattermostNotification(mattermost, {

Copilot uses AI. Check for mistakes.
Comment on lines +425 to +427
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The channel field extraction and inclusion in the payload is redundant. The sendMattermostNotification function already handles the channel field from the connection object if it exists (line 160-162 in utils.ts). Passing channel separately in the message object and then spreading the connection will result in the channel being included twice in the payload, which is unnecessary.

Suggested change
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
await sendMattermostNotification(mattermost, {

Copilot uses AI. Check for mistakes.
Comment on lines +458 to +466
],
actions: [
{
type: "button",
name: "build_details",
text: "View Build Details",
integration: {
url: buildLink,
},
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The action button structure may not work correctly with Mattermost's incoming webhooks. According to Mattermost's documentation, the actions field with 'integration' property is used for interactive message buttons that require a Mattermost app with proper OAuth configuration. For simple incoming webhooks, either remove the actions array or use a simpler approach by including the link in the message text or pretext. The current implementation may fail silently or be ignored by Mattermost.

Suggested change
],
actions: [
{
type: "button",
name: "build_details",
text: "View Build Details",
integration: {
url: buildLink,
},
{
title: "Build Details",
value: buildLink,
short: false,

Copilot uses AI. Check for mistakes.
Comment on lines +415 to +417
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The channel field extraction and inclusion in the payload is redundant. The sendMattermostNotification function already handles the channel field from the connection object if it exists (line 160-162 in utils.ts). Passing channel separately in the message object and then spreading the connection will result in the channel being included twice in the payload, which is unnecessary.

Suggested change
const { channel } = mattermost;
await sendMattermostNotification(mattermost, {
channel: channel,
await sendMattermostNotification(mattermost, {

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +39
<svg
viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"
className={cn("size-8", className)}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The SVG element has inconsistent formatting with extra whitespace. The opening tag spans two lines (37-38) with improper indentation. This should be reformatted to follow standard JSX/TSX formatting conventions for better readability and consistency with the rest of the codebase.

Suggested change
<svg
viewBox="0 0 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"
className={cn("size-8", className)}
<svg
viewBox="0 0 256 256"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid"
className={cn("size-8", className)}

Copilot uses AI. Check for mistakes.
</div>
)}
{notification.notificationType === "mattermost" && (
<div className="flex items-center justify-center rounded-lg">
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

There are two consecutive spaces in the className attribute. This should be a single space for consistency and to avoid potential styling issues.

Copilot uses AI. Check for mistakes.
Comment on lines +1117 to +1165
export const createMattermostNotification = async (
input: typeof apiCreateMattermost._type,
organizationId: string,
) => {
await db.transaction(async (tx) => {
const newMattermost = await tx
.insert(mattermost)
.values({
webhookUrl: input.webhookUrl,
channel: input.channel,
})
.returning()
.then((value) => value[0]);

if (!newMattermost) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error input: Inserting mattermost",
});
}

const newDestination = await tx
.insert(notifications)
.values({
mattermostId: newMattermost.mattermostId,
name: input.name,
appDeploy: input.appDeploy,
appBuildError: input.appBuildError,
databaseBackup: input.databaseBackup,
volumeBackup: input.volumeBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "mattermost",
organizationId: organizationId,
serverThreshold: input.serverThreshold,
})
.returning()
.then((value) => value[0]);

if (!newDestination) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error input: Inserting notification",
});
}

return newDestination;
});
};
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The createMattermostNotification function doesn't return the result from the transaction. The transaction's return value is not being returned from the outer function, which will cause the function to return undefined. Add a return statement before db.transaction to match the pattern used by other notification creation functions.

Copilot uses AI. Check for mistakes.
Comment on lines +1167 to +1207
export const updateMattermostNotification = async (
input: typeof apiUpdateMattermost._type,
) => {
await db.transaction(async (tx) => {
const newDestination = await tx
.update(notifications)
.set({
name: input.name,
appDeploy: input.appDeploy,
appBuildError: input.appBuildError,
databaseBackup: input.databaseBackup,
volumeBackup: input.volumeBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
organizationId: input.organizationId,
serverThreshold: input.serverThreshold,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
.then((value) => value[0]);

if (!newDestination) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error Updating notification",
});
}

await tx
.update(mattermost)
.set({
webhookUrl: input.webhookUrl,
channel: input.channel,
})
.where(eq(mattermost.mattermostId, input.mattermostId))
.returning()
.then((value) => value[0]);

return newDestination;
});
};
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The updateMattermostNotification function doesn't return the result from the transaction. The transaction's return value is not being returned from the outer function, which will cause the function to return undefined. Add a return statement before db.transaction to match the pattern used by other notification update functions.

Copilot uses AI. Check for mistakes.
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.

2 participants