# 機能設計書 95-Slack連携

## 概要

本ドキュメントは、GitLabにおけるSlack連携機能の設計仕様を記載する。本機能は、GitLabで発生した各種イベント（プッシュ、マージリクエスト、イシュー等）をSlackワークスペースに通知する連携機能を提供する。Slack通知（Incoming Webhook方式）とGitLab for Slack app（OAuth方式）の2種類の連携方式がある。

### 本機能の処理概要

Slack連携機能は、GitLabのプロジェクト/グループイベントをSlackチャンネルにリアルタイム通知する。開発チームの作業進捗共有、コードレビュー依頼の通知、デプロイ完了の報告など、チームコミュニケーションを効率化する。

**業務上の目的・背景**：分散型の開発チームでは、GitLabでの活動をSlackでリアルタイムに共有することでコラボレーションを促進できる。コードプッシュ、MR作成、パイプライン結果などの重要なイベントを適切なチャンネルに通知することで、チームメンバーが素早く対応できる。

**機能の利用シーン**：本機能は以下のシーンで利用される。
- コードプッシュ時の開発チャンネルへの通知
- マージリクエスト作成時のレビュアーへの通知
- パイプライン失敗時のアラート通知
- イシュー作成時のサポートチャンネルへの通知
- デプロイ完了時の運用チャンネルへの通知
- Wikiページ更新時のドキュメントチャンネルへの通知

**主要な処理内容**：
1. Slack連携の設定（Webhook URLまたはSlack App OAuth）
2. 通知対象イベントの選択と設定
3. 通知先チャンネルの設定（イベントごと）
4. イベント発生時のSlack APIへのメッセージ送信
5. ラベルフィルタによる通知制御
6. ブランチフィルタによる通知制御

**関連システム・外部連携**：Slack API、Slack Incoming Webhooks、Slack OAuth 2.0

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

## 関連画面

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

## 機能種別

インテグレーション / 外部サービス連携 / 通知

## 入力仕様

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| webhook | String | Yes | Slack Incoming Webhook URL | パブリックURL、https://hooks.slack.com/services/... 形式 |
| username | String | No | 通知時のユーザー名 | - |
| channel | String | No | デフォルト通知先チャンネル | - |
| push_events | Boolean | No | プッシュイベントを通知 | - |
| push_events_branch_filter | String | No | ブランチフィルタ | - |
| issues_events | Boolean | No | イシューイベントを通知 | - |
| confidential_issues_events | Boolean | No | 機密イシューイベントを通知 | - |
| merge_requests_events | Boolean | No | MRイベントを通知 | - |
| tag_push_events | Boolean | No | タグプッシュイベントを通知 | - |
| note_events | Boolean | No | コメントイベントを通知 | - |
| confidential_note_events | Boolean | No | 機密コメントイベントを通知 | - |
| pipeline_events | Boolean | No | パイプラインイベントを通知 | - |
| wiki_page_events | Boolean | No | Wikiイベントを通知 | - |
| deployment_events | Boolean | No | デプロイイベントを通知 | - |
| alert_events | Boolean | No | アラートイベントを通知 | Slack固有 |
| notify_only_broken_pipelines | Boolean | No | 失敗パイプラインのみ通知 | デフォルト: true |
| 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 |
| *_channel | String | No | イベントごとの通知先チャンネル | 10チャンネル上限 |

### 入力パラメータ（GitLab for Slack app）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| (OAuth認証) | - | Yes | Slackワークスペースとの認証連携 | Slack OAuth 2.0 |

### 入力データソース

- 画面入力（プロジェクト/グループ設定 > インテグレーション > Slack）
- Slack OAuth連携（GitLab for Slack app）
- イベントデータ（各種モデルからのトリガー）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pretext | String | メッセージ本文（プレーンテキスト） |
| attachments | Array | リッチフォーマットの添付データ |
| channel | String | 送信先チャンネル |
| username | String | 送信者名 |

### 出力先

- Slack API（chat.postMessage）
- Slack Incoming Webhook

## 処理フロー

### 処理シーケンス

```
1. イベント発生
   └─ プッシュ、MR作成、イシュー作成等のイベント発生

2. インテグレーション実行判定
   └─ Slack連携が有効か確認
   └─ 該当イベントが通知対象か確認
   └─ ブランチフィルタのチェック
   └─ ラベルフィルタのチェック

3. メッセージ構築
   └─ イベント種別に応じたMessageクラスを選択
   └─ pretext、attachmentsを構築

4. 通知先チャンネル決定
   └─ イベント固有チャンネル設定を確認
   └─ なければデフォルトチャンネルを使用

5. 送信処理
   └─ Slack通知: Slack::Messenger.pingでWebhookへPOST
   └─ GitLab for Slack app: Slack API chat.postMessageを呼び出し

6. ログ記録
   └─ 使用状況ログ（HLLカウンター）
   └─ エラー時のログ出力
```

