# 画面設計書 76-ボードユーザー検索プロンプト画面

## 概要

本ドキュメントは、Fizzyアプリケーションにおける「ボードユーザー検索プロンプト画面」の設計仕様を記述したものである。

### 本画面の処理概要

ボードユーザー検索プロンプト画面は、特定のボードにアクセス権を持つユーザーを検索・選択するためのオートコンプリート機能を提供するAPI画面である。No.75のユーザー検索プロンプト画面がアカウント全体のユーザーを対象とするのに対し、本画面は指定されたボードにアクセス可能なユーザーのみを対象とする。

**業務上の目的・背景**：ボードにはアクセス制御が設定されており、全員がアクセスできるボード（all_access）と、特定のユーザーのみがアクセス可能なボードが存在する。カードへの担当者アサインや、ボード内でのユーザーメンション時には、そのボードにアクセス権を持つユーザーのみを候補として表示することで、誤った操作を防止し、ユーザー体験を向上させる。

**画面へのアクセス方法**：ボード詳細画面内のリッチテキストエディタやカードアサイン画面で使用される。URLは `/prompts/boards/:board_id/users` であり、Ajax（Fetch API）経由で非同期に呼び出される。

**主要な操作・処理内容**：
1. 指定ボードにアクセス可能なアクティブユーザーをアルファベット順で取得
2. フロントエンドでのクライアントサイドフィルタリング（名前、イニシャル、「me」による検索）
3. ユーザー選択によるメンション挿入またはアサイン

**画面遷移**：
- 遷移元：ボード詳細画面、カードアサイン画面、カード編集画面内のリッチテキストエディタ
- 遷移先：なし（ユーザーが選択されて呼び出し元に返却される）

**権限による表示制御**：認証必須。指定されたボードにアクセス可能なアクティブユーザーのみが表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 64 | ユーザー一覧表示 | 主機能 | ボード内ユーザー検索用のプロンプト |

## 画面種別

APIレスポンス画面（オートコンプリートプロンプト）

## URL/ルーティング

| パス | HTTPメソッド | コントローラ#アクション |
|------|-------------|----------------------|
| `/prompts/boards/:board_id/users` | GET | `Prompts::Boards::UsersController#index` |

## 入出力項目

### 入力項目

| 項目 | パラメータ名 | 必須 | 説明 |
|------|-------------|------|------|
| ボードID | board_id | 必須 | 対象ボードのID |

### 出力項目

| 項目 | 説明 |
|------|------|
| ユーザー候補リスト | lexxy-prompt-item要素のリスト |

## 表示項目

### ユーザー候補アイテム（lexxy-prompt-item）

| 項目 | 属性 | 説明 |
|------|------|------|
| search | 属性 | ユーザー名 + イニシャル + "me"（自分の場合） |
| sgid | 属性 | ユーザーのGlobal ID（ActionText用） |
| メニュー表示（menu） | テンプレート | アバター画像 + ユーザー名 |
| エディタ挿入時表示（editor） | テンプレート | アバター画像 + ファーストネーム |

## イベント仕様

### 1-ボードユーザー一覧取得

画面初回アクセス時にAjax経由でAPI呼び出しが行われる。

- リクエスト: `GET /prompts/boards/:board_id/users`
- レスポンス: HTMLフラグメント（lexxy-prompt-itemのリスト）

### 2-ユーザー選択

候補リストからユーザーを選択すると、エディタにユーザーメンションが挿入される、またはアサイン対象として選択される。

- 挿入形式: アバター + ファーストネーム
- sgid属性: ActionText用のGlobal ID

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

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

本画面は読み取り専用であり、データベースの更新は発生しない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ユーザー一覧取得 | users, accesses | SELECT | ボードにアクセス可能なアクティブユーザーの取得 |

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

#### users（参照のみ）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name | board.users.active | ボードアクセス権+アクティブ条件 |

## メッセージ仕様

本画面では特定のメッセージ表示はない（候補が0件の場合は空のレスポンス）。

