# 機能設計書 111-ユーザー管理

## 概要

本ドキュメントは、GitLab管理画面におけるユーザー管理機能の設計仕様を記述する。システム管理者が全ユーザーの一覧表示、詳細閲覧、作成、編集、削除、状態管理（ブロック/アンブロック/Ban/承認等）を行うための機能である。

### 本機能の処理概要

**業務上の目的・背景**：GitLabインスタンスを運用する上で、システム管理者は全ユーザーを一元的に管理する必要がある。ユーザーの作成・編集・削除に加え、セキュリティ上の理由でユーザーをブロックしたり、不正利用者をBanしたり、新規登録ユーザーの承認を行うなど、多様な管理操作が求められる。本機能はこれらの管理業務を効率的に行うための中核機能である。

**機能の利用シーン**：
- 新入社員のGitLabアカウント作成時
- 退職者のアカウント削除・ブロック時
- セキュリティインシデント発生時のユーザーBan処理
- 自己登録ユーザーの承認待ち対応
- ユーザー情報の一括確認・検索

**主要な処理内容**：
1. ユーザー一覧の表示（フィルタリング、検索、ソート、ページネーション対応）
2. ユーザー詳細情報の表示（プロジェクト参加状況、SSHキー一覧等）
3. 新規ユーザーの作成（パスワードリセットメール送信含む）
4. 既存ユーザー情報の編集（プロファイル、権限、クレジットカード検証状態等）
5. ユーザーの削除（非同期削除、ゴーストユーザーへの移行）
6. ユーザー状態管理（activate/deactivate、block/unblock、ban/unban、trust/untrust）
7. ユーザー承認・却下（pending approval状態のユーザー対応）
8. ユーザーの偽装（impersonate）機能
9. 2要素認証の無効化
10. ユーザーメールの削除

**関連システム・外部連携**：
- LDAP連携（LDAPブロックされたユーザーは手動でアンブロック不可）
- メール通知システム（パスワードリセット通知、アカウント作成通知）
- 監査ログシステム（偽装操作のログ記録）

**権限による制御**：
- 本機能は管理者（Admin）権限を持つユーザーのみがアクセス可能
- 偽装機能は設定（`Gitlab.config.gitlab.impersonation_enabled`）で有効/無効を制御可能
- 内部ユーザー（bot等）はブロック対象外

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 224 | ユーザー一覧 | 主画面 | 管理者向けユーザー一覧表示、フィルタ・検索・ソート |
| 225 | ユーザー詳細 | 主画面 | ユーザー詳細情報、プロジェクト参加状況、SSHキー表示 |
| 226 | ユーザー新規作成 | 主画面 | 新規ユーザーアカウント作成フォーム |
| 227 | ユーザー編集 | 主画面 | ユーザー情報編集フォーム |
| 228 | アイデンティティ一覧 | 補助画面 | ユーザーアイデンティティ（外部認証連携）の管理 |
| 229 | アイデンティティ新規作成 | 補助画面 | 外部アイデンティティの追加 |
| 230 | アイデンティティ編集 | 補助画面 | 外部アイデンティティの編集 |
| 231 | SSHキー詳細 | 補助画面 | ユーザーSSHキーの詳細表示 |

## 機能種別

CRUD操作 / ユーザー状態管理 / 認証・認可制御

## 入力仕様

### 入力パラメータ

#### ユーザー作成・編集時

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ユーザー名（表示名） | 最大127文字 |
| username | String | Yes | ユーザーID | 2〜255文字、英数字とアンダースコア |
| email | String | Yes | メールアドレス | 有効なメールアドレス形式 |
| password | String | No | パスワード（編集時のみ） | ポリシーに準拠 |
| access_level | String | No | アクセスレベル | admin/regular |
| projects_limit | Integer | No | 作成可能プロジェクト数上限 | 0以上の整数 |
| can_create_group | Boolean | No | グループ作成権限 | true/false |
| external | Boolean | No | 外部ユーザーフラグ | true/false |
| private_profile | Boolean | No | プロファイル非公開 | true/false |
| avatar | File | No | アバター画像 | 画像ファイル |
| bio | String | No | 自己紹介 | テキスト |
| linkedin/twitter/github等 | String | No | SNSリンク | URL形式 |
| organization_id | Integer | No | 所属組織ID | 有効な組織ID |
| note | String | No | 管理者メモ | テキスト |

