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

## 概要

本ドキュメントは、Ghost管理画面における「プロフィール画面（Profile）」の設計仕様を記述したものである。この画面では、自分または他のユーザーのActivityPubプロフィールを表示し、投稿一覧、いいね一覧、フォロー/フォロワーリストを確認できる。

### 本画面の処理概要

プロフィール画面は、ActivityPubアカウントの詳細情報を表示するビューである。自分のプロフィールの場合は編集も可能。投稿、いいね、フォロー中、フォロワーの4つのタブでコンテンツを切り替えて表示できる。

**業務上の目的・背景**：ソーシャルウェブにおいて、プロフィールは自分のアイデンティティを表現する重要な要素である。この画面により、自分のプロフィールを確認・編集したり、他のユーザーのプロフィールを閲覧してフォローするかどうかを判断できる。また、フォロー/フォロワーの管理も行える。

**画面へのアクセス方法**：Ghost管理画面のサイドバーから「Social」セクションへアクセスし、「Profile」を選択。他のユーザーのプロフィールは、ノートやコメントからのリンクでアクセス。URL は `/ghost/#/activitypub/profile` または `/ghost/#/activitypub/profile/:handle/:tab?`。

**主要な操作・処理内容**：
1. プロフィール情報の表示（アバター、名前、ハンドル、バイオ、カスタムフィールド）
2. 投稿一覧の表示（Posts タブ）
3. いいね一覧の表示（Likes タブ、自分のみ）
4. フォロー中一覧の表示（Following タブ）
5. フォロワー一覧の表示（Followers タブ）
6. フォロー/アンフォロー操作
7. プロフィール編集（自分のみ）

**画面遷移**：サイドバー、ノート、通知などからアクセス。タブ切り替えでURLが更新される。設定画面からプロフィール編集ダイアログを開ける。

**権限による表示制御**：ActivityPub機能が有効化されている場合にのみ表示される。Likesタブは自分のプロフィールのみ表示。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 57 | ActivityPub | 主機能 | ActivityPubプロフィールの表示・編集 |

## 画面種別

詳細画面 + タブビュー

## URL/ルーティング

- 自分のプロフィール: `/ghost/#/activitypub/profile`
- 自分のいいね: `/ghost/#/activitypub/profile/likes`
- 自分のフォロー中: `/ghost/#/activitypub/profile/following`
- 自分のフォロワー: `/ghost/#/activitypub/profile/followers`
- 他のユーザー: `/ghost/#/activitypub/profile/:handle`
- 他のユーザー（タブ付き）: `/ghost/#/activitypub/profile/:handle/:tab`
- ページタイトル: 「Profile」

## 入出力項目

### 表示用データ

| 項目名 | データ型 | 入力/出力 | 説明 |
|--------|----------|----------|------|
| アカウント | Account | 出力 | プロフィール情報 |
| 投稿一覧 | Activity[] | 出力 | 投稿タブのコンテンツ |
| いいね一覧 | Activity[] | 出力 | いいねタブのコンテンツ |
| フォロー中 | Account[] | 出力 | フォロー中タブのコンテンツ |
| フォロワー | Account[] | 出力 | フォロワータブのコンテンツ |

## 表示項目

### プロフィールヘッダー

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| カバー画像 | 画像 | プロフィールのカバー/バナー画像 |
| アバター | 画像 | プロフィールアバター |
| 名前 | テキスト | 表示名 |
| ハンドル | テキスト | @username@domain形式 |
| バイオ | テキスト | 自己紹介文 |
| カスタムフィールド | テキスト | 追加情報（リンク等） |
| フォローボタン | ボタン | フォロー/フォロー中（他ユーザー時） |
| 編集ボタン | ボタン | プロフィール編集（自分時） |
| フォロー数 | 数値 | フォロー中の数 |
| フォロワー数 | 数値 | フォロワーの数 |

### タブ一覧

