# 画面設計書 124-メンバー一覧

## 概要

本ドキュメントは、GitLabプロジェクトにおけるメンバー一覧画面の設計仕様を定義するものです。

### 本画面の処理概要

メンバー一覧画面は、プロジェクトに所属するメンバーの一覧表示と管理を行うための画面です。直接追加されたメンバー、グループ経由で継承されたメンバー、招待中のメンバー、アクセス要求中のメンバーを確認できます。また、新規メンバーの招待やグループの追加も本画面から実行可能です。

**業務上の目的・背景**：プロジェクトへのアクセス管理は、ソフトウェア開発におけるセキュリティと協働の両立に不可欠です。本画面は、プロジェクト管理者がメンバーの追加・削除・ロール変更を行い、適切なアクセス制御を実現するために必要です。直接メンバーとグループ経由のメンバーを区別して表示することで、アクセス権限の出所を明確にし、監査やコンプライアンス要件にも対応します。

**画面へのアクセス方法**：プロジェクトのサイドメニューから「管理」→「メンバー」を選択してアクセスします。URLパターンは `/:namespace/:project/-/project_members` です。

**主要な操作・処理内容**：
1. プロジェクトメンバー一覧の表示（直接メンバー、継承メンバー）
2. メンバーの検索・フィルタリング
3. 新規メンバーの招待
4. グループの招待（共有）
5. 他プロジェクトからのメンバーインポート
6. メンバーのロール変更
7. メンバーの削除（退会処理）
8. アクセス要求の承認・拒否
9. 招待の再送・取り消し

**画面遷移**：プロジェクトメニューから直接遷移。メンバー招待ダイアログ、グループ招待ダイアログ、メンバーインポートダイアログがモーダルとして表示されます。

**権限による表示制御**：閲覧は全メンバーが可能。メンバー管理機能（招待、削除、ロール変更等）は`admin_project_member`権限を持つユーザー（Owner, Maintainer）のみ利用可能。招待メンバーやアクセス要求者の表示も管理者権限が必要です。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 84 | プロジェクトメンバー管理 | 主機能 | プロジェクトメンバーの一覧表示 |
| 86 | 招待機能 | 補助機能 | メンバー招待 |

## 画面種別

一覧

## URL/ルーティング

- パス: `/:namespace/:project/-/project_members`
- コントローラー: `Projects::ProjectMembersController#index`
- HTTPメソッド: GET

## 入出力項目

### 検索・フィルターフォーム

| 項目名 | 項目ID | 入出力 | 型 | 必須 | 説明 |
|--------|--------|--------|-----|------|------|
| 検索キーワード | search | 入力 | string | - | メンバー名・ユーザー名での検索 |
| グループ検索 | search_groups | 入力 | string | - | グループ名での検索 |
| 最大ロール | max_role | 入力 | select | - | ロールでのフィルタリング |

## 表示項目

### メンバー一覧

| 項目名 | 説明 |
|--------|------|
| アバター | ユーザーのプロフィール画像 |
| 名前 | ユーザーの表示名 |
| ユーザー名 | @ユーザー名 |
| ソース | アクセス権限の出所（直接、継承グループ名等） |
| 有効期限 | アクセス有効期限（設定されている場合） |
| ロール | Guest, Reporter, Developer, Maintainer, Owner |
| 最終アクティビティ | 最終ログイン日時 |
| 操作 | 編集・削除ボタン |

### 招待中メンバー一覧

| 項目名 | 説明 |
|--------|------|
| メールアドレス | 招待したメールアドレス |
| 招待者 | 招待を送信したユーザー |
| ロール | 招待時に設定したロール |
| 招待日 | 招待メール送信日 |
| 状態 | 招待状態（pending等） |
| 操作 | 再送・削除ボタン |

### アクセス要求一覧

| 項目名 | 説明 |
|--------|------|
| アバター | 要求者のプロフィール画像 |
| 名前 | 要求者の表示名 |
| 要求日 | アクセス要求日 |
| 操作 | 承認・拒否ボタン |

## イベント仕様

### 1-メンバー招待

「Invite members」ボタン押下時の処理:

1. メンバー招待モーダルダイアログを表示
2. ユーザー選択またはメールアドレス入力
3. ロール選択
4. 有効期限設定（オプション）
5. 招待実行
6. 成功時: 招待中メンバー一覧に追加、招待メール送信
7. 画面リロード

### 2-グループ招待

「Invite a group」ボタン押下時の処理:

1. グループ招待モーダルダイアログを表示
2. グループ選択
3. ロール選択
4. 有効期限設定（オプション）
5. グループリンク作成
6. 成功時: 画面リロード

### 3-メンバーインポート

「Import members」トリガー押下時の処理:

1. インポートモーダルダイアログを表示
2. ソースプロジェクト選択
3. インポート実行
4. 成功時: 画面リロード

### 4-ロール変更

メンバーのロールドロップダウン変更時:

1. 確認処理
2. APIでロール更新
3. 成功時: 即座に反映

### 5-メンバー削除

削除ボタン押下時の処理:

1. 確認ダイアログ表示
2. APIでメンバー削除
3. 成功時: 一覧から削除

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| メンバー招待 | members | INSERT | メンバーレコードの作成 |
| メンバー招待 | users | INSERT | 新規ユーザーの場合 |
| グループ招待 | project_group_links | INSERT | グループリンクの作成 |
| ロール変更 | members | UPDATE | access_levelの更新 |
| メンバー削除 | members | DELETE | メンバーレコードの削除 |
| アクセス要求承認 | members | UPDATE | requested_atをnullに、access_levelを設定 |
| アクセス要求拒否 | members | DELETE | メンバーレコードの削除 |

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

#### members

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | 招待ユーザーID | 既存ユーザーの場合 |
| INSERT | source_id | プロジェクトID | |
| INSERT | source_type | 'Project' | |
| INSERT | access_level | 選択したロール値 | 10-50 |
| INSERT | expires_at | 設定した有効期限 | オプション |
| INSERT | invite_email | 招待メールアドレス | 新規招待の場合 |
| UPDATE | access_level | 新しいロール値 | ロール変更時 |

#### project_group_links

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | project_id | プロジェクトID | |
| INSERT | group_id | 招待グループID | |
| INSERT | group_access | 選択したロール値 | |
| INSERT | expires_at | 設定した有効期限 | オプション |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|-----------|----------|
| 成功 | Members were successfully added. | メンバー追加成功時 |
| 成功 | Group link was created. | グループリンク作成成功時 |
| 成功 | User was successfully removed. | メンバー削除成功時 |
| 成功 | Access request approved. | アクセス要求承認時 |
| 情報 | Members can be added by project Maintainers or Owners | 招待権限がない場合 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| 権限不足 | 管理機能を非表示、一覧のみ表示 |
| プロジェクト共有不可設定 | グループ招待機能を非表示 |
| 自分自身の削除 | leave機能へ誘導 |

## 備考

- メンバー一覧はJavaScriptアプリケーション（Vue.js）でレンダリング
- ページネーションはAPIベースで実装
- 直接メンバーと継承メンバーは`include_relations`パラメータで切り替え表示
- メンバーガイドラインが設定されている場合は画面上部に表示される
- 昇格保留中のメンバー数も表示される（EE機能）

---

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

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

### 推奨読解順序

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

メンバー管理に関連するデータモデルを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | member.rb | `app/models/member.rb` | Memberモデルの基本構造、access_level定義 |
| 1-2 | project_member.rb | `app/models/project_member.rb` | プロジェクトメンバー固有の実装 |
| 1-3 | project_group_link.rb | `app/models/project_group_link.rb` | グループ共有の関連 |

**読解のコツ**: access_levelは数値で管理され、10(Guest), 20(Reporter), 30(Developer), 40(Maintainer), 50(Owner)となります。

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

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

**主要処理フロー**:
1. **10行目**: `authorize_admin_project_member!` - 管理権限チェック（except: [:index, :leave, :request_access]）
2. **15-27行目**: `index`アクション - メンバー一覧取得ロジック
3. **17行目**: `requested_relations` - 直接/継承メンバーの切り替え

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.html.haml | `app/views/projects/project_members/index.html.haml` | メインビューの構成 |

**主要処理フロー**:
- **7-38行目**: ヘッダーセクション（招待ボタン群）
- **39-47行目**: Vue.jsアプリケーションマウントポイント

#### Step 4: フロントエンドの構成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | project_members_app_data_json | Helperメソッド | Vue.jsに渡すデータ構造 |

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

```
Projects::ProjectMembersController#index
    │
    ├─ @sort = pagination_params[:sort] || sort_value_name
    │
    ├─ @include_relations = requested_relations(:groups_with_inherited_permissions)
    │
    ├─ members (MembersFinder)
    │      ├─ invited_members (権限があれば)
    │      ├─ non_invited_members
    │      └─ requesters (権限があれば)
    │
    ├─ group_member_links (Featureフラグ有効時)
    │      ├─ project_group_links
    │      └─ group_group_links
    │
    └─ View: index.html.haml
           └─ .js-project-members-list-app (Vue.js)
                  └─ project_members_app_data_json
```

### データフロー図

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

検索/フィルタ ───▶ MembersFinder ───▶ Memberコレクション
                        │
                        ├─ non_invite (通常メンバー)
                        ├─ invite (招待中)
                        └─ AccessRequestsFinder (要求者)

招待フォーム ───▶ Members::InviteService ───▶ members (INSERT)
                                                 │
                                                 └─ 招待メール送信

グループ招待 ───▶ ProjectGroupLink.create ───▶ project_group_links (INSERT)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| project_members_controller.rb | `app/controllers/projects/project_members_controller.rb` | コントローラー | メインコントローラー |
| membership_actions.rb | `app/controllers/concerns/membership_actions.rb` | Concern | CRUD共通処理 |
| index.html.haml | `app/views/projects/project_members/index.html.haml` | ビュー | メインビュー |
| member.rb | `app/models/member.rb` | モデル | 基底メンバーモデル |
| project_member.rb | `app/models/project_member.rb` | モデル | プロジェクトメンバー |
| project_group_link.rb | `app/models/project_group_link.rb` | モデル | グループリンク |
| members_finder.rb | `app/finders/members_finder.rb` | Finder | メンバー検索 |
| invite_service.rb | `app/services/members/invite_service.rb` | サービス | 招待処理 |
