# 画面設計書 50-ボード一覧

## 概要

本ドキュメントは、GitLabのボード一覧（Issue Boards Index）画面の設計仕様を記載したものである。

### 本画面の処理概要

ボード一覧画面は、プロジェクトまたはグループの課題ボード（Issue Board）を表示するための画面である。カンバン形式で課題をビジュアルに管理でき、ステータスやラベルに基づいたリスト（列）で課題を整理できる。

**業務上の目的・背景**：アジャイル開発やスクラムにおいて、カンバンボードは作業の可視化と進捗管理に不可欠なツールである。本画面は、課題をドラッグ&ドロップで移動したり、リストを追加・編集したりすることで、チームの作業管理を効率化する。

**画面へのアクセス方法**：以下のいずれかの方法でアクセス可能
1. プロジェクトサイドバーの「Plan」>「Issue boards」をクリック
2. グループサイドバーの「Issue boards」をクリック
3. 直接URL（`/:namespace/:project/-/boards`）を指定

**主要な操作・処理内容**：
1. ボードの一覧表示（複数ボードがある場合は選択可能）
2. 課題のリスト間ドラッグ&ドロップ移動
3. リスト（カラム）の追加・削除・並び替え
4. 課題のフィルタリング（ラベル、担当者、マイルストーン等）
5. 課題のクイック作成
6. ボードの新規作成・編集・削除

**画面遷移**：
- 遷移元: プロジェクトダッシュボード、グループダッシュボード、サイドバー
- 遷移先: 課題詳細、ボード表示（個別ボード）

**権限による表示制御**：
- ボード閲覧には`read_issue_board`権限が必要
- リスト管理には`admin_issue_board_list`権限が必要
- ボード管理には`admin_issue_board`権限が必要
- 課題更新には`admin_issue`権限が必要

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 39 | イシューボード | 主機能 | 課題ボードの一覧表示 |

## 画面種別

一覧

## URL/ルーティング

```
GET /:namespace/:project/-/boards
GET /:namespace/:project/-/boards/:id
GET /groups/:group_id/-/boards
GET /groups/:group_id/-/boards/:id
```

## 入出力項目

| 項目名 | I/O | 型 | 必須 | 説明 |
|--------|-----|-----|------|------|
| id | 入力 | Integer | 任意 | ボードID（指定時は特定ボードを表示） |

## 表示項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ボード名 | String | 現在選択中のボード名 |
| ボード切り替え | Dropdown | 複数ボード時の選択 |
| リスト（カラム） | Array | ボードのリスト一覧 |
| 課題カード | Array | 各リスト内の課題カード |
| フィルター | Component | 課題のフィルタリング |
| 新規ボード作成 | Button | 新規ボード作成ボタン |
| ボード設定 | Button | ボード設定・削除ボタン |
| サイドバー | Panel | 課題詳細のサイドバー |

## イベント仕様

### 1-ボード選択

1. ボード選択ドロップダウンから対象ボードを選択
2. 選択されたボードのIDでURLを更新
3. ボードのリストと課題を読み込み表示
4. `Boards::Visits::CreateService`で訪問履歴を更新

### 2-課題のドラッグ&ドロップ

1. 課題カードをドラッグして別リストにドロップ
2. リストタイプに応じた更新処理を実行
3. ラベルリストの場合：ラベルを付け替え
4. 担当者リストの場合：担当者を変更
5. マイルストーンリストの場合：マイルストーンを変更

### 3-リスト追加

1. 「リスト追加」ボタンをクリック
2. リストタイプを選択（ラベル、担当者、マイルストーン等）
3. 対象を選択
4. `Lists::CreateService`でリストを作成

### 4-課題クイック作成

1. リスト下部の「新規課題」フォームに入力
2. Enterで確定
3. `Issues::CreateService`で課題を作成
4. 作成された課題をリストに追加

### 5-フィルター適用

1. フィルターバーで条件を設定
2. URLのクエリパラメータを更新
3. 該当する課題のみを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ボード表示 | board_project_recent_visits | INSERT/UPDATE | 訪問履歴更新 |
| リスト追加 | lists | INSERT | 新規リスト作成 |
| リスト削除 | lists | DELETE | リスト削除 |
| リスト移動 | lists | UPDATE | position更新 |
| 課題移動 | label_links | INSERT/DELETE | ラベル付け替え |
| 課題移動 | issue_assignees | INSERT/DELETE | 担当者変更 |
| 課題移動 | issues | UPDATE | milestone_id変更 |

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

#### board_project_recent_visits

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | user_id | current_user.id | 訪問ユーザー |
| INSERT/UPDATE | project_id | プロジェクトID | 対象プロジェクト |
| INSERT/UPDATE | board_id | ボードID | 訪問ボード |
| INSERT/UPDATE | updated_at | 現在時刻 | 訪問日時 |