#### ユーザー一覧検索時

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| search_query | String | No | 検索キーワード | 名前、ユーザー名、メールで検索 |
| filter | String | No | フィルタ条件 | admins/blocked/two_factor_disabled等 |
| sort | String | No | ソート条件 | name_asc/name_desc/created_asc等 |
| page | Integer | No | ページ番号 | 正の整数 |

### 入力データソース

- 画面入力（ユーザー作成・編集フォーム）
- URLパラメータ（検索・フィルタ条件）
- セッション情報（現在の管理者ユーザー）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| users | Array[User] | ユーザー一覧データ |
| user | User | 個別ユーザー詳細データ |
| personal_projects | Array[Project] | ユーザーの個人プロジェクト |
| joined_projects | Array[Project] | 参加プロジェクト |
| group_members | Array[GroupMember] | グループメンバーシップ |
| keys | Array[Key] | SSHキー一覧 |
| flash_message | String | 操作結果メッセージ |

### 出力先

- 画面表示（HTML/JSON）
- リダイレクト（操作完了後）
- メール送信（ユーザー作成時のパスワードリセット通知）

## 処理フロー

### 処理シーケンス

```
1. ユーザー一覧表示（index）
   └─ filter_users → search → sort → paginate → render
2. ユーザー詳細表示（show）
   └─ find_routable!(User) → set_shared_view_parameters → render
3. ユーザー作成（create）
   └─ Users::CreateService.new.execute → notify_new_user → redirect
4. ユーザー更新（update）
   └─ Users::UpdateService.new.execute → prepare_user_for_update → redirect
5. ユーザー削除（destroy）
   └─ ensure_destroy_prerequisites_met → user.delete_async → redirect
6. ユーザーブロック（block）
   └─ Users::BlockService.new.execute → after_block_hook → redirect/json
7. 偽装開始（impersonate）
   └─ check_impersonation_availability → warden.set_user → log_impersonation_event → redirect
```

### フローチャート

