# 通知設計書 111-project_import_complete

## 概要

本ドキュメントは、GitLabにおけるプロジェクトインポート完了通知（project_import_complete）の設計仕様を記述する。

### 本通知の処理概要

プロジェクトインポート完了通知は、外部ソース（GitHub、GitLab.com等）からのプロジェクトインポート処理が完了した際に、関係者に対して完了を知らせるメール通知を送信する。

**業務上の目的・背景**：外部サービスからGitLabへのプロジェクト移行は時間がかかる処理であり、ユーザーは処理完了を待つことなく他の作業を行いたい。本通知により、インポート完了をユーザーに知らせ、後続のユーザーマッピング作業やインポート結果の確認を促すことで、移行作業の効率化を図る。

**通知の送信タイミング**：プロジェクトインポート処理が完了（成功・失敗問わず）した時点で、ImportCompletionNotificationWorkerを通じて非同期で送信される。

**通知の受信者**：プロジェクト作成者、およびユーザーマッピングが有効な場合はルートグループのオーナー全員に送信される。ただし、人間ユーザー（Bot以外）のみが対象となる。

**通知内容の概要**：インポート元のホスト名、開始日、完了状態を通知する。ユーザーマッピングが有効で未割り当てのプレースホルダーユーザーが存在する場合は、貢献の再割り当て機能についても案内する。

**期待されるアクション**：受信者はインポート結果を確認し、必要に応じてユーザーマッピング（プレースホルダーユーザーの再割り当て）を実施する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 低（urgency: low） |
| リトライ | Sidekiqデフォルト設定に従う |

### 送信先決定ロジック

1. プロジェクト作成者（project.creator）が人間ユーザーの場合、受信者に追加
2. ユーザーマッピングが有効かつグループオーナー通知が有効な場合:
   - プロジェクトのルートグループのオーナー全員を受信者に追加（人間ユーザーのみ）
   - 重複は除外される

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンス設定に従う |
| 送信元名称 | GitLab |
| 件名 | `{project_name} | Import from {hostname} completed` |
| 形式 | テキスト |

### 本文テンプレート

