# 画面設計書 35-アカウント一般設定画面

## 概要

ユーザーの基本的なアカウント情報（表示名、メールアドレス、アバター）を管理し、ログアウトを行うための設定画面。

### 本画面の処理概要

**業務上の目的・背景**：ユーザーが自身のプロフィール情報を管理し、Giselleサービスからのログアウトを行うための画面である。表示名は他のチームメンバーに表示される名前として使用され、アバター画像はプロフィールアイコンとして各所に表示される。

**画面へのアクセス方法**：設定画面 > アカウント設定 > 一般 からアクセスする。URLは `/settings/account/general`。

**主要な操作・処理内容**：
1. 表示名の変更：表示名フィールドを編集して「Save」ボタンで保存
2. アバターの変更：アバター画像をクリックしてファイルをアップロード
3. メールアドレスの表示：アカウントに紐づくメールアドレスを表示（変更不可）
4. ログアウト：「Log Out」ボタンで全セッションからログアウト

**画面遷移**：
- 前画面：アカウント設定画面（/settings/account）
- 関連画面：認証設定画面（/settings/account/authentication）

**権限による表示制御**：
- 全てのログイン済みユーザーがアクセス可能
- メールアドレスは読み取り専用

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 96 | ユーザー認証 | 主機能 | 表示名、メールアドレス設定、ログアウト処理 |

## 画面種別

編集

## URL/ルーティング

`/settings/account/general`

## 入出力項目

### 表示名フォーム

| 項目名 | 入出力 | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| Display Name | 入力 | string | - | ユーザーの表示名 |
| Avatar | 入力 | File | - | プロフィール画像（画像ファイル） |

### メールアドレス表示

| 項目名 | 入出力 | データ型 | 必須 | 説明 |
|--------|--------|----------|------|------|
| Email address | 表示 | string | - | アカウントのメールアドレス（読み取り専用） |

## 表示項目

### アカウント情報

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| Display Name | string | 現在の表示名 |
| Avatar | string | アバター画像URL |
| Email | string | メールアドレス（読み取り専用） |

## イベント仕様

### 1-表示名保存ボタン押下

表示名を編集後、「Save」ボタンを押下して保存する。

1. フォームデータを取得
2. `updateDisplayName` Server Action を呼び出し
3. `users` テーブルの displayName カラムを更新
4. `revalidatePath` で画面を更新
5. 成功時：成功メッセージを表示
6. 失敗時：エラーメッセージを表示

### 2-アバター変更

アバター画像をクリックしてファイルを選択する。

1. ファイル選択ダイアログを開く
2. 画像ファイルを選択
3. `updateAvatar` Server Action を呼び出し
4. マジックバイトによるファイル形式検証
5. Supabase Storage にアップロード
6. `users` テーブルの avatarUrl カラムを更新
7. 古いアバター画像を削除（失敗しても処理続行）
8. `revalidatePath` で画面を更新

### 3-ログアウトボタン押下

「Log Out」ボタンを押下して全セッションからログアウトする。

1. `SignOutButton` コンポーネントがクリックイベントを処理
2. Supabase の signOut を呼び出し
3. ログイン画面にリダイレクト

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 表示名保存 | users | UPDATE | displayName カラムの更新 |
| アバター変更 | users | UPDATE | avatarUrl カラムの更新 |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | display_name | フォーム入力値 | 表示名の更新 |
| UPDATE | avatar_url | Storage URL | アバター画像URLの更新 |

### ストレージ更新

