# 機能設計書 35-一般設定

## 概要

本ドキュメントは、Ghostの一般設定機能に関する設計仕様を定義する。この機能により、サイトのタイトル、説明文、ロゴ、タイムゾーン、ナビゲーションなど、サイト全体の基本設定を管理できる。

### 本機能の処理概要

一般設定は、Ghostサイトの基本的な構成情報を管理する機能である。設定値は`settings`テーブルに保存され、settingsキャッシュを通じてサイト全体で利用される。

**業務上の目的・背景**：サイト運営者がGhostの基本的な動作とブランディングを制御できるようにする。サイト名、説明、ロゴなどの設定はSEOや訪問者への第一印象に直接影響するため、容易に変更できることが重要である。

**機能の利用シーン**：
- 新規サイトの初期設定を行う場合
- サイトのブランディングを変更する場合（ロゴ、アイコン、カバー画像）
- サイトのタイムゾーンを設定する場合
- ナビゲーションメニューを編集する場合
- サイトをパスワード保護する場合（プライベートサイト）
- 実験的機能（Labs）を有効/無効にする場合

**主要な処理内容**：
1. Settings APIを通じた設定値の取得（browse/read）
2. Settings APIを通じた設定値の更新（edit）
3. 設定変更時のキャッシュ更新とイベント発火
4. 画像設定のURL変換処理
5. バリデーション処理（長さ制限、形式チェック等）

**関連システム・外部連携**：
- settingsキャッシュ：設定値の高速参照
- テーマエンジン：設定値をテンプレートで利用
- メール配信：サポートメールアドレス等

**権限による制御**：管理者（Administrator）以上のロールを持つスタッフユーザーが設定を編集できる。一部の設定（labs）はOwnerのみ編集可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 32 | 設定画面 | 主画面 | サイト設定の総合管理画面 |
| 33 | タイトルと説明設定 | 参照画面 | サイトのタイトル・説明文の設定 |
| 34 | タイムゾーン設定 | 参照画面 | サイトのタイムゾーン設定 |
| 39 | サイトロック設定 | 参照画面 | サイトのパスワード保護設定 |
| 42 | ナビゲーション設定 | 参照画面 | サイトナビゲーションメニューの設定 |
| 44 | アクセス設定 | 参照画面 | デフォルトのコンテンツアクセス権限設定 |
| 47 | スパムフィルター設定 | 参照画面 | スパム防止フィルターの設定 |
| 61 | Labs設定 | 参照画面 | 実験的機能のフラグ管理 |
| 62 | 履歴・監査ログ | 参照画面 | ユーザーアクションの履歴表示 |

## 機能種別

CRUD操作 / 設定管理

## 入力仕様

### 入力パラメータ（主要な設定項目）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | String | No | サイトタイトル | 最大150文字 |
| description | String | No | サイト説明文 | 最大200文字 |
| logo | String | No | サイトロゴURL | URL形式 |
| cover_image | String | No | カバー画像URL | URL形式 |
| icon | String | No | ファビコンURL | URL形式 |
| accent_color | String | No | アクセントカラー | 16進数カラーコード |
| locale | String | No | サイトの言語設定 | 空でないこと |
| timezone | String | No | タイムゾーン | 有効なタイムゾーン |
| navigation | Array | No | メインナビゲーション | JSON配列 |
| secondary_navigation | Array | No | セカンダリナビゲーション | JSON配列 |
| is_private | Boolean | No | プライベートサイト設定 | true/false |
| password | String | No | プライベートサイトパスワード | 文字列 |

### 入力データソース

- 管理画面（Ghost Admin > Settings）からの入力
- Admin API経由

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| key | String | 設定キー |
| value | String/Boolean/Array | 設定値 |
| group | String | 設定グループ（site, members, private等） |

### 出力先

- settingsテーブル（データベース）
- settingsキャッシュ
- Admin APIレスポンス

## 処理フロー

### 処理シーケンス

```
1. 設定取得（browse）
   └─ settingsBREADService.browse() 呼び出し
   └─ 全設定を取得してJSON形式で返却

2. 設定更新（edit）
   └─ 更新データのバリデーション
   └─ Settingsモデル経由でDBを更新
   └─ emitChangeでイベント発火
   └─ settingsキャッシュの更新
   └─ キャッシュ無効化ヘッダー設定
```

### フローチャート

