# 機能設計書 97-Mattermost連携

## 概要

本ドキュメントは、GitLabにおけるMattermost連携機能の設計仕様を記載する。本機能は、GitLabのイベント通知をMattermostチャンネルに送信する通知機能と、Mattermostからスラッシュコマンドでgitlab操作を行う双方向連携を提供する。

### 本機能の処理概要

Mattermost連携機能は、2つの主要なインテグレーションで構成される：(1) Mattermost通知 - GitLabのイベント（プッシュ、イシュー、MR等）をMattermostチャンネルにWebhookで通知、(2) Mattermostスラッシュコマンド - MattermostからGitLabの操作を実行。

**業務上の目的・背景**：オープンソースのチャットツールMattermostを利用する組織において、GitLabとの連携によりチーム内の情報共有とコラボレーションを強化する。Slack連携と同等の機能を自前インフラで実現可能。

**機能の利用シーン**：本機能は以下のシーンで利用される。
- コミット/MRの通知をMattermostチャンネルに送信
- イシュー作成/更新をチームに即座に共有
- Mattermostからスラッシュコマンドでイシュー作成
- パイプライン失敗をリアルタイムで通知

**主要な処理内容**：
1. Incoming Webhook URLの設定
2. イベント発生時のメッセージ構築
3. Webhook経由でのメッセージ送信
4. スラッシュコマンドのトークン検証
5. コマンド実行と応答生成

**関連システム・外部連携**：Mattermost Server

**権限による制御**：プロジェクト/グループのMaintainer以上が設定可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 142 | インテグレーション設定 | 主機能 | Mattermost連携の設定 |

## 機能種別

インテグレーション / チャット通知

## 入力仕様

### 入力パラメータ（Mattermost通知）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| webhook | String | Yes | Mattermost Incoming Webhook URL | パブリックURL |
| username | String | No | 通知時の表示ユーザー名 | - |
| channel | String | No | デフォルト通知チャンネル | - |
| notify_only_broken_pipelines | Boolean | No | 失敗パイプラインのみ通知 | - |
| branches_to_be_notified | String | No | 通知対象ブランチ（all/default/protected/default_and_protected） | - |
| labels_to_be_notified | String | No | 通知対象ラベル（カンマ区切り） | - |
| labels_to_be_notified_behavior | String | No | ラベルマッチ方式（match_any/match_all） | - |
| push_channel | String | No | プッシュイベント専用チャンネル | - |
| issue_channel | String | No | イシューイベント専用チャンネル | - |
| merge_request_channel | String | No | MRイベント専用チャンネル | - |
| note_channel | String | No | コメントイベント専用チャンネル | - |
| pipeline_channel | String | No | パイプラインイベント専用チャンネル | - |
| wiki_page_channel | String | No | Wikiイベント専用チャンネル | - |

### 入力パラメータ（スラッシュコマンド）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| token | String | Yes | Mattermostスラッシュコマンドトークン | - |

### 入力データソース

- 画面入力（プロジェクト/グループ設定 > インテグレーション > Mattermost）
- Mattermost管理画面（Webhook URL、トークン取得）
- REST API

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 通知メッセージ | Object | 添付ファイル形式のメッセージ |
| コマンド応答 | Object | スラッシュコマンド実行結果 |

### 出力先

- Mattermost Webhook（通知）
- Mattermostチャンネル（コマンド応答）

## 処理フロー

### 処理シーケンス（通知）

```
1. イベント発生
   └─ push, issue, merge_request, note, pipeline, wiki_page, deployment, incident

2. ChatNotificationでイベント処理
   └─ execute(data)が呼ばれる

3. メッセージ構築
   └─ ChatMessage::*でイベントに応じたメッセージ作成

4. 通知先チャンネル決定
   └─ イベント専用チャンネル or デフォルトチャンネル

5. Webhook送信
   └─ SlackMattermostNotifierでSlack::Messenger使用

6. 使用状況ログ
   └─ HLLカウンター
```

### 処理シーケンス（スラッシュコマンド）

