# 機能設計書 9-ボード編集

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるボードの名前、アクセス権限、自動延期設定を編集する機能の設計書である。ボードの管理者が設定を変更し、チームメンバーのアクセス権を管理できる。

### 本機能の処理概要

**業務上の目的・背景**：プロジェクトの進行に伴い、ボードの設定変更が必要になることがある。ボード名の変更、アクセス権限の調整、自動延期期間の設定など、運用中のボード設定を柔軟に変更できる機能が必要である。

**機能の利用シーン**：ボード管理者がボード設定画面から名前を変更したり、新しいメンバーにアクセス権を付与したり、不要なメンバーのアクセス権を取り消したりする際に使用する。

**主要な処理内容**：
1. ボード編集画面の表示
2. アクセス権を持つユーザーの一覧取得
3. ボード設定（名前、アクセス権限、自動延期）の更新
4. アクセス権の付与・取り消し
5. 変更保存後のリダイレクト

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

**権限による制御**：ボード管理者（can_administer_board?）のみがボード編集可能。自分がアクセス権を失った場合はルート画面にリダイレクト。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | ボード設定画面 | 主画面 | ボードの名前・アクセス権限・自動延期設定を編集 |
| 17 | ボード参加設定画面 | 参照画面 | ボードへの参加設定を更新 |

## 機能種別

CRUD操作 / データ更新

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | Yes | ボードID | UUID形式 |
| name | String | No | ボード名 | - |
| all_access | Boolean | No | 全員アクセス可能フラグ | - |
| auto_postpone_period | Integer | No | 自動延期期間 | - |
| public_description | Text | No | 公開用説明文 | - |
| user_ids | Array | No | アクセス権を付与するユーザーIDの配列 | - |

### 入力データソース

- URLパラメータ（ボードID）
- 画面入力（ボード設定フォーム）
- 画面入力（ユーザー選択）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @board | Board | 更新されたボードレコード |
| @selected_users | Array<User> | 選択済みユーザー一覧 |
| @unselected_users | Array<User> | 未選択ユーザー一覧 |

### 出力先

- データベース（boards, accessesテーブル）
- リダイレクト（ボード設定画面またはルート画面）

## 処理フロー

### 処理シーケンス

```
1. ボード編集画面表示（BoardsController#edit）
   └─ set_boardでボード取得
   └─ ensure_permission_to_admin_boardで権限チェック
   └─ ユーザー一覧を選択済み/未選択で分割
2. ボード更新（BoardsController#update）
   └─ ensure_permission_to_admin_boardで権限チェック
   └─ @board.update!でボード設定更新
   └─ grantees_changed?でユーザー変更判定
   └─ accesses.reviseでアクセス権更新
3. リダイレクト
   └─ アクセス権残存: ボード設定画面へ
   └─ アクセス権喪失: ルート画面へ
```

### フローチャート

