# 画面設計書 10-ボード詳細画面

## 概要

本ドキュメントは、Fizzyアプリケーションのボード詳細画面（`app/views/boards/show.html.erb`）の設計仕様を記述したものです。

### 本画面の処理概要

ボード詳細画面は、カンバンボードの詳細を表示するメイン画面です。カラム単位でカードを表示し、ドラッグ&ドロップによるカードの移動や、フィルター機能によるカードの絞り込みが可能です。

**業務上の目的・背景**：プロジェクト管理やタスク管理において、カンバンボード形式でカードを視覚的に整理・管理するための画面です。ストリーム、カスタムカラム、Not Now、クローズドといった複数のカラムでカードを分類し、ワークフローを可視化します。リアルタイム更新（Turbo Streams）により、複数ユーザーでの同時編集にも対応しています。

**画面へのアクセス方法**：マイメニューやアクティビティ一覧からボードを選択、または`/boards/:id`に直接アクセス

**主要な操作・処理内容**：
1. ボード内のカラムとカードを表示する
2. カードをドラッグ&ドロップで別のカラムに移動する
3. フィルター機能でカードを絞り込む
4. 新規カードを作成する（トリアージ待ちに追加）
5. カードをクリックして詳細画面に遷移する

**画面遷移**：
- 遷移元：マイメニュー、アクティビティ一覧、ボード一覧、通知
- 遷移先：カード詳細画面、ボード設定画面、カラム詳細画面、カード作成

**権限による表示制御**：
- 認証済みユーザーのみアクセス可能
- ユーザーがアクセス権を持つボードのみ表示
- 管理者のみWebhook設定リンクが表示される
- ボード管理権限がないユーザーには編集リンクが非表示

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | ボード詳細表示 | 主機能 | ボードの詳細（カラムとカード）を表示 |
| 12 | カラム一覧表示 | 補助機能 | ボード内のカラム一覧を表示 |
| 17 | カード一覧表示 | 補助機能 | フィルター条件に基づいてカードの一覧を表示 |
| 18 | カード作成 | 補助機能 | 新しいカードを下書きとして作成 |
| 24 | カードをカラムに振り分け（トリアージ） | 補助機能 | トリアージ待ちのカードを特定のカラムに振り分け |
| 13 | カラム作成 | API連携 | 新しいカラムをボードに追加 |

## 画面種別

詳細（カンバンボード）

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| URL | `/boards/:id` |
| HTTPメソッド | GET |
| コントローラー | `BoardsController` |
| アクション | `show` |
| レイアウト | application（デフォルト） |

## 入出力項目

### 入力項目（クエリパラメータ）

| No | 項目名 | 物理名 | データ型 | 必須 | 説明 | 備考 |
|----|--------|--------|---------|------|------|------|
| 1 | フィルターID | filter_id | integer | 任意 | 保存済みフィルターのID | - |
| 2 | ボードID | board_ids[] | array | 任意 | フィルター用（自動設定） | hidden fieldで自動追加 |
| 3 | 展開フラグ | expand_all | boolean | 任意 | すべて展開して表示 | - |

### 入力項目（パスパラメータ）

| No | 項目名 | 物理名 | データ型 | 必須 | 説明 | 備考 |
|----|--------|--------|---------|------|------|------|
| 1 | ボードID | id | integer | 必須 | 表示するボードのID | - |

### 出力項目

なし（画面表示のみ）

## 表示項目

| No | 項目名 | 表示条件 | データソース | 備考 |
|----|--------|----------|-------------|------|
| 1 | ページタイトル | 常時 | @board.name | ブラウザタブに表示 |
| 2 | ヘッダータイトル | 常時 | @board.name | ボード名 |
| 3 | Webhook設定リンク | 管理者のみ | - | Current.user.admin? |
| 4 | 編集リンク | ボード管理権限時 | - | link_to_edit_board |
| 5 | フィルター設定 | 常時 | @user_filtering | フィルターUI |
| 6 | カード追加ボタン | 非フィルター時 | - | トリアージ待ちに追加 |
| 7 | カラム一覧 | 非フィルター時 | @board.columns | ドラッグ&ドロップ対応 |
| 8 | フィルター結果カード | フィルター時 | @filter.cards | グリッド表示 |
| 9 | 共有ボタン | 常時 | - | ブリッジ（ネイティブアプリ）連携 |

## イベント仕様

### 1-ボード表示（通常モード）

**トリガー**: 画面アクセス（フィルター未使用時）

**処理フロー**:
1. `set_board`でボードを取得（`Current.user.boards.find`）
2. `set_filter`と`set_user_filtering`でフィルター設定
3. `show_columns`が呼ばれる
4. トリアージ待ちカードをページネーションで取得
5. `fresh_when`でETa​gキャッシュ設定
6. カラムビュー（`boards/show/_columns`）をレンダリング

**レスポンス**:
- HTML（カラムビュー）

### 2-ボード表示（フィルターモード）

**トリガー**: 画面アクセス（フィルター使用時）