#### lists

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | board_id | ボードID | 所属ボード |
| INSERT | list_type | 選択タイプ | label/assignee/milestone等 |
| INSERT | label_id | ラベルID | ラベルリスト時 |
| INSERT | position | リスト内順序 | 自動計算 |
| UPDATE | position | 新しい順序 | ドラッグ時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ | 表示条件 |
|-------------|------|-----------|----------|
| MSG-001 | 成功 | リスト追加成功 | リスト作成成功時 |
| MSG-002 | エラー | "Something went wrong" | 操作失敗時 |
| MSG-003 | 情報 | "Board has been disabled" | ボード無効時 |

## 例外処理

| 例外状態 | 処理内容 |
|---------|----------|
| ボードが存在しない | 自動的に新規ボードを作成 |
| 権限不足 | 403 Forbiddenを返却 |
| ボード無効 | disabled状態を表示、課題移動を無効化 |

## 備考

- ボードが存在しない場合、`Boards::CreateService`で自動作成される
- 複数ボード機能はライセンスに依存（`multiple_issue_boards_available?`）
- 最近訪問したボードへの自動リダイレクト機能あり
- `RECENT_BOARDS_SIZE = 4`で最近のボード履歴数を制限
- Work Item Tasks機能フラグ（`work_item_tasks_on_boards`）に対応
- エピックボード（EpicBoard）との共通表示処理あり

---

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

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

### 推奨読解順序

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

ボード（Board）モデルとリスト（List）の関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | board.rb | `app/models/board.rb` | ボードのデータ構造、スコープ |
| 1-2 | list.rb | `app/models/list.rb` | リスト（カラム）の構造 |

**読解のコツ**: `Board`は`has_many :lists`でリストを持ち、`project`または`group`に所属する。`RECENT_BOARDS_SIZE = 4`（行6）で最近のボード数を制限。

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

コントローラーの`index`アクションが処理の起点。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | boards_controller.rb | `app/controllers/projects/boards_controller.rb` | コントローラー定義 |
| 2-2 | boards_actions.rb | `app/controllers/concerns/boards_actions.rb` | 共通アクション |

**主要処理フロー**:
1. **行7**: `check_issues_available!` - 課題機能の確認
2. **boards_actions.rb 行8**: `authorize_read_board!` - 権限チェック
3. **boards_actions.rb 行9**: `redirect_to_recent_board` - 最近のボードへリダイレクト
4. **boards_actions.rb 行14-17**: indexアクション - ボード存在確認と自動作成

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.haml | `app/views/projects/boards/index.html.haml` | エントリポイント |
| 3-2 | _show.html.haml | `app/views/shared/boards/_show.html.haml` | メインビュー |

**主要処理フロー**:
- **index.html.haml 行1**: `_show`パーシャルをrender
- **_show.html.haml 行22**: `#js-issuable-board-app`でVueコンポーネント

#### Step 4: ヘルパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | boards_helper.rb | `app/helpers/boards_helper.rb` | board_dataの構築 |

**主要処理フロー**:
- **行8-30**: `board_data` - Vueコンポーネントへ渡すデータ

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

```
BoardsController#index
    │
    ├─ before_action :check_issues_available!
    │
    ├─ before_action :authorize_read_board!
    │      └─ can?(current_user, :read_issue_board, project)
    │
    ├─ before_action :redirect_to_recent_board (条件付き)
    │      └─ Boards::VisitsFinder.new().latest
    │
    ├─ before_action :board
    │      └─ Boards::BoardsFinder.new().execute.first
    │
    └─ (ボード未存在時)
           └─ Boards::CreateService.new().execute
                  └─ Board.create

render "index"
    └─ render "shared/boards/show"
           └─ #js-issuable-board-app (Vue component)
                  └─ board_data (from BoardsHelper)
```

### データフロー図

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

Request ───▶ BoardsController#index ───▶ HTML Response
                    │
                    ├─▶ authorize_read_board!
                    │       └─▶ 権限チェック
                    │
                    ├─▶ redirect_to_recent_board (条件付き)
                    │       └─▶ Boards::VisitsFinder
                    │
                    ├─▶ Boards::BoardsFinder
                    │       └─▶ @board
                    │
                    ├─▶ (ボード未存在時)
                    │       └─▶ Boards::CreateService
                    │
                    └─▶ BoardsHelper#board_data
                            └─▶ Vue component props
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| boards_controller.rb | `app/controllers/projects/boards_controller.rb` | コントローラー | リクエスト処理 |
| boards_actions.rb | `app/controllers/concerns/boards_actions.rb` | Concern | 共通アクション |
| index.html.haml | `app/views/projects/boards/index.html.haml` | テンプレート | エントリポイント |
| _show.html.haml | `app/views/shared/boards/_show.html.haml` | パーシャル | メインビュー |
| board.rb | `app/models/board.rb` | モデル | ボードデータ構造 |
| list.rb | `app/models/list.rb` | モデル | リストデータ構造 |
| boards_helper.rb | `app/helpers/boards_helper.rb` | ヘルパー | Vueデータ構築 |
| boards_finder.rb | `app/finders/boards/boards_finder.rb` | Finder | ボード検索 |
| create_service.rb | `app/services/boards/create_service.rb` | サービス | ボード作成 |
| project.rb | `config/routes/project.rb` | ルーティング | URL定義（行242） |
