# 画面設計書 23-カードボード変更画面

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるカードボード変更画面の設計を記述したものです。カードボード変更画面は、カードを別のボードに移動するためのポップアップ形式の画面です。

### 本画面の処理概要

**業務上の目的・背景**：プロジェクト管理において、タスク（カード）の所属先を変更する必要が生じることがあります。例えば、プロジェクトの再編成、タスクの優先度変更、チーム間でのタスク移管などの場面で、カードを別のボードに移動する機能が必要となります。この画面により、ユーザーは簡単にカードの所属ボードを変更できます。

**画面へのアクセス方法**：カード詳細画面からボード変更ボタンをクリックすると、Turbo Frameとしてこの画面がポップアップ表示されます。URLは `/cards/:card_id/board/edit` です。

**主要な操作・処理内容**：
1. 現在のユーザーがアクセス可能なボード一覧の表示
2. ボード名によるフィルター検索
3. 移動先ボードの選択
4. カードの別ボードへの移動実行

**画面遷移**：
- 遷移元：カード詳細画面（ボード変更ボタンクリック）
- 遷移先：カード詳細画面（移動完了後リダイレクト）

**権限による表示制御**：ログインユーザーのみアクセス可能です。移動先として選択可能なボードは、ユーザーがアクセス権限を持つボードに限定されます。現在所属しているボードも一覧に表示されますが、選択済み状態として表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | カードを別ボードに移動 | 主機能 | カードを別のボードに移動 |

## 画面種別

選択（ポップアップ）

## URL/ルーティング

| HTTPメソッド | URL | コントローラー#アクション |
|-------------|-----|------------------------|
| GET | `/cards/:card_id/board/edit` | `cards/boards#edit` |
| PATCH | `/cards/:card_id/board` | `cards/boards#update` |

## 入出力項目

| 項目名 | 入出力 | データ型 | 必須 | 説明 |
|-------|-------|---------|-----|------|
| search | 入力 | String | - | ボード名のフィルター検索文字列 |
| board_id | 入力 | UUID | 必須 | 移動先のボードID |

## 表示項目

| 項目名 | データソース | 説明 |
|-------|-------------|------|
| ポップアップタイトル | filter_title | 「Move this card to...」 |
| フィルター入力欄 | - | ボード名を絞り込むための入力欄 |
| ボード一覧 | @boards | ユーザーがアクセス可能なボードの一覧 |
| 現在のボード | @card.board | チェックマーク付きで表示 |

## イベント仕様

### 1-ボード選択（クリック/Enter）

ボード項目をクリックまたはEnterキーで選択すると、PATCHリクエストが送信され、カードが選択したボードに移動します。

**処理内容**：
1. `card_board_path`へPATCHリクエスト送信
2. `@card.move_to(@board)`でカードを移動
3. HTMLフォーマットではカード詳細画面にリダイレクト
4. JSONフォーマットでは204 No Contentを返却

### 2-フィルター入力

検索ボックスに文字を入力すると、リアルタイムでボード一覧がフィルタリングされます。

**処理内容**：
1. `filter`コントローラーの`filter`アクションが発火
2. JavaScriptで表示/非表示を切り替え（サーバー通信なし）

### 3-キーボードナビゲーション

上下キーでボード一覧を移動し、Enterで選択できます。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 画面表示 | boards | SELECT | アクセス可能なボード一覧を取得 |
| ボード選択 | cards | UPDATE | board_idの更新 |
| ボード選択 | events | UPDATE | 関連イベントのboard_id更新 |

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

#### cards

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | board_id | 新しいボードのID | 移動先ボード |
| UPDATE | column_id | NULL | 移動時にカラムはリセット |
| UPDATE | updated_at | 現在時刻 | 自動更新 |

#### events

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | board_id | 新しいボードのID | カードに関連する全イベント |

## メッセージ仕様

本画面では明示的なメッセージ表示はありません。ボード選択後はリダイレクトします。

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| カードが存在しない | 404エラーページを表示 |
| カードへのアクセス権限がない | 404エラーページを表示 |
| 移動先ボードへのアクセス権限がない | 422エラー |

## 備考