```mermaid
flowchart TD
    A[管理者がユーザー管理画面にアクセス] --> B{操作種別}
    B -->|一覧表示| C[filter_users]
    C --> D[search/sort/paginate]
    D --> E[ユーザー一覧表示]

    B -->|作成| F[new画面表示]
    F --> G[フォーム入力]
    G --> H[Users::CreateService.execute]
    H --> I{成功?}
    I -->|Yes| J[notify_new_user]
    J --> K[一覧へリダイレクト]
    I -->|No| L[エラー表示]

    B -->|編集| M[edit画面表示]
    M --> N[フォーム入力]
    N --> O[Users::UpdateService.execute]
    O --> P{成功?}
    P -->|Yes| Q[詳細へリダイレクト]
    P -->|No| R[エラー表示]

    B -->|削除| S[ensure_destroy_prerequisites_met]
    S --> T{前提条件OK?}
    T -->|Yes| U[user.delete_async]
    U --> V[一覧へリダイレクト]
    T -->|No| W[エラー表示]

    B -->|ブロック| X[Users::BlockService.execute]
    X --> Y{成功?}
    Y -->|Yes| Z[詳細へリダイレクト]
    Y -->|No| AA[エラー表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-111-01 | 内部ユーザーブロック禁止 | 内部ユーザー（bot等）はブロックできない | ブロック操作時 |
| BR-111-02 | LDAPブロック解除禁止 | LDAPによりブロックされたユーザーは手動でアンブロックできない | アンブロック操作時 |
| BR-111-03 | 単独オーナーグループ確認 | 削除対象ユーザーが単独オーナーのグループがある場合、先に所有権移転または削除が必要 | 削除操作時（hard_delete=false） |
| BR-111-04 | 偽装設定確認 | 偽装機能は設定で有効化されている必要がある | 偽装操作時 |
| BR-111-05 | パスワード有効期限 | 管理者が他ユーザーのパスワードを変更した場合、即座に有効期限切れとなる | パスワード変更時 |
| BR-111-06 | ページネーション最適化 | ユーザー数が1000を超える場合、カウントなしページネーションを使用 | 一覧表示時 |

### 計算ロジック

特になし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧表示 | users | SELECT | ユーザー一覧取得（フィルタ、検索、ソート適用） |
| 詳細表示 | users, projects, keys, group_members | SELECT | ユーザー関連情報取得 |
| 作成 | users, namespaces | INSERT | 新規ユーザーと個人名前空間作成 |
| 更新 | users, identities, credit_card_validations | UPDATE | ユーザー情報更新 |
| 削除 | users, members, projects, groups | DELETE/UPDATE | ユーザー関連データ削除・移行 |
| ブロック | users, user_custom_attributes | UPDATE/INSERT | ユーザー状態更新、ブロック情報記録 |

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

#### usersテーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, username, email, state, admin, created_at等 | フィルタ・検索条件に応じて | identities, trusted_with_spam_attribute含むinclude |
| INSERT | name, username, email, encrypted_password, admin等 | フォーム入力値 | skip_confirmation=true |
| UPDATE | 各プロファイル項目、state | フォーム入力値、状態変更値 | skip_reconfirmation |
| UPDATE | state | blocked/active/banned等 | 状態管理操作時 |

#### user_custom_attributesテーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPSERT | user_id, key, value | BLOCKED_BY: "username/id+timestamp" | ブロック時に記録 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | 権限エラー | 偽装機能が無効な状態で偽装を試行 | access_denied!を返す |
| 422 | バリデーションエラー | 入力値が不正 | エラーメッセージを表示して再入力を促す |
| 303 | 前提条件エラー | 単独オーナーグループがある状態で削除を試行 | エラーメッセージを表示して詳細画面にリダイレクト |
| 404 | 存在しないリソース | 指定されたユーザーが見つからない | 404エラーページ表示 |

### リトライ仕様

- ユーザー削除は非同期処理（`delete_async`）で実行され、失敗時はバックグラウンドワーカーによりリトライされる
- ゴーストユーザー移行処理は`Users::MigrateRecordsToGhostUserInBatchesWorker`により定期的に再試行される

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

- ユーザー作成・更新はサービスクラス内で単一トランザクションとして処理
- ユーザー削除は非同期処理のため、即座にコミットされ、関連データの移行は別トランザクションで処理

## パフォーマンス要件

- ユーザー一覧表示：1000件以上の場合はカウントなしページネーション（`without_count`）を使用
- 検索機能：`search`メソッドによる全文検索、`with_private_emails: true`オプションでプライベートメール検索も対応

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

- 管理者権限（Admin）が必須
- 偽装操作は`Gitlab::AppLogger`に記録される
- パスワードはDeviseによりハッシュ化して保存
- 2要素認証無効化は`TwoFactor::DestroyService`を通じて実行
- クレジットカード検証情報の操作は管理者のみ

## 備考

- 本機能はEnterprise Edition（EE）で拡張される可能性があり、`prepend_mod_with`によりモジュールが追加される
- ユーザー削除は「ハード削除」と「ソフト削除（ゴーストユーザーへの移行）」の2種類をサポート

---

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

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

### 推奨読解順序

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

まず、ユーザーモデルとその関連モデルの構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | Userモデルの属性、リレーション、バリデーション、状態管理メソッドを理解 |
| 1-2 | identity.rb | `app/models/identity.rb` | 外部認証連携（OAuth、LDAP）の構造を理解 |

**読解のコツ**: Userモデルは多数のモジュールをincludeしている。特に`HasUserType`（ユーザー種別）、`Devise`関連モジュール（認証）、状態管理関連を重点的に確認する。

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

コントローラーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | users_controller.rb | `app/controllers/admin/users_controller.rb` | 各アクション（index/show/create/update/destroy等）の処理フローを理解 |

**主要処理フロー**:
1. **16-32行目**: `index`アクション - フィルタリング、検索、ソート、ページネーション
2. **55-72行目**: `impersonate`アクション - ユーザー偽装処理とログ記録
3. **74-82行目**: `approve`アクション - ユーザー承認処理
4. **116-130行目**: `block`アクション - ユーザーブロック処理
5. **214-237行目**: `create`アクション - ユーザー作成処理
6. **239-275行目**: `update`アクション - ユーザー更新処理
7. **277-284行目**: `destroy`アクション - ユーザー削除処理

#### Step 3: サービス層を理解する

ビジネスロジックはサービスクラスに実装されている。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create_service.rb | `app/services/users/create_service.rb` | ユーザー作成ロジック、`Users::BuildService`との連携 |
| 3-2 | update_service.rb | `app/services/users/update_service.rb` | ユーザー更新ロジック、同期属性の処理、アイデンティティ更新 |
| 3-3 | destroy_service.rb | `app/services/users/destroy_service.rb` | ユーザー削除ロジック、ゴーストユーザー移行処理 |
| 3-4 | block_service.rb | `app/services/users/block_service.rb` | ユーザーブロックロジック |
| 3-5 | approve_service.rb | `app/services/users/approve_service.rb` | ユーザー承認ロジック |

**主要処理フロー**:
- **create_service.rb 12-16行目**: ユーザー作成の実行フロー
- **destroy_service.rb 39-80行目**: 削除時の単独オーナーグループ処理、個人プロジェクト削除、ゴーストユーザー移行

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

```
Admin::UsersController
    │
    ├─ index
    │      ├─ filter_users (User.filter_items)
    │      ├─ User#search
    │      └─ users_with_included_associations
    │
    ├─ create
    │      └─ Users::CreateService#execute
    │             ├─ Users::BuildService#execute
    │             ├─ User#save
    │             └─ NewUserNotifier#notify_new_user
    │
    ├─ update
    │      └─ Users::UpdateService#execute
    │             ├─ assign_attributes
    │             ├─ assign_identity
    │             └─ User#save
    │
    ├─ destroy
    │      └─ User#delete_async
    │             └─ Users::DestroyService#execute
    │                    ├─ User#block
    │                    ├─ Members#destroy_all
    │                    ├─ Groups::DestroyService#execute
    │                    ├─ Projects::DestroyService#execute
    │                    └─ Users::GhostUserMigration.create!
    │
    ├─ block
    │      └─ Users::BlockService#execute
    │             ├─ User#block
    │             └─ UserCustomAttribute.upsert_custom_attributes
    │
    └─ impersonate
           ├─ helpers.can_impersonate_user
           ├─ warden.set_user
           └─ log_impersonation_event