| タブ名 | 表示条件 | 説明 |
|--------|----------|------|
| Posts | 常時 | 投稿一覧 |
| Likes | 自分のみ | いいねした投稿一覧 |
| Following | 常時 | フォロー中アカウント一覧 |
| Followers | 常時 | フォロワーアカウント一覧 |

## イベント仕様

### 1-タブ切り替え

1. タブをクリック
2. URLを更新（`/profile/likes`、`/profile/following` 等）
3. 対応するタブコンポーネントを表示
4. データが未取得の場合は取得開始

### 2-フォロー操作

1. FollowButton をクリック
2. フォロー/アンフォロー API を呼び出し
3. 成功時：ボタン状態を反転、フォロー数を更新
4. 失敗時：エラートースト表示

### 3-プロフィール編集

1. 編集ボタンをクリック（自分のプロフィールのみ）
2. 編集ダイアログ/モーダルを開く
3. 変更を入力
4. 保存ボタンで API 呼び出し
5. 成功時：プロフィール情報を更新
6. 失敗時：エラートースト表示

### 4-投稿/いいね無限スクロール

1. スクロールがリスト下部に到達
2. `hasNextPage` が true の場合
3. `fetchNextPage` を実行
4. 追加コンテンツを取得・表示

### 5-フォロー/フォロワーリスト無限スクロール

1. スクロールがリスト下部に到達
2. `hasNextPage` が true の場合
3. `fetchNextPage` を実行
4. 追加アカウントを取得・表示

### 6-ブロック解除（フォローリスト内）

1. ブロック中のアカウントでUnblockButtonをクリック
2. 確認ダイアログを表示
3. 確認後、ブロック解除APIを呼び出し
4. リストを更新

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

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

この画面からの直接的なGhostデータベース更新はなし。ActivityPub APIを経由したリモートサーバーとの通信が行われる。

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| プロフィール取得 | ActivityPub API | GET | アカウント情報の取得 |
| 投稿取得 | ActivityPub API | GET | 投稿一覧の取得 |
| フォロー | ActivityPub API | POST | Follow操作 |
| アンフォロー | ActivityPub API | DELETE | Unfollow操作 |
| プロフィール更新 | ActivityPub API | PATCH | プロフィール編集 |

## メッセージ仕様

| メッセージ種別 | メッセージ内容 | 表示条件 |
|---------------|---------------|----------|
| 情報 | {handle} hasn't posted anything yet | 投稿がない場合 |
| 情報 | You haven't posted anything yet. | 自分の投稿がない場合 |
| 情報 | {handle} have no following | フォロー中がいない場合 |
| 情報 | {handle} have no followers yet | フォロワーがいない場合 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| API エラー（404以外） | AppError コンポーネントでエラー表示 |
| アカウント404 | アカウントが見つからないことを表示 |
| ネットワークエラー | ローディング表示継続 |

## 備考

- 自分のプロフィールは `handle='me'` または未指定でアクセス
- Likesタブは自分のプロフィールでのみ表示される
- カスタムフィールドは `Object.keys(account.customFields)` から動的に生成
- ブロック状態のアカウントは `blockedByMe`、`domainBlockedByMe` でチェック
- プロフィール編集は設定画面（Preferences）からも可能

---

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

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

### 推奨読解順序

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

プロフィール画面では `Account` 型とそれに関連するデータを扱う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | activitypub.ts | `apps/activitypub/src/api/activitypub.ts` | Account型の定義 |

**読解のコツ**: `Account` 型には `customFields` オブジェクトがあり、キー・バリュー形式の追加情報を持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | profile.tsx | `apps/activitypub/src/views/profile/profile.tsx` | Profileコンポーネント（140-176行目） |

**主要処理フロー**:
1. **141行目**: URLパラメータ取得
2. **143行目**: `useAccountForUser` でアカウント情報取得
3. **145-147行目**: handle変更時のrefetch
4. **153-158行目**: カスタムフィールドの構築
5. **160-173行目**: タブコンポーネントの構築

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | profile.tsx | `apps/activitypub/src/views/profile/profile.tsx` | PostsTab, LikesTab, FollowingTab, FollowersTab（16-138行目） |

