# 画面設計書 332-OAuthアプリケーション編集

## 概要

本ドキュメントは、GitLabにおけるOAuthアプリケーション編集画面の設計仕様を定義する。

### 本画面の処理概要

OAuthアプリケーション編集画面は、ユーザーが作成したOAuth2.0アプリケーションの設定を変更するための画面である。

**業務上の目的・背景**：OAuthアプリケーションの設定は、外部サービスとの連携において重要な役割を果たす。アプリケーション名の変更、コールバックURLの追加・変更、スコープの調整など、運用中に発生する様々な変更ニーズに対応するため、本編集画面が必要である。特にコールバックURLの変更は、アプリケーションのデプロイ先変更時やセキュリティ要件の変更時に頻繁に発生する。

**画面へのアクセス方法**：
1. GitLabにログイン後、プロフィールアイコンをクリック
2. 「User Settings」から「Applications」を選択
3. アプリケーション一覧から対象アプリケーション名をクリックして詳細画面へ
4. 「Edit」ボタンをクリック
5. または、直接URL `/oauth/applications/:id/edit` にアクセス

**主要な操作・処理内容**：
1. アプリケーション名の変更
2. コールバックURL（Redirect URI）の変更（複数URI対応）
3. 機密性（Confidential）設定の変更
4. 許可スコープの変更
5. 変更内容の保存
6. 変更のキャンセル

**画面遷移**：
- 遷移元：OAuthアプリケーション詳細画面（No.331）
- 遷移先：OAuthアプリケーション詳細画面（No.331）、OAuthアプリケーション一覧画面（No.330）

**権限による表示制御**：
- ログインユーザーのみアクセス可能
- 自分が所有するアプリケーションのみ編集可能
- 管理者は全アプリケーションを編集可能（Admin Area経由）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 88 | OAuth2プロバイダ | 主機能 | OAuthアプリケーション編集 |
| 81 | 個人アクセストークン | 補助機能 | トークンスコープの設定 |

## 画面種別

編集

## URL/ルーティング

| メソッド | パス | アクション |
|---------|------|-----------|
| GET | `/oauth/applications/:id/edit` | `oauth/applications#edit` |
| PATCH/PUT | `/oauth/applications/:id` | `oauth/applications#update` |

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 必須 | 最大長 | 説明 |
|--------|----------|---------|------|--------|------|
| Name | 入力 | String | Yes | 255 | アプリケーション名 |
| Redirect URI | 入力 | Text | Yes | - | コールバックURL（複数行対応） |
| Confidential | 入力 | Boolean | No | - | 機密性設定チェックボックス |
| Scopes | 入力 | Array | No | - | 許可スコープ選択 |

## 表示項目

| 項目名 | データソース | 表示形式 | 備考 |
|--------|-------------|---------|------|
| Name | @application.name | テキストフィールド | 編集可能 |
| Redirect URI | @application.redirect_uri | テキストエリア | 複数行入力可能 |
| Confidential | @application.confidential | チェックボックス | ヘルプテキスト付き |
| Scopes | @scopes | チェックボックスリスト | 選択可能なスコープ一覧 |

## イベント仕様

### 1-保存ボタン

**トリガー**: 「Save application」ボタンをクリック

**処理内容**:
1. フォームデータをPATCH `/oauth/applications/:id` に送信
2. バリデーション実行
3. 成功時：詳細画面へリダイレクト
4. 失敗時：エラーメッセージ表示、フォーム再表示

**バリデーション**:
- Name: 必須、空白不可
- Redirect URI: 必須、有効なURI形式
- Redirect URI: `data://`, `vbscript://`, `javascript://` スキームは禁止

---

### 2-キャンセル（ページ離脱）

**トリガー**: ブラウザの戻るボタンまたはナビゲーション

**処理内容**:
1. 変更内容が破棄される
2. 遷移元画面に戻る

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | oauth_applications | SELECT | アプリケーション情報の取得 |
| 保存ボタン | oauth_applications | UPDATE | アプリケーション情報の更新 |

### テーブル別更新項目詳細

#### oauth_applications

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | name, redirect_uri, confidential, scopes | WHERE id = :id AND owner_id = :current_user_id | 編集画面表示用 |
| UPDATE | name | params[:doorkeeper_application][:name] | ユーザー入力値 |
| UPDATE | redirect_uri | params[:doorkeeper_application][:redirect_uri] | ユーザー入力値（複数行） |
| UPDATE | confidential | params[:doorkeeper_application][:confidential] | Boolean |
| UPDATE | scopes | params[:doorkeeper_application][:scopes] | 配列形式 |
| UPDATE | updated_at | Time.current | 自動更新 |

## メッセージ仕様