### フローチャート

```mermaid
flowchart TD
    A[イベント発生] --> B{Slack連携有効?}
    B -->|No| C[終了]
    B -->|Yes| D{イベント対象?}
    D -->|No| C
    D -->|Yes| E{ブランチ対象?}
    E -->|No| C
    E -->|Yes| F{ラベル対象?}
    F -->|No| C
    F -->|Yes| G[メッセージ構築]
    G --> H[チャンネル決定]
    H --> I{送信方式}
    I -->|Webhook| J[Slack::Messenger.ping]
    I -->|App| K[Slack API call]
    J --> L{成功?}
    K --> L
    L -->|Yes| M[使用状況ログ]
    L -->|No| N[エラーログ]
    M --> C
    N --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-95-01 | チャンネル上限 | イベントごとに最大10チャンネルまで設定可能 | 全イベント |
| BR-95-02 | パイプライン通知 | notify_only_broken_pipelinesが有効な場合、成功パイプラインは通知しない | パイプラインイベント |
| BR-95-03 | ブランチ通知制御 | branches_to_be_notified設定に従いブランチをフィルタ | プッシュ/パイプライン |
| BR-95-04 | ラベル通知制御 | labels_to_be_notified設定に従いラベルをフィルタ | イシュー/MR/コメント |
| BR-95-05 | ラベルマッチ方式 | match_any: いずれかのラベル一致、match_all: すべてのラベル一致 | ラベルフィルタ時 |
| BR-95-06 | 更新イベント除外 | イシュー/MRの'update'アクションは通知しない | イシュー/MRイベント |
| BR-95-07 | 機密チャンネル継承 | confidential_issue_channelが未設定の場合issue_channelを使用 | 機密イシュー |
| BR-95-08 | Webhook必須 | Slack通知ではwebhook URLが必須 | Slack通知 |
| BR-95-09 | App再インストール | GitLab for Slack appは再インストールで通知有効化 | GitLab for Slack app |

### 対応イベント一覧

| イベント種別 | object_kind | 説明 |
|------------|-------------|------|
| プッシュ | push | コードプッシュ |
| タグプッシュ | tag_push | タグの追加・削除 |
| イシュー | issue | イシューの作成・クローズ |
| 機密イシュー | confidential_issue | 機密イシューの作成・クローズ |
| マージリクエスト | merge_request | MRの作成・マージ・クローズ |
| コメント | note | コメントの追加 |
| 機密コメント | confidential_note | 機密コメントの追加 |
| パイプライン | pipeline | パイプラインの完了 |
| Wikiページ | wiki_page | Wikiの更新 |
| デプロイ | deployment | デプロイの実行 |
| インシデント | incident | インシデントの発生 |
| アラート | alert | アラートの発生（Slack固有） |
| グループメンション | group_mention | グループへのメンション（グループレベルのみ） |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定保存 | integrations | INSERT/UPDATE | Slack連携設定の保存 |
| Slack App連携 | slack_integrations | INSERT | GitLab for Slack app連携情報の保存 |

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

#### integrations

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

#### slack_integrations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | integration_id, bot_access_token, bot_user_id | OAuth連携時 | GitLab for Slack app用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| channel_not_found | Slack API エラー | 指定チャンネルが存在しない | プライベートチャンネルへのアプリ追加 |
| invalid_auth | Slack API エラー | トークンが無効 | 再認証 |
| - | HTTP エラー | ネットワーク障害等 | リトライ |
| - | 検証エラー | webhook URL無効 | 正しいURLを入力 |

### リトライ仕様

HTTPエラー発生時はGitlab::ErrorTrackingでエラー追跡。明示的なリトライ機構はなし。

## トランザクション仕様

インテグレーション設定の保存はActiveRecordトランザクション内で実行。通知送信は非同期ではなく同期実行。

## パフォーマンス要件

- チャンネル数上限：10チャンネル/イベント
- Webhook URLバリデーション：パブリックURL検証

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

- **Webhook URL保護**：Webhook URLはpropertiesカラムに暗号化保存
- **トークン保護**：bot_access_tokenは暗号化保存
- **SSL検証**：Slack APIへの通信はHTTPS必須
- **チャンネル検証**：プライベートチャンネルはアプリ追加が必要

## 備考

- Slack通知とGitLab for Slack appは別々のインテグレーションとして管理される
- GitLab for Slack appはOAuth認証後に設定が編集可能になる
- Slack Messenger gemを使用してメッセージ送信

---

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

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Slackインテグレーションのモデル構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | slack.rb | `app/models/integrations/slack.rb` | Slack通知（Webhook方式）のインテグレーションクラス |
| 1-2 | gitlab_slack_application.rb | `app/models/integrations/gitlab_slack_application.rb` | GitLab for Slack appのインテグレーションクラス |

**読解のコツ**:
- `Integrations::Slack`はWebhook方式で、`SlackMattermostNotifier`を使用
- `Integrations::GitlabSlackApplication`はSlack API方式で、`Slack::API`を使用
- 両者とも`Base::SlackNotification`と`SlackMattermostFields`をinclude

#### Step 2: 共通機能を理解する

Slack/Mattermostで共通のフィールドと通知ロジック。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | slack_mattermost_fields.rb | `app/models/concerns/integrations/slack_mattermost_fields.rb` | 共通フィールド定義 |
| 2-2 | slack_mattermost_notifier.rb | `app/models/concerns/integrations/slack_mattermost_notifier.rb` | Webhook通知処理 |
| 2-3 | slack_notification.rb | `app/models/concerns/integrations/base/slack_notification.rb` | Slack固有の拡張（alert対応等） |

**主要処理フロー（slack_mattermost_fields.rb）**:
- **8-14行目**: webhook フィールド定義
- **21-23行目**: channel フィールド定義
- **25-29行目**: notify_only_broken_pipelines 設定
- **31-39行目**: branches_to_be_notified 設定
- **41-46行目**: labels_to_be_notified 設定

#### Step 3: ChatNotificationベースを理解する

チャット通知の基本機能。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | chat_notification.rb | `app/models/concerns/integrations/base/chat_notification.rb` | チャット通知の基本実装 |

**主要処理フロー**:
- **14-17行目**: `SUPPORTED_EVENTS` - サポートされるイベント一覧
- **113-143行目**: `execute` - メイン実行メソッド
- **184-186行目**: `channel_limit_per_event` - チャンネル上限（10）
- **265-284行目**: `get_message` - イベント種別に応じたメッセージクラス選択
- **339-344行目**: `channels_for_event` - イベントごとのチャンネル取得
- **352-365行目**: `validate_channel_limit` - チャンネル数上限バリデーション

#### Step 4: メッセージクラスを理解する

各イベント種別のメッセージフォーマット。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | push_message.rb | `app/models/integrations/chat_message/push_message.rb` | プッシュ通知メッセージ |
| 4-2 | merge_message.rb | `app/models/integrations/chat_message/merge_message.rb` | MR通知メッセージ |
| 4-3 | issue_message.rb | `app/models/integrations/chat_message/issue_message.rb` | イシュー通知メッセージ |

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

```
Project/Group#execute_integrations
    |
    +-- Integrations::Slack#execute
    |       |
    |       +-- Base::ChatNotification#execute
    |               |
    |               +-- should_execute?
    |               +-- notify_label?
    |               +-- get_message (Message選択)
    |               +-- channels_for_event
    |               +-- SlackMattermostNotifier#notify
    |                       |
    |                       +-- Slack::Messenger.ping
    |
    +-- Integrations::GitlabSlackApplication#execute
            |
            +-- Base::ChatNotification#execute
                    |
                    +-- GitlabSlackApplication#notify
                            |
                            +-- Slack::API.post('chat.postMessage')
