# 機能設計書 77-ユーザープロファイル

## 概要

本ドキュメントは、GitLabのユーザープロファイル機能について、その処理概要、入出力仕様、処理フロー、データベース操作仕様を定義する。

### 本機能の処理概要

ユーザープロファイル機能は、ユーザー情報の表示・編集を行う機能である。名前、アバター、ソーシャルメディアリンク、ステータス、プロフィール設定など、ユーザーの公開情報およびアカウント設定を管理する。

**業務上の目的・背景**：GitLabを利用するユーザーは、自身のプロフィールを設定することで、他のユーザーに自分の情報を公開したり、プラットフォーム全体での表示名やアバターを設定したりできる。また、ユーザー名の変更や各種トークンのリセットなど、アカウント管理機能も提供する。

**機能の利用シーン**：
- ユーザーが自分のプロフィール情報を設定・更新する場合
- ユーザー名を変更する場合
- アバター画像をアップロードする場合
- ステータスを設定してチームに状況を共有する場合
- 各種アクセストークンをリセットする場合
- プライバシー設定を変更する場合

**主要な処理内容**：
1. プロフィール情報の編集（名前、役職、所在地、自己紹介等）
2. アバター画像のアップロード
3. ソーシャルメディアリンクの設定（LinkedIn、Twitter、Mastodon等）
4. ユーザー名の変更
5. ステータス設定（絵文字、メッセージ、可用性）
6. 各種トークンのリセット（Incoming Email、Feed、Static Object）
7. プライバシー設定（プライベートプロファイル、貢献の公開設定）

**関連システム・外部連携**：
- ファイルストレージ（アバター画像）
- Users::UpdateService（プロフィール更新サービス）
- Users::ResetFeedTokenService（Feedトークンリセット）

**権限による制御**：
- プロフィール表示: 公開設定による
- プロフィール編集: 本人のみ
- ユーザー名変更: 本人のみ（変更可能設定による）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 192 | プロフィール編集 | 主画面 | ユーザープロフィールの編集 |
| 202 | アカウント設定 | 参照画面 | アカウント設定の管理 |
| 203 | 表示設定 | 参照画面 | 表示・言語設定 |
| 215 | ユーザープロフィール | 結果表示画面 | 公開ユーザープロフィールの表示 |

## 機能種別

CRUD操作 / ファイルアップロード

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | No | フルネーム | 最大127文字 |
| username | String | No | ユーザー名 | 2-255文字、英数字・ハイフン・アンダースコア |
| email | String | No | メールアドレス | 有効なメール形式 |
| avatar | File | No | アバター画像 | 画像ファイル |
| bio | String | No | 自己紹介 | 最大文字数制限あり |
| job_title | String | No | 役職 | - |
| location | String | No | 所在地 | - |
| website_url | String | No | Webサイト | 有効なURL |
| linkedin | String | No | LinkedInプロフィール | - |
| twitter | String | No | Twitterハンドル | - |
| mastodon | String | No | Mastodonアカウント | - |
| bluesky | String | No | Blueskyアカウント | - |
| discord | String | No | DiscordID | - |
| github | String | No | GitHubユーザー名 | - |
| private_profile | Boolean | No | プロファイル非公開 | true/false |
| include_private_contributions | Boolean | No | プライベート貢献を含める | true/false |
| status.emoji | String | No | ステータス絵文字 | - |
| status.message | String | No | ステータスメッセージ | - |
| status.availability | String | No | 可用性 | - |
| status.clear_status_after | String | No | ステータスクリア時間 | - |

### 入力データソース

- 画面入力（プロフィール編集フォーム）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | ユーザーID |
| username | String | ユーザー名 |
| name | String | フルネーム |
| avatar_url | String | アバターURL |
| bio | String | 自己紹介 |
| job_title | String | 役職 |
| location | String | 所在地 |
| website_url | String | Webサイト |
| status | Object | ステータス情報 |
| social_links | Object | ソーシャルリンク |

### 出力先

- 画面表示（HTML）
- JSON API レスポンス

## 処理フロー

### 処理シーケンス