| 操作 | バケット | 内容 |
|-----|---------|------|
| アップロード | avatars | 新しいアバター画像を保存 |
| 削除 | avatars | 古いアバター画像を削除 |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|---------|
| 成功 | （画面更新） | 表示名/アバター更新成功時 |
| エラー | User not found | ユーザーが見つからない場合 |
| エラー | Missing avatar file | アバターファイルが未選択の場合 |
| エラー | （画像形式エラー） | 不正な画像形式の場合 |
| 情報 | This email will be used for account-related notifications. | メールアドレスフィールドの説明 |
| 情報 | Log out of all sessions. | セッションセクションの説明 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| ユーザー未検出 | エラー「User not found」をスロー |
| ファイル未選択 | エラー「Missing avatar file」をスロー |
| 画像形式不正 | バリデーションエラーをスロー |
| アップロード失敗 | エラーをスローし、処理を中止 |
| 古いアバター削除失敗 | エラーをログに記録するが、処理は成功として扱う |

## 備考

- メールアドレスは認証プロバイダー経由で設定されるため、この画面では変更不可
- アバター画像は以下の形式をサポート：PNG, JPEG, GIF, WebP
- アバター画像はマジックバイトで検証され、拡張子のみのチェックではない
- 古いアバターの削除に失敗しても、新しいアバターの設定は成功として扱う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | page.tsx | `apps/studio.giselles.ai/app/(main)/settings/account/general/page.tsx` | Server Component としてのページレンダリング |

**主要処理フロー**:
1. **行9**: getAccountInfo() でアカウント情報を取得
2. **行15-19**: AccountDisplayNameForm のレンダリング
3. **行20-33**: Email フィールドの表示（読み取り専用）
4. **行34-42**: セッションセクション（ログアウトボタン）

#### Step 2: Server Actions を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | actions.ts | `apps/studio.giselles.ai/app/(main)/settings/account/actions.ts` | getAccountInfo, updateDisplayName, updateAvatar |

**主要処理フロー**:
- **行85-107**: getAccountInfo - ユーザー情報取得
- **行109-137**: updateDisplayName - 表示名更新
- **行168-230**: updateAvatar - アバター更新（バリデーション、アップロード、削除）

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

```
AccountGeneralPage (page.tsx)
    │
    ├─ getAccountInfo() ─────────────────────────────────▶ ユーザー情報取得
    │      └─ db.select() → users + supabaseUserMappings
    │
    ├─ AccountDisplayNameForm
    │      └─ updateDisplayName()
    │             └─ db.update() → users.displayName
    │
    ├─ SignOutButton
    │      └─ Supabase signOut()
    │
    └─ アバタークリック
           └─ updateAvatar()
                  ├─ validateImageFileWithMagicBytes()
                  ├─ uploadAvatar() → Supabase Storage
                  ├─ db.update() → users.avatarUrl
                  └─ deleteAvatar() → 古い画像削除
```

### データフロー図

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

User Session ───────────────▶   getAccountInfo() ──────────────▶ {displayName, email, avatarUrl}
                                        │
                                        ▼
                                ┌─────────────────────┐
                                │ AccountDisplay      │
                                │ NameForm            │ ─────────▶ 画面表示
                                └─────────────────────┘

Form Input ─────────────────▶   updateDisplayName() ───────────▶ users.displayName 更新
(displayName)

File Input ─────────────────▶   updateAvatar() ────────────────▶ users.avatarUrl 更新
(avatar)                               │
                                       ├─ validateImageFileWithMagicBytes()
                                       ├─ uploadAvatar() → Storage
                                       └─ deleteAvatar() → 古い画像削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| page.tsx | `apps/studio.giselles.ai/app/(main)/settings/account/general/page.tsx` | ソース | ページのエントリーポイント |
| actions.ts | `apps/studio.giselles.ai/app/(main)/settings/account/actions.ts` | ソース | Server Actions |
| account-display-name-form.tsx | `apps/studio.giselles.ai/app/(main)/settings/account/account-display-name-form.tsx` | ソース | 表示名編集フォームコンポーネント |
| avatar-upload.ts | `apps/studio.giselles.ai/app/(main)/settings/utils/avatar-upload.ts` | ソース | アバターアップロードユーティリティ |
| sign-out-button.tsx | `apps/studio.giselles.ai/services/accounts/components/user-button/sign-out-button.tsx` | ソース | ログアウトボタンコンポーネント |