```mermaid
flowchart TD
    A[設定更新リクエスト] --> B[バリデーション]
    B --> C{有効?}
    C -->|No| D[ValidationError返却]
    C -->|Yes| E[Settingsモデル.edit]
    E --> F[DBに保存]
    F --> G[emitChange発火]
    G --> H[settingsキャッシュ更新]
    H --> I[X-Cache-Invalidate設定]
    I --> J[更新後の設定を返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | デフォルト値 | 各設定には定義されたデフォルト値が設定される | 初期化時 |
| BR-35-02 | 長さ制限 | title最大150文字、description最大200文字 | 設定更新時 |
| BR-35-03 | タイムゾーン検証 | 有効なタイムゾーン文字列であること | timezone更新時 |
| BR-35-04 | 画像URL変換 | 画像URLは内部形式（__GHOST_URL__）で保存 | logo, icon, cover_image等 |
| BR-35-05 | Labs設定制限 | labs設定は許可されたキーのみ変更可能 | labs更新時 |
| BR-35-06 | Stripe検証 | Stripe APIキーは特定の形式で検証 | stripe_*_key更新時 |

### 計算ロジック

- 動的デフォルト値: `db_hash`, `public_hash`, `admin_session_secret`等は起動時に自動生成
- site_uuid: `getOrGenerateSiteUuid()`で生成・取得

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定取得 | settings | SELECT | 全設定または特定キーの取得 |
| 設定更新 | settings | UPDATE | 設定値の更新 |
| デフォルト投入 | settings | INSERT | 起動時のデフォルト値投入 |

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

#### settings

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | key, value, group | 全件または特定key | browseまたはread |
| UPDATE | value | ユーザー入力値 | バリデーション後 |
| INSERT | id, key, value, group, type, created_at, updated_at | デフォルト値 | 初期化時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | 設定キーが空 | 「Value in [settings.key] cannot be blank」 |
| - | NotFoundError | 存在しない設定キー | 「Unable to find setting to update: {key}」 |
| - | ValidationError | 長さ制限超過 | バリデーションエラーメッセージを返却 |
| - | ValidationError | Stripeキー形式不正 | キー形式エラーメッセージを返却 |

### リトライ仕様

リトライは不要。バリデーションエラーの場合は正しい値を入力して再試行。

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

- 複数設定の同時更新は各設定ごとに個別にコミット
- 全設定の一括処理はPromise.allで並列実行

## パフォーマンス要件

- 設定値はsettingsキャッシュに保存され、DBアクセスを最小化
- 設定変更時のみキャッシュ更新とイベント発火が発生

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

- 管理者権限を持つユーザーのみが設定を変更可能
- Stripe APIキーなどの機密情報は適切に検証
- パスワード設定（is_private）は暗号化されずに保存される点に注意

## 備考

- 設定グループ: core, site, theme, private, members, portal, email, amp, labs, slack, unsplash, views, firstpromoter, oauth, editor, announcements, pintura, recommendations, donations
- PUBLIC/ROフラグを持つ設定は公開APIで参照可能/読み取り専用

---

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

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

### 推奨読解順序

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

まず、設定のデータ構造とデフォルト値を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | default-settings.json | `ghost/core/core/server/data/schema/default-settings/default-settings.json` | 全設定項目のデフォルト値、バリデーション、タイプ、フラグ定義 |
| 1-2 | settings.js | `ghost/core/core/server/models/settings.js` | **98-193行目**: Settingsモデル定義、parse/formatメソッド |

**読解のコツ**:
- default-settings.jsonはカテゴリ別に整理されている
- flags: "PUBLIC"は公開API参照可能、"RO"は読み取り専用
- validationsでバリデーションルールを確認

#### Step 2: モデル層を理解する

Settingsモデルの詳細な実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | settings.js | `ghost/core/core/server/models/settings.js` | **194-443行目**: 静的メソッド（findOne, edit, populateDefaults, validators） |

**主要処理フロー**:
1. **48-86行目**: parseDefaultSettings - デフォルト設定のフラット化
2. **195-206行目**: findOne - 単一設定の取得
3. **208-260行目**: edit - 設定の更新（配列入力対応）
4. **262-315行目**: populateDefaults - デフォルト値の投入
5. **317-442行目**: validators - 各設定固有のバリデーション

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

Settings APIの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | settings.js | `ghost/core/core/server/api/endpoints/settings.js` | **24-184行目**: browse/read/edit/upload/downloadエンドポイント |

**主要処理フロー**:
1. **28-37行目**: browse - 設定一覧取得
2. **39-59行目**: read - 特定設定取得
3. **124-148行目**: edit - 設定更新、キャッシュ無効化

#### Step 4: 設定キャッシュを理解する

設定値のキャッシュ機構を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | settings-cache | `ghost/core/core/shared/settings-cache/` | 設定キャッシュの実装 |

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

```
Settings API (browse/read/edit)
    │
    ├─ settingsBREADService.browse/read/edit()
    │      │
    │      └─ Settings Model
    │             │
    │             ├─ findOne/findAll/edit
    │             │      └─ settings table
    │             │
    │             ├─ validators (バリデーション)
    │             │
    │             └─ emitChange (イベント発火)
    │
    └─ settingsCache (キャッシュ更新)

Ghost起動
    │
    └─ Settings.populateDefaults()
           │
           ├─ 既存設定の取得
           │
           └─ 不足設定のINSERT
                  └─ getDefaultValue() (動的デフォルト値)
```

### データフロー図

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

管理画面入力 ───────▶ Settings API edit
                              │
                              ▼
                        バリデーション
                              │
                              ▼
                        Settings Model edit
                              │
                              ▼
                        settings table UPDATE
                              │
                              ├─▶ emitChange (イベント)
                              │
                              └─▶ settingsCache更新
                                        │
                                        ▼
                              テーマ/フロントエンドで参照
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| default-settings.json | `ghost/core/core/server/data/schema/default-settings/default-settings.json` | 設定 | デフォルト値定義 |
| settings.js | `ghost/core/core/server/models/settings.js` | ソース | Settingsモデル |
| settings.js | `ghost/core/core/server/api/endpoints/settings.js` | ソース | Settings API |
| settings-bread-service.js | `ghost/core/core/server/services/settings/settings-bread-service.js` | ソース | BREADサービス |
| settings-cache | `ghost/core/core/shared/settings-cache/` | ソース | 設定キャッシュ |
| settings-service.js | `ghost/core/core/server/services/settings/settings-service.js` | ソース | 設定サービス |
