# 機能設計書 80-Webhook一覧表示

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるボードに設定されたWebhook一覧を表示する機能の設計を記述する。

### 本機能の処理概要

特定のボードに設定されたWebhookの一覧を表示する機能である。Webhookは外部サービス（Slack、Campfire、Basecamp等）と連携し、カードの作成やコメント追加などのイベントを通知するための仕組みである。管理者はこの画面からWebhookの管理（作成、編集、削除）へアクセスできる。

**業務上の目的・背景**：チーム内のコミュニケーションを効率化するため、Fizzyでのイベントを外部のチャットツールやサービスに自動通知する必要がある。この一覧画面により、ボードに設定されているすべてのWebhookを把握し、管理することができる。

**機能の利用シーン**：
- ボードに設定されているWebhookを確認したい場合
- 新しいWebhookを追加したい場合
- 不要なWebhookを削除したい場合
- Webhookの動作状況を確認したい場合

**主要な処理内容**：
1. ボード詳細画面からWebhook設定画面にアクセス
2. ボードに紐づくWebhook一覧を取得
3. ページネーション付きで一覧表示
4. 各Webhookの名前と削除ボタンを表示

**関連システム・外部連携**：
- Webhook送信先：Slack、Campfire、Basecamp等の外部サービス

**権限による制御**：管理者（admin）ロールを持つユーザーのみがWebhook一覧にアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | Webhook一覧画面 | 主画面 | ボードに設定されたWebhook一覧を表示 |

## 機能種別

データ参照（一覧表示）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| board_id | UUID | Yes | 対象ボードのID（URLパラメータ） | アクセス権のあるボード |
| page | Integer | No | ページ番号 | 正の整数 |

### 入力データソース

- URLパラメータ：board_id
- クエリパラメータ：page（ページネーション用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @board | Board | 対象ボード |
| @page | Page | ページネーション付きWebhook一覧 |
| @page.records | Webhook[] | 現在のページのWebhook配列 |

### 出力先

- 画面表示：webhooks/index.html.erb

## 処理フロー

### 処理シーケンス

