# 画面設計書 58-インテグレーション設定

## 概要

本ドキュメントは、Ghost管理画面における「インテグレーション設定」画面の設計仕様を記述するものである。

### 本画面の処理概要

インテグレーション設定画面は、Ghostと外部サービスを連携するためのインテグレーションを管理する画面である。ビルトインインテグレーション（Zapier、Slack、Unsplash等）とカスタムインテグレーション（ユーザー定義）の2種類を管理できる。

**業務上の目的・背景**：現代のウェブパブリッシングでは、複数のツールやサービスを組み合わせたワークフローが一般的である。インテグレーション機能により、Ghostと他のサービス（オートメーション、通知、画像、アフィリエイト等）を連携させ、業務効率を向上できる。また、カスタムインテグレーションを作成することで、独自のAPIクライアントやWebhookを設定できる。

**画面へのアクセス方法**：管理画面のサイドメニューから「Settings」を選択し、「Advanced」セクション内の「Integrations」項目をクリックしてアクセスする。URLパスは`#/settings/integrations`となる。

**主要な操作・処理内容**：
1. ビルトインインテグレーションの一覧表示と設定
2. カスタムインテグレーションの一覧表示・作成・削除
3. 各インテグレーションの詳細設定（モーダル）

**画面遷移**：設定画面のAdvancedセクションからアクセスする。各インテグレーション項目クリックで設定モーダルが開く。「Add custom integration」ボタンからは新規作成モーダル（integrations/new）へ遷移する。

**権限による表示制御**：Administrator（管理者）およびOwner（オーナー）ロールのみがこの設定にアクセス・編集可能である。Ghost ProではZapierなど一部機能が制限される場合がある。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 46 | カスタムインテグレーション | 主機能 | 外部サービス連携の設定 |
| 47 | Webhook | 補助機能 | Webhookの設定・管理 |
| 89 | APIキー管理 | 補助機能 | APIキーの発行・管理 |

## 画面種別

一覧（タブ切り替え式）

## URL/ルーティング

- 管理画面URL: `/ghost/#/settings/integrations`
- 内部ルーティング: `navid='integrations'`
- ReactコンポーネントID: `TopLevelGroup` with `testId='integrations'`
- モーダルルート（ビルトイン）: `/ghost/#/settings/integrations/{serviceName}`
- モーダルルート（カスタム）: `/ghost/#/settings/integrations/{integrationId}`
- モーダルルート（新規作成）: `/ghost/#/settings/integrations/new`

## 入出力項目

| 項目名 | 項目ID | データ型 | 入力/出力 | 必須 | 最大長 | 説明 |
|--------|--------|----------|-----------|------|--------|------|
| （この画面自体には入力項目なし - モーダルで設定） | - | - | - | - | - | - |

## 表示項目

| 項目名 | 表示条件 | 説明 |
|--------|----------|------|
| ヘッダー画像 | 常時 | integrations-settings.png - インテグレーションの紹介画像 |
| Built-inタブ | 常時 | ビルトインインテグレーションの一覧 |
| Customタブ | 常時 | カスタムインテグレーションの一覧 |
| Add custom integrationボタン | 常時 | 新規カスタムインテグレーション作成ボタン |
| Zapierインテグレーション | Built-inタブ | Zapierとの連携設定 |
| Slackインテグレーション | Built-inタブ | Slackとの連携設定（Active状態表示あり） |
| Unsplashインテグレーション | Built-inタブ | Unsplashとの連携設定（Active状態表示あり） |
| FirstPromoterインテグレーション | Built-inタブ | FirstPromoterとの連携設定（Active状態表示あり） |
| Pinturaインテグレーション | Built-inタブ | Pinturaとの連携設定（Active状態表示あり） |
| Transistorインテグレーション | Built-inタブ（フィーチャーフラグ有効時） | Transistorとの連携設定（Active状態表示あり） |
| カスタムインテグレーションリスト | Customタブ | 作成済みカスタムインテグレーションの一覧 |
| 空状態メッセージ | Customタブ（インテグレーションなし） | 「No custom integration.」の表示 |

## イベント仕様

### 1-タブ切り替え

TabViewコンポーネントでタブを選択すると、selectedTab状態が更新され、対応するリストが表示される。初期値は'built-in'。

### 2-ビルトインインテグレーション項目クリック

