# 機能設計書 46-カスタムインテグレーション

## 概要

本ドキュメントは、Ghost CMSにおけるカスタムインテグレーション機能の設計仕様を記載したものである。

### 本機能の処理概要

カスタムインテグレーション機能は、外部サービスやアプリケーションとGhostを連携させるためのAPIキーとWebhookを管理する機能である。インテグレーションを作成すると、Content APIキーとAdmin APIキーが自動的に発行され、外部からGhostのAPIにアクセスできるようになる。また、Webhookを設定することでGhost内のイベントを外部サービスに通知できる。

**業務上の目的・背景**：Ghost CMSをヘッドレスCMSとして利用したり、外部サービスと連携してワークフローを自動化する需要が増加している。カスタムインテグレーション機能により、安全にAPIアクセスを提供し、イベント駆動の連携を実現する。各インテグレーションは独立して管理され、必要に応じて無効化・削除できる。

**機能の利用シーン**：
- ヘッドレスCMSとしてフロントエンドアプリとの連携
- Zapier/Integromat等の自動化ツールとの連携
- カスタム管理ダッシュボードの構築
- コンテンツ公開時の外部システム通知
- 静的サイトジェネレーターとの連携

**主要な処理内容**：
1. インテグレーションの作成（Add）：名前、説明、アイコンを指定して作成
2. APIキーの自動発行：Content APIキーとAdmin APIキーを同時生成
3. インテグレーションの編集（Edit）：名前、説明、アイコンの更新
4. APIキーの再生成（Refresh）：セキュリティのためのキーローテーション
5. Webhookの管理：インテグレーションに紐づくWebhookの追加・編集
6. インテグレーションの削除（Destroy）：APIキー・Webhookも連動削除

**関連システム・外部連携**：
- APIキー管理（ApiKey Model）との連携
- Webhook管理（Webhook Model）との連携
- 制限管理サービス（Limit Service）による数量制限

**権限による制御**：
- Owner/Administratorのみインテグレーションを管理可能
- カスタムインテグレーション数に制限がある場合あり（プラン依存）
- APIキー経由でインテグレーションのCRUD操作は制限

## 関連画面

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

## 機能種別

CRUD操作 / 自動生成 / 連携管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes（Add時） | インテグレーション名 | 必須、最大191文字 |
| icon_image | string | No | アイコン画像URL | 最大2000文字 |
| description | string | No | 説明文 | 最大2000文字 |
| webhooks | array | No | 紐づくWebhook配列 | Webhookオブジェクト形式 |
| include | string | No | 関連データ取得指定 | api_keys, webhooks |
| limit | integer | No | 取得件数 | 正の整数 |
| id | string | Yes（Edit/Destroy時） | インテグレーションID | 24文字のID |
| keyid | string | No（Edit時） | 再生成するAPIキーID | 24文字のID |

### 入力データソース

- 管理画面のインテグレーション設定
- Admin API（POST/PUT/DELETE）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | インテグレーションの一意識別子 |
| type | string | タイプ（custom/internal/builtin） |
| name | string | インテグレーション名 |
| slug | string | URLスラッグ |
| icon_image | string | アイコン画像URL |
| description | string | 説明文 |
| api_keys | array | 関連するAPIキー配列（include指定時） |
| webhooks | array | 関連するWebhook配列（include指定時） |
| created_at | dateTime | 作成日時 |
| updated_at | dateTime | 更新日時 |

### 出力先

- APIレスポンス（JSON形式）
- 管理画面のインテグレーション一覧・詳細

## 処理フロー

### 処理シーケンス

```
1. インテグレーション作成リクエスト受信
   └─ POST /ghost/api/admin/integrations/
2. 権限チェック
   └─ Owner/Administrator権限の確認
3. 制限チェック
   └─ カスタムインテグレーション数上限の確認
4. スラッグ生成
   └─ 名前からURLスラッグを自動生成
5. APIキー生成
   ├─ Content APIキー生成
   └─ Admin APIキー生成
6. データベース保存
   └─ integrations, api_keysテーブルへINSERT
7. レスポンス返却
   └─ 作成されたインテグレーションデータを返却
```

### フローチャート

