# 機能設計書 69-制限管理

## 概要

本ドキュメントは、Ghost CMSにおける制限管理機能の設計を記述する。この機能は、ホスティングプランに応じた機能制限を管理し、制限を超えた操作を防止するための機能である。

### 本機能の処理概要

この機能では、メンバー数、スタッフユーザー数、カスタムインテグレーション数などの制限を設定・監視し、制限に達した場合に適切なエラーや警告を表示する。

**業務上の目的・背景**：Ghost Proなどのホスティングサービスでは、プランに応じた機能制限が必要である。この機能により、各プランの制限を統一的に管理し、超過時のユーザー体験を制御できる。

**機能の利用シーン**：
- メンバー登録時の上限チェック
- スタッフユーザー招待時の上限チェック
- カスタムインテグレーション作成時の上限チェック
- ニュースレター作成時の上限チェック

**主要な処理内容**：
1. 制限設定の読み込み（hostSettings:limits）
2. 制限チェック（isLimitReached）
3. 制限エラー投げ（errorIfIsOverLimit）
4. 制限警告投げ（errorIfWouldGoOverLimit）

**関連システム・外部連携**：Ghost Pro課金システム

**権限による制御**：内部処理のため、直接的な権限制御は適用されない

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 77 | Pro画面 | 主機能 | Ghost Pro機能の案内・アップグレード |

## 機能種別

システム基盤 / バリデーション

## 入力仕様

### 入力パラメータ（loadLimits）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| limits | object | Yes | 制限設定オブジェクト | - |
| subscription | object | No | サブスクリプション情報 | - |
| subscription.startDate | Date | No | 開始日 | - |
| subscription.interval | string | No | 間隔（month等） | - |
| db | object | Yes | データベース接続 | - |
| helpLink | string | No | ヘルプリンク | - |
| errors | object | Yes | エラーモジュール | - |

### 入力データソース

- 設定ファイル（hostSettings:limits）
- 設定ファイル（hostSettings:subscription）
- 設定ファイル（hostSettings:billing:url）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isLimited | boolean | 制限に達しているか |
| error | Error | 制限エラー（超過時） |

### 出力先

- API レスポンス（エラー時）
- ログ出力（警告時）

## 処理フロー

### 処理シーケンス

```
1. 初期化（init）
   ├─ helpLink設定
   ├─ subscription設定
   └─ loadLimits呼び出し

2. 制限チェック
   ├─ isLimitReached: 現在値が制限に達しているか
   ├─ errorIfIsOverLimit: 超過時エラー
   └─ errorIfWouldGoOverLimit: 操作後超過時エラー

3. エラー処理
   └─ HostLimitError投げ（ヘルプリンク付き）
```

### フローチャート

```mermaid
flowchart TD
    A[init呼び出し] --> B[helpLink設定]
    B --> C[subscription設定]
    C --> D[loadLimits呼び出し]
    D --> E{設定エラー?}
    E -->|Yes| F[IncorrectUsageError警告]
    E -->|No| G[初期化完了]
    F --> G

    H[制限チェック] --> I{isLimitReached?}
    I -->|Yes| J[HostLimitError]
    I -->|No| K[処理続行]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ヘルプリンクデフォルト | billing:urlがなければghost.org/helpを使用 | init時 |
| BR-02 | 設定エラー許容 | IncorrectUsageErrorは警告としてブート継続 | loadLimits時 |
| BR-03 | subscription設定 | interval='month'固定 | subscription設定時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 制限チェック | 各テーブル | SELECT | 現在値カウント（LimitServiceが実行） |

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

制限チェックに応じて、@tryghost/limit-serviceが以下のテーブルをカウント:
- members（メンバー制限）
- users（スタッフ制限）
- integrations（インテグレーション制限）
- newsletters（ニュースレター制限）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | HostLimitError | 制限超過 | ヘルプリンク付きエラー |
| - | IncorrectUsageError | 設定エラー | 警告ログ出力、ブート継続 |

### リトライ仕様

該当なし

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

データベース操作を伴わないため、トランザクション制御は不要

## パフォーマンス要件

制限チェックは軽量なCOUNTクエリのため、パフォーマンス影響は最小限

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

- 制限設定はサーバーサイドで管理
- クライアントからの制限変更は不可

## 備考

- @tryghost/limit-serviceパッケージを使用
- Ghost Proでのみ実質的に使用される

---

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

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

### 推奨読解順序

#### Step 1: サービス初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | limits.js | `ghost/core/core/server/services/limits.js` | 初期化とエクスポート |

**読解のコツ**: LimitServiceインスタンスがシングルトンとして管理されている。init関数でloadLimitsを呼び出す。

**主要処理フロー**:
- **6行目**: LimitServiceインスタンス生成
- **8-44行目**: init関数 - 設定読み込みとloadLimits呼び出し
- **11-15行目**: helpLink設定（billing:url優先）
- **17-23行目**: subscription設定
- **26行目**: hostLimits取得
- **28-35行目**: loadLimits呼び出し
- **36-43行目**: エラーハンドリング（警告として処理）
- **46行目**: limitServiceエクスポート

#### Step 2: 使用箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | 各APIエンドポイント | `ghost/core/core/server/api/endpoints/` | 制限チェックの呼び出し |

**読解のコツ**: 各APIで`limitService.errorIfIsOverLimit`や`limitService.errorIfWouldGoOverLimit`が呼び出されている箇所を探す。

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

```
limits.js
    │
    ├─ init()
    │      │
    │      └─ limitService.loadLimits({
    │              limits: hostSettings:limits,
    │              subscription: {...},
    │              db: db,
    │              helpLink: billing:url || ghost.org/help,
    │              errors: @tryghost/errors
    │         })
    │
    └─ module.exports = limitService
           │
           ├─ isLimitReached(limitName)
           │      └─ 現在値が制限に達しているか
           │
           ├─ errorIfIsOverLimit(limitName)
           │      └─ 超過時HostLimitError
           │
           └─ errorIfWouldGoOverLimit(limitName)
                  └─ 操作後超過時HostLimitError

APIエンドポイント
    │
    └─ limitService.errorIfWouldGoOverLimit('members')
           │
           └─ HostLimitError（制限超過時）
```

### データフロー図

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

config ────────────▶ init() ───────────────▶ LimitService
 │                        │                    (初期化済み)
 ├─ hostSettings         │
 │   └─ limits          │
 │   └─ subscription    │
 │   └─ billing:url     │
 │                       │
 └─ db                   ▼
                   loadLimits()
                        │
                        ▼
API呼び出し ───▶ errorIfWouldGoOverLimit() ──▶ エラー/成功
                        │
                        └─ DB COUNT() ──▶ 現在値取得
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| limits.js | `ghost/core/core/server/services/limits.js` | ソース | サービス初期化・エクスポート |
| @tryghost/limit-service | node_modules | 外部ライブラリ | 制限管理ロジック |
| config/defaults.json | `ghost/core/core/shared/config/defaults.json` | 設定 | デフォルト制限設定 |
