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

## 概要

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

### 本画面の処理概要

ユーザー検索プロンプト画面は、テキスト入力フィールドでユーザーを検索・選択するためのオートコンプリート機能を提供するAPI画面である。主にリッチテキストエディタ内でユーザーをメンション（@）する際に使用され、アカウント内のアクティブなユーザーをアルファベット順で表示する。

**業務上の目的・背景**：カードやコメント内で特定のユーザーに言及することは、タスク管理において重要なコミュニケーション手段である。「@」に続けてユーザー名の一部を入力することで、ユーザー候補をリアルタイムに絞り込み、メンションを挿入できる。メンションされたユーザーには通知が送信されるため、確実な情報伝達が可能となる。

**画面へのアクセス方法**：リッチテキストエディタ（Lexxyエディタ）内で「@」を入力するとプロンプトが表示される。URLは `/prompts/users` であり、Ajax（Fetch API）経由で非同期に呼び出される。

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

**画面遷移**：
- 遷移元：カード編集画面、コメント入力欄等のリッチテキストエディタ
- 遷移先：なし（ユーザーメンションがエディタに挿入される）

**権限による表示制御**：認証必須。同一アカウント内のアクティブユーザーのみが表示される。

## 関連機能

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

## 画面種別

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

## URL/ルーティング

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

## 入出力項目

### 入力項目

本APIはパラメータを受け取らない（全アクティブユーザーを返却）。

### 出力項目

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

## 表示項目

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

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

## イベント仕様

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

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

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

### 2-ユーザー選択

候補リストからユーザーを選択すると、エディタにユーザーメンションが挿入される。

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

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

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ユーザー一覧取得 | users | SELECT | アカウント内アクティブユーザーの取得 |

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

#### users（参照のみ）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name | account_id = Current.account.id AND active = true | alphabeticallyスコープ適用 |

## メッセージ仕様

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

## 例外処理

| 条件 | 処理内容 |
|------|---------|
| 未認証アクセス | ログイン画面へリダイレクト |

## 備考

- レイアウトなし（`render layout: false`）
- ETagベースのキャッシュを使用（`stale? etag: @users`）
- 全アクティブユーザーを返却し、フロントエンドで `search` 属性を使ってフィルタリング
- search属性には「名前 イニシャル me（自分の場合）」が含まれ、多様な検索方法に対応
- `attachable_sgid` はActionTextでユーザーをリッチテキストに埋め込むために使用
- パーシャルは `prompts/boards/users/_user.html.erb` を共用

---

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

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

### 推奨読解順序

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

ユーザーモデルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | Userモデルの定義、Named/Attachableモジュール |
| 1-2 | named.rb | `app/models/user/named.rb` | alphabeticallyスコープ（5行目）、initials/first_nameメソッド |

**読解のコツ**: `Named` モジュールにより `alphabetically`、`first_name`、`initials` などのメソッドが提供される。

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

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

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

**主要処理フロー**:
1. **3行目**: `@users = Current.account.users.active.alphabetically` - アクティブユーザーをアルファベット順で取得
2. **5-7行目**: ETagキャッシュ確認、変更がない場合は304を返却

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.erb | `app/views/prompts/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` 要素の生成
  - search属性: `#{user.name} #{user.initials} #{"me" if user == Current.user}`
  - sgid属性: `user.attachable_sgid`
  - menu: アバター + フルネーム
  - editor: アバター + ファーストネーム

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

```
Prompts::UsersController#index
    │
    ├─ Current.account.users.active.alphabetically
    │      │
    │      ├─ User.active
    │      │      └─ where(active: true)
    │      │
    │      └─ User::Named.alphabetically
    │             └─ order("lower(name)")
    │
    └─ stale? etag: @users
           │
           └─ render layout: false
                  │
                  └─ index.html.erb
                         └─ prompts/boards/users/_user.html.erb (collection)
```

### データフロー図

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

(なし) ─────▶ Prompts::UsersController#index
                       │
                       ▼
              Current.account.users.active.alphabetically
                       │
                       ▼
                   @users
                       │
                       ▼
               index.html.erb
                       │
                       ▼
              lexxy-prompt-item (HTML)
                       │
                       ▼
              フロントエンド
              (search属性でフィルタリング)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| users_controller.rb | `app/controllers/prompts/users_controller.rb` | コントローラー | リクエストハンドリング |
| index.html.erb | `app/views/prompts/users/index.html.erb` | テンプレート | メインビュー |
| _user.html.erb | `app/views/prompts/boards/users/_user.html.erb` | パーシャル | ユーザー候補アイテム（共用） |
| user.rb | `app/models/user.rb` | モデル | ユーザーモデル |
| named.rb | `app/models/user/named.rb` | Concern | 名前関連機能 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（185行目） |