```mermaid
flowchart TD
    A[インテグレーション作成リクエスト] --> B{権限チェック}
    B -->|Denied| C[403 Forbidden]
    B -->|Allowed| D{制限チェック}
    D -->|Over Limit| E[HostLimitError]
    D -->|OK| F[スラッグ生成]
    F --> G[Content APIキー生成]
    G --> H[Admin APIキー生成]
    H --> I[DB保存]
    I --> J[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-001 | APIキー自動発行 | 作成時にContent/Admin両方のAPIキーを自動発行 | インテグレーション作成時 |
| BR-46-002 | スラッグ自動生成 | 名前からURLスラッグを自動生成 | 作成・名前変更時 |
| BR-46-003 | カスケード削除 | 削除時に関連APIキー・Webhookも削除 | インテグレーション削除時 |
| BR-46-004 | 数量制限 | プランに応じたカスタムインテグレーション数制限 | 作成時 |
| BR-46-005 | タイプ固定 | カスタムインテグレーションはtype='custom' | 作成時 |
| BR-46-006 | キーローテーション | APIキーの再生成（Refresh）が可能 | 編集時 |

### 計算ロジック

スラッグ生成:
```javascript
// Integration.onSaving内で実行
if (this.hasChanged('slug') || !this.get('slug')) {
    const slug = await ghostBookshelf.Model.generateSlug(
        Integration,
        this.get('slug') || this.get('name'),
        {transacting: options.transacting}
    );
    this.set({slug});
}
```

## データベース操作仕様

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | integrations | INSERT | インテグレーションレコード作成 |
| 作成 | api_keys | INSERT | Content/Admin APIキー2件作成 |
| 編集 | integrations | UPDATE | インテグレーション情報更新 |
| キー再生成 | api_keys | UPDATE | APIキーのsecret再生成 |
| 削除 | integrations | DELETE | インテグレーションレコード削除 |
| 削除 | api_keys | DELETE | 関連APIキーのカスケード削除 |
| 削除 | webhooks | DELETE | 関連Webhookのカスケード削除 |

### テーブル別操作詳細

#### integrations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, type, name, slug, icon_image, description, created_at, updated_at | 新規データ | type='custom' |
| UPDATE | name, slug, icon_image, description, updated_at | 変更データ | |
| DELETE | - | id指定 | カスケード削除あり |

#### api_keys

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id, type, secret, integration_id, created_at, updated_at | Content/Adminの2件 | |
| UPDATE | secret, updated_at | キー再生成時 | ApiKeyModel.refreshSecret |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証なし | 認証情報を付与 |
| 403 | NoPermissionError | 権限不足 | Owner/Administratorで操作 |
| 404 | NotFoundError | インテグレーション/APIキーが存在しない | 有効なIDを指定 |
| 429 | HostLimitError | カスタムインテグレーション数上限超過 | プランをアップグレード |

### リトライ仕様

該当なし

## トランザクション仕様

- インテグレーション作成とAPIキー作成は同一トランザクション
- Bookshelf ORMのトランザクションサポートを使用
- 削除時もカスケード削除がトランザクション内で実行

## パフォーマンス要件

- 一覧取得: 200ms以内
- 作成: 500ms以内（APIキー生成を含む）
- 削除: 300ms以内

## セキュリティ考慮事項

- Admin APIキーは厳重に管理
- APIキー再生成機能で定期的なローテーションを推奨
- 不要なインテグレーションは削除
- actionsCollectCRUDで操作履歴を記録

## 備考

- type: 'internal' はGhost内部使用のインテグレーション
- type: 'builtin' は標準で提供されるインテグレーション（Zapier等）
- type: 'core' はGhostコアのインテグレーション
- カスタムインテグレーションのみユーザーが作成・削除可能

---

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

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

### 推奨読解順序

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

まず、インテグレーションのデータモデルとスキーマを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | integration.js | `ghost/core/core/server/models/integration.js` | Integrationモデル定義 |
| 1-2 | schema.js | `ghost/core/core/server/data/schema/schema.js` | integrationsテーブル定義（337-352行目） |

**読解のコツ**:
- relationshipsにapi_keys, webhooksが定義されている
- defaults()でtype: 'custom'を設定
- onSaving()でスラッグ生成処理

**主要処理フロー**:
- **6行目**: tableName: 'integrations'
- **12-25行目**: relationships, relationshipConfig, relationshipBelongsToの定義
- **27-31行目**: defaults関数でtype='custom'を設定
- **38-48行目**: onSaving関数でスラッグ生成
- **87-99行目**: permissible関数でカスタムインテグレーション制限チェック

#### Step 2: APIエンドポイントを理解する

インテグレーションのAPIコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | integrations.js | `ghost/core/core/server/api/endpoints/integrations.js` | APIエンドポイント |

**主要処理フロー**:
1. **18-37行目**: browseアクションでfindPageを使用
2. **38-71行目**: readアクションで単一インテグレーション取得
3. **72-101行目**: editアクションでインテグレーション更新
4. **103-139行目**: addアクションでインテグレーション作成
5. **130-137行目**: addでapi_keys（Content/Admin）を自動作成
6. **140-167行目**: destroyアクションでインテグレーション削除

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

APIキー再生成などのビジネスロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | integrations-service.js | `ghost/core/core/server/services/integrations/integrations-service.js` | インテグレーションサービス |

**主要処理フロー**:
- **14-36行目**: edit関数でkeyid指定時のAPIキー再生成処理
- **16-24行目**: ApiKeyModel.findOneで対象キーを取得
- **26行目**: ApiKeyModel.refreshSecretでシークレット再生成
- **28-30行目**: withRelatedで更新後のインテグレーションを取得

#### Step 4: 制限チェックを理解する

カスタムインテグレーション数の制限チェックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | integration.js | `ghost/core/core/server/models/integration.js` | permissible関数 |

**主要処理フロー**:
- **87行目**: isAdd = (action === 'add')でアクション判定
- **90-94行目**: limitService.isLimited('customIntegrations')で制限チェック
- **93行目**: errorIfWouldGoOverLimitで上限超過時エラー

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

```
API Request (POST /ghost/api/admin/integrations/)
    │
    ├─ integrations.js (controller)
    │      │
    │      ├─ permissions check
    │      │
    │      └─ query()
    │             │
    │             ├─ Integration.permissible()
    │             │      └─ limitService.errorIfWouldGoOverLimit()
    │             │
    │             └─ Integration.add()
    │                    │
    │                    ├─ onSaving() - スラッグ生成
    │                    │
    │                    └─ api_keys自動作成
    │                           ├─ ApiKey.add({type: 'content'})
    │                           └─ ApiKey.add({type: 'admin'})
    │
    └─ Response (JSON)