**処理フロー**:
1. `@filter.used?(ignore_boards: true)`でフィルター使用判定
2. `show_filtered_cards`が呼ばれる
3. フィルター条件に合致するカードを取得
4. フィルター結果ビュー（`boards/show/_filtered_cards`）をレンダリング

**レスポンス**:
- HTML（フィルター結果ビュー）

### 3-カードドラッグ&ドロップ

**トリガー**: カードのドラッグ開始

**処理フロー**:
1. `drag-and-drop` Stimulusコントローラーがイベント処理
2. `drag-and-strum`でカラム展開/折りたたみ
3. ドロップ時に対応するカラムにカード移動リクエスト
4. サーバーで位置更新後、Turbo Streamで全員に反映

### 4-フィルター変更

**トリガー**: フィルターUIの操作

**処理フロー**:
1. フィルター条件を変更
2. フォームが`cards_container` Turbo Frameをターゲットに送信
3. Turbo Frameで表示内容が更新される

### 5-カード追加

**トリガー**: カード追加ボタン押下

**処理フロー**:
1. `columns/show/_add_card_button`のボタンをクリック
2. カード作成画面またはモーダルが表示される
3. 作成後、トリアージ待ち（Stream）にカードが追加される

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

なし（参照のみ、カード移動等は別エンドポイント）

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | boards | SELECT | ボード情報取得 |
| 画面表示 | columns | SELECT | カラム一覧取得 |
| 画面表示 | cards | SELECT | カード一覧取得 |
| 画面表示 | filters | SELECT | フィルター設定取得 |

## メッセージ仕様

| No | メッセージ種別 | メッセージ内容 | 表示条件 |
|----|--------------|---------------|---------|
| 1 | 情報 | No cards match this filter | フィルター結果が0件 |

## 例外処理

| 例外パターン | 対応内容 | 備考 |
|------------|---------|------|
| ボードが見つからない | ActiveRecord::RecordNotFoundエラー | 404ページ表示 |
| アクセス権限なし | ActiveRecord::RecordNotFoundエラー | Current.user.boardsでフィルタ |
| フィルターが見つからない | ActiveRecord::RecordNotFoundエラー | filter_idが無効な場合 |

## 備考

- `turbo_exempts_page_from_cache`により、このページはTurboのキャッシュから除外される
- `turbo_stream_from @board`により、ボードへのリアルタイム更新を購読
- `contained-scrolling` body classにより、カラムの横スクロールが独立して動作
- `fresh_when`によるHTTPキャッシュ（ETag）が実装されている（カラムビューのみ）
- `collapsible-columns` Stimulusコントローラーでカラムの折りたたみ機能
- `drag-and-drop` Stimulusコントローラーでカードのドラッグ&ドロップ機能
- `navigable-list` Stimulusコントローラーでキーボードナビゲーション対応
- `card-hotkeys` Stimulusコントローラーでカードのショートカットキー対応
- フィルター使用時はカラムビューではなくグリッドビューに切り替わる
- `bridged_share_url_button`でネイティブアプリからの共有機能を提供

---

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

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

### 推奨読解順序

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

まず、ボードとカラム、カードの関係を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | board.rb | `app/models/board.rb` | Boardモデルの構造、include、関連 |
| 1-2 | board/cards.rb | `app/models/board/cards.rb` | cardsとの関連 |
| 1-3 | column.rb | `app/models/column.rb` | Columnモデルの構造 |
| 1-4 | card.rb | `app/models/card.rb` | Cardモデルの構造、scope |

**読解のコツ**: Boardは`Accessible`, `Cards`, `Triageable`など多くのConcernをincludeしています。各Concernの役割を把握することが重要です。

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

処理の起点となるコントローラーを特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | boards_controller.rb | `app/controllers/boards_controller.rb` | showアクションの分岐ロジック |
| 2-2 | filter_scoped.rb | `app/controllers/concerns/filter_scoped.rb` | フィルター設定ロジック |

**主要処理フロー**:
1. **4行目（boards_controller.rb）**: `before_action :set_board` - ボード取得
2. **16-22行目（boards_controller.rb）**: `show`アクション - フィルター使用有無で分岐
3. **83-86行目（boards_controller.rb）**: `show_filtered_cards` - フィルター表示
4. **88-92行目（boards_controller.rb）**: `show_columns` - カラム表示

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

画面表示のテンプレートを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.erb | `app/views/boards/show.html.erb` | 全体構造、Turbo Stream購読 |
| 3-2 | _columns.html.erb | `app/views/boards/show/_columns.html.erb` | カラムビュー、Stimulusコントローラー |
| 3-3 | _filtered_cards.html.erb | `app/views/boards/show/_filtered_cards.html.erb` | フィルター結果表示 |
| 3-4 | _settings.html.erb | `app/views/filters/_settings.html.erb` | フィルターUI |

**主要処理フロー**:
- **1-3行目**: ページタイトル、body class、キャッシュ除外設定
- **5行目**: `turbo_stream_from @board` - リアルタイム更新購読
- **7-19行目**: ヘッダー部（タイトル、Webhook、編集リンク）
- **21-23行目**: フィルター設定
- **25-32行目**: `cards_container` Turbo Frame（カラムまたはフィルター結果）

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

