# 機能設計書 59-フィーチャーフラグ

## 概要

本ドキュメントは、GitLabのフィーチャーフラグ（Feature Flags）管理機能について記述した機能設計書である。

### 本機能の処理概要

フィーチャーフラグ機能は、コードのデプロイとフィーチャーのリリースを分離し、特定のユーザーや環境に対して段階的に機能を公開するための仕組みを提供する。

**業務上の目的・背景**：新機能のリリースは常にリスクを伴う。フィーチャーフラグを使用することで、コードはデプロイ済みの状態で機能のON/OFFを制御でき、問題発生時には即座に機能を無効化できる。また、A/Bテストや段階的ロールアウトにより、限定的なユーザーで機能を検証してからフルリリースすることが可能となる。

**機能の利用シーン**：
- 新機能を特定のユーザーグループのみに公開する場合
- 段階的ロールアウトでリスクを低減する場合
- A/Bテストで機能の効果を検証する場合
- 本番環境で問題が発生した際に機能を即座に無効化する場合
- 環境ごとに異なるフラグ設定を適用する場合

**主要な処理内容**：
1. フィーチャーフラグの作成（名前、説明、ストラテジー）
2. フィーチャーフラグの編集（有効化/無効化、ストラテジー変更）
3. フィーチャーフラグの削除
4. フィーチャーフラグ一覧の表示
5. Unleashクライアントへの設定提供

**関連システム・外部連携**：
- Unleash SDKクライアント
- Webhook（フラグ変更通知）
- Issue連携

**権限による制御**：
- フラグ閲覧: `read_feature_flag`権限が必要
- フラグ作成: `create_feature_flag`権限が必要
- フラグ更新: `update_feature_flag`権限が必要
- フラグ削除: `destroy_feature_flag`権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 82 | フィーチャーフラグ一覧 | 主画面 | フラグ一覧の表示、有効化/無効化 |
| 83 | フィーチャーフラグ作成/編集 | 主画面 | フラグの作成・編集 |

## 機能種別

CRUD操作 / 設定管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | フラグ名 | 2-63文字、小文字/数字/`_`/`-`、先頭は文字 |
| description | String | No | フラグの説明 | 最大255文字 |
| active | Boolean | No | 有効/無効状態 | デフォルト: true |
| version | String | No | バージョン | new_version_flag のみ |
| strategies_attributes | Array | No | ストラテジー設定 | ネスト属性 |

### ストラテジータイプ

| ストラテジー名 | 説明 | 必須パラメータ |
|---------------|------|---------------|
| default | 全ユーザーに適用 | なし |
| userWithId | 特定ユーザーIDに適用 | userIds |
| gradualRolloutUserId | ユーザーIDベースの段階的ロールアウト | groupId, percentage |
| flexibleRollout | 柔軟なロールアウト | groupId, rollout, stickiness |
| gitlabUserList | ユーザーリストに基づく適用 | user_list_id |

### 入力データソース

- 画面入力（フィーチャーフラグ設定フォーム）
- APIリクエスト
- Unleash API

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | フィーチャーフラグID |
| iid | Integer | プロジェクト内連番 |
| name | String | フラグ名 |
| description | String | 説明 |
| active | Boolean | 有効/無効状態 |
| version | String | バージョン |
| strategies | Array | ストラテジー一覧 |
| created_at | DateTime | 作成日時 |
| updated_at | DateTime | 更新日時 |

### 出力先

- 画面表示（フィーチャーフラグ一覧、詳細）
- JSONレスポンス（API）
- Unleash API（SDKクライアント向け）

## 処理フロー

### 処理シーケンス

