# 画面設計書 304-ソースユーザー確認

## 概要

本ドキュメントは、GitLabのインポートソースユーザー再割り当て確認画面の設計仕様を定義する。

### 本画面の処理概要

本画面は、他のGitLabインスタンスからインポートされたコントリビューション（コミット、イシュー、マージリクエスト等）の作成者情報を、現在のGitLabインスタンスのユーザーに再割り当てする際の確認・承認を行うための画面である。インポート時に自動マッピングできなかったユーザーの貢献を、適切なユーザーに紐付けるプロセスの一部である。

**業務上の目的・背景**：異なるGitLabインスタンス間でデータを移行する際、ソースインスタンスのユーザーとインポート先インスタンスのユーザーが一致しない場合がある。このような場合、インポートされたデータは「プレースホルダーユーザー」に一時的に割り当てられる。本画面は、管理者やグループオーナーが適切なユーザーへの再割り当てを要求した際に、対象ユーザーがその要求を確認・承認できるようにするためのものである。これにより、正確なコントリビューション履歴の維持と、適切なユーザーへの帰属が保証される。

**画面へのアクセス方法**：
- 再割り当て要求時に送信されるメールのリンクから遷移
- URLに直接アクセス（トークン付き）

**主要な操作・処理内容**：
1. 再割り当て詳細情報の表示（ソースユーザー、インポート元、再割り当て先、要求者）
2. 再割り当ての承認
3. 再割り当ての拒否

**画面遷移**：
- 遷移元：メールリンク
- 遷移先：ダッシュボード（承認/拒否後）、ヘルプドキュメント

**権限による表示制御**：
- 再割り当て対象ユーザー（`reassign_to_user`）のみがアクセス可能
- ソースユーザーが`awaiting_approval`状態の場合のみ表示
- トークンが一致しない場合はアクセス不可

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 110 | バルクインポート | 主機能 | インポートソースユーザー確認 |

## 画面種別

確認・承認画面

## URL/ルーティング

| メソッド | パス | アクション | 説明 |
|---------|------|----------|------|
| GET | `/import/source_users/:namespace_id/:reassignment_token` | show | 確認画面表示（名前空間指定あり） |
| GET | `/import/source_users/:reassignment_token` | show | 確認画面表示（名前空間指定なし） |
| POST | `/import/source_users/:namespace_id/:reassignment_token/accept` | accept | 再割り当て承認 |
| POST | `/import/source_users/:namespace_id/:reassignment_token/decline` | decline | 再割り当て拒否 |
| POST | `/import/source_users/:reassignment_token/accept` | accept | 再割り当て承認（名前空間指定なし） |
| POST | `/import/source_users/:reassignment_token/decline` | decline | 再割り当て拒否（名前空間指定なし） |

## 入出力項目

### 入力項目（パスパラメータ）

| 項目名 | データ型 | 必須 | 説明 |
|--------|---------|------|------|
| namespace_id | Integer | No | 名前空間ID |
| reassignment_token | String | Yes | 再割り当てトークン（32文字） |

## 表示項目

### 再割り当て詳細

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| source_name | String | ソースユーザーの名前 |
| source_username | String | ソースユーザーのユーザー名（@付き） |
| source_hostname | String | ソースGitLabインスタンスのホスト名 |
| destination_group | String | インポート先グループ（名前とパス） |
| reassign_to_name | String | 再割り当て先ユーザーの名前 |
| reassign_to_username | String | 再割り当て先ユーザーの参照（@付き） |
| reassigned_by_name | String | 再割り当て要求者の名前 |
| reassigned_by_username | String | 再割り当て要求者の参照（@付き） |

## イベント仕様

### 1-再割り当て承認

「Approve reassignment」ボタン押下時の処理：
1. `POST /import/source_users/:namespace_id/:reassignment_token/accept`にリクエスト送信
2. `Import::SourceUsers::AcceptReassignmentService`が実行される
3. 成功時：バナー表示後、ダッシュボードへリダイレクト
4. 失敗時：エラーメッセージ表示後、ダッシュボードへリダイレクト

### 2-再割り当て拒否

「Reject」ボタン押下時の処理：
1. `POST /import/source_users/:namespace_id/:reassignment_token/decline`にリクエスト送信
2. `Import::SourceUsers::RejectReassignmentService`が実行される
3. 成功時：バナー表示後、ダッシュボードへリダイレクト
4. 失敗時：エラーメッセージ表示後、ダッシュボードへリダイレクト

### 3-ヘルプリンク

「How do I accept reassignments?」リンククリック時、ヘルプドキュメント（`/help/user/import/mapping.md#accept-contribution-reassignment`）に遷移する。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 承認 | import_source_users | UPDATE | status更新、reassignment_tokenクリア |
| 拒否 | import_source_users | UPDATE | status更新、reassignment_tokenクリア |

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