```
BoardsController#show
    │
    ├─ [before_action] set_board
    │      └─ Current.user.boards.find(params[:id])
    │
    ├─ [before_action] set_filter (FilterScoped)
    │      └─ Current.user.filters.from_params or find
    │
    ├─ [before_action] set_user_filtering (FilterScoped)
    │      └─ User::Filtering.new(Current.user, @filter, expanded: expanded_param)
    │
    └─ @filter.used?(ignore_boards: true)?
           │
           ├─ [true] show_filtered_cards
           │      │
           │      ├─ @filter.board_ids = [@board.id]
           │      │
           │      └─ set_page_and_extract_portion_from @filter.cards
           │             │
           │             └─ render show (filtered_cards)
           │
           └─ [false] show_columns
                  │
                  ├─ @board.cards.awaiting_triage.latest.with_golden_first.preloaded
                  │
                  ├─ set_page_and_extract_portion_from cards
                  │
                  └─ fresh_when etag: [@board, @page.records, @user_filtering, Current.account]
                         │
                         └─ render show (columns)
                                │
                                ├─ boards/show.html.erb
                                │      │
                                │      ├─ turbo_stream_from @board
                                │      │
                                │      ├─ header部分
                                │      │      ├─ link_to_webhooks (admin only)
                                │      │      └─ link_to_edit_board
                                │      │
                                │      ├─ filters/_settings
                                │      │
                                │      └─ cards_container (turbo_frame)
                                │             │
                                │             ├─ [filtered] boards/show/_filtered_cards
                                │             │
                                │             └─ [columns] boards/show/_columns
                                │                    │
                                │                    ├─ boards/show/_not_now
                                │                    ├─ boards/show/_stream
                                │                    ├─ boards/show/_column (collection)
                                │                    └─ boards/show/_closed
                                │
                                └─ レスポンス
```

### データフロー図

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

id (path param) ─────▶ BoardsController#show
filter_id (param) ───▶        │
expand_all (param) ──▶        │
                              │
                              ├──▶ set_board
                              │        │
                              │        └─▶ Board取得（アクセス権チェック含む）
                              │
                              ├──▶ set_filter
                              │        │
                              │        └─▶ Filter取得/生成
                              │
                              ├──▶ set_user_filtering
                              │        │
                              │        └─▶ User::Filtering生成
                              │
                              └──▶ show (分岐)
                                       │
                                       ├─▶ [フィルター使用] カードグリッド表示
                                       │
                                       └─▶ [通常] カラムビュー表示
                                                  │
                                                  └─▶ HTML出力（カンバンボード）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| boards_controller.rb | `app/controllers/boards_controller.rb` | コントローラー | ボードの制御 |
| show.html.erb | `app/views/boards/show.html.erb` | ビュー | ボード詳細画面テンプレート |
| _columns.html.erb | `app/views/boards/show/_columns.html.erb` | パーシャル | カラムビュー |
| _filtered_cards.html.erb | `app/views/boards/show/_filtered_cards.html.erb` | パーシャル | フィルター結果表示 |
| _column.html.erb | `app/views/boards/show/_column.html.erb` | パーシャル | 個別カラム |
| _stream.html.erb | `app/views/boards/show/_stream.html.erb` | パーシャル | ストリームカラム |
| _not_now.html.erb | `app/views/boards/show/_not_now.html.erb` | パーシャル | Not Nowカラム |
| _closed.html.erb | `app/views/boards/show/_closed.html.erb` | パーシャル | クローズドカラム |
| _settings.html.erb | `app/views/filters/_settings.html.erb` | パーシャル | フィルターUI |
| _add_card_button.html.erb | `app/views/columns/show/_add_card_button.html.erb` | パーシャル | カード追加ボタン |
| board.rb | `app/models/board.rb` | モデル | ボード管理 |
| column.rb | `app/models/column.rb` | モデル | カラム管理 |
| card.rb | `app/models/card.rb` | モデル | カード管理 |
| filter.rb | `app/models/filter.rb` | モデル | フィルター管理 |
| filter_scoped.rb | `app/controllers/concerns/filter_scoped.rb` | Concern | フィルター設定 |
| collapsible_columns_controller.js | `app/javascript/controllers/collapsible_columns_controller.js` | Stimulus | カラム折りたたみ |
| drag_and_drop_controller.js | `app/javascript/controllers/drag_and_drop_controller.js` | Stimulus | ドラッグ&ドロップ |
| drag_and_strum_controller.js | `app/javascript/controllers/drag_and_strum_controller.js` | Stimulus | ドラッグ時のカラム展開 |
| navigable_list_controller.js | `app/javascript/controllers/navigable_list_controller.js` | Stimulus | キーボードナビゲーション |
| card_hotkeys_controller.js | `app/javascript/controllers/card_hotkeys_controller.js` | Stimulus | カードショートカット |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
