# 通知設計書 67-project_was_moved_email

## 概要

本ドキュメントは、GitLabにおける「プロジェクトが移動されたことを通知する」メール通知機能の設計書である。

### 本通知の処理概要

本通知は、プロジェクトが別のnamespace（グループまたはユーザー）に移動された際に、プロジェクトのメンバーに通知メールを送信する機能である。

**業務上の目的・背景**：プロジェクトの移動は、URLパスやGitリモートURLの変更を伴う重要な操作である。開発者がローカルリポジトリのリモートURLを更新する必要があり、また既存のブックマークやCI/CD設定の更新が必要になる可能性がある。この通知により、プロジェクトメンバーは移動を認識し、必要な対応を取ることができる。

**通知の送信タイミング**：プロジェクトが正常に別のnamespaceに移動された直後に送信される。Projects::TransferServiceの処理が成功した際にトリガーされる。

**通知の受信者**：プロジェクトのオーナーおよびメンテナーに送信される。カスタム通知設定で「moved_project」アクションが有効になっているユーザーにも送信される。

**通知内容の概要**：移動元のパス、移動先の新しいパスとURL、SSHおよびHTTPのリモートURL更新コマンドが含まれる。

**期待されるアクション**：ユーザーはローカルリポジトリのリモートURLを更新するコマンドを実行する。また、ブックマークやCI/CD設定など、プロジェクトパスを参照している箇所を更新することが期待される。

## 通知種別

メール

## 送信仕様

### 基本情報

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

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

1. NotificationService.project_was_movedメソッドが呼び出される
2. MembersFinder経由でプロジェクトのオーナー・メンテナーを取得
3. カスタム通知設定で「moved_project」が有効なユーザーをフィルタリング
4. 各受信者の通知用メールアドレス（`notification_email_for`）に送信

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | Gitlab.config.gitlab.email_from |
| 送信元名称 | Gitlab.config.gitlab.email_display_name |
| 件名 | "[project_name] | Project was moved" |
| 形式 | HTML/テキスト（マルチパート） |

### 本文テンプレート

```
Project [old_path_with_namespace] was moved to another location.

The project is now located under [new_project_full_name].
[新しいプロジェクトURL]

To update the remote url in your local repository run (for ssh):
  git remote set-url origin [ssh_url_to_repo]
or for http(s):
  git remote set-url origin [http_url_to_repo]
```

### 添付ファイル

なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @user | 通知対象ユーザー | User | Yes |
| @project | 移動されたプロジェクト | Project | Yes |
| @old_path_with_namespace | 移動前のパス | 引数 | Yes |
| @target_url | 新しいプロジェクトURL | project_url(@project) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作/API | プロジェクト移動完了 | カスタム通知設定で有効 | NotificationService.project_was_moved呼び出し時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| カスタム通知設定で無効 | custom_action: :moved_project が無効 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[プロジェクト移動リクエスト] --> B[Projects::TransferService#execute]
    B --> C{移動成功?}
    C -->|Yes| D[NotificationService.project_was_moved]
    C -->|No| E[エラー返却]
    D --> F[MembersFinder:オーナー・メンテナー取得]
    F --> G[notifiable_usersでフィルタリング]
    G --> H{受信者あり?}
    H -->|Yes| I[各受信者に対してproject_was_moved_email]
    H -->|No| J[処理終了]
    I --> K[deliver_later]
    K --> L[Sidekiqキューに追加]
    L --> M[非同期でメール送信]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| users | 送信先ユーザー情報取得 | notification_email_for |
| projects | プロジェクト情報取得 | パス、URL |
| members | プロジェクトメンバー取得 | オーナー・メンテナー |
| notification_settings | 通知設定確認 | custom_action |

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

#### projects

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | プロジェクト識別 | - |
| name | 件名に使用 | - |
| path | リポジトリパス | - |
| namespace_id | 所属namespace | - |

### 更新テーブル一覧

なし（メール送信のみ。プロジェクト移動自体はTransferServiceで処理）

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPサーバー接続エラー | Sidekiqリトライ |
| 宛先不正 | メールアドレス形式エラー | ログ記録、スキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト（25回） |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | SMTP接続エラー等の一時的エラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | プロジェクト/グループごとにレート制限適用 |
| 1日あたり上限 | プロジェクト/グループごとにレート制限適用 |

### 配信時間帯

制限なし

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

- プロジェクトパスやURLはエスケープ処理が適用される
- メール本文にはパスワードなどの機密情報は含まれない
- 権限のあるメンバーのみに送信される

## 備考

- プロジェクト移動後は、CI/CD変数やWebhookなども影響を受ける可能性がある
- 移動先namespaceの制限（容量、機能）が適用される
- MembersFinderを使用してオーナー・メンテナーを効率的に取得

---

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

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

### 推奨読解順序

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

通知で使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Project | `app/models/project.rb` | プロジェクトモデル、full_path、ssh_url_to_repo、http_url_to_repo |
| 1-2 | User | `app/models/user.rb` | ユーザーモデル、notification_email_for |

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

処理の起点となるサービスを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NotificationService | `app/services/notification_service.rb` | project_was_movedメソッド（行513-524） |

**主要処理フロー**:
1. **行513-524**: `project_was_moved`メソッドで通知処理
2. **行514**: `project_moved_recipients`で受信者を取得
3. **行515**: `notifiable_users`でカスタム通知設定をフィルタリング
4. **行517-523**: 各受信者に`project_was_moved_email`を送信

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Emails::Projects | `app/mailers/emails/projects.rb` | メール送信ロジック（行7-16） |
| 3-2 | project_was_moved_email.html.haml | `app/views/notify/project_was_moved_email.html.haml` | HTMLテンプレート |
| 3-3 | project_was_moved_email.text.erb | `app/views/notify/project_was_moved_email.text.erb` | テキストテンプレート |

**主要処理フロー**:
- **行7-16**: `project_was_moved_email`メソッドでメール生成
- **行8-11**: ユーザー、プロジェクト、古いパス、target_urlを設定
- **行14**: 件名「Project was moved」

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

```
Projects::TransferService#execute
    │
    └─ NotificationService#project_was_moved (行513)
           │
           ├─ project_moved_recipients (行970-976)
           │      └─ MembersFinder.new(project).execute
           │             └─ active_without_invites_and_requests
           │                    └─ owners_and_maintainers
           │
           ├─ notifiable_users (行515)
           │      └─ custom_action: :moved_project
           │
           └─ [各受信者に対して]
                  │
                  └─ Notify#project_was_moved_email (行7)
                         │
                         ├─ email_with_layout
                         │
                         └─ deliver_later
                                └─ Sidekiq Job登録
```

### データフロー図

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

管理者操作                    コントローラー/API
(プロジェクト移動)            (transfer)
    │                              │
    ▼                              ▼
project_id ───────────────▶ Projects::TransferService
new_namespace_id                   │
                                   ▼
                           Project.namespace更新
                           (データベース更新)
                                   │
                                   ▼
                           NotificationService
                           .project_was_moved
                                   │
                                   ▼
                           MembersFinder
                           (オーナー・メンテナー取得)
                                   │
                                   ▼
                           Notify#project_was_moved
                           _email × 受信者数
                                   │
                                   ▼
                           Sidekiq ───────────────────▶ メール送信
                                                        (メンバーへ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Projects::TransferService | `app/services/projects/transfer_service.rb` | サービス | プロジェクト移動ロジック |
| NotificationService | `app/services/notification_service.rb` | サービス | 通知ロジックの中核 |
| MembersFinder | `app/finders/members_finder.rb` | ファインダー | メンバー検索 |
| Emails::Projects | `app/mailers/emails/projects.rb` | メーラー | プロジェクト関連メール定義 |
| Notify | `app/mailers/notify.rb` | メーラー | メインメーラークラス |
| project_was_moved_email.html.haml | `app/views/notify/project_was_moved_email.html.haml` | テンプレート | HTML形式のメールテンプレート |
| project_was_moved_email.text.erb | `app/views/notify/project_was_moved_email.text.erb` | テンプレート | テキスト形式のメールテンプレート |