IntegrationItemコンポーネントのクリックイベントでopenModal関数が呼び出される。updateRoute('integrations/{serviceName}')を実行して設定モーダルが表示される。

### 3-カスタムインテグレーション項目クリック

IntegrationItemコンポーネントのクリックイベントでupdateRoute('integrations/{integrationId}')が呼び出され、詳細設定モーダルが表示される。

### 4-カスタムインテグレーション削除

IntegrationItemのDeleteボタンクリックでConfirmationModalが表示される。確認後、deleteIntegration APIが呼び出されてインテグレーションが削除される。削除成功時にはトースト通知が表示される。

### 5-Add custom integration押下

ボタン押下時にupdateRoute('integrations/new')が呼び出され、新規作成モーダルが表示される。同時にselectedTabが'custom'に変更される。

### 6-Upgradeボタン押下（制限時）

ZapierなどがGhost Pro制限で無効化されている場合、「Upgrade」ボタンが表示される。クリックするとupdateRoute({route: 'pro', isExternal: true})が実行され、Proプランへのアップグレードページへ遷移する。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| カスタムインテグレーション作成（モーダル） | integrations | INSERT | 新規インテグレーションレコードを作成 |
| カスタムインテグレーション編集（モーダル） | integrations | UPDATE | インテグレーションレコードを更新 |
| カスタムインテグレーション削除 | integrations | DELETE | インテグレーションレコードを削除 |
| カスタムインテグレーション削除 | api_keys | DELETE | 関連するAPIキーを削除 |
| カスタムインテグレーション削除 | webhooks | DELETE | 関連するWebhookを削除 |

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

#### integrations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | name | インテグレーション名 | |
| INSERT | description | 説明文 | |
| INSERT | type | 'custom' | |
| INSERT | icon_image | アイコン画像URL | オプション |
| DELETE | id | 削除対象のID | |

## メッセージ仕様

| メッセージID | 種類 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| MSG-001 | 説明 | Make Ghost work with apps and tools. | 説明文 |
| MSG-002 | 確認 | Are you sure? | 削除確認ダイアログタイトル |
| MSG-003 | 確認 | Deleting this integration will remove all webhooks and api keys associated with it. | 削除確認ダイアログ本文 |
| MSG-004 | 成功 | Integration deleted | 削除成功トースト |
| MSG-005 | 情報 | No custom integration. | カスタムインテグレーションがない場合 |
| MSG-006 | ラベル | Active | インテグレーションが有効な場合のバッジ |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| Ghost Pro制限 | Upgradeボタンを表示、項目をグレーアウト |
| 削除API失敗 | handleError関数でエラートーストを表示 |
| セッション切れ | 認証画面へリダイレクト |

## 備考

- ビルトインインテグレーション一覧：
  - Zapier: アプリ間オートメーション（Ghost Proで制限あり）
  - Slack: チーム通知（slackUrl && slackUsernameで有効判定）
  - Unsplash: 無料画像素材（unsplash設定で有効判定）
  - FirstPromoter: アフィリエイトプログラム（firstpromoter設定で有効判定）
  - Pintura: 画像編集（pinturaEditor.isEnabledで有効判定）
  - Transistor: ポッドキャスト（transistorフィーチャーフラグ && transistor設定で表示・有効判定）
- カスタムインテグレーションにはAPIキー（Content API / Admin API）とWebhookが関連付けられる
- インテグレーション削除時は関連するAPIキーとWebhookも自動削除される

---

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

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

### 推奨読解順序

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

Integration型とAPI定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | integrations.ts | `apps/admin-x-framework/src/api/integrations.ts` | Integration型の定義（7-18行目）、useBrowseIntegrations等 |
| 1-2 | api-keys.ts | `apps/admin-x-framework/src/api/api-keys.ts` | APIKey型の定義 |
| 1-3 | webhooks.ts | `apps/admin-x-framework/src/api/webhooks.ts` | Webhook型の定義 |

**読解のコツ**: Integrationにはtype（builtin/core/custom）があり、APIキーとWebhookの配列を持つ。

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

インテグレーション設定画面のメインファイルを読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | integrations.tsx | `apps/admin-x-settings/src/components/settings/advanced/integrations.tsx` | コンポーネント全体の構造、タブ管理 |