| 種別 | メッセージID | メッセージ内容 | 表示条件 |
|------|-------------|---------------|---------|
| 成功 | flash.applications.update.notice | Application was successfully updated. | 更新成功時 |
| エラー | activerecord.errors.models.doorkeeper/application.attributes.name.blank | Name can't be blank | 名前未入力時 |
| エラー | activerecord.errors.models.doorkeeper/application.attributes.redirect_uri.blank | Redirect URI can't be blank | URI未入力時 |
| エラー | activerecord.errors.models.doorkeeper/application.attributes.redirect_uri.invalid_uri | Redirect URI is invalid | 無効なURI形式 |
| エラー | activerecord.errors.models.doorkeeper/application.attributes.redirect_uri.forbidden_uri | Redirect URI uses a forbidden scheme | 禁止スキーム使用時 |
| ヘルプ | confidential_help | Enable only for confidential applications... | Confidentialチェックボックス下部 |
| ヘルプ | redirect_uri_help | Use one line per URI | Redirect URIフィールド下部 |

## 例外処理

| 例外状況 | 処理内容 | 表示/遷移先 |
|---------|---------|------------|
| アプリケーションが見つからない | ActiveRecord::RecordNotFound | 404エラーページ |
| 権限不足 | 所有者以外のアクセス | 404エラーページ |
| バリデーションエラー | エラー一覧表示 | 編集フォーム再表示 |
| OAuthアプリケーション機能が無効 | リダイレクト | プロフィール画面 |

## 備考

- Redirect URIは1行に1つのURIを記述（複数対応）
- Confidentialをオフにすると、シークレットを安全に保管できないクライアント向けになる
- スコープの変更は既存のアクセストークンには影響しない（新規トークン発行時から有効）
- 編集時にシークレットは変更されない（別途renewが必要）

---

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

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

### 推奨読解順序

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

OAuthアプリケーションのデータモデルとバリデーションを理解。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | oauth_application.rb | `app/models/authn/oauth_application.rb` | モデル定義 |
| 1-2 | doorkeeper.rb | `config/initializers/doorkeeper.rb` | バリデーション設定（forbid_redirect_uri等） |

**読解のコツ**: Doorkeeperの設定で`forbid_redirect_uri`がコールバックとして定義されており、危険なスキームをブロックしている点に注目。

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

コントローラのedit/updateアクションを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | applications_controller.rb | `app/controllers/oauth/applications_controller.rb` | edit/updateアクション |

**主要処理フロー**:
1. **行17**: `load_scopes` - 利用可能スコープの読み込み（edit, update時）
2. **行76-78**: `set_application` - アプリケーション取得（Doorkeeper親クラスのbefore_action）
3. **行84-89**: `application_params` - Strong Parameters、owner/organizationの設定

#### Step 3: ビューテンプレートを理解する

編集フォームの構造を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit.html.haml | `app/views/doorkeeper/applications/edit.html.haml` | メインビュー |
| 3-2 | _form.html.haml | `app/views/shared/doorkeeper/applications/_form.html.haml` | フォームpartial |

**主要処理フロー**:
- **edit.html.haml 行4**: 共有フォームpartialのレンダリング
- **_form.html.haml 行3**: `gitlab_ui_form_for` によるフォーム生成
- **_form.html.haml 行6-8**: Name入力フィールド
- **_form.html.haml 行10-15**: Redirect URI入力（textarea）
- **_form.html.haml 行17-19**: Confidentialチェックボックス
- **_form.html.haml 行21-23**: スコープ選択

#### Step 4: スコープフォームを理解する

スコープ選択UIの実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | _scopes_form.html.haml | `app/views/shared/tokens/_scopes_form.html.haml` | スコープ選択フォーム |

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

```
Oauth::ApplicationsController#edit
    │
    ├─ load_scopes (before_action)
    │      └─ Gitlab::Auth.all_available_scopes
    │
    ├─ set_application (Doorkeeper before_action)
    │      └─ current_user.oauth_applications.find(params[:id])
    │
    └─ render 'edit.html.haml'
           └─ render 'shared/doorkeeper/applications/form'
                  ├─ form_errors(@application)
                  └─ render 'shared/tokens/scopes_form'

Oauth::ApplicationsController#update
    │
    ├─ set_application (before_action)
    │
    ├─ @application.update(application_params)
    │      └─ Strong Parameters filtering
    │
    └─ redirect_to (success) or render :edit (failure)
```

### データフロー図

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

フォームデータ ───▶ ApplicationsController#update
    │                      │
    │                      ├─ application_params (Strong Parameters)
    │                      │      └─ :name, :redirect_uri, :confidential, :scopes
    │                      │
    │                      ├─ @application.update
    │                      │      └─ ActiveRecord バリデーション
    │                      │
    │                      └─ 成功 ───▶ redirect_to show
    │                         失敗 ───▶ render :edit (errors表示)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| applications_controller.rb | `app/controllers/oauth/applications_controller.rb` | コントローラ | リクエスト処理 |
| oauth_application.rb | `app/models/authn/oauth_application.rb` | モデル | データモデル |
| edit.html.haml | `app/views/doorkeeper/applications/edit.html.haml` | テンプレート | メインビュー |
| _form.html.haml | `app/views/shared/doorkeeper/applications/_form.html.haml` | テンプレート | フォームpartial |
| _scopes_form.html.haml | `app/views/shared/tokens/_scopes_form.html.haml` | テンプレート | スコープ選択 |
| doorkeeper.rb | `config/initializers/doorkeeper.rb` | 設定 | Doorkeeper設定・バリデーション |
