# 画面設計書 89-プロフィール設定画面

## 概要

本ドキュメントは、Chatwootのユーザープロフィール設定画面の設計を記述したものです。この画面では、ユーザーの基本情報、インターフェース設定、メッセージ署名、パスワード、通知設定などを管理します。

### 本画面の処理概要

**業務上の目的・背景**：ユーザーが自身のプロフィール情報やアプリケーションの使い勝手に関する設定をカスタマイズするための画面です。個人の作業効率向上やコミュニケーションスタイルの反映を可能にします。

**画面へのアクセス方法**：画面右上のユーザーアバターをクリックして表示されるメニューから「プロフィール設定」を選択、またはサイドメニューの「設定」から「プロフィール」を選択してアクセスします。URLパスは `/app/accounts/:accountId/profile/settings` です。

**主要な操作・処理内容**：
1. プロフィール画像のアップロード・削除
2. 基本情報（名前、表示名、メール）の編集
3. インターフェース設定（フォントサイズ、言語）の変更
4. メッセージ署名の設定
5. メッセージ送信ホットキーの選択
6. パスワードの変更
7. MFA設定への遷移
8. 音声通知設定
9. 通知設定
10. アクセストークンの表示・リセット

**画面遷移**：
- 遷移元：ユーザーメニュー、設定メニュー
- 遷移先：MFA設定画面

**権限による表示制御**：全ロールでアクセス可能です。一部設定項目はglobalConfigの設定により非表示になる場合があります。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 171 | ユーザープロフィール | 主機能 | プロフィール表示・編集 |
| 172 | アバター管理 | 補助機能 | ユーザーアバターの設定 |
| 173 | 可用性設定 | 補助機能 | Online/Offline状態の設定 |
| 176 | リセットトークン | 補助機能 | アクセストークンのリセット |
| 101 | 通知設定 | 補助機能 | 通知プリファレンスの設定 |

## 画面種別

設定

## URL/ルーティング

- **パス**: `/app/accounts/:accountId/profile/settings`
- **ルート名**: `profile_settings_index`

## 入出力項目

### 基本情報

| 項目名 | データ型 | 必須 | バリデーション | 説明 |
|--------|----------|------|----------------|------|
| name | String | 必須 | 空でないこと | フルネーム |
| displayName | String | 任意 | - | 表示名 |
| email | String | 必須 | メール形式 | メールアドレス |

### インターフェース設定

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| fontSize | String | フォントサイズ設定 |
| locale | String | 言語設定 |

### その他設定

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| messageSignature | String | メッセージ署名 |
| editorMessageKey | String | 送信ホットキー（enter/cmd_enter） |
| password | String | 新しいパスワード（変更時） |

## 表示項目

### プロフィールセクション

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| プロフィール画像 | 画像 + アップロードボタン + 削除ボタン | ユーザーアバター |
| 名前入力 | テキストフィールド | フルネーム |
| 表示名入力 | テキストフィールド | 表示名 |
| メール入力 | テキストフィールド | メールアドレス（無効化可能） |

### インターフェースセクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| フォントサイズ | ドロップダウン | フォントサイズ選択 |
| 言語 | ドロップダウン | 言語選択 |

### メッセージ署名セクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| 署名エディタ | リッチテキストエディタ | 署名内容の編集 |

### 送信ホットキーセクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| Enter | HotKeyCard | Enterキーで送信 |
| Cmd/Ctrl+Enter | HotKeyCard | Cmd/Ctrl+Enterで送信 |

### パスワードセクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| パスワード変更フォーム | パスワード入力 | 新しいパスワード設定 |

### セキュリティセクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| MFA設定カード | MfaSettingsCard | MFA状態表示、設定へのリンク |

### 通知セクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| 音声通知設定 | AudioNotifications | 音声アラートの設定 |
| 通知設定 | NotificationPreferences | 通知のON/OFF設定 |

### アクセストークンセクション（FormSection）

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| トークン表示 | コード表示 | 現在のアクセストークン |
| コピーボタン | ボタン | トークンをクリップボードにコピー |
| リセットボタン | ボタン | 新しいトークンを生成 |

## イベント仕様

### 1-プロフィール画像アップロード

ファイル選択時：
1. updateProfilePictureでfileとurlを更新
2. プレビュー表示を更新