```
1. 認証確認
   └─ ログイン済みか確認
2. ユーザー情報取得
   └─ current_userを取得
3. バリデーション
   └─ 入力パラメータの検証
4. ユーザー名変更（該当する場合）
   └─ 変更可能か確認、レート制限チェック
5. プロフィール更新
   └─ Users::UpdateServiceで更新
6. アバターアップロード（該当する場合）
   └─ ファイル保存
7. レスポンス返却
   └─ 成功/失敗の結果を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{認証済み?}
    B -->|No| C[ログイン画面へ]
    B -->|Yes| D{操作種別}
    D -->|プロフィール編集| E[Users::UpdateService]
    D -->|ユーザー名変更| F{変更可能?}
    F -->|No| G[404エラー]
    F -->|Yes| H{レート制限OK?}
    H -->|No| I[エラー応答]
    H -->|Yes| J[ユーザー名更新]
    D -->|トークンリセット| K[トークン再生成]
    E --> L{更新成功?}
    J --> L
    K --> L
    L -->|Yes| M[成功メッセージ]
    L -->|No| N[エラーメッセージ]
    M --> O[リダイレクト]
    N --> O
    O --> P[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-77-01 | ユーザー名変更制限 | can_change_username?がfalseの場合、ユーザー名変更不可 | ユーザー名変更時 |
| BR-77-02 | ユーザー名変更レート制限 | profile_update_usernameレート制限が適用される | ユーザー名変更時 |
| BR-77-03 | パスワード検証 | 一部の操作ではvalidation_passwordによる確認が必要 | 機密操作時 |
| BR-77-04 | ユーザー名最大長 | 最大255文字 | ユーザー名変更時 |
| BR-77-05 | 名前最大長 | 最大127文字 | プロフィール編集時 |

### 計算ロジック

なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロフィール編集 | users | UPDATE | ユーザー情報更新 |
| ユーザー名変更 | users | UPDATE | ユーザー名更新 |
| ステータス設定 | user_statuses | UPSERT | ステータス情報更新 |
| アバター更新 | uploads | INSERT | アバターファイル保存 |
| トークンリセット | users | UPDATE | トークン再生成 |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | ユーザー入力値 | 任意 |
| UPDATE | username | ユーザー入力値 | 変更可能な場合のみ |
| UPDATE | bio | ユーザー入力値 | 任意 |
| UPDATE | job_title | ユーザー入力値 | 任意 |
| UPDATE | location | ユーザー入力値 | 任意 |
| UPDATE | website_url | ユーザー入力値 | 任意 |
| UPDATE | linkedin | ユーザー入力値 | 任意 |
| UPDATE | twitter | ユーザー入力値 | 任意 |
| UPDATE | mastodon | ユーザー入力値 | 任意 |
| UPDATE | bluesky | ユーザー入力値 | 任意 |
| UPDATE | discord | ユーザー入力値 | 任意 |
| UPDATE | github | ユーザー入力値 | 任意 |
| UPDATE | private_profile | ユーザー入力値 | true/false |
| UPDATE | include_private_contributions | ユーザー入力値 | true/false |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未ログイン | ログイン画面へリダイレクト |
| 404 | NotFound | ユーザー名変更不可の状態で変更試行 | 404ページ表示 |
| 422 | バリデーションエラー | 入力値不正 | エラー内容を表示 |
| 429 | レート制限 | ユーザー名変更過多 | 待機を促すメッセージ |

### リトライ仕様

特になし

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

- プロフィール更新はUsers::UpdateServiceのトランザクション内で実行

## パフォーマンス要件

- プロフィール取得: 1秒以内
- プロフィール更新: 2秒以内

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

- 本人のみ編集可能
- 一部操作でパスワード確認
- レート制限によるユーザー名変更乱用防止
- プライベートプロファイル機能

## 備考

- ユーザー名変更時は関連するURL等も変更される
- アバターはCarrierWaveで管理
- ステータスは絵文字、メッセージ、可用性の組み合わせ

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | Userモデルの属性を確認 |
| 1-2 | user_status.rb | `app/models/user_status.rb` | ステータス関連の構造を確認 |

**読解のコツ**:
- Userモデルは多くの属性を持つため、プロフィール関連の属性に注目
- user_params_attributesで許可されている属性を確認

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | profiles_controller.rb | `app/controllers/profiles_controller.rb` | プロフィールコントローラーの構造を確認 |

**主要処理フロー**:
1. **9行目**: `authorize_change_username!`でユーザー名変更可能か確認
2. **10-12行目**: ユーザー名変更時のレート制限チェック
3. **17-23行目**: `reset_incoming_email_token`でトークンリセット
4. **25-35行目**: `reset_feed_token`でFeedトークンリセット
5. **44-59行目**: `update_username`でユーザー名更新
6. **76-109行目**: `user_params_attributes`で許可属性を定義

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update_service.rb | `app/services/users/update_service.rb` | ユーザー更新サービス |
| 3-2 | reset_feed_token_service.rb | `app/services/users/reset_feed_token_service.rb` | Feedトークンリセット |

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

```
ProfilesController
    │
    ├─ reset_incoming_email_token
    │      └─ Users::UpdateService
    │             └─ user.reset_incoming_email_token!
    │
    ├─ reset_feed_token
    │      └─ Users::ResetFeedTokenService
    │
    ├─ reset_static_object_token
    │      └─ Users::UpdateService
    │             └─ user.reset_static_object_token!
    │
    └─ update_username
           └─ Users::UpdateService
                  └─ user.update(username: ...)
```

### データフロー図

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

プロフィールフォーム ───▶ ProfilesController ───▶ リダイレクト
    │                        │
    │                        └─▶ Users::UpdateService
    │                                  │
    │                                  └─▶ User.update
    │                                            │
    │                                            └─▶ usersテーブル
    │
    └── params[:user]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| profiles_controller.rb | `app/controllers/profiles_controller.rb` | コントローラー | プロフィール操作 |
| user.rb | `app/models/user.rb` | モデル | ユーザーデータ構造 |
| user_status.rb | `app/models/user_status.rb` | モデル | ステータスデータ構造 |
| update_service.rb | `app/services/users/update_service.rb` | サービス | ユーザー更新処理 |
| reset_feed_token_service.rb | `app/services/users/reset_feed_token_service.rb` | サービス | Feedトークンリセット |
| application_controller.rb | `app/controllers/profiles/application_controller.rb` | コントローラー | プロフィール共通ベース |