```

### データフロー図

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

管理者操作 ───────▶ Admin::UsersController ───────▶ HTMLレスポンス
  │                      │                              │
  │                      ▼                              │
  │               Users::*Service                       │
  │                      │                              │
  │                      ▼                              │
  │                 User Model                          │
  │                      │                              │
  └──────────────▶ users テーブル ────────────────▶ メール通知
                         │
                         ▼
                  関連テーブル
           (identities, members, projects等)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| users_controller.rb | `app/controllers/admin/users_controller.rb` | コントローラー | ユーザー管理のエントリーポイント |
| user.rb | `app/models/user.rb` | モデル | ユーザーデータモデル |
| create_service.rb | `app/services/users/create_service.rb` | サービス | ユーザー作成ロジック |
| update_service.rb | `app/services/users/update_service.rb` | サービス | ユーザー更新ロジック |
| destroy_service.rb | `app/services/users/destroy_service.rb` | サービス | ユーザー削除ロジック |
| block_service.rb | `app/services/users/block_service.rb` | サービス | ユーザーブロックロジック |
| unblock_service.rb | `app/services/users/unblock_service.rb` | サービス | ユーザーアンブロックロジック |
| ban_service.rb | `app/services/users/ban_service.rb` | サービス | ユーザーBanロジック |
| approve_service.rb | `app/services/users/approve_service.rb` | サービス | ユーザー承認ロジック |
| build_service.rb | `app/services/users/build_service.rb` | サービス | ユーザービルドロジック |
| index.html.haml | `app/views/admin/users/index.html.haml` | ビュー | ユーザー一覧画面 |
| show.html.haml | `app/views/admin/users/show.html.haml` | ビュー | ユーザー詳細画面 |
| new.html.haml | `app/views/admin/users/new.html.haml` | ビュー | ユーザー作成画面 |
| edit.html.haml | `app/views/admin/users/edit.html.haml` | ビュー | ユーザー編集画面 |