```
1. Mattermostからリクエスト受信
   └─ /gitlabコマンド実行

2. トークン検証
   └─ 設定されたトークンと照合

3. コマンド解析
   └─ help, issue create, deploy等

4. コマンド実行
   └─ SlashCommandsサービスで処理

5. 応答返却
   └─ JSON形式で結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[GitLabイベント発生] --> B{Mattermost連携有効?}
    B -->|No| C[終了]
    B -->|Yes| D[イベントフィルタ]
    D --> E{通知対象?}
    E -->|No| C
    E -->|Yes| F[ブランチフィルタ]
    F --> G{対象ブランチ?}
    G -->|No| C
    G -->|Yes| H[ラベルフィルタ]
    H --> I{対象ラベル?}
    I -->|No| C
    I -->|Yes| J[メッセージ構築]
    J --> K[チャンネル決定]
    K --> L[Webhook送信]
    L --> M{成功?}
    M -->|Yes| C
    M -->|No| N[エラーログ]
    N --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-97-01 | チャンネル上限 | イベントあたり最大10チャンネルまで指定可能 | チャンネル設定時 |
| BR-97-02 | ブランチフィルタ | デフォルトはdefaultブランチのみ通知 | パイプライン/プッシュイベント |
| BR-97-03 | 失敗パイプラインのみ | デフォルトで失敗パイプラインのみ通知 | notify_only_broken_pipelines有効時 |
| BR-97-04 | ラベルマッチ | match_anyはいずれかのラベル一致で通知 | ラベルフィルタ有効時 |
| BR-97-05 | updateイベント除外 | 更新イベントは通知対象外 | イベント判定時 |
| BR-97-06 | SSO認証 | スラッシュコマンドはGitLab SSOで認証 | MattermostがGitLab SSOを使用時 |

### サポートイベント

| イベント | 説明 |
|---------|------|
| push | コミットプッシュ |
| issue | イシュー作成/更新/クローズ |
| confidential_issue | 機密イシュー |
| merge_request | MR作成/更新/マージ |
| note | コメント |
| confidential_note | 機密コメント |
| tag_push | タグプッシュ |
| pipeline | パイプライン完了 |
| wiki_page | Wikiページ更新 |
| deployment | デプロイメント |
| incident | インシデント |

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定保存 | integrations | INSERT/UPDATE | Mattermost連携設定の保存 |

### テーブル別操作詳細

#### integrations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | type, active, project_id/group_id, properties | フォーム入力値 | type='Integrations::Mattermost' or 'Integrations::MattermostSlashCommands' |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 接続エラー | Mattermostに接続できない | Webhook URLを確認 |
| - | 認証エラー | トークン不一致 | トークンを再設定 |
| - | JSON解析エラー | Mattermost応答解析失敗 | Mattermostのバージョン確認 |
| - | SSOエラー | GitLab SSOセッション取得失敗 | MattermostのSSO設定確認 |

## セキュリティ考慮事項

- **トークン暗号化**：スラッシュコマンドトークンは暗号化保存
- **Webhook URL検証**：パブリックURLのみ許可（ローカルアドレス拒否）
- **SSO認証**：スラッシュコマンドはGitLab SSOで認証されたユーザーコンテキストで実行
- **排他制御**：Mattermostセッション取得に60秒のリースタイムアウト

## 備考

- Slack連携と共通のSlackMattermostNotifier/SlackMattermostFieldsを使用
- Slack::Messenger gemを使用してWebhook送信（Mattermostも同じプロトコル）
- Mattermost SSOにはGitLabをOAuthプロバイダとして設定が必要
- スラッシュコマンドはMattermost管理画面でのコマンド登録も必要

---

## コードリーディングガイド

### 推奨読解順序

#### Step 1: Mattermost通知インテグレーション

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mattermost.rb | `app/models/integrations/mattermost.rb` | Mattermost通知のメインクラス |

**主要処理フロー**:
- **4-8行目**: include構成（ChatNotification, SlackMattermostNotifier, SlackMattermostFields）
- **36-39行目**: configurable_channels?でイベント別チャンネル設定を有効化

#### Step 2: 共通モジュール

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | slack_mattermost_notifier.rb | `app/models/concerns/integrations/slack_mattermost_notifier.rb` | Webhook送信処理 |

**主要処理フロー**:
- **7-31行目**: notifyメソッド - Slack::Messengerを使用した通知送信
- **16-21行目**: notifier.ping呼び出し
- **23-30行目**: HTTPエラー時のログ出力

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-2 | slack_mattermost_fields.rb | `app/models/concerns/integrations/slack_mattermost_fields.rb` | 設定フィールド定義 |

**主要処理フロー**:
- **8-14行目**: webhook フィールド定義
- **25-29行目**: notify_only_broken_pipelines設定
- **31-39行目**: branches_to_be_notified設定
- **41-58行目**: ラベルフィルタ設定

#### Step 3: スラッシュコマンド

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | mattermost_slash_commands.rb | `app/models/integrations/mattermost_slash_commands.rb` | スラッシュコマンドのモデル |

**主要処理フロー**:
- **4-6行目**: Base::MattermostSlashCommandsをinclude

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-2 | base/mattermost_slash_commands.rb | `app/models/concerns/integrations/base/mattermost_slash_commands.rb` | 実装詳細 |

**主要処理フロー**:
- **8行目**: MATTERMOST_URL テンプレート
- **28-34行目**: tokenフィールド定義
- **44-52行目**: configure - Mattermostへのコマンド登録
- **54-58行目**: list_teams - チーム一覧取得
- **60-70行目**: redirect_url - リダイレクトURL生成

#### Step 4: Mattermost API クライアント

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | client.rb | `lib/mattermost/client.rb` | Mattermost API クライアント |

**主要処理フロー**:
- **13-15行目**: with_session - セッション管理
- **51-61行目**: json_response - レスポンス解析

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-2 | session.rb | `lib/mattermost/session.rb` | SSO セッション管理 |

**主要処理フロー**:
- **28行目**: LEASE_TIMEOUT = 60（排他制御タイムアウト）
- **41-54行目**: with_session - セッション作成・破棄のブロック実行
- **107-119行目**: create - OAuth経由でトークン取得
- **125-142行目**: oauth_uri - OAuthリダイレクト処理

### プログラム呼び出し階層図

```
Project#execute_integrations
    |
    +-- Integrations::Mattermost#execute
            |
            +-- Base::ChatNotification#execute
                    |
                    +-- SlackMattermostNotifier#notify
                            |
                            +-- Slack::Messenger#ping
                                    |
                                    +-- HTTPClient.post