**主要処理フロー**:
- **16-37行目**: PostsTab - `usePostsByAccount` で投稿取得
- **39-52行目**: LikesTab - `usePostsLikedByAccount` でいいね取得
- **54-96行目**: FollowingTab - `useAccountFollowsForUser` でフォロー中取得
- **98-138行目**: FollowersTab - `useAccountFollowsForUser` でフォロワー取得

#### Step 4: プロフィールページコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | profile-page.tsx | `apps/activitypub/src/views/profile/components/profile-page.tsx` | ProfilePageコンポーネント |

**主要処理フロー**:
- プロフィールヘッダー表示
- タブナビゲーション
- 各タブコンテンツの表示

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

```
Profile (profile.tsx)
    │
    ├─ useParams() → handle, tab取得
    │
    ├─ useAccountForUser(handle || 'me')
    │      └─ GET /accounts/{handle}
    │
    ├─ カスタムフィールド構築
    │      └─ Object.keys(account.customFields).map()
    │
    └─ ProfilePage (profile-page.tsx)
           │
           ├─ プロフィールヘッダー
           │      ├─ カバー画像
           │      ├─ アバター
           │      ├─ 名前・ハンドル
           │      ├─ バイオ
           │      ├─ カスタムフィールド
           │      └─ FollowButton / 編集ボタン
           │
           └─ タブナビゲーション
                  │
                  ├─ PostsTab
                  │      └─ usePostsByAccount
                  │             └─ Posts コンポーネント
                  │
                  ├─ LikesTab（自分のみ）
                  │      └─ usePostsLikedByAccount
                  │             └─ Likes コンポーネント
                  │
                  ├─ FollowingTab
                  │      └─ useAccountFollowsForUser('following')
                  │             └─ ActorList コンポーネント
                  │
                  └─ FollowersTab
                         └─ useAccountFollowsForUser('followers')
                                └─ ActorList コンポーネント
```

### データフロー図

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

URL params ─────────▶ handle, tab
                            │
                            └─ useAccountForUser(handle || 'me')
                                   │
                                   └─ GET /accounts/{handle}
                                          │
                                          └─ Account ─────────▶ ヘッダー表示

タブ選択 ───────────▶ tab状態更新
                            │
                            ├─ 'posts' ──▶ PostsTab
                            │                  └─ usePostsByAccount
                            │
                            ├─ 'likes' ──▶ LikesTab
                            │                  └─ usePostsLikedByAccount
                            │
                            ├─ 'following' ▶ FollowingTab
                            │                  └─ useAccountFollowsForUser
                            │
                            └─ 'followers' ▶ FollowersTab
                                               └─ useAccountFollowsForUser
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| profile.tsx | `apps/activitypub/src/views/profile/profile.tsx` | ソース | Profileメインコンポーネント |
| profile-page.tsx | `apps/activitypub/src/views/profile/components/profile-page.tsx` | ソース | プロフィールページ表示 |
| posts.tsx | `apps/activitypub/src/views/profile/components/posts.tsx` | ソース | 投稿一覧タブ |
| likes.tsx | `apps/activitypub/src/views/profile/components/likes.tsx` | ソース | いいね一覧タブ |
| actor-list.tsx | `apps/activitypub/src/views/profile/components/actor-list.tsx` | ソース | フォロー/フォロワー一覧 |
| profile-menu.tsx | `apps/activitypub/src/views/profile/components/profile-menu.tsx` | ソース | プロフィールメニュー |
| use-activity-pub-queries.ts | `apps/activitypub/src/hooks/use-activity-pub-queries.ts` | ソース | ActivityPub APIフック |
| routes.tsx | `apps/activitypub/src/routes.tsx` | ソース | ルーティング定義 |
