# 機能設計書 98-外部イシュートラッカー連携

## 概要

本ドキュメントは、GitLabにおける外部イシュートラッカー連携機能の設計仕様を記載する。本機能は、GitLabのイシュー管理機能の代わりに外部のイシュートラッカー（Jira以外）を使用するための統合機能を提供する。

### 本機能の処理概要

外部イシュートラッカー連携機能は、Redmine、Bugzilla、YouTrack、カスタムイシュートラッカーなどの外部イシュー管理システムとGitLabプロジェクトを連携させる。コミットメッセージ内のイシュー参照を自動的にリンク化し、外部トラッカーへのナビゲーションを容易にする。

**業務上の目的・背景**：多くの組織では既存のイシュー管理システムを使用しており、GitLabのイシュー機能と並行運用または完全に外部システムで管理したいニーズがある。本機能により既存の業務フローを維持しながらGitLabを導入できる。

**機能の利用シーン**：本機能は以下のシーンで利用される。
- RedmineでイシューをトラッキングしながらGitLabでコード管理
- BugzillaでバグをトラッキングしながらGitLabでソースコード管理
- YouTrackでプロジェクト管理しながらGitLabでCI/CD運用
- 独自のイシュートラッカーシステムとの統合

**主要な処理内容**：
1. 外部トラッカーのURL設定（プロジェクトURL、イシューURL、新規イシューURL）
2. コミットメッセージ内のイシュー参照パターンの認識
3. イシュー参照のリンク化
4. 外部トラッカーへの接続確認

**関連システム・外部連携**：Redmine、Bugzilla、JetBrains YouTrack、カスタムイシュートラッカー

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 142 | インテグレーション設定 | 主機能 | 外部イシュートラッカーの設定 |

## 機能種別

インテグレーション / イシュートラッカー

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| project_url | String | Yes | プロジェクトURL | パブリックURL、2048文字以内 |
| issues_url | String | Yes | イシューURL（:idプレースホルダー含む） | パブリックURL、2048文字以内 |
| new_issue_url | String | Conditional | 新規イシューURL | パブリックURL、2048文字以内（YouTrack以外で必須） |

### 入力データソース

- 画面入力（プロジェクト設定 > インテグレーション > 各トラッカー）
- REST API

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| イシューリンク | HTML | イシュー参照のリンク化されたHTML |
| 接続確認結果 | Boolean | 外部トラッカーへの接続成功可否 |

### 出力先

- GitLab画面（コミット一覧、MR、イシュー参照箇所）
- ログ（接続確認結果）

## 処理フロー

### 処理シーケンス

```
1. 設定保存
   └─ project_url, issues_url, new_issue_urlを保存

2. イシュー参照検出
   └─ コミットメッセージ、MRタイトル/説明からイシューキーを検出

3. リンク生成
   └─ issues_urlの:idを実際のイシュー番号に置換

4. 表示
   └─ リンク化されたイシュー参照を表示

5. 接続テスト（オプション）
   └─ project_urlへのHEADリクエストで接続確認
```

### フローチャート