### 2-プロフィール画像削除

削除ボタン押下時：
1. `$store.dispatch('deleteAvatar')`を実行
2. avatarUrlをクリア

### 3-基本情報更新

フォーム送信時：
1. updateProfile関数を実行
2. メール変更時は特別なメッセージを表示
3. `$store.dispatch('updateProfile', payload)`を実行

### 4-メッセージ署名更新

署名保存時：
1. updateSignature関数を実行
2. `$store.dispatch('updateProfile', { message_signature })`を実行

### 5-ホットキー切り替え

HotKeyCard選択時：
1. toggleHotKey関数を実行
2. `updateUISettings({ editor_message_key: key })`を実行

### 6-アクセストークンコピー

コピーボタン押下時：
1. copyTextToClipboard関数を実行
2. 成功メッセージを表示

### 7-アクセストークンリセット

リセットボタン押下時：
1. `$store.dispatch('resetAccessToken')`を実行
2. 成功/失敗メッセージを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 基本情報更新 | users | UPDATE | name, email, display_name更新 |
| アバターアップロード | users | UPDATE | avatar添付ファイル更新 |
| アバター削除 | users | UPDATE | avatar削除 |
| 署名更新 | users | UPDATE | message_signature更新 |
| パスワード変更 | users | UPDATE | encrypted_password更新 |
| トークンリセット | users | UPDATE | access_token再生成 |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | name | フォーム入力値 | 必須 |
| UPDATE | email | フォーム入力値 | 変更時は再認証必要 |
| UPDATE | display_name | フォーム入力値 | |
| UPDATE | message_signature | フォーム入力値 | |
| UPDATE | avatar | アップロードファイル | ActiveStorage |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|----------|--------------|
| PROFILE_SETTINGS.UPDATE_SUCCESS | 成功 | 更新成功時 | プロフィールが更新されました |
| PROFILE_SETTINGS.AFTER_EMAIL_CHANGED | 成功 | メール変更時 | 確認メールを送信しました |
| RESET_PASSWORD.API.ERROR_MESSAGE | エラー | 更新失敗時 | 更新に失敗しました |
| PROFILE_SETTINGS.AVATAR_DELETE_SUCCESS | 成功 | アバター削除成功時 | アバターが削除されました |
| PROFILE_SETTINGS.AVATAR_DELETE_FAILED | エラー | アバター削除失敗時 | アバターの削除に失敗しました |
| FORM.MESSAGE_SIGNATURE_SECTION.API_SUCCESS | 成功 | 署名更新成功時 | 署名が更新されました |
| FORM.SEND_MESSAGE.UPDATE_SUCCESS | 成功 | ホットキー更新時 | 設定が更新されました |
| FORM.ACCESS_TOKEN.RESET_SUCCESS | 成功 | トークンリセット成功時 | トークンがリセットされました |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| API呼び出し失敗 | parseAPIErrorResponseでエラーメッセージを抽出して表示 |
| メール変更 | ログアウト処理（clearCookiesOnLogout） |
| globalConfig.disableUserProfileUpdate | メール入力を無効化、パスワードセクションを非表示 |

## 備考

- メールアドレス変更時は確認メールが送信され、確認後に変更が反映される
- MFA設定はisMfaEnabledがtrueの場合のみ表示
- 音声通知と通知設定はROLES/CONVERSATION_PERMISSIONSによるPolicy制御あり
- globalConfig.disableUserProfileUpdateがtrueの場合、メール変更とパスワード変更が無効化

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | auth/index.js | `app/javascript/dashboard/store/modules/auth/index.js` | currentUser, updateProfile, deleteAvatar, resetAccessTokenアクション |
| 1-2 | useUISettings.js | `app/javascript/dashboard/composables/useUISettings.js` | isEditorHotKeyEnabled, updateUISettings |

