# 画面設計書 92-ポータル新規作成画面

## 概要

本ドキュメントは、Chatwootのヘルプセンター機能における「ポータル新規作成画面」の設計仕様を記述したものである。

### 本画面の処理概要

ポータル新規作成画面は、ヘルプセンターポータルが存在しない場合に表示される画面であり、新しいポータルの作成を促すエンプティステート（空状態）画面として機能する。

**業務上の目的・背景**：顧客サポート業務において、セルフサービス型のヘルプセンターを初めて構築する際のエントリーポイントとなる画面である。ユーザーがヘルプセンター機能に初めてアクセスした際、直感的にポータル作成を開始できるようにガイダンスを提供する。視覚的なサンプル記事カードを表示することで、ポータル作成後の完成イメージを伝える。

**画面へのアクセス方法**：サイドナビゲーションの「ヘルプセンター」メニューをクリック後、ポータルが存在しない場合に自動リダイレクト、または直接URL `/app/accounts/:accountId/portals/new` にアクセスする。

**主要な操作・処理内容**：
1. ヘルプセンターの概要説明を表示
2. サンプル記事カードによるビジュアルプレビューを表示
3. 「Create Portal」ボタン押下でポータル作成ダイアログを開く
4. ダイアログでポータル名とスラッグを入力して作成
5. 作成成功後、記事一覧画面へ遷移

**画面遷移**：
- 遷移元：ポータル一覧画面（ポータル不在時の自動リダイレクト）
- 遷移先：記事一覧画面（portals_articles_index）- 作成成功時

**権限による表示制御**：administrator、knowledge_base_manage権限を持つユーザーのみアクセス可能。HELP_CENTERフィーチャーフラグが有効である必要がある。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 151 | ポータル | 主機能 | 新しいポータルの作成 |

## 画面種別

登録（エンプティステート・作成誘導画面）

## URL/ルーティング

| 項目 | 値 |
|------|-----|
| パス | `/app/accounts/:accountId/portals/new` |
| ルート名 | `portals_new` |
| コンポーネント | `PortalsNewPage.vue` |

## 入出力項目

### 入力項目（URLパラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| accountId | Number | Yes | アカウントID |

### 入力項目（ダイアログフォーム）

| 項目名 | 型 | 必須 | バリデーション | 説明 |
|--------|-----|------|--------------|------|
| name | String | Yes | 必須入力 | ポータル名（例：User Guide \| Chatwoot） |
| slug | String | Yes | 必須入力、英数字・ハイフン形式 | URLスラッグ（例：user-guide） |

### 出力項目

| 項目名 | 型 | 説明 |
|--------|-----|------|
| portalSlug | String | 作成されたポータルのスラッグ |
| locale | String | デフォルトロケール（通常 "en"） |

## 表示項目

### エンプティステートレイアウト

| 項目名 | 型 | 説明 |
|--------|-----|------|
| タイトル | String | "Help Center" |
| サブタイトル | String | ヘルプセンターの説明文 |
| サンプル記事カード | Component | 記事プレビュー表示（2列グリッド） |
| 作成ボタン | Button | "Create Portal" ボタン |

### 作成ダイアログ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ダイアログタイトル | String | "Create new portal" |
| 説明文 | String | ポータル作成のガイダンス |
| 名前入力フィールド | Input | ポータル名入力 |
| スラッグ入力フィールド | Input | URLスラッグ入力 |
| 作成ボタン | Button | "Create" ボタン |

## イベント仕様

### 1-ポータル作成ダイアログを開く

**トリガー**: 「Create Portal」ボタンクリック

**処理フロー**:
1. CreatePortalDialogコンポーネントのdialogRef.open()を呼び出し
2. ダイアログがモーダル表示される

### 2-ポータルを作成

**トリガー**: ダイアログ内の「Create」ボタンクリック

**処理フロー**:
1. フォームバリデーション（名前・スラッグの必須チェック）
2. スラッグの形式チェック（英数字・ハイフンのみ）
3. `portals/create` アクションをディスパッチ
4. POST `/api/v1/accounts/:accountId/portals` を呼び出し
5. 成功時：記事一覧画面へ遷移
6. 失敗時：エラーメッセージを表示

