# 画面設計書 46-ポータル設定

## 概要

本ドキュメントは、Ghost管理画面の「ポータル設定」画面の設計仕様を定義する。この画面は会員登録・ログインを行う「Portal」ウィジェットのカスタマイズを行う機能を提供する。

### 本画面の処理概要

この画面では、サイト訪問者がメンバー登録やアカウント管理を行う「Portal」UIのデザインと動作をカスタマイズする。サインアップオプション、外観、アカウントページの設定が可能である。

**業務上の目的・背景**：Portalはサイト訪問者とメンバーシップ機能をつなぐ重要なインターフェースである。ブランドに合わせたカスタマイズにより、一貫したユーザーエクスペリエンスを提供し、会員登録率の向上やメンバー満足度の向上を図ることができる。

**画面へのアクセス方法**：管理画面のサイドバーから「Settings」→「Membership」セクション→「Signup portal」カードの「Customize」ボタンをクリックしてアクセスする。URLは`/ghost/#/settings/portal/edit`となる。

**主要な操作・処理内容**：
1. サインアップオプションの設定（表示ティア、無料/有料プランの切り替え）
2. 外観のカスタマイズ（アイコン、ボタンカラー、表示テキスト）
3. アカウントページの設定（サポートメールアドレス）
4. Signupプレビュー、Accountプレビュー、Linksプレビューの確認
5. サポートメールアドレスの変更と検証

**画面遷移**：設定画面のMembershipセクションから遷移し、ポータル設定モーダルが表示される。保存またはキャンセル後は設定画面に戻る。

**権限による表示制御**：Administrator以上のロールを持つユーザーのみがポータル設定にアクセスできる。メンバーシップ機能が「Nobody」に設定されている場合、Customizeボタンは無効化される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 71 | Portal | 主機能 | 会員ポータルのカスタマイズ設定 |

## 画面種別

設定画面（プレビューモーダル型）

## URL/ルーティング

- メイン画面: `/ghost/#/settings` (navid: `portal`)
- 編集モーダル: `/ghost/#/settings/portal/edit`

## 入出力項目

| 項目名 | 種別 | データ型 | 必須 | 説明 |
|--------|------|---------|------|------|
| Portal plans | 入力 | string[] | - | 表示するプラン（free/monthly/yearly） |
| Portal button | 入力 | boolean | - | Portalボタンの表示有無 |
| Portal button style | 入力 | enum | - | ボタンスタイル（icon-and-text/icon-only/text-only） |
| Portal button text | 入力 | string | - | ボタンに表示するテキスト |
| Portal button icon | 入力 | string | - | ボタンに表示するアイコン |
| Accent color | 入力 | string | - | アクセントカラー |
| Members support address | 入力 | string | - | サポートメールアドレス |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| Signup preview | iframe | サインアップ画面のプレビュー |
| Account preview | iframe | アカウントページのプレビュー |
| Links preview | - | Portalリンクの一覧 |

## イベント仕様

### 1-Customizeボタン押下

「Customize」ボタンをクリックすると：

1. メンバーシップが無効（`members_signup_access === 'none'`）の場合はボタン無効
2. 有効な場合、`portal/edit`ルートへ遷移しモーダルを表示

### 2-タブ切り替え（プレビュー）

「Signup」「Account page」「Links」タブを切り替えると：

1. 対応するプレビューが表示される
2. Signupはサインアップフローのプレビュー
3. Account pageはメンバーアカウントページのプレビュー
4. Linksは埋め込み用リンクの一覧

### 3-タブ切り替え（サイドバー）

「Signup options」「Look & feel」「Account page」タブを切り替えると：

1. 対応する設定フォームが表示される

### 4-サインアップオプション変更

プラン選択やティア設定を変更すると：

1. `updateSetting`でローカル設定を更新
2. プレビューがリアルタイムで反映

### 5-外観設定変更

カラーやテキストを変更すると：

1. `updateSetting`でローカル設定を更新
2. プレビューがリアルタイムで反映

### 6-サポートメールアドレス変更

メールアドレスを変更すると：

1. 保存時にメール検証が必要
2. 検証メールが送信される
3. 検証完了まで古いアドレスを使用

### 7-保存

「Save」ボタンをクリックすると：

1. エラーがある場合は保存を中断
2. ティアの変更は`editTier`で保存
3. 設定の変更は`editSettings`で保存
4. メール変更時は検証モーダルを表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ポータル設定保存 | settings | UPDATE | portal_*設定更新 |
| ティア設定変更 | tiers | UPDATE | ティアの可視性等更新 |

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

#### settings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | key='portal_plans' | JSON配列 | 表示プラン |
| UPDATE | key='portal_button' | boolean | ボタン表示 |
| UPDATE | key='portal_button_style' | enum | ボタンスタイル |
| UPDATE | key='portal_button_text' | string | ボタンテキスト |
| UPDATE | key='portal_button_icon' | string | ボタンアイコン |
| UPDATE | key='members_support_address' | string | サポートアドレス |

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|-----------|----------|
| 確認 | We've sent a confirmation email to {email} | サポートアドレス変更時 |
| 成功 | Support address verified | メール検証完了時 |
| エラー | Error verifying support address | 検証トークン期限切れ時 |