- ボード一覧は最近アクセスした順（`ordered_by_recently_accessed`）で表示されます
- Turbo Frameで読み込まれ、`turbo_frame_tag "board_picker"`でフレームを識別します
- 現在所属しているボードは`aria-checked="true"`で選択済み状態として表示されます
- ETTagによるキャッシュ制御が実装されています（`fresh_when @boards`）
- カード移動時、`handle_board_change`コールバックにより以下の処理が実行されます：
  - カラムがNULLにリセット
  - ボード変更イベントの記録
  - アクセス権限の付与（必要な場合）
  - 通知とデータのクリーンアップ

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | card.rb | `app/models/card.rb` | Cardモデル、belongs_to :board、move_toメソッド |
| 1-2 | schema.rb | `db/schema.rb` | cardsテーブル（board_id）、eventsテーブル |

**読解のコツ**: move_toメソッド（57-63行目）がカード移動のコア処理です。トランザクション内でカードとイベントのboard_idを更新しています。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | boards_controller.rb | `app/controllers/cards/boards_controller.rb` | edit/updateアクションの処理 |
| 2-2 | board_scoped.rb | `app/controllers/concerns/board_scoped.rb` | BoardScopedモジュール |

**主要処理フロー**:
1. **4行目**: `skip_before_action :set_board` - editではボード設定をスキップ
2. **7-9行目**: `edit` - アクセス可能なボード一覧を取得
3. **12-18行目**: `update` - `@card.move_to(@board)`で移動実行

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

画面の表示内容を構成するビューファイルを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | edit.html.erb | `app/views/cards/boards/edit.html.erb` | メインビュー、filter/navigable-listコントローラー |

**主要処理フロー**:
- **1行目**: `turbo_frame_tag "board_picker"` - Turbo Frameの定義
- **8行目**: `filter_title "Move this card to..."` - タイトル表示
- **14-23行目**: ボード一覧のループ処理とフォーム

#### Step 4: カード移動処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | card.rb | `app/models/card.rb` | move_toメソッド（57-63行目）とhandle_board_change（74-85行目） |

**主要処理フロー**:
- **57-63行目**: `move_to` - カードとイベントのboard_id更新
- **74-85行目**: `handle_board_change` - after_updateコールバック

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

```
GET /cards/:card_id/board/edit
    |
    +-- Cards::BoardsController#edit
           |
           +-- set_card (before_action)
           |      +-- Current.user.accessible_cards.find_by!
           |
           +-- Current.user.boards.ordered_by_recently_accessed
           |
           +-- render 'cards/boards/edit'

PATCH /cards/:card_id/board
    |
    +-- Cards::BoardsController#update
           |
           +-- set_card (before_action)
           +-- BoardScoped#set_board (before_action)
           |
           +-- @card.move_to(@board)
                  |
                  +-- transaction do
                         +-- card.update!(board: new_board)
                         +-- card.events.update_all(board_id:)
                         +-- Event.where(eventable: card.comments).update_all
                  |
                  +-- handle_board_change (after_update callback)
                         +-- update!(column: nil)
                         +-- track_board_change_event
                         +-- grant_access_to_assignees
                         +-- remove_inaccessible_notifications_later
                         +-- clean_inaccessible_data_later
```

### データフロー図

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

リクエスト               BoardsController                  レスポンス
card_id ──────────────▶ set_card ─────────────────────▶ カード取得
board_id ─────────────▶ set_board ────────────────────▶ 移動先ボード
                              |
                              ▼
                        move_to(board)
                              |
                        ┌─────┼─────┐
                        ▼     ▼     ▼
                     cards  events comments.events
                    UPDATE UPDATE   UPDATE
                              |
                              ▼
                        handle_board_change
                              |
                        ┌─────┴─────┐
                        ▼           ▼
                    column=nil   event記録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| boards_controller.rb | `app/controllers/cards/boards_controller.rb` | ソース | ボード変更コントローラー |
| board_scoped.rb | `app/controllers/concerns/board_scoped.rb` | ソース | ボード取得の共通処理 |
| edit.html.erb | `app/views/cards/boards/edit.html.erb` | テンプレート | ボード選択画面のビュー |
| card.rb | `app/models/card.rb` | ソース | Cardモデル（move_to含む） |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
| schema.rb | `db/schema.rb` | 設定 | データベーススキーマ |
