# 機能設計書 83-Webhook編集

## 概要

本ドキュメントは、Fizzyアプリケーションにおける「Webhook編集」機能の設計仕様を定義する。既存のWebhook設定の名前と購読イベントを編集する機能である。

### 本機能の処理概要

Webhook編集機能は、作成済みのWebhook設定を変更するための機能である。Webhookの名前と購読するイベントを変更できる。ただし、ペイロードURLはセキュリティ上の理由から変更できない。

**業務上の目的・背景**：チーム管理者がWebhookの設定を運用状況に合わせて調整できるようにするための機能である。例えば、購読イベントの追加・削除や、より分かりやすい名前への変更が可能である。URLの変更が不可なのは、悪意のある変更によるデータ漏洩を防ぐためである。

**機能の利用シーン**：管理者がWebhookの通知対象イベントを変更したい場合や、Webhook名を分かりやすく修正したい場合に使用する。URLを変更したい場合は、既存のWebhookを削除して新規作成する必要がある。

**主要な処理内容**：
1. 指定されたWebhookの情報をデータベースから取得
2. 編集フォームの表示
3. 名前と購読イベントの更新（URLは変更不可）
4. 更新完了後、Webhook詳細画面へリダイレクト

**関連システム・外部連携**：なし

**権限による制御**：ボードの管理者（admin）権限を持つユーザーのみがWebhookを編集できる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 64 | Webhook詳細画面 | 参照画面 | 編集ボタンからこの機能を呼び出す |
| 65 | Webhook編集画面 | 主画面 | Webhook編集フォームを表示・送信 |

## 機能種別

CRUD操作（Update）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| board_id | UUID | Yes | ボードID | URLパラメータ |
| id | UUID | Yes | WebhookID | URLパラメータ |
| name | String | Yes | Webhookの名前 | 必須、空白不可 |
| subscribed_actions | Array | No | 購読するイベントアクションの配列 | PERMITTED_ACTIONSに含まれるもののみ |

### 入力データソース

URLパラメータ + 画面フォームからの入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | UUID | 更新されたWebhookの一意識別子 |
| name | String | 更新後のWebhook名 |
| subscribed_actions | Array | 更新後の購読イベント一覧 |

### 出力先

- データベース（webhooksテーブル）
- 画面遷移（Webhook詳細画面へリダイレクト）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ PUT /boards/:board_id/webhooks/:id
2. 認証・認可チェック
   └─ ログインユーザーかつボード管理者権限を確認
3. ボード取得
   └─ Current.userのボードからboard_idで検索
4. Webhook取得
   └─ @board.webhooks.find(params[:id])
5. パラメータ抽出
   └─ webhook_params.except(:url) でURLを除外
6. Webhook更新
   └─ @webhook.update!(webhook_params.except(:url))
