# 画面設計書 215-ユーザープロフィール

## 概要

本ドキュメントは、GitLabの公開ユーザープロフィール画面の設計仕様を記載したものです。

### 本画面の処理概要

ユーザープロフィール画面は、GitLabユーザーの公開プロフィール情報を表示するための画面です。ユーザーの基本情報、活動履歴、プロジェクト、グループなどを確認できます。

**業務上の目的・背景**：オープンソース開発やチーム開発において、他の開発者のプロフィールや活動状況を把握することは重要です。この画面を通じて、ユーザーは他のメンバーの貢献履歴、参加プロジェクト、スキルセットなどを確認できます。また、自分のプロフィールを公開することで、コミュニティ内での認知度向上やコラボレーションの機会創出につながります。

**画面へのアクセス方法**：ユーザー名をクリックするか、URLに直接ユーザー名を入力してアクセスします。URLは `/{username}` の形式です。

**主要な操作・処理内容**：
1. 基本情報の表示：アバター、名前、ユーザー名、ステータス、自己紹介
2. タブによる情報切り替え：概要、活動、グループ、貢献プロジェクト、プロジェクト、スターしたプロジェクト、スニペット、フォロワー、フォロー中
3. 貢献カレンダーの表示：年間の貢献活動をグラフ表示
4. フォロー/アンフォロー：他のユーザーをフォロー
5. プロフィール編集（自分のみ）：編集画面への遷移
6. 不正利用報告（他のユーザー）：報告画面への遷移

**画面遷移**：サイトの様々な箇所からユーザー名をクリックすることで遷移します。プロフィール編集画面、プロジェクト詳細画面、グループ詳細画面などへ遷移できます。

**権限による表示制御**：ユーザーのプライバシー設定により、表示内容が制御されます。プライベートプロフィールの場合は限定的な情報のみ表示されます。ブロックされたユーザーの場合は「このユーザーはブロックされています」のメッセージが表示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 77 | ユーザープロファイル | 主機能 | 公開ユーザープロフィールの表示 |

## 画面種別

詳細画面（タブによる複数ビュー）

## URL/ルーティング

| メソッド | パス | アクション |
|----------|------|-----------|
| GET | /:username | show |
| GET | /users/:username/activity | activity |
| GET | /users/:username/groups | groups |
| GET | /users/:username/projects | projects |
| GET | /users/:username/contributed | contributed |
| GET | /users/:username/starred | starred |
| GET | /users/:username/snippets | snippets |
| GET | /users/:username/followers | followers |
| GET | /users/:username/following | following |
| GET | /users/:username/calendar | calendar |
| GET | /users/:username/calendar_activities | calendar_activities |
| POST | /users/:username/follow | follow |
| POST | /users/:username/unfollow | unfollow |

```ruby
# config/routes/user.rb (lines 95-129)
scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) do
  scope(path: 'users/:username', as: :user, controller: :users) do
    get :calendar
    get :calendar_activities
    get :groups
    get :projects
    # ...
  end
end
```

## 入出力項目

### 入力項目

| 項目名 | 項目ID | 型 | 必須 | 説明 |
|--------|--------|-----|------|------|
| ユーザー名 | username | string | ○ | URL パラメータとして渡される |
| 日付 | date | date | - | カレンダー活動取得時のオプション |

### 出力項目

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| アバター | @user.avatar | ユーザーアバター画像 |
| 表示名 | @user.name | ユーザーの表示名 |
| ユーザー名 | @user.to_reference | @付きのユーザー名 |
| ステータス | @user.status | ユーザーのステータス（絵文字・メッセージ） |
| 自己紹介 | @user.bio | ユーザーの自己紹介文 |
| フォロワー数 | @user.followers.count | フォロワー数 |
| フォロー数 | @user.followees.count | フォロー中の数 |

## 表示項目

### ヘッダー部

| 項目名 | 説明 |
|--------|------|
| アバター | 96pxサイズのユーザーアバター |
| 表示名 | ユーザーの名前（h1タグ） |
| ユーザー名 | @username形式 |
| ステータス | ビジー状態バッジ、カスタムステータス |
| アクションボタン | フォロー、プロフィール編集、GPGキー表示、管理者エリアへのリンク |

### タブコンテンツ

| タブ名 | 表示内容 |
|--------|----------|
| Overview | 概要情報、貢献カレンダー |
| Activity | 活動履歴 |
| Groups | 参加グループ一覧 |
| Contributed | 貢献したプロジェクト一覧 |
| Projects | 所有プロジェクト一覧 |
| Starred | スターしたプロジェクト一覧 |
| Snippets | スニペット一覧 |
| Followers | フォロワー一覧 |
| Following | フォロー中一覧 |

## イベント仕様

### 1-画面読み込み時

画面読み込み時に以下の処理が実行されます：
1. URLからユーザー名を取得
2. ユーザーの存在確認と権限チェック
3. プロフィール情報の取得
4. デフォルトタブ（概要）のコンテンツを表示
5. Vue.jsアプリケーションのマウント（フィーチャーフラグ有効時）