**読解のコツ**: プロフィール情報はauthモジュールのcurrentUserに格納される

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Index.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue` | setup関数、data()、computed、methods |

**主要処理フロー**:
1. **行46-56**: setup関数でcomposablesを使用
2. **行95-104**: computed（currentUser, globalConfig, isMfaEnabled）
3. **行105-117**: mountedでinitializeUser
4. **行118-132**: dispatchUpdateでAPI呼び出しと結果処理
5. **行133-156**: updateProfileで基本情報更新
6. **行157-167**: updateSignatureで署名更新
7. **行182-188**: toggleHotKeyでホットキー設定
8. **行193-200**: resetAccessTokenでトークンリセット

#### Step 3: コンポーネント層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | UserProfilePicture.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/UserProfilePicture.vue` | アバターアップロード/削除UI |
| 3-2 | UserBasicDetails.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/UserBasicDetails.vue` | 基本情報入力フォーム |
| 3-3 | MessageSignature.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/MessageSignature.vue` | 署名エディタ |
| 3-4 | HotKeyCard.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/HotKeyCard.vue` | ホットキー選択カード |
| 3-5 | ChangePassword.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/ChangePassword.vue` | パスワード変更フォーム |
| 3-6 | NotificationPreferences.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/NotificationPreferences.vue` | 通知設定 |
| 3-7 | AccessToken.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/AccessToken.vue` | トークン表示/リセット |

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

```
Index.vue (エントリーポイント)
    │
    ├─ mounted → initializeUser
    │      └─ currentUserからローカルstate初期化
    │
    ├─ UserProfilePicture.vue
    │      ├─ @change → updateProfilePicture
    │      └─ @delete → deleteProfilePicture
    │              └─ $store.dispatch('deleteAvatar')
    │
    ├─ UserBasicDetails.vue
    │      └─ @update-user → updateProfile
    │              └─ dispatchUpdate('updateProfile')
    │
    ├─ MessageSignature.vue
    │      └─ @update-signature → updateSignature
    │              └─ dispatchUpdate({ message_signature })
    │
    ├─ HotKeyCard.vue (x2)
    │      └─ @click → toggleHotKey
    │              └─ updateUISettings({ editor_message_key })
    │
    ├─ ChangePassword.vue
    │      └─ 内部でパスワード更新処理
    │
    ├─ MfaSettingsCard.vue（v-if="isMfaEnabled"）
    │      └─ MFA設定画面へのリンク
    │
    ├─ AudioNotifications.vue（Policy制御）
    │
    ├─ NotificationPreferences.vue（Policy制御）
    │
    └─ AccessToken.vue
           ├─ @on-copy → onCopyToken
           │      └─ copyTextToClipboard
           └─ @on-reset → resetAccessToken
                   └─ $store.dispatch('resetAccessToken')
```

### データフロー図

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

currentUser ────────────▶ initializeUser ──────────────▶ ローカルstate
                              │
フォーム入力 ──────────────────▶
                              │
                              ▼
                      updateProfile / updateSignature
                              │
                              ▼
                      dispatchUpdate
                              │
                              ▼
                      $store.dispatch('updateProfile') ─▶ API呼び出し
                              │                                │
                              ▼                                ▼
                      成功/失敗メッセージ               users テーブル更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Index.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue` | ソース | メインページコンポーネント |
| UserProfilePicture.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/UserProfilePicture.vue` | ソース | アバター管理 |
| UserBasicDetails.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/UserBasicDetails.vue` | ソース | 基本情報フォーム |
| MessageSignature.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/MessageSignature.vue` | ソース | 署名エディタ |
| HotKeyCard.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/HotKeyCard.vue` | ソース | ホットキーカード |
| ChangePassword.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/ChangePassword.vue` | ソース | パスワード変更 |
| NotificationPreferences.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/NotificationPreferences.vue` | ソース | 通知設定 |
| AudioNotifications.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/AudioNotifications.vue` | ソース | 音声通知設定 |
| AccessToken.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/AccessToken.vue` | ソース | トークン管理 |
| MfaSettingsCard.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/MfaSettingsCard.vue` | ソース | MFA設定カード |
| FontSize.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/FontSize.vue` | ソース | フォントサイズ設定 |
| UserLanguageSelect.vue | `app/javascript/dashboard/routes/dashboard/settings/profile/UserLanguageSelect.vue` | ソース | 言語設定 |
| FormSection.vue | `app/javascript/dashboard/components/FormSection.vue` | ソース | フォームセクション |
| auth/index.js | `app/javascript/dashboard/store/modules/auth/index.js` | ソース | 認証Vuexモジュール |
| useUISettings.js | `app/javascript/dashboard/composables/useUISettings.js` | ソース | UI設定composable |