## 例外処理

| 状態 | 処理内容 |
|------|----------|
| メンバーシップ無効 | Customizeボタンを無効化 |
| メール検証トークン期限切れ | エラーモーダルを表示 |
| バリデーションエラー | 保存を中断 |

## 備考

- Portalはサイトに埋め込まれる会員登録・ログインウィジェット
- プレビューはiframeでリアルタイム表示
- サポートメールアドレスの変更には検証が必要
- ティア設定の変更も同時に保存可能
- メンバーシップが「Nobody」の場合は設定不可

---

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

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

### 推奨読解順序

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

まず、ポータル設定に関連する設定値を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | portal-modal.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx` | 設定値の取得（69-70行目） |

**読解のコツ**: `portal_*`プレフィックスの設定が主要なポータル設定を構成する。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | portal.tsx | `apps/admin-x-settings/src/components/settings/membership/portal.tsx` | メインコンポーネントの構造（26-82行目） |
| 2-2 | portal-modal.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx` | モーダルコンポーネントの構造（63-240行目） |

**主要処理フロー**:
1. **portal.tsx 31-33行目**: アクセントカラーとアイコンの取得
2. **portal.tsx 39行目**: メンバーシップ無効時のボタン無効化
3. **portal-modal.tsx 115-155行目**: useFormフックによる設定管理

#### Step 3: サイドバーUIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | signup-options.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/signup-options.tsx` | サインアップオプション設定 |
| 3-2 | look-and-feel.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/look-and-feel.tsx` | 外観設定 |
| 3-3 | account-page.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/account-page.tsx` | アカウントページ設定 |

**主要処理フロー**:
- **portal-modal.tsx 17-61行目**: Sidebarコンポーネントのタブ構成

#### Step 4: プレビューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | portal-preview.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-preview.tsx` | プレビュー表示 |
| 4-2 | portal-frame.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-frame.tsx` | iframeプレビュー |
| 4-3 | portal-links.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-links.tsx` | リンク一覧 |

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

```
Portal (portal.tsx)
    │
    └─ openPreviewModal()
           │
           └─ updateRoute('portal/edit')
                  │
                  └─ PortalModal (portal-modal.tsx)
                         │
                         ├─ useGlobalData()
                         │      └─ settings, siteData, config
                         │
                         ├─ useBrowseTiers()
                         │      └─ allTiers: Tier[]
                         │
                         ├─ useForm()
                         │      ├─ formState: {settings, tiers}
                         │      └─ handleSave()
                         │
                         ├─ Sidebar (TabView)
                         │      ├─ SignupOptions
                         │      ├─ LookAndFeel
                         │      └─ AccountPage
                         │
                         ├─ PortalPreview
                         │      └─ PortalFrame (iframe)
                         │
                         └─ handleSave()
                                ├─ editTier() ──► PUT /tiers/{id}/
                                └─ editSettings() ──► PUT /settings/
```

### データフロー図

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

                    ┌─────────────────┐
Settings DB ────────┤  useGlobalData   │
Tiers DB ───────────┤  useBrowseTiers  │
                    └────────┬─────────┘
                             │
                    ┌────────▼────────┐
                    │     useForm      │
                    │  formState: {    │
                    │    settings,     │
                    │    tiers         │
                    │  }               │
                    └────────┬─────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
    ┌─────────▼────┐  ┌──────▼─────┐  ┌────▼────────┐
    │   Sidebar    │  │  Preview   │  │   Links     │
    │ (設定フォーム)│  │ (iframe)   │  │ (コピー)    │
    └──────┬───────┘  └────────────┘  └─────────────┘
           │
ユーザー入力 ─┘
           │
           │                    ┌─────────────────┐
           │                    │  dirty settings  │
           │                    │  dirty tiers     │
           │                    └────────┬─────────┘
           │                             │
           │                    ┌────────▼────────┐
handleSave() ───────────────────┤   API Calls      │
                                │ editTier()       │
                                │ editSettings()   │
                                └────────┬─────────┘
                                         │
                                ┌────────▼────────┐
                                │      DB         │
                                └─────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| portal.tsx | `apps/admin-x-settings/src/components/settings/membership/portal.tsx` | ソース | メイン設定カードコンポーネント |
| portal-modal.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx` | ソース | ポータル設定モーダル |
| signup-options.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/signup-options.tsx` | ソース | サインアップオプション設定 |
| look-and-feel.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/look-and-feel.tsx` | ソース | 外観設定 |
| account-page.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/account-page.tsx` | ソース | アカウントページ設定 |
| portal-preview.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-preview.tsx` | ソース | プレビュー表示 |
| portal-frame.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-frame.tsx` | ソース | iframeプレビュー |
| portal-links.tsx | `apps/admin-x-settings/src/components/settings/membership/portal/portal-links.tsx` | ソース | リンク一覧 |
