# 画面設計書 144-グループメンバー一覧

## 概要

本ドキュメントは、GitLabにおけるグループメンバー一覧画面の設計仕様を定義するものである。グループに所属するメンバーの一覧表示、招待、権限管理などを行うための画面を提供する。

### 本画面の処理概要

グループメンバー一覧画面は、グループに所属するメンバーの管理を行う画面である。直接メンバー、招待中メンバー、アクセスリクエスト中のメンバー、継承メンバー（親グループから）などをカテゴリ別に表示し、メンバーの招待、権限変更、削除などの操作を提供する。

**業務上の目的・背景**：グループ運用において、適切なアクセス制御とメンバー管理は重要である。この画面では、誰がどのような権限でグループにアクセスできるかを一元的に把握し、必要に応じてメンバーの追加・削除・権限変更を行える。LDAP連携環境では同期状態の確認も可能。セキュリティ監査やコンプライアンス対応においても、メンバー一覧は重要な情報源となる。

**画面へのアクセス方法**：以下のいずれかの方法でアクセス可能である。
- グループ詳細画面のサイドバーから「Manage > Members」を選択
- URL直接アクセス: `/groups/{group_path}/-/group_members`
- グループ設定メニューからアクセス

**主要な操作・処理内容**：
1. 直接メンバーの一覧表示（ページネーション、検索、フィルタリング）
2. 招待中メンバーの一覧表示
3. アクセスリクエストの承認/拒否
4. 新規メンバーの招待（ユーザー単体、グループ招待）
5. メンバーの権限（ロール）変更
6. メンバーの有効期限設定
7. メンバーの削除/退出

**画面遷移**：
- 遷移元：グループ詳細画面、グループサイドバー
- 遷移先：ユーザープロフィール、グループ招待モーダル

**権限による表示制御**：
- Guest：メンバー一覧の閲覧のみ（read_group_member権限）
- Developer以上：アクセスリクエスト送信可能
- Maintainer以上：メンバー招待、権限変更、削除が可能（admin_group_member権限）
- Owner：全機能へのフルアクセス

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 85 | グループメンバー管理 | 主機能 | グループメンバーの一覧表示 |
| 86 | 招待機能 | 補助機能 | メンバー招待処理 |

## 画面種別

一覧

## URL/ルーティング

- パス: `/groups/{group_path}/-/group_members`
- ルーティング: `groups/group_members#index`
- HTTPメソッド: GET

## 入出力項目

| 項目名 | 種別 | 必須 | データ型 | 説明 |
|--------|------|------|----------|------|
| page | クエリパラメータ | 任意 | Integer | ページ番号（メンバー一覧） |
| invited_members_page | クエリパラメータ | 任意 | Integer | ページ番号（招待メンバー） |
| sort | クエリパラメータ | 任意 | String | ソート順（name_asc等） |
| search | クエリパラメータ | 任意 | String | メンバー検索クエリ |
| search_invited | クエリパラメータ | 任意 | String | 招待メール検索クエリ |
| two_factor | クエリパラメータ | 任意 | String | 2FA有効/無効フィルタ |
| user_type | クエリパラメータ | 任意 | String | ユーザータイプフィルタ |
| max_role | クエリパラメータ | 任意 | Integer | 最大ロールフィルタ |

## 表示項目

| 項目名 | データ型 | 説明 | 表示条件 |
|--------|----------|------|----------|
| ページヘッダー | Component | タイトルとメンバーガイドライン | 常時 |
| 招待ボタン（グループ） | Button | グループ招待ボタン | create_group_link権限 |
| 招待ボタン（メンバー） | Button | メンバー招待ボタン | invite権限 |
| メンバーリスト | Vue App | メンバー一覧（Vueコンポーネント） | 常時 |
| 招待メンバーリスト | List | 招待中メンバー一覧 | admin_group_member権限 |
| アクセスリクエスト | List | リクエスト一覧 | 常時 |
| ブロックメンバー | List | ブロックされたメンバー | EE機能 |
| LDAPシンクステータス | Component | LDAP同期状態 | LDAP有効時 |
| プレースホルダーユーザー数 | Counter | インポート中ユーザー数 | インポート時 |

## イベント仕様

### 1-メンバー一覧表示（GET）

1. `authorize_read_group_member!`による閲覧権限チェック
2. ソート順の決定（デフォルト: name_asc）
3. `GroupMembersFinder`によるメンバー取得
4. `include_relations`パラメータで継承メンバー含む/含まないを制御
5. admin_group_member権限がある場合、招待中メンバーも取得
6. `AccessRequestsFinder`によるアクセスリクエスト取得
7. `present_members`でプレゼンター適用
8. プレースホルダーユーザー数の取得（インポート機能用）

### 2-メンバー招待

1. 招待モーダル（Vue）の表示
2. メールアドレスまたはユーザー名の入力
3. ロールと有効期限の選択
4. `Members::InviteService`による招待処理
5. 招待メール送信

### 3-権限変更（PATCH/PUT）

1. `authorize_admin_group_member!`による権限チェック
2. 新しいアクセスレベルの検証
3. `Members::UpdateService`によるメンバー更新
4. 変更通知の送信

### 4-メンバー削除（DELETE）

1. 権限チェック
2. `Members::DestroyService`によるメンバー削除
3. 関連する権限の即時失効

### 5-アクセスリクエスト承認/拒否

1. リクエストの取得
2. 承認時：`Members::ApproveAccessRequestService`
3. 拒否時：`Members::DestroyService`

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 一覧表示 | members | SELECT | グループメンバー取得 |
| 一覧表示 | users | SELECT | ユーザー情報取得 |
| メンバー招待 | members | INSERT | メンバーレコード作成 |
| 権限変更 | members | UPDATE | access_level更新 |
| メンバー削除 | members | DELETE | メンバーレコード削除 |
| アクセスリクエスト | members | UPDATE | requested_at更新 |

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