### 3-作成成功後の画面遷移

**トリガー**: ポータル作成成功

**処理フロー**:
1. onPortalCreateコールバックが呼び出される
2. 作成されたポータルのslugとlocaleをパラメータに設定
3. router.pushで `portals_articles_index` へ遷移

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ポータル作成 | portals | INSERT | 新しいポータルレコードを作成 |

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

#### portals

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | フォーム入力値 | 必須 |
| INSERT | slug | フォーム入力値 | 必須、一意制約 |
| INSERT | account_id | Current.account.id | 自動設定 |
| INSERT | config | { default_locale: 'en', allowed_locales: ['en'] } | デフォルト設定 |
| INSERT | archived | false | デフォルト |
| INSERT | created_at | 現在日時 | 自動設定 |
| INSERT | updated_at | 現在日時 | 自動設定 |

## メッセージ仕様

| 種別 | メッセージキー | メッセージ内容 | 表示条件 |
|------|--------------|--------------|----------|
| 画面タイトル | HELP_CENTER.TITLE | "Help Center" | 常時 |
| 画面説明 | HELP_CENTER.NEW_PAGE.DESCRIPTION | "Create self-service help center portals..." | 常時 |
| ボタン | HELP_CENTER.NEW_PAGE.CREATE_PORTAL_BUTTON | "Create Portal" | 常時 |
| ダイアログタイトル | HELP_CENTER.CREATE_PORTAL_DIALOG.TITLE | "Create new portal" | ダイアログ表示時 |
| 名前エラー | HELP_CENTER.CREATE_PORTAL_DIALOG.NAME.ERROR | "Name is required" | バリデーションエラー時 |
| スラッグエラー | HELP_CENTER.CREATE_PORTAL_DIALOG.SLUG.ERROR | "Slug is required" | バリデーションエラー時 |
| スラッグ形式エラー | HELP_CENTER.CREATE_PORTAL_DIALOG.SLUG.FORMAT_ERROR | "Please enter a valid slug..." | 形式エラー時 |
| 成功 | HELP_CENTER.PORTAL_SETTINGS.API.CREATE_PORTAL.SUCCESS_MESSAGE | "Portal created successfully" | 作成成功時 |
| 失敗 | HELP_CENTER.PORTAL_SETTINGS.API.CREATE_PORTAL.ERROR_MESSAGE | "Unable to create portal" | 作成失敗時 |

## 例外処理

| 例外状況 | 処理内容 |
|---------|---------|
| バリデーションエラー | フォームにエラーメッセージを表示、送信を阻止 |
| スラッグ重複 | APIエラーレスポンスでエラーメッセージを表示 |
| ネットワークエラー | アラートでエラーメッセージを表示 |
| 権限不足 | ルートガードによりアクセス拒否 |

## 備考

- 本画面はポータルが存在しない場合のエントリーポイント
- サンプル記事カードはハードコードされたダミーデータ
- フィーチャーフラグ `HELP_CENTER` が有効である必要がある
- administrator または knowledge_base_manage 権限が必要（agentは不可）

---

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

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

### 推奨読解順序

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

ポータルのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Portal (Model) | `app/models/portal.rb` | ポータルのスキーマ定義、バリデーション |
| 1-2 | portals_controller.rb | `app/controllers/api/v1/accounts/portals_controller.rb` | createアクションのパラメータ |

**読解のコツ**: portal_paramsメソッドで許可されているパラメータを確認し、必須項目を把握する。

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

画面のエントリーポイントとコンポーネント構成を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | PortalsNewPage.vue | `app/javascript/dashboard/routes/dashboard/helpcenter/pages/PortalsNewPage.vue` | 画面のシンプルな構成 |
| 2-2 | PortalEmptyState.vue | `app/javascript/dashboard/components-next/HelpCenter/EmptyState/Portal/PortalEmptyState.vue` | エンプティステートUI |
| 2-3 | helpcenter.routes.js | `app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js` | ルート定義とmeta情報 |

**主要処理フロー**:
1. **PortalsNewPage.vue**: PortalEmptyStateコンポーネントをラップするだけ
2. **PortalEmptyState.vue 11-13行目**: openDialog関数でダイアログを開く
3. **PortalEmptyState.vue 17-22行目**: onPortalCreate関数で作成後の遷移処理