```mermaid
flowchart TD
    A[外部イシュートラッカー設定] --> B{バリデーション}
    B -->|失敗| C[エラー表示]
    B -->|成功| D[設定保存]
    D --> E[有効化]
    E --> F[コミット/MR表示時]
    F --> G{イシュー参照パターン検出?}
    G -->|No| H[通常表示]
    G -->|Yes| I[リンク生成]
    I --> J[外部トラッカーへのリンク表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-98-01 | 排他制御 | 1プロジェクトに1つの外部イシュートラッカーのみ有効可 | 有効化時 |
| BR-98-02 | イシューURL形式 | :idプレースホルダーが必須 | issues_url設定時 |
| BR-98-03 | パブリックURL制限 | ローカルアドレスは拒否 | URL設定時 |
| BR-98-04 | 参照パターン | PROJECT-123形式（大文字英字-数字） | イシュー検索時 |
| BR-98-05 | YouTrack例外 | new_issue_urlは不要 | YouTrack使用時 |
| BR-98-06 | プッシュイベントのみ | supported_eventsはpushのみ | イベント処理時 |

### サポートされるイシュートラッカー

| トラッカー | to_param | 備考 |
|-----------|----------|------|
| Redmine | redmine | 標準的なイシュートラッカー |
| Bugzilla | bugzilla | Mozillaのバグトラッキング |
| JetBrains YouTrack | youtrack | new_issue_url不要、カスタム参照パターン |
| カスタム | custom_issue_tracker | 任意のイシュートラッカー |

### イシュー参照パターン

| トラッカー | パターン | 例 |
|-----------|----------|-----|
| Redmine/Bugzilla/Custom | /(\b[A-Z][A-Z0-9_]*-)(\d+)/ | ABC-123, PROJECT_1-45 |
| YouTrack | /\b[A-Za-z][A-Za-z0-9_]*-\d+\b/ | YT-1, gl-030, PRJ-123 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定保存 | integrations | INSERT/UPDATE | インテグレーション設定の保存 |
| データ保存 | issue_tracker_data | INSERT/UPDATE | URL等のデータ保存 |

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

#### integrations

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

#### issue_tracker_data

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | encrypted_project_url, encrypted_issues_url, encrypted_new_issue_url | 暗号化されたURL | integration_idが外部キー |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 必須フィールド未入力 | フォームを確認 |
| - | URL形式エラー | 無効なURL形式 | 正しいURL形式で入力 |
| - | 排他エラー | 他の外部イシュートラッカーが有効 | 既存トラッカーを無効化 |
| - | 接続エラー | 外部トラッカーに接続できない | URLを確認 |

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

- **URL暗号化**：issue_tracker_dataテーブルでURL情報を暗号化保存
- **パブリックURL検証**：ローカルアドレス（127.0.0.1、localhost等）を拒否
- **長さ制限**：URLは2048文字以内に制限
- **XSS対策**：イシュー参照のリンク生成時にエスケープ処理

## 備考

- Jira連携は別機能（No.96）として提供され、より高度な双方向連携をサポート
- 外部イシュートラッカー有効時、GitLab内蔵のイシュー機能は引き続き使用可能
- issues_urlの:idプレースホルダーは実際のイシュー番号に置換される
- YouTrackは小文字を含むイシューキーをサポート

---

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

### 推奨読解順序

#### Step 1: 基底クラス（IssueTracker）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | issue_tracker.rb | `app/models/concerns/integrations/base/issue_tracker.rb` | イシュートラッカーの共通処理 |

**主要処理フロー**:
- **8-9行目**: REFERENCE_PATTERN定義（イシュー参照パターン）
- **12行目**: one_issue_trackerバリデーション（排他制御）
- **14行目**: category = 'issue_tracker'
- **21-23行目**: supported_events = ['push']
- **30-34行目**: base_reference_pattern（参照パターン取得）
- **74-77行目**: issue_url - イシューURLの生成（:id置換）
- **102-125行目**: execute - 接続テスト実行

#### Step 2: 共通フィールド定義

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

**主要処理フロー**:
- **8行目**: field_storage = :data_fields
- **10-14行目**: project_urlフィールド定義
- **16-26行目**: issues_urlフィールド定義（:idプレースホルダー説明）
- **28-32行目**: new_issue_urlフィールド定義

#### Step 3: 各イシュートラッカー実装

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | base/redmine.rb | `app/models/concerns/integrations/base/redmine.rb` | Redmine連携 |

**主要処理フロー**:
- **8-9行目**: IssueTracker、HasIssueTrackerFieldsをinclude
- **33行目**: project_url, issues_url, new_issue_url必須バリデーション

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-2 | base/bugzilla.rb | `app/models/concerns/integrations/base/bugzilla.rb` | Bugzilla連携 |

**主要処理フロー**:
- **27-29行目**: attribution_notice（ロゴ商標表記）
- **37行目**: 3つのURL必須バリデーション

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-3 | base/youtrack.rb | `app/models/concerns/integrations/base/youtrack.rb` | YouTrack連携 |

**主要処理フロー**:
- **12行目**: FIELDS = ['project_url', 'issues_url']（new_issue_url不要）
- **34-36行目**: fieldsメソッドオーバーライド
- **45行目**: project_url, issues_urlのみ必須
- **48-53行目**: 独自のreference_pattern（小文字許可）

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-4 | base/custom_issue_tracker.rb | `app/models/concerns/integrations/base/custom_issue_tracker.rb` | カスタムトラッカー |

**主要処理フロー**:
- **12-13行目**: title = 'Custom issue tracker'
- **33行目**: 3つのURL必須バリデーション

#### Step 4: データモデル

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | issue_tracker_data.rb | `app/models/integrations/issue_tracker_data.rb` | データ保存 |

**主要処理フロー**:
- **9-11行目**: attr_encrypted（URL暗号化）
- **15-17行目**: 長さ制限バリデーション（2048文字）

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

```
Project#external_issue_tracker
    |
    +-- Integrations::Redmine / Bugzilla / Youtrack / CustomIssueTracker
            |
            +-- Base::IssueTracker (concern)
                    |
                    +-- issue_url(iid) -- :id置換
                    +-- reference_pattern -- パターン取得
                    +-- execute(data) -- 接続テスト

コミット/MR表示時:
    |
    +-- Banzai::Filter::ExternalIssueReferenceFilter
            |
            +-- project.external_issue_tracker
            +-- reference_pattern -- イシューキー検出
            +-- issue_url(iid) -- リンク生成
```

### データフロー図

```
[設定時]
管理者
    ↓
project_url, issues_url, new_issue_url 入力
    ↓
バリデーション（パブリックURL、長さ制限）
    ↓
one_issue_tracker（排他チェック）
    ↓
issue_tracker_data に暗号化保存

[表示時]
コミットメッセージ / MRタイトル
    ↓
Banzai パイプライン
    ↓
ExternalIssueReferenceFilter
    ↓
reference_pattern でイシューキー検出
    ↓
issue_url(iid) でリンクURL生成
    ↓
リンク化されたHTML出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| issue_tracker.rb | `app/models/concerns/integrations/base/issue_tracker.rb` | ソース | イシュートラッカー基底 |
| has_issue_tracker_fields.rb | `app/models/concerns/integrations/has_issue_tracker_fields.rb` | ソース | 共通フィールド定義 |
| redmine.rb | `app/models/concerns/integrations/base/redmine.rb` | ソース | Redmine連携 |
| bugzilla.rb | `app/models/concerns/integrations/base/bugzilla.rb` | ソース | Bugzilla連携 |
| youtrack.rb | `app/models/concerns/integrations/base/youtrack.rb` | ソース | YouTrack連携 |
| custom_issue_tracker.rb | `app/models/concerns/integrations/base/custom_issue_tracker.rb` | ソース | カスタムトラッカー |
| issue_tracker_data.rb | `app/models/integrations/issue_tracker_data.rb` | ソース | データモデル |
| redmine.rb | `app/models/integrations/redmine.rb` | ソース | Redmineモデル |
| bugzilla.rb | `app/models/integrations/bugzilla.rb` | ソース | Bugzillaモデル |
| youtrack.rb | `app/models/integrations/youtrack.rb` | ソース | YouTrackモデル |
| custom_issue_tracker.rb | `app/models/integrations/custom_issue_tracker.rb` | ソース | カスタムトラッカーモデル |