```
Import completed

(プロジェクト作成者宛の場合)
The import you started on {start_date} from {hostname} has completed.

(プロジェクト作成者以外の場合)
The import {project_creator_name} started on {start_date} from {hostname} has completed.

(ユーザーマッピング利用不可の場合)
You can now review your import results.

(ユーザーマッピング利用可でグループオーナーの場合)
You can reassign contributions on the "Members" page of the group.

(ユーザーマッピング利用可でグループオーナー以外の場合)
Users with the Owner role for the group can reassign contributions on the "Members" page.

(ユーザーマッピング利用可でグループオーナーの場合)
Reassign contributions: {group_members_url}

(それ以外の場合)
View import results: {import_history_url}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイルはない |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @project | インポート対象プロジェクト | Project.find(project_id) | Yes |
| @namespace | プロジェクトのルート名前空間 | @project.root_ancestor | Yes |
| @hostname | インポート元ホスト名（マスク済み） | safe_import_url | Yes |
| @user_mapping_available | ユーザーマッピング利用可能フラグ | 複合条件判定 | Yes |
| @is_group_owner | グループオーナーかどうか | user.can?(:admin_namespace, @namespace) | Yes |
| @is_project_creator | プロジェクト作成者かどうか | user_id == @project.creator_id | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バックグラウンドジョブ | ImportCompletionNotificationWorker.perform | project.notify_project_import_complete? が true | インポート完了時にWorkerがキューイングされる |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| プロジェクトが存在しない | project_idに該当するプロジェクトが見つからない場合 |
| notify_project_import_complete?がfalse | プロジェクトの状態により通知不要と判断された場合 |
| 受信者が人間ユーザーでない | Botなどのシステムユーザーは除外される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[インポート完了] --> B[ImportCompletionNotificationWorker起動]
    B --> C{プロジェクト存在?}
    C -->|No| D[処理終了]
    C -->|Yes| E{notify_project_import_complete?}
    E -->|No| D
    E -->|Yes| F[受信者リスト作成]
    F --> G[プロジェクト作成者を追加]
    G --> H{user_mapping_enabled && notify_group_owners?}
    H -->|Yes| I[グループオーナーを追加]
    H -->|No| J[受信者ごとにメール送信]
    I --> J
    J --> K[Notify.project_import_complete.deliver_later]
    K --> L[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| projects | インポート対象プロジェクト情報取得 | |
| users | プロジェクト作成者・グループオーナー取得 | |
| namespaces | ルート名前空間取得 | |
| import_source_users | 未割り当てプレースホルダー確認 | awaiting_reassignmentスコープ使用 |
| members | グループオーナー判定 | |

### テーブル別参照項目詳細

#### projects

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | プロジェクト特定 | Project.find_by_id(project_id) |
| creator_id | プロジェクト作成者特定 | |
| created_at | インポート開始日表示 | |

#### import_source_users

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| status | 再割り当て待ちユーザー確認 | namespace.import_source_users.awaiting_reassignment |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | 本通知処理ではDB更新は行わない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| プロジェクト未存在 | Project.find_by_id で見つからない | 処理を終了（ログなし） |
| ユーザー未存在 | User.find で見つからない | ActiveRecord::RecordNotFoundが発生 |
| メール送信失敗 | SMTPエラー等 | Sidekiqのリトライに委ねる |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト設定 |
| リトライ間隔 | Sidekiqデフォルト設定 |
| リトライ対象エラー | メール送信に関連するエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | システム設定に従う |
| 1日あたり上限 | システム設定に従う |

### 配信時間帯

制限なし（24時間送信可能）

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

- インポート元URLはsafe_import_urlを使用し、パスワード等の認証情報をマスク処理
- ユーザー名表示時はsanitize_nameを使用してXSS対策を実施

## 備考

- ユーザーマッピング機能はGitLab 16.0以降で利用可能
- data_consistency: delayedにより、レプリカDBからの読み取りを許容

---

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

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

### 推奨読解順序

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

まず、通知で使用されるデータ構造とモデルの関係を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | project.rb | `app/models/project.rb` | インポート関連のメソッド、root_ancestor、notify_project_import_complete? |
| 1-2 | import_source_user.rb | `app/models/import/source_user.rb` | プレースホルダーユーザーの状態管理、awaiting_reassignmentスコープ |

**読解のコツ**: Railsのstate_machineパターンとスコープ定義に注目

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

通知処理の起点となるWorkerクラスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | import_completion_notification_worker.rb | `app/workers/projects/import_export/import_completion_notification_worker.rb` | perform、completion_notification_recipients |

**主要処理フロー**:
1. **15-25行目**: performメソッドでプロジェクト存在確認と通知可否判定
2. **29-35行目**: send_completion_notificationで受信者ごとにメール送信
3. **37-48行目**: completion_notification_recipientsで受信者リスト生成

#### Step 3: メーラー実装を理解する

メール本文生成ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imports.rb | `app/mailers/emails/imports.rb` | project_import_completeメソッド（15-38行目） |

**主要処理フロー**:
- **15-38行目**: user_mapping_availableの複合条件判定、is_group_owner/is_project_creator判定

#### Step 4: テンプレートを理解する

メール本文テンプレートの条件分岐を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | project_import_complete.text.erb | `app/views/notify/project_import_complete.text.erb` | 条件分岐によるメッセージ出し分け |

**主要処理フロー**:
- **3-14行目**: is_project_creator、user_mapping_available、is_group_ownerによる条件分岐
- **16-20行目**: リンク先の出し分け

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

```
ImportCompletionNotificationWorker#perform
    │
    ├─ Project.find_by_id
    │
    ├─ project.notify_project_import_complete?
    │
    └─ send_completion_notification
           │
           ├─ completion_notification_recipients
           │      ├─ project.creator
           │      └─ project.root_ancestor.owners
           │
           └─ Notify.project_import_complete.deliver_later
                  │
                  ├─ User.find
                  ├─ Project.find
                  ├─ user.can?(:admin_namespace, namespace)
                  │
                  └─ email_with_layout
```

### データフロー図

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

project_id ─────────────────┬─▶ ImportCompletionNotificationWorker ──┬──▶ メール送信
user_mapping_enabled ───────┤                                        │
notify_group_owners ────────┤                                        │
safe_import_url ────────────┘                                        │
                                                                     │
                            Project ─────────────────────────────────┤
                            │                                        │
                            ├─ creator ──────────────────────────────┤
                            ├─ root_ancestor ────────────────────────┤
                            │      └─ owners ────────────────────────┤
                            │      └─ import_source_users ───────────┘
                            └─ created_at
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| import_completion_notification_worker.rb | `app/workers/projects/import_export/import_completion_notification_worker.rb` | ソース | 通知送信Workerの実装 |
| imports.rb | `app/mailers/emails/imports.rb` | ソース | メーラーのimport関連メソッド定義 |
| project_import_complete.text.erb | `app/views/notify/project_import_complete.text.erb` | テンプレート | メール本文テンプレート |
| project.rb | `app/models/project.rb` | ソース | プロジェクトモデル |
| import_source_user.rb | `app/models/import/source_user.rb` | ソース | インポートソースユーザーモデル |
| imports_spec.rb | `spec/mailers/emails/imports_spec.rb` | テスト | メーラーのテスト仕様 |