```
1. 認証・権限チェック
   └─ 操作に応じた権限確認

2. 操作種別の判定
   └─ 一覧/作成/更新/削除

3. サービス層実行
   └─ CreateService/UpdateService/DestroyService

4. Webhook実行（更新時）
   └─ active状態変更時にHookService実行

5. レスポンス生成
   └─ HTML/JSONレスポンス
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{操作種別}
    B -->|一覧| C[FeatureFlagsFinder]
    B -->|作成| D{create権限?}
    B -->|更新| E{update権限?}
    B -->|削除| F{destroy権限?}
    D -->|No| G[403 Access Denied]
    D -->|Yes| H[CreateService実行]
    E -->|No| G
    E -->|Yes| I[UpdateService実行]
    F -->|No| G
    F -->|Yes| J[DestroyService実行]
    C --> K[JSON/HTMLレスポンス]
    H --> L{成功?}
    I --> L
    J --> L
    L -->|Yes| M[Webhook実行]
    L -->|No| N[エラーレスポンス]
    M --> K
    K --> O[終了]
    N --> O
    G --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | フラグ名一意性 | プロジェクト内でフラグ名は一意 | 作成/更新時 |
| BR-59-02 | フラグ名形式 | 小文字/数字/`_`/`-`、先頭は文字、末尾は`_`/`-`不可 | 作成時 |
| BR-59-03 | IIDの自動採番 | プロジェクト内で連番を自動付与 | 作成時 |
| BR-59-04 | Webhook発火 | active状態変更時にWebhook実行 | 更新時 |
| BR-59-05 | ストラテジーパラメータ検証 | ストラテジーごとに必須パラメータが異なる | 作成/更新時 |
| BR-59-06 | percentage範囲 | 0-100の整数（文字列形式） | gradualRollout使用時 |
| BR-59-07 | stickiness設定 | default/userId/sessionId/randomのいずれか | flexibleRollout使用時 |

### 計算ロジック

- `iid`: プロジェクト内連番（has_internal_id）
- `reference`: `[feature_flag:{project}/#{iid}]`形式
- ポーリング間隔: 10秒（JSON応答時）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フラグ作成 | operations_feature_flags | INSERT | フラグレコード作成 |
| フラグ作成 | operations_strategies | INSERT | ストラテジー作成 |
| フラグ作成 | operations_scopes | INSERT | スコープ作成 |
| フラグ更新 | operations_feature_flags | UPDATE | フラグ情報更新 |
| フラグ更新 | operations_strategies | INSERT/UPDATE/DELETE | ストラテジー更新 |
| フラグ削除 | operations_feature_flags | DELETE | フラグ削除（カスケード） |

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

#### operations_feature_flags

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ユーザー入力値 | 2-63文字 |
| INSERT | description | ユーザー入力値 | 最大255文字 |
| INSERT | active | true/false | デフォルト: true |
| INSERT | version | 2 (new_version_flag) | - |
| INSERT | iid | 自動採番 | プロジェクト内連番 |
| UPDATE | active | true/false | 有効化/無効化 |

#### operations_strategies

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | ストラテジー名 | STRATEGIES.keysのいずれか |
| INSERT | parameters | JSON形式 | ストラテジー固有パラメータ |
| INSERT | feature_flag_id | 親フラグID | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Access Denied | 権限不足 | 適切な権限を取得 |
| 400 | Bad Request | バリデーションエラー | 入力値を修正 |
| 400 | Version Invalid | 無効なバージョン指定 | new_version_flagを使用 |
| 404 | Not Found | フラグ未検出 | 正しいIIDを確認 |

### リトライ仕様

- 作成/更新/削除失敗時は自動リトライなし

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

- フラグ作成/更新時はフラグとストラテジーを同一トランザクションで処理
- 更新成功後にWebhook実行（run_after_commit）

## パフォーマンス要件

- フラグ一覧取得: 1秒以内（30件/ページ）
- フラグ作成/更新: 1秒以内
- Unleash API応答: 500ms以内

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

- プロジェクト単位での権限チェック
- 操作ごとの細かい権限分離（read/create/update/destroy）
- 監査ログへの記録（作成/更新/削除）

## 備考

- version: new_version_flag（2）のみサポート
- reference_prefix: `[feature_flag:`
- ポーリング間隔: 10,000ms (10秒)
- プロジェクトごとのフラグ数制限あり（Limitable）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | feature_flag.rb | `app/models/operations/feature_flag.rb` | フィーチャーフラグの属性、関連を理解する |
| 1-2 | strategy.rb | `app/models/operations/feature_flags/strategy.rb` | ストラテジーの種類とパラメータ検証を理解する |

**読解のコツ**:
- **feature_flag.rb 17行目**: `has_internal_id :iid`でIID自動採番を確認
- **feature_flag.rb 19-20行目**: デフォルト値（active: true, version: new_version_flag）を確認
- **feature_flag.rb 28-36行目**: フラグ名のバリデーション（2-63文字、形式チェック）を確認
- **feature_flag.rb 49-51行目**: `enum :version`でバージョン値を確認
- **feature_flag.rb 62-68行目**: `for_unleash_client`でUnleash API用クエリを確認
- **strategy.rb 6-17行目**: 5種類のストラテジーと必須パラメータを確認
- **strategy.rb 19行目**: `STICKINESS_SETTINGS`で利用可能な値を確認
- **strategy.rb 87-98行目**: percentage/groupIdのバリデーションを確認

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | feature_flags_controller.rb | `app/controllers/projects/feature_flags_controller.rb` | 各アクションの処理フローを確認 |

**主要処理フロー**:
- **6-9行目**: before_actionで操作別の権限チェック
- **16-31行目**: indexアクションで一覧取得（30件/ページ、ポーリング10秒）
- **45-57行目**: createアクションでCreateService呼び出し
- **61-73行目**: updateアクションでUpdateService呼び出し
- **75-89行目**: destroyアクションでDestroyService呼び出し
- **97-114行目**: create_paramsでネスト属性（strategies_attributes）を許可

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/feature_flags/create_service.rb` | フラグ作成のビジネスロジック |
| 3-2 | update_service.rb | `app/services/feature_flags/update_service.rb` | フラグ更新とWebhook実行 |

**主要処理フロー**:
- **create_service.rb 5-20行目**: 権限チェック、バージョン検証、トランザクション内でsave
- **create_service.rb 44-46行目**: `can_create?`で権限チェック
- **update_service.rb 15-39行目**: 権限チェック、user_list検証、トランザクション内で更新
- **update_service.rb 43-51行目**: `execute_hooks_after_commit`でactive変更時にWebhook実行

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

```
Projects::FeatureFlagsController
    │
    ├─ #index
    │      ├─ FeatureFlagsFinder#execute
    │      └─ FeatureFlagSerializer#represent
    │
    ├─ #create
    │      └─ FeatureFlags::CreateService#execute
    │             └─ project.operations_feature_flags.new.save
    │
    ├─ #update
    │      └─ FeatureFlags::UpdateService#execute
    │             ├─ feature_flag.assign_attributes
    │             ├─ feature_flag.save
    │             └─ HookService#execute (after_commit)
    │
    └─ #destroy
           └─ FeatureFlags::DestroyService#execute
```

### データフロー図

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

フラグ設定
フォーム ───────▶ FeatureFlagsController ───────▶ フラグ一覧/詳細
                      │
                      ▼
              Operations::FeatureFlag
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
   operations_    operations_   operations_
   feature_flags  strategies     scopes

                      │
                      ▼
              Unleash API ────▶ SDK クライアント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| feature_flag.rb | `app/models/operations/feature_flag.rb` | モデル | フィーチャーフラグのデータモデル |
| strategy.rb | `app/models/operations/feature_flags/strategy.rb` | モデル | ストラテジーのデータモデル |
| scope.rb | `app/models/operations/feature_flags/scope.rb` | モデル | 環境スコープのデータモデル |
| user_list.rb | `app/models/operations/feature_flags/user_list.rb` | モデル | ユーザーリストのデータモデル |
| feature_flags_controller.rb | `app/controllers/projects/feature_flags_controller.rb` | コントローラー | フラグ操作のエンドポイント |
| create_service.rb | `app/services/feature_flags/create_service.rb` | サービス | フラグ作成ロジック |
| update_service.rb | `app/services/feature_flags/update_service.rb` | サービス | フラグ更新ロジック |
| destroy_service.rb | `app/services/feature_flags/destroy_service.rb` | サービス | フラグ削除ロジック |
| feature_flags_finder.rb | `app/finders/feature_flags_finder.rb` | Finder | フラグ検索ロジック |
| feature_flag_serializer.rb | `app/serializers/feature_flag_serializer.rb` | シリアライザー | JSON出力フォーマット |
| hook_service.rb | `app/services/feature_flags/hook_service.rb` | サービス | Webhook実行ロジック |