### 2-タブ切り替え

タブをクリックすると：
1. 選択されたタブのコンテンツをAJAXで取得
2. 表示を更新

### 3-フォローボタン押下

フォローボタンを押下すると：
1. フォロー/アンフォローの処理を実行
2. ボタン表示を更新
3. フォロワー数を更新

### 4-カレンダー日付クリック

貢献カレンダーの日付をクリックすると：
1. 指定日の活動一覧を取得
2. モーダルまたはインラインで表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| フォロー | users_relationships | INSERT | フォロー関係の作成 |
| アンフォロー | users_relationships | DELETE | フォロー関係の削除 |

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

#### users_relationships（フォロー時）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | follower_id | current_user.id | フォローするユーザー |
| INSERT | followee_id | @user.id | フォローされるユーザー |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|------------|------|--------------|---------|
| MSG001 | 情報 | This user is blocked | ユーザーがブロック状態 |
| MSG002 | 情報 | This user has a private profile | プライベートプロフィール |
| MSG003 | 情報 | Busy | ビジーステータス設定時 |
| MSG004 | エラー | Action not allowed. | フォロー操作エラー時 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ユーザーが見つからない | 404エラー表示 |
| プロフィール参照権限なし | アクセス拒否エラー |
| ブロックされたユーザー | ブロックメッセージ表示 |
| プライベートプロフィール | プライベートメッセージ表示 |

## 備考

- Atom フィードに対応（`/:username.atom`）
- SSH公開鍵一覧に対応（`/:username.keys`）
- GPG公開鍵一覧に対応（`/:username.gpg`）
- `profile_tabs_vue` フィーチャーフラグでVue.js版タブの切り替え
- Schema.org Person スキーマに対応（SEO）
- RSS自動検出タグを出力

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | user.rb | `app/models/user.rb` | Userモデルの基本構造、アソシエーション |

**読解のコツ**: Userモデルは非常に大きいため、`followers`, `followees`, `status` などのアソシエーションに注目して読み解きます。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | users_controller.rb | `app/controllers/users_controller.rb` | コントローラーの全体構造 |

**主要処理フロー**:
1. **行24-25**: `skip_before_action :authenticate_user!` - 認証不要
2. **行26**: `before_action :user` - ユーザー取得
3. **行28-30**: `authorize_read_user_profile!` - 権限チェック
4. **行59-73**: `show` アクション - プロフィール表示
5. **行199-201**: `calendar` アクション - カレンダーデータ取得
6. **行203-213**: `calendar_activities` アクション - 日別活動取得

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.haml | `app/views/users/show.html.haml` | メインビュー |

**主要処理フロー**:
- **行11**: `profile_actions(@user)` で利用可能なアクションを取得
- **行49**: フィーチャーフラグによりVue.js版タブを表示
- **行62**: サイドバーの表示（ブロック時以外）

#### Step 4: ヘルパーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | users_helper.rb | `app/helpers/users_helper.rb` | ヘルパーメソッド |

**主要処理フロー**:
- **行40-46**: `profile_actions` - 表示可能なタブの決定
- **行224-236**: `user_profile_app_data` - Vue.jsに渡すデータ
- **行250-266**: `user_profile_actions_data` - アクションデータ

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

```
HTTP Request: GET /:username
    |
    +-- UsersController#show
           |
           +-- before_action :user
           |       +-- find_routable!(User, params[:username])
           |
           +-- before_action :authorize_read_user_profile!
           |       +-- can?(current_user, :read_user_profile, user)
           |
           +-- render show.html.haml
                  |
                  +-- profile_actions(@user)
                  |
                  +-- user_profile_app_data(@user) (Vue.js時)
                  |
                  +-- render 'users/profile_sidebar' (非ブロック時)
```

### データフロー図

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

URLパラメータ ───▶ UsersController#show ───▶ プロフィール表示
(username)              |
                        ▼
                 find_routable!(User)
                        |
                        ▼
                 権限チェック
                        |
                        ▼
              ユーザー情報・統計取得
                        |
                        ▼
              Vue.js or Legacyタブ ───▶ 画面表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| users_controller.rb | `app/controllers/users_controller.rb` | コントローラー | リクエスト処理 |
| show.html.haml | `app/views/users/show.html.haml` | テンプレート | メインビュー |
| users_helper.rb | `app/helpers/users_helper.rb` | ヘルパー | ビューヘルパー |
| user.rb | `config/routes/user.rb` | ルーティング | URL定義 |
| calendar_activities.html.haml | `app/views/users/calendar_activities.html.haml` | テンプレート | 日別活動表示 |
| _profile_sidebar.html.haml | `app/views/users/_profile_sidebar.html.haml` | テンプレート | サイドバー |
| _follow_user.html.haml | `app/views/users/_follow_user.html.haml` | テンプレート | フォローボタン |