```

### データフロー図

```
[入力]                      [処理]                           [出力]

イベントデータ      ---->   Integration#execute          ---->  Slack API
(push, MR等)                |
                            +-- ChatNotification#execute
                            |       |
                            |       +-- notify_label? (フィルタ)
                            |       +-- notify_for_ref? (フィルタ)
                            |       +-- get_message (メッセージ構築)
                            |
                            +-- notify
                                    |
                                    +-- SlackMattermostNotifier  ---> Incoming Webhook
                                    or
                                    +-- GitlabSlackApplication   ---> chat.postMessage API
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| slack.rb | `app/models/integrations/slack.rb` | ソース | Slack通知インテグレーション |
| gitlab_slack_application.rb | `app/models/integrations/gitlab_slack_application.rb` | ソース | GitLab for Slack appインテグレーション |
| slack_mattermost_fields.rb | `app/models/concerns/integrations/slack_mattermost_fields.rb` | ソース | 共通フィールド定義 |
| slack_mattermost_notifier.rb | `app/models/concerns/integrations/slack_mattermost_notifier.rb` | ソース | Webhook通知処理 |
| slack_notification.rb | `app/models/concerns/integrations/base/slack_notification.rb` | ソース | Slack固有拡張 |
| chat_notification.rb | `app/models/concerns/integrations/base/chat_notification.rb` | ソース | チャット通知基底 |
| push_message.rb | `app/models/integrations/chat_message/push_message.rb` | ソース | プッシュメッセージ |
| merge_message.rb | `app/models/integrations/chat_message/merge_message.rb` | ソース | MRメッセージ |
| issue_message.rb | `app/models/integrations/chat_message/issue_message.rb` | ソース | イシューメッセージ |
| slack_event_service.rb | `app/services/integrations/slack_event_service.rb` | ソース | Slackイベント処理サービス |
| slack_interaction_service.rb | `app/services/integrations/slack_interaction_service.rb` | ソース | Slackインタラクション処理 |