## 例外処理

| 条件 | 処理内容 |
|------|---------|
| 未認証アクセス | ログイン画面へリダイレクト |
| ボードが存在しない | 404 Not Found |
| ボードへのアクセス権がない | 404 Not Found |

## 備考

- レイアウトなし（`render layout: false`）
- ETagベースのキャッシュを使用（`stale? etag: @users`）
- BoardScopedモジュールにより、ユーザーがアクセス可能なボードのみ対象
- 全アクティブユーザーを返却し、フロントエンドで `search` 属性を使ってフィルタリング
- No.75のユーザー検索プロンプト画面と同じパーシャル（`prompts/boards/users/_user.html.erb`）を使用

---

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

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

### 推奨読解順序

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

ボードとユーザーの関連を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | board.rb | `app/models/board.rb` | Boardモデル、Accessibleモジュールのinclude |
| 1-2 | user.rb | `app/models/user.rb` | Userモデル、Accessorモジュール |

**読解のコツ**: `Board.users` は `Accessible` モジュールによりアクセス権を持つユーザーを返す。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | users_controller.rb | `app/controllers/prompts/boards/users_controller.rb` | indexアクションの実装 |
| 2-2 | board_scoped.rb | `app/controllers/concerns/board_scoped.rb` | BoardScopedモジュール |

**主要処理フロー**:
1. **board_scoped.rb 10行目**: `@board = Current.user.boards.find(params[:board_id])` - ボード取得（アクセス権チェック含む）
2. **5行目**: `@users = @board.users.active.alphabetically` - ボードにアクセス可能なアクティブユーザーを取得
3. **7-9行目**: ETagキャッシュ確認、変更がない場合は304を返却

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

テンプレートの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.erb | `app/views/prompts/boards/users/index.html.erb` | ユーザーコレクションのレンダリング |
| 3-2 | _user.html.erb | `app/views/prompts/boards/users/_user.html.erb` | 個別ユーザーの表示形式 |

**主要処理フロー**:
- **index.html.erb 1行目**: `render partial: "prompts/boards/users/user", collection: @users`
- **_user.html.erb 1-10行目**: `lexxy-prompt-item` 要素の生成（No.75と同じ）

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

```
Prompts::Boards::UsersController#index
    │
    ├─ BoardScoped (before_action)
    │      └─ set_board
    │             └─ Current.user.boards.find(params[:board_id])
    │
    ├─ @board.users.active.alphabetically
    │      │
    │      ├─ Board#users (Accessible経由)
    │      │
    │      ├─ User.active
    │      │      └─ where(active: true)
    │      │
    │      └─ User::Named.alphabetically
    │             └─ order("lower(name)")
    │
    └─ stale? etag: @users
           │
           └─ render layout: false
                  │
                  └─ index.html.erb
                         └─ _user.html.erb (collection)
```

### データフロー図

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

board_id ──────▶ BoardScoped#set_board
                       │
                       ▼
              Current.user.boards.find(board_id)
                       │
                       ▼
                   @board
                       │
                       ▼
              @board.users.active.alphabetically
                       │
                       ▼
                   @users
                       │
                       ▼
               index.html.erb
                       │
                       ▼
              lexxy-prompt-item (HTML)
                       │
                       ▼
              フロントエンド
              (search属性でフィルタリング)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| users_controller.rb | `app/controllers/prompts/boards/users_controller.rb` | コントローラー | リクエストハンドリング |
| board_scoped.rb | `app/controllers/concerns/board_scoped.rb` | Concern | ボードスコープ共通処理 |
| index.html.erb | `app/views/prompts/boards/users/index.html.erb` | テンプレート | メインビュー |
| _user.html.erb | `app/views/prompts/boards/users/_user.html.erb` | パーシャル | ユーザー候補アイテム |
| user.rb | `app/models/user.rb` | モデル | ユーザーモデル |
| board.rb | `app/models/board.rb` | モデル | ボードモデル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（187-191行目） |