#### import_source_users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| 承認 | status | 2 (reassignment_in_progress) | 承認処理開始 |
| 承認 | reassignment_token | NULL | トークンクリア |
| 拒否 | status | 3 (rejected) | 拒否状態に変更 |
| 拒否 | reassignment_token | NULL | トークンクリア |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| MSG-304-001 | 通知 | Review reassignment details | ページタイトル |
| MSG-304-002 | 警告 | Approve reassignments only from users you trust. After you approve, contributions are assigned to you permanently. | 常に表示 |
| MSG-304-003 | エラー | The invitation could not be accepted. | 承認失敗時 |
| MSG-304-004 | エラー | The invitation could not be declined. | 拒否失敗時 |
| MSG-304-005 | 情報 | Import details: | 常に表示 |
| MSG-304-006 | 情報 | Reassignment details: | 常に表示 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| トークンが無効 | バナー表示後、ダッシュボードへリダイレクト |
| ソースユーザーが`awaiting_approval`でない | バナー表示後、ダッシュボードへリダイレクト |
| 現在のユーザーが再割り当て対象でない | バナー表示後、ダッシュボードへリダイレクト |
| 承認処理失敗 | エラーメッセージ表示後、ダッシュボードへリダイレクト |
| 拒否処理失敗 | エラーメッセージ表示後、ダッシュボードへリダイレクト |

## 備考

- 再割り当てトークンは32文字のセキュアランダム文字列
- 承認後は非同期で実際の再割り当て処理が実行される
- 一度拒否された場合でも、管理者は再度再割り当てを要求可能
- 信頼できるユーザーからの要求のみ承認するよう警告文が表示される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | source_user.rb | `app/models/import/source_user.rb` | 状態遷移（state_machine）、STATUSES定義 |

**読解のコツ**: `awaiting_approval`状態からの遷移（accept -> reassignment_in_progress, reject -> rejected）を理解する。`reassignment_token`は`awaiting_approval`状態でのみ存在する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | source_users_controller.rb | `app/controllers/import/source_users_controller.rb` | show/accept/declineアクション |

**主要処理フロー**:
1. **行40-44**: `check_source_user_valid!`でアクセス制御
2. **行10-21**: `accept`アクションでAcceptReassignmentService呼び出し
3. **行23-34**: `decline`アクションでRejectReassignmentService呼び出し
4. **行51-60**: `source_user`メソッドで名前空間ID/トークンによる検索

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/import/source_users/show.html.haml` | カード形式のUI、表示データ取得 |

**主要処理フロー**:
- **行3-12**: ソースユーザーと再割り当て関連情報の取得
- **行14-48**: Pajamas::CardComponentでカード形式UI
- **行49-56**: 承認/拒否ボタン

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | accept_reassignment_service.rb | `app/services/import/source_users/accept_reassignment_service.rb` | 承認処理ロジック |
| 4-2 | reject_reassignment_service.rb | `app/services/import/source_users/reject_reassignment_service.rb` | 拒否処理ロジック |

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

```
Import::SourceUsersController
    │
    ├─ before_action :check_source_user_valid!
    │      └─ source_user.awaiting_approval? && current_user_matches_invite?
    │
    ├─ #show (GET)
    │      └─ View: show.html.haml
    │              └─ @source_user情報表示
    │
    ├─ #accept (POST)
    │      └─ Import::SourceUsers::AcceptReassignmentService#execute
    │              └─ source_user.accept! (状態遷移)
    │
    └─ #decline (POST)
           └─ Import::SourceUsers::RejectReassignmentService#execute
                  └─ source_user.reject! (状態遷移)
```

### データフロー図

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

メールリンク ───▶ Import::SourceUsersController#show ───▶ 確認画面表示
(reassignment_token)           │
                              ▼
                    check_source_user_valid!
                              │
                              ├─ source_user.awaiting_approval?
                              └─ current_user == reassign_to_user?
                                        │
                                        ▼
                              View: show.html.haml
                                        │
    ┌───────────────────────────────────┴───────────────────────────────────┐
    │                                                                       │
    ▼                                                                       ▼
承認ボタン ───▶ AcceptReassignmentService ───▶ ダッシュボード    拒否ボタン ───▶ RejectReassignmentService ───▶ ダッシュボード
                     │                                                            │
                     ▼                                                            ▼
               status = 2                                                   status = 3
               (reassignment_in_progress)                                   (rejected)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| source_users_controller.rb | `app/controllers/import/source_users_controller.rb` | コントローラー | 画面制御・API提供 |
| show.html.haml | `app/views/import/source_users/show.html.haml` | テンプレート | 確認画面HTML |
| source_user.rb | `app/models/import/source_user.rb` | モデル | ソースユーザー管理 |
| accept_reassignment_service.rb | `app/services/import/source_users/accept_reassignment_service.rb` | サービス | 承認処理 |
| reject_reassignment_service.rb | `app/services/import/source_users/reject_reassignment_service.rb` | サービス | 拒否処理 |
| import.rb | `config/routes/import.rb` | ルーティング | URL定義（行92-102） |