7. リダイレクト
   └─ Webhook詳細画面へ遷移
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{ログイン済み?}
    B -->|No| C[ログイン画面へ]
    B -->|Yes| D{管理者権限?}
    D -->|No| E[403 Forbidden]
    D -->|Yes| F[ボード取得]
    F --> G{ボード存在?}
    G -->|No| H[404 Not Found]
    G -->|Yes| I[Webhook取得]
    I --> J{Webhook存在?}
    J -->|No| K[404 Not Found]
    J -->|Yes| L[パラメータ検証]
    L --> M{名前有効?}
    M -->|No| N[バリデーションエラー]
    M -->|Yes| O[Webhook更新]
    O --> P[詳細画面へリダイレクト]
    P --> Q[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-83-01 | URL変更不可 | ペイロードURLは編集できない | 常時 |
| BR-83-02 | アクション制限 | PERMITTED_ACTIONSに定義されたアクションのみ購読可能 | イベント選択時 |
| BR-83-03 | 名前必須 | 名前は空にできない | 更新時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Webhook取得 | webhooks | SELECT | 指定IDのWebhookを取得 |
| Webhook更新 | webhooks | UPDATE | name, subscribed_actionsを更新 |

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

#### webhooks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全カラム | id = params[:id] AND board_id = @board.id | 単一レコード取得 |
| UPDATE | name | ユーザー入力 | 必須 |
| UPDATE | subscribed_actions | ユーザー選択（JSON配列） | 空配列可 |
| UPDATE | updated_at | 現在時刻 | 自動設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 未ログイン | ログイン画面へリダイレクト |
| 403 | Forbidden | 管理者権限なし | 権限エラー表示 |
| 404 | NotFound | ボードまたはWebhookが存在しない | エラーページ表示 |
| 422 | UnprocessableEntity | バリデーションエラー | フォーム再表示、エラーメッセージ表示 |

### リトライ仕様

該当なし

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

単一レコードの更新のため、ActiveRecordのデフォルトトランザクション制御に従う。

## パフォーマンス要件

- レスポンス時間: 1秒以内

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

- 管理者権限チェックによる認可制御
- URLの変更を禁止することで、悪意のあるリダイレクト攻撃を防止
- CSRF対策（Railsデフォルト）

## 備考

URLを変更したい場合は、既存のWebhookを削除して新規作成する必要がある。これはセキュリティ上の設計判断である。

---

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

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

### 推奨読解順序

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

Webhookモデルのバリデーションルールを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | webhook.rb | `app/models/webhook.rb` | nameのバリデーション、subscribed_actionsの正規化 |

**読解のコツ**: `validates :name, presence: true`で名前が必須であること、`normalizes :subscribed_actions`でアクションが正規化されることを確認。

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

コントローラーのedit/updateアクションが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | webhooks_controller.rb | `app/controllers/webhooks_controller.rb` | edit/updateアクションの処理フロー |

**主要処理フロー**:
1. **4行目**: `before_action :ensure_admin` - 管理者権限チェック
2. **5行目**: `before_action :set_webhook` - Webhook取得
3. **23-24行目**: `edit`アクション - 編集フォーム表示
4. **26-29行目**: `update`アクション - 更新処理
5. **27行目**: `webhook_params.except(:url)` - URLを除外して更新

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit.html.erb | `app/views/webhooks/edit.html.erb` | 編集フォームの構造 |
| 3-2 | _actions.html.erb | `app/views/webhooks/form/_actions.html.erb` | イベント選択UI |

**主要処理フロー**:
- **10行目**: フォームの送信先（PUT @webhook）
- **12行目**: name入力フィールド
- **16-21行目**: アクション選択パーシャル呼び出し
- URLフィールドがないことに注目（編集不可）

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

```
WebhooksController#update
    │
    ├─ BoardScoped#set_board
    │      └─ Current.user.boards.find(params[:board_id])
    │
    ├─ ApplicationController#ensure_admin
    │      └─ Current.user.admin?
    │
    ├─ set_webhook
    │      └─ @board.webhooks.find(params[:id])
    │
    └─ @webhook.update!(webhook_params.except(:url))
           │
           └─ Webhook.normalizes :subscribed_actions
```

### データフロー図

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

フォーム入力 ───▶ WebhooksController ───▶ webhooksテーブル
  - name                    │
  - subscribed_actions      │
  (urlは除外)               ▼
                    Webhookモデル
                      - validate_name
                      - normalize_actions
                            │
                            ▼
                    リダイレクト ───▶ Webhook詳細画面
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| webhooks_controller.rb | `app/controllers/webhooks_controller.rb` | ソース | edit/updateアクション実装 |
| webhook.rb | `app/models/webhook.rb` | ソース | Webhookモデル |
| edit.html.erb | `app/views/webhooks/edit.html.erb` | テンプレート | 編集フォーム |
| _actions.html.erb | `app/views/webhooks/form/_actions.html.erb` | テンプレート | イベント選択UI |
| webhooks_helper.rb | `app/helpers/webhooks_helper.rb` | ソース | ヘルパーメソッド |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