#### Step 3: ダイアログコンポーネントを理解する

ポータル作成ダイアログの処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CreatePortalDialog.vue | `app/javascript/dashboard/components-next/HelpCenter/PortalSwitcher/CreatePortalDialog.vue` | ダイアログ本体 |

**主要処理フロー**:
- フォームバリデーション
- createアクションの呼び出し
- 成功/失敗時のハンドリング

#### Step 4: Vuex Actionsを理解する

ポータル作成のAPI呼び出し処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | actions.js | `app/javascript/dashboard/store/modules/helpCenterPortals/actions.js` | createアクションの実装（39-50行目） |
| 4-2 | portals.js (API) | `app/javascript/dashboard/api/helpCenter/portals.js` | create APIメソッド（継承元） |

**主要処理フロー**:
- **39-50行目**: createアクション - UIフラグ設定、API呼び出し、ストア更新

#### Step 5: バックエンドAPIを理解する

RailsコントローラーでのAPI処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | portals_controller.rb | `app/controllers/api/v1/accounts/portals_controller.rb` | createアクション（17-22行目） |

**主要処理フロー**:
- **17行目**: Current.account.portals.buildでポータルオブジェクト構築
- **18行目**: custom_domainのパース処理
- **19行目**: 保存処理
- **20行目**: ロゴのアタッチ処理

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

```
PortalsNewPage.vue
    │
    └─ PortalEmptyState.vue
           │
           ├─ EmptyStateLayout.vue (UI)
           │      └─ ArticleCard.vue[] (サンプル表示)
           │
           ├─ Button (@click)
           │      └─ openDialog()
           │             └─ createPortalDialogRef.open()
           │
           └─ CreatePortalDialog.vue
                  │
                  ├─ onSubmit()
                  │      └─ store.dispatch('portals/create')
                  │             └─ actions.create()
                  │                    └─ portalAPIs.create()
                  │                           └─ POST /api/v1/accounts/:id/portals
                  │                                  └─ PortalsController#create
                  │
                  └─ @create (emit)
                         └─ onPortalCreate()
                                └─ router.push('portals_articles_index')
```

### データフロー図

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

フォーム入力 ────────▶ CreatePortalDialog ──────────▶ portals/create
  - name                      │
  - slug                      ▼
                         Vuex Action
                              │
                              ▼
                         PortalsAPI.create()
                              │
                              ▼
                         PortalsController#create ──▶ portals INSERT
                              │
                              ▼
                         emit('create') ─────────▶ onPortalCreate()
                              │
                              ▼
                         router.push() ──────────▶ portals_articles_index
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| PortalsNewPage.vue | `app/javascript/dashboard/routes/dashboard/helpcenter/pages/PortalsNewPage.vue` | ソース | 画面コンポーネント |
| PortalEmptyState.vue | `app/javascript/dashboard/components-next/HelpCenter/EmptyState/Portal/PortalEmptyState.vue` | ソース | エンプティステートUI |
| CreatePortalDialog.vue | `app/javascript/dashboard/components-next/HelpCenter/PortalSwitcher/CreatePortalDialog.vue` | ソース | 作成ダイアログ |
| EmptyStateLayout.vue | `app/javascript/dashboard/components-next/EmptyStateLayout.vue` | ソース | レイアウトコンポーネント |
| ArticleCard.vue | `app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue` | ソース | サンプル記事カード |
| helpcenter.routes.js | `app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js` | ソース | ルート定義 |
| actions.js | `app/javascript/dashboard/store/modules/helpCenterPortals/actions.js` | ソース | Vuexアクション |
| portals.js | `app/javascript/dashboard/api/helpCenter/portals.js` | ソース | APIクライアント |
| portals_controller.rb | `app/controllers/api/v1/accounts/portals_controller.rb` | ソース | APIコントローラー |
| portal.rb | `app/models/portal.rb` | ソース | モデル定義 |
| helpCenter.json | `app/javascript/dashboard/i18n/locale/en/helpCenter.json` | 設定 | i18nメッセージ |