```

### データフロー図

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

name ────────────────────▶ ┌──────────────────────────┐
icon_image ──────────────▶ │   integrations.js (API)  │
description ─────────────▶ │          │               │
                           │          ▼               │
                           │   権限チェック            │
                           │          │               │
                           │          ▼               │
                           │   制限チェック            │
                           │          │               │
                           │          ▼               │
                           │   Integration.add()      │
                           │          │               │
                           │          ├─ スラッグ生成   │
                           │          │               │
                           │          ├─ Content APIキー│
                           │          │               │
                           │          └─ Admin APIキー │
                           └──────────────────────────┘
                                       │
                                       ▼
                           ┌──────────────────────────┐
                           │  JSON Response           │
                           │  {                       │
                           │    integrations: [{      │
                           │      id, name, slug,     │
                           │      api_keys: [...]     │
                           │    }]                    │
                           │  }                       │
                           └──────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| integration.js | `ghost/core/core/server/models/integration.js` | ソース | Integrationモデル定義 |
| integrations.js | `ghost/core/core/server/api/endpoints/integrations.js` | ソース | APIエンドポイント |
| integrations-service.js | `ghost/core/core/server/services/integrations/integrations-service.js` | ソース | インテグレーションサービス |
| api-key.js | `ghost/core/core/server/models/api-key.js` | ソース | APIキーモデル |
| webhook.js | `ghost/core/core/server/models/webhook.js` | ソース | Webhookモデル |
| limits.js | `ghost/core/core/server/services/limits.js` | ソース | 制限管理サービス |
| schema.js | `ghost/core/core/server/data/schema/schema.js` | 設定 | DBスキーマ定義 |