#### members

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | user_id, access_level, expires_at | source_type='Namespace', source_id=group_id | グループメンバー |
| INSERT | user_id | 招待対象ユーザーID | 新規メンバー |
| INSERT | access_level | 選択されたロール | 10:Guest〜50:Owner |
| INSERT | invite_email | 招待メールアドレス | メール招待時 |
| INSERT | expires_at | 選択された有効期限 | 任意 |
| UPDATE | access_level | 新しいロール | 権限変更時 |
| DELETE | - | member_id | メンバー削除時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 成功 | Member was successfully added. | メンバー追加成功時 |
| MSG-002 | 成功 | Members were successfully added. | 複数メンバー追加成功時 |
| MSG-003 | 成功 | Access request approved. | リクエスト承認時 |
| MSG-004 | 成功 | Member was successfully removed. | メンバー削除時 |
| MSG-005 | エラー | You cannot change the owner of a personal namespace. | 権限変更不可時 |

## 例外処理

| 例外条件 | 処理内容 | 遷移先 |
|----------|----------|--------|
| 閲覧権限なし | 403エラー | アクセス拒否画面 |
| メンバー不存在 | 404エラー | エラーページ |
| 最後のOwner削除 | エラーメッセージ表示 | 同画面 |
| 自分自身のOwner権限変更 | エラーメッセージ表示 | 同画面 |

## 備考

- メンバーリストはVueコンポーネント（`js-group-members-list-app`）でレンダリング
- ページネーションは1ページあたり50件（MEMBER_PER_PAGE_LIMIT）
- 継承メンバー（親グループから）も表示可能（include_relations パラメータ）
- LDAPシンクが有効な場合、同期状態の表示と手動シンクが可能（EE機能）
- ブロックメンバー一覧はEE機能

---

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

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

### 推奨読解順序

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

グループメンバーの構造とユーザーとの関連を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | member.rb | `app/models/member.rb` | メンバー基底クラス、access_level定義 |
| 1-2 | group_member.rb | `app/models/group_member.rb` | グループメンバー固有の実装 |
| 1-3 | group.rb | `app/models/group.rb` | has_many :group_members関連 |

**読解のコツ**: `access_level`のenum定義（GUEST=10, REPORTER=20, DEVELOPER=30, MAINTAINER=40, OWNER=50）を把握。

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

コントローラーの`index`アクションがエントリーポイント。

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

**主要処理フロー**:
1. **27-47行目**: indexアクションの定義
2. **28行目**: ソート順の決定
3. **29行目**: include_relationsの取得
4. **31-39行目**: admin権限時は招待中メンバーも取得
5. **41行目**: 非招待メンバーの取得とプレゼント
6. **44-46行目**: アクセスリクエストの取得

#### Step 3: ファインダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | group_members_finder.rb | `app/finders/group_members_finder.rb` | メンバー検索ロジック |
| 3-2 | access_requests_finder.rb | `app/finders/access_requests_finder.rb` | アクセスリクエスト検索 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.html.haml | `app/views/groups/group_members/index.html.haml` | メインテンプレート |

**主要処理フロー**:
- **6-24行目**: 管理者向けヘッダーとアクションボタン
- **26行目**: グループ招待モーダル
- **30-39行目**: Vueアプリケーションマウントポイント（group_members_app_data）

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

```
Groups::GroupMembersController#index
    │
    ├─ authorize_read_group_member! (before_action)
    │
    ├─ @sort 設定
    │
    ├─ @include_relations 設定 (requested_relations)
    │
    ├─ members (private method)
    │      └─ GroupMembersFinder.new(@group, current_user, params).execute
    │
    ├─ [admin_group_member権限時]
    │      ├─ invited_members
    │      │      └─ members.invite.with_invited_user_state
    │      └─ present_invited_members
    │
    ├─ non_invited_members
    │      └─ members.non_invite
    │
    ├─ present_group_members
    │      └─ present_members (pagination, プレゼンター適用)
    │
    ├─ placeholder_users_count
    │      └─ Import::SourceUsersFinder
    │
    └─ @requesters
           └─ AccessRequestsFinder.new(@group).execute(current_user)
```

### データフロー図

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

Request params ──────────▶ GroupMembersController ──────▶ HTML Response
(page, sort, search)              │                       (Vue App mount)
                                  │
                                  ├── GroupMembersFinder
                                  │        │
                                  │        ▼
                                  │   members table (SELECT)
                                  │        │
                                  │        ▼
                                  │   users table (JOIN)
                                  │
                                  ├── AccessRequestsFinder
                                  │        │
                                  │        ▼
                                  │   members table (requested_at IS NOT NULL)
                                  │
                                  └── group_members_app_data (JSON)
                                           │
                                           ▼
                                      Vue Application
                                      (メンバーリスト表示)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| group_members_controller.rb | `app/controllers/groups/group_members_controller.rb` | コントローラー | indexアクション定義 |
| group_member.rb | `app/models/group_member.rb` | モデル | グループメンバーデータ構造 |
| member.rb | `app/models/member.rb` | モデル | メンバー基底クラス |
| index.html.haml | `app/views/groups/group_members/index.html.haml` | ビュー | メインテンプレート |
| group_members_finder.rb | `app/finders/group_members_finder.rb` | ファインダー | メンバー検索 |
| access_requests_finder.rb | `app/finders/access_requests_finder.rb` | ファインダー | アクセスリクエスト検索 |
| members_presentation.rb | `app/controllers/concerns/members_presentation.rb` | Concern | プレゼンター適用 |
| group_members_helper.rb | `app/helpers/group_members_helper.rb` | ヘルパー | Vueデータ生成 |