**主要処理フロー**:
1. **220-223行目**: useBrowseIntegrationsでインテグレーション一覧を取得
2. **221行目**: selectedTab状態の管理（'built-in' | 'custom'）
3. **225-236行目**: tabs配列の定義（BuiltInIntegrations, CustomIntegrations）
4. **238-249行目**: Add custom integrationボタンの定義

#### Step 3: ビルトインインテグレーションを理解する

BuiltInIntegrationsコンポーネントの実装を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | integrations.tsx | `apps/admin-x-settings/src/components/settings/advanced/integrations.tsx` | BuiltInIntegrationsコンポーネント（75-163行目） |

**主要処理フロー**:
- **76-77行目**: config取得、制限チェック用
- **83行目**: zapierDisabledでGhost Pro制限チェック
- **86行目**: usePinturaEditorでPintura有効状態取得
- **89-95行目**: 各サービスの有効状態を設定から取得
- **99-159行目**: 各IntegrationItemの定義

#### Step 4: カスタムインテグレーションを理解する

CustomIntegrationsコンポーネントの実装を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | integrations.tsx | `apps/admin-x-settings/src/components/settings/advanced/integrations.tsx` | CustomIntegrationsコンポーネント（165-218行目） |

**主要処理フロー**:
- **166-168行目**: updateRoute/deleteIntegration/handleError取得
- **170-212行目**: インテグレーションがある場合のリスト表示
- **186-208行目**: 削除処理（ConfirmationModal + deleteIntegration API）

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

```
Integrations (integrations.tsx)
    │
    ├─ useBrowseIntegrations()
    │      └─ GET /integrations/?include=api_keys,webhooks
    │
    ├─ TabView
    │      ├─ Tab: Built-in
    │      │      └─ BuiltInIntegrations
    │      │             ├─ useGlobalData() ... config取得
    │      │             ├─ usePinturaEditor() ... Pintura状態
    │      │             ├─ useFeatureFlag('transistor')
    │      │             └─ IntegrationItem (multiple)
    │      │                    ├─ active判定 (設定値から)
    │      │                    ├─ disabled判定 (Ghost Pro制限)
    │      │                    └─ onClick → openModal()
    │      │
    │      └─ Tab: Custom
    │             └─ CustomIntegrations
    │                    ├─ useDeleteIntegration()
    │                    └─ IntegrationItem (multiple)
    │                           ├─ onClick → updateRoute(id)
    │                           └─ onDelete → ConfirmationModal
    │                                  └─ deleteIntegration(id)
    │
    └─ Add custom integration ボタン
           └─ updateRoute('integrations/new')
```

### データフロー図

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

API取得
/integrations/ ───▶ useBrowseIntegrations ───▶ integrations[]
    │
    └─ filter(type === 'custom') ───▶ CustomIntegrations

Built-in判定
settings ───▶ getSettingValues
    ├─ unsplash → Unsplash Active状態
    ├─ firstpromoter → FirstPromoter Active状態
    ├─ slack_url + slack_username → Slack Active状態
    └─ transistor → Transistor Active状態

config ───▶ hostSettings.limits ───▶ zapierDisabled

ユーザー操作
Item click (Built-in) ───▶ openModal(serviceName) ───▶ integrations/{serviceName}
Item click (Custom) ───▶ updateRoute(id) ───▶ integrations/{id}
Delete click ───▶ ConfirmationModal
    │
    └─ Confirm ───▶ deleteIntegration(id) ───▶ DELETE /integrations/{id}/
                                                   │
                                                   └─ Toast: 'Integration deleted'
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| integrations.tsx | `apps/admin-x-settings/src/components/settings/advanced/integrations.tsx` | ソース | インテグレーション設定画面のメインコンポーネント |
| integrations.ts | `apps/admin-x-framework/src/api/integrations.ts` | ソース | Integrations API定義 |
| api-keys.ts | `apps/admin-x-framework/src/api/api-keys.ts` | ソース | API Keys API定義 |
| webhooks.ts | `apps/admin-x-framework/src/api/webhooks.ts` | ソース | Webhooks API定義 |
| use-pintura-editor.ts | `apps/admin-x-settings/src/hooks/use-pintura-editor.ts` | ソース | Pintura有効状態フック |
| use-feature-flag.ts | `apps/admin-x-settings/src/hooks/use-feature-flag.ts` | ソース | フィーチャーフラグフック |
| integrations-settings.png | `apps/admin-x-settings/src/assets/images/integrations-settings.png` | アセット | ヘッダー画像 |