```
1. 管理者がボード設定からWebhook一覧にアクセス
   └─ GET /boards/:board_id/webhooks

2. 権限チェック
   └─ ensure_adminで管理者権限を確認

3. ボード取得
   └─ BoardScopedでアクセス権のあるボードを取得

4. Webhook一覧取得
   └─ @board.webhooks.ordered
   └─ ページネーション処理（set_page_and_extract_portion_from）

5. 画面レンダリング
   └─ Webhook一覧を表示
   └─ 新規作成リンクを表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始: Webhook一覧アクセス] --> B{管理者権限あり?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D{ボードアクセス権あり?}
    D -->|No| E[404 Not Found]
    D -->|Yes| F[Webhook一覧取得]
    F --> G[ページネーション処理]
    G --> H{Webhookあり?}
    H -->|Yes| I[Webhook一覧を表示]
    H -->|No| J[説明文と新規作成リンクを表示]
    I --> K[終了]
    J --> K
    C --> K
    E --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-80-01 | 管理者限定 | Webhook一覧は管理者のみアクセス可能 | indexアクション時 |
| BR-80-02 | ボードスコープ | Webhookはボード単位で管理される | 全操作時 |
| BR-80-03 | ソート順 | name ASC、id DESCの順でソート | 一覧取得時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ボード取得 | boards | SELECT | アクセス権のあるボードを取得 |
| Webhook一覧取得 | webhooks | SELECT | ボードに紐づくWebhook一覧取得 |

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

#### webhooks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | board_id, name, active, url | board_id一致 | orderedスコープ適用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | 権限エラー | 非管理者によるアクセス | Forbiddenエラー |
| 404 | 未検出 | ボードが存在しない、またはアクセス権なし | Not Foundエラー |

### リトライ仕様

特になし（参照のみの機能）

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

参照のみの機能のためトランザクション管理は不要

## パフォーマンス要件

- レスポンス時間：1秒以内
- ページネーションによりデータ量を制限

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

- ensure_adminによる管理者権限チェック
- BoardScopedによるボードアクセス権チェック

## 備考

- Webhookの作成、編集、削除は別機能（No.81-84）で実装
- Webhookのアクティベーション（有効/無効切り替え）はNo.85で実装
- 削除確認はturbo_confirmを使用

---

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

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

### 推奨読解順序

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

Webhookのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Webhook | `app/models/webhook.rb` | Webhookモデルの全体像 |

**読解のコツ**:
- 4-6行目: URL正規表現でSlack、Campfire、Basecampを判定
- 8行目: PERMITTED_SCHEMES = ["http", "https"]
- 9-21行目: PERMITTED_ACTIONSで購読可能なイベントを定義
- 33行目: scope :orderedでname ASC、id DESCでソート
- 40-41行目: validatesでnameの必須とURLの検証
- 55-65行目: for_slack?、for_campfire?、for_basecamp?メソッド

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

処理の起点となるコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WebhooksController | `app/controllers/webhooks_controller.rb` | indexアクションの実装 |

**主要処理フロー**:
1. **2行目**: include BoardScoped - ボードスコープの適用
2. **4行目**: before_action :ensure_admin - 管理者権限チェック
3. **5行目**: before_action :set_webhook, except: %i[index new create]
4. **7-9行目**: indexアクション
5. **8行目**: set_page_and_extract_portion_from @board.webhooks.ordered

#### Step 3: ボードスコープを理解する

BoardScopedモジュールの動作を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BoardScoped | `app/controllers/concerns/board_scoped.rb` | ボードのアクセス権制御 |

#### Step 4: ビューを理解する

画面表示の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.erb | `app/views/webhooks/index.html.erb` | 一覧画面 |
| 4-2 | _webhook.html.erb | `app/views/webhooks/_webhook.html.erb` | Webhookアイテムパーシャル |

**読解のコツ**:
- index.html.erb:
  - 12-14行目: @page.records.any?で分岐
  - 13-15行目: render partial: "webhooks/webhook"でコレクション描画
  - 16-18行目: Webhookが無い場合の説明文
  - 21-24行目: 新規作成リンク
- _webhook.html.erb:
  - 2-4行目: link_to webhookで詳細へのリンク
  - 8-12行目: button_to method: :deleteで削除ボタン

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

```
WebhooksController#index
    │
    ├─ BoardScoped (include)
    │      └─ set_board (before_action)
    │             └─ Current.user.accessible_boards.find(params[:board_id])
    │
    ├─ ensure_admin (before_action)
    │      └─ Current.user.admin? ─▶ 403 if false
    │
    └─ set_page_and_extract_portion_from @board.webhooks.ordered
           │
           ├─ webhooks.ordered
           │      └─ ORDER BY name ASC, id DESC
           │
           └─ Paginator#extract_portion
                  └─ LIMIT/OFFSET
```

### データフロー図

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

board_id ───────────▶ WebhooksController#index ───────────▶ index.html.erb
(URLパラメータ)            │                                    │
                           │                                    ├── Webhook一覧
page ──────────────▶       ├──▶ BoardScopedでボード取得        │
(クエリパラメータ)         │                                    └── 新規作成リンク
                           ├──▶ ensure_adminで権限確認
                           │
                           └──▶ webhooks SELECT
                                  (board_id, ordered)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WebhooksController | `app/controllers/webhooks_controller.rb` | コントローラー | Webhook CRUD操作 |
| Webhook | `app/models/webhook.rb` | モデル | Webhookデータ管理 |
| BoardScoped | `app/controllers/concerns/board_scoped.rb` | コントローラーConcern | ボードアクセス権制御 |
| index.html.erb | `app/views/webhooks/index.html.erb` | ビュー | 一覧画面 |
| _webhook.html.erb | `app/views/webhooks/_webhook.html.erb` | ビュー（パーシャル） | Webhookアイテム表示 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（47行目） |