MattermostSlashCommandsController
    |
    +-- Integrations::MattermostSlashCommands#trigger
            |
            +-- Base::SlashCommands#perform
                    |
                    +-- Gitlab::SlashCommands::*

Mattermost::Client#with_session
    |
    +-- Mattermost::Session#with_session
            |
            +-- Mattermost::Session#create (OAuth)
            +-- Mattermost::Session#destroy (logout)
```

### データフロー図

```
[Mattermost通知]
GitLabイベント
    ↓
execute(data) [ChatNotification]
    ↓
get_message(data) [メッセージ構築]
    ↓
channels_for_event [チャンネル決定]
    ↓
notify(message, opts) [SlackMattermostNotifier]
    ↓
Slack::Messenger#ping
    ↓
HTTPClient.post → Mattermost Webhook

[スラッシュコマンド]
Mattermost → /gitlab コマンド
    ↓
POST /projects/:id/integrations/mattermost_slash_commands/trigger
    ↓
token検証
    ↓
SlashCommands::Command.new(project, chat_user, params).execute
    ↓
JSON応答 → Mattermost
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mattermost.rb | `app/models/integrations/mattermost.rb` | ソース | Mattermost通知インテグレーション |
| mattermost_slash_commands.rb | `app/models/integrations/mattermost_slash_commands.rb` | ソース | スラッシュコマンドインテグレーション |
| slack_mattermost_notifier.rb | `app/models/concerns/integrations/slack_mattermost_notifier.rb` | ソース | Webhook送信共通モジュール |
| slack_mattermost_fields.rb | `app/models/concerns/integrations/slack_mattermost_fields.rb` | ソース | 設定フィールド共通モジュール |
| base/mattermost_slash_commands.rb | `app/models/concerns/integrations/base/mattermost_slash_commands.rb` | ソース | スラッシュコマンド実装 |
| base/chat_notification.rb | `app/models/concerns/integrations/base/chat_notification.rb` | ソース | チャット通知基底 |
| client.rb | `lib/mattermost/client.rb` | ソース | Mattermost APIクライアント |
| session.rb | `lib/mattermost/session.rb` | ソース | SSOセッション管理 |
| command.rb | `lib/mattermost/command.rb` | ソース | コマンド登録API |
| team.rb | `lib/mattermost/team.rb` | ソース | チーム取得API |