```mermaid
flowchart TD
    A[ボード編集画面] --> B{管理者権限?}
    B -->|No| C[403 Forbidden]
    B -->|Yes| D[設定変更]
    D --> E[更新ボタン]
    E --> F[@board.update!]
    F --> G{user_ids変更?}
    G -->|Yes| H[accesses.revise]
    G -->|No| I[スキップ]
    H --> J{自分にアクセス権残存?}
    I --> J
    J -->|Yes| K[ボード設定画面へリダイレクト]
    J -->|No| L[ルート画面へリダイレクト]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 管理者権限 | can_administer_board?がtrueのユーザーのみ編集可能 | 編集・更新時 |
| BR-002 | アクセス権付与 | 指定されたユーザーにアクセス権を付与 | user_ids指定時 |
| BR-003 | アクセス権取り消し | 指定されなかったユーザーからアクセス権を取り消し | user_ids指定時 |
| BR-004 | all_accessの場合 | all_access時はアクセス権取り消しをスキップ | all_access=true |
| BR-005 | 自己アクセス権喪失 | 自分のアクセス権を失った場合はルートへリダイレクト | 更新後 |

### 計算ロジック

- grantees: account.users.active.where(id: user_ids)
- revokees: board.users.where.not(id: user_ids)

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ボード更新 | boards | UPDATE | ボード設定更新 |
| アクセス権付与 | accesses | INSERT | 新規ユーザーへのアクセス権付与 |
| アクセス権取り消し | accesses | DELETE | 指定外ユーザーのアクセス権削除 |

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

#### boards

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | 入力された名前 | |
| UPDATE | all_access | 入力された値 | |
| UPDATE | auto_postpone_period | 入力された期間 | |
| UPDATE | public_description | 入力された説明文 | |

#### accesses

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | board_id, user_id, account_id | 付与対象ユーザー | insert_allで一括 |
| DELETE | user_id | 取り消し対象ユーザー | revoke_from |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | 管理者権限なし | 403レスポンス |
| 404 | Not Found | ボードが存在しないまたはアクセス権なし | 404画面表示 |
| 422 | バリデーションエラー | 入力値不正 | エラーメッセージ表示 |

### リトライ仕様

該当なし

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

- accesses.revise: トランザクション内で付与と取り消しを実行
- all_accessの場合は取り消しをスキップ

## パフォーマンス要件

- insert_all: アクセス権の一括付与
- 大量ユーザーの場合も効率的に処理

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

- 管理者権限チェック: ensure_permission_to_admin_boardで厳格にチェック
- 自己アクセス権喪失: 適切にリダイレクト処理

## 備考

- editアクションでユーザーを選択済み/未選択で分割
- all_access=trueの場合、revoke_fromはスキップされる（アクセス権は全員に維持）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | board.rb | `app/models/board.rb` | Boardモデルの構造 |
| 1-2 | accessible.rb | `app/models/board/accessible.rb` | アクセス権管理、reviseメソッド |

**読解のコツ**: accesses関連のreviseメソッドはhas_manyのブロック内で定義されている。

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

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

**主要処理フロー**:
1. **5行目**: ensure_permission_to_admin_boardでの権限チェック
2. **37-41行目**: editアクションでユーザー分割
3. **43-57行目**: updateアクションの実装
4. **44-45行目**: update!とrevise
5. **47-54行目**: リダイレクト分岐

#### Step 3: アクセス権管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | accessible.rb | `app/models/board/accessible.rb` | revise, grant_to, revoke_fromメソッド |

**主要処理フロー**:
- **6-10行目**: reviseメソッドでgrant_to, revoke_from呼び出し
- **12-14行目**: grant_toでinsert_all
- **16-18行目**: revoke_fromでdestroy_by（all_access時はスキップ）

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

```
BoardsController#update
    │
    ├─ ensure_permission_to_admin_board
    │      └─ Current.user.can_administer_board?(@board)
    │
    ├─ @board.update!(board_params)
    │
    └─ [grantees_changed?] @board.accesses.revise(granted:, revoked:)
           │
           ├─ grant_to(grantees)
           │      └─ Access.insert_all([...])
           │
           └─ revoke_from(revokees)
                  └─ [!all_access?] destroy_by(user: users)
```

### データフロー図

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

name ─────────────────▶ BoardsController#update
all_access                    │
auto_postpone_period          ├──▶ @board.update! ──────────▶ Board更新（DB）
public_description            │
                              │
user_ids ─────────────────────▶ accesses.revise ─────────────▶ Access更新（DB）
                              │                                 │
                              │                                 ├──▶ grant_to
                              │                                 │
                              └──▶ accessible_to? ──────────────▶ リダイレクト先判定
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| boards_controller.rb | `app/controllers/boards_controller.rb` | コントローラー | ボード編集処理 |
| board.rb | `app/models/board.rb` | モデル | ボードモデル |
| accessible.rb | `app/models/board/accessible.rb` | コンサーン | アクセス権管理 |
| access.rb | `app/models/access.rb` | モデル | アクセス権モデル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
