# データベース設計書

## 概要

本ドキュメントは、Payload CMS のデータベース設計について記述します。Payload は複数のデータベースアダプターをサポートするヘッドレス CMS であり、MongoDB (Mongoose) と SQL データベース (PostgreSQL, SQLite, Vercel Postgres, D1 SQLite) の両方に対応しています。

本設計書では、Drizzle ORM ベースの SQL データベースアダプターにおけるスキーマ構造を中心に解説し、フィールドタイプとデータベースカラムの対応関係を明確にします。

## データベースアダプター

Payload は以下のデータベースアダプターをサポートしています:

| アダプター名 | パッケージ | データベース |
| --- | --- | --- |
| MongoDB | @payloadcms/db-mongodb | MongoDB (Mongoose) |
| PostgreSQL | @payloadcms/db-postgres | PostgreSQL (Drizzle ORM) |
| SQLite | @payloadcms/db-sqlite | SQLite (Drizzle ORM) |
| Vercel Postgres | @payloadcms/db-vercel-postgres | Vercel Postgres (Drizzle ORM) |
| D1 SQLite | @payloadcms/db-d1-sqlite | Cloudflare D1 SQLite (Drizzle ORM) |

## テーブル一覧

### 基本テーブル構造

各コレクションに対して以下のテーブルが自動生成されます:

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| {collection} | コレクション本体 | コレクションのメインテーブル |
| {collection}_locales | ローカライズフィールド | ローカライズされたフィールドを格納 |
| {collection}_rels | リレーションシップ | hasMany/polymorphic リレーションシップを格納 |
| {collection}_texts | hasMany テキスト | hasMany 指定されたテキストフィールドを格納 |
| {collection}_numbers | hasMany 数値 | hasMany 指定された数値フィールドを格納 |
| {collection}_{array} | 配列フィールド | 配列型フィールドの子要素を格納 |
| {collection}_blocks_{block} | ブロックフィールド | ブロック型フィールドの各ブロックを格納 |
| {collection}_{select} | hasMany セレクト | hasMany 指定されたセレクトフィールドを格納 |
| {collection}_v | バージョン | バージョン管理有効時のバージョンデータを格納 |

### グローバル用テーブル

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| {global} | グローバル本体 | グローバルのメインテーブル |
| {global}_locales | ローカライズフィールド | ローカライズされたフィールドを格納 |
| {global}_rels | リレーションシップ | hasMany/polymorphic リレーションシップを格納 |
| {global}_v | バージョン | バージョン管理有効時のバージョンデータを格納 |

### システムテーブル

| テーブル名 | 対応エンティティ | 説明 |
| --- | --- | --- |
| payload_locked_documents | ロックドキュメント | 編集中のドキュメントロック情報 |
| payload_preferences | ユーザー設定 | ユーザーごとの設定情報 |
| payload_migrations | マイグレーション | マイグレーション履歴 |

## 各テーブル定義

### 1. コレクションテーブル ({collection})

コレクションのメインテーブルで、各コレクションのドキュメントを格納します。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial/uuid/varchar/numeric | NO | 主キー (IDタイプ設定による) |
| created_at | timestamp(3) with time zone | NO | 作成日時 |
| updated_at | timestamp(3) with time zone | NO | 更新日時 |
| {field} | (フィールド定義による) | (設定による) | 各フィールドのカラム |

### 2. ローカライズテーブル ({collection}_locales)

ローカライズが有効なフィールドを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| _locale | enum | NO | ロケールコード |
| _parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| {localized_field} | (フィールド定義による) | (設定による) | ローカライズされたフィールド |

**インデックス:**
- `{table}_locale_parent_id_unique`: (_locale, _parent_id) のユニークインデックス

### 3. リレーションシップテーブル ({collection}_rels)

hasMany リレーションシップおよび polymorphic リレーションシップを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| order | integer | YES | 順序 |
| parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| path | varchar | NO | フィールドパス |
| locale | enum | YES | ロケールコード (ローカライズ時) |
| {relation}_id | (関連テーブルのID型) | YES | 各関連コレクションへの外部キー |

### 4. テキストテーブル ({collection}_texts)

hasMany 指定されたテキストフィールドを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| order | integer | NO | 順序 |
| parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| path | varchar | NO | フィールドパス |
| text | varchar | YES | テキスト値 |
| locale | enum | YES | ロケールコード (ローカライズ時) |

### 5. 数値テーブル ({collection}_numbers)

hasMany 指定された数値フィールドを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| order | integer | NO | 順序 |
| parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| path | varchar | NO | フィールドパス |
| number | numeric | YES | 数値 |
| locale | enum | YES | ロケールコード (ローカライズ時) |

### 6. 配列テーブル ({collection}_{array})

配列型フィールドの各要素を格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| _order | integer | NO | 配列内の順序 |
| _parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| _locale | enum | YES | ロケールコード (ローカライズ時) |
| {array_field} | (フィールド定義による) | (設定による) | 配列要素内のフィールド |

### 7. ブロックテーブル ({collection}_blocks_{block})

ブロック型フィールドの各ブロックを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| _order | integer | NO | ブロック配列内の順序 |
| _parent_id | (ルートテーブルのID型) | NO | ルートレコードへの外部キー |
| _path | text | NO | ブロックのパス |
| _locale | enum | YES | ロケールコード (ローカライズ時) |
| {block_field} | (フィールド定義による) | (設定による) | ブロック内のフィールド |

### 8. セレクトテーブル ({collection}_{select})

hasMany 指定されたセレクトフィールドを格納するテーブルです。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| order | integer | NO | 順序 |
| parent_id | (親テーブルのID型) | NO | 親レコードへの外部キー |
| value | enum | YES | 選択値 |
| locale | enum | YES | ロケールコード (ローカライズ時) |

### 9. バージョンテーブル ({collection}_v)

バージョン管理が有効な場合のバージョンデータを格納します。

| カラム名 | データ型 | NULL | 説明 |
| --- | --- | --- | --- |
| id | serial | NO | 主キー |
| parent | (親テーブルのID型) | YES | 親ドキュメントへの参照 |
| version | jsonb | NO | バージョンデータ |
| created_at | timestamp(3) with time zone | NO | 作成日時 |
| updated_at | timestamp(3) with time zone | NO | 更新日時 |
| latest | boolean | YES | 最新バージョンフラグ |
| autosave | boolean | YES | 自動保存フラグ |
| published_locale | varchar | YES | 公開ロケール |
| snapshot | boolean | YES | スナップショットフラグ |

## フィールドタイプとデータベースカラムの対応

Payload のフィールドタイプは、データベースアダプターによって適切なカラム型に変換されます。

### PostgreSQL / SQLite カラム型マッピング

| Payload フィールドタイプ | PostgreSQL カラム型 | SQLite カラム型 | 説明 |
| --- | --- | --- | --- |
| text | varchar | text | 単一行テキスト |
| text (hasMany) | _texts テーブル | _texts テーブル | 複数テキスト |
| email | varchar | text | メールアドレス |
| code | varchar | text | コード |
| textarea | varchar | text | 複数行テキスト |
| number | numeric | real | 数値 |
| number (hasMany) | _numbers テーブル | _numbers テーブル | 複数数値 |
| checkbox | boolean | integer | ブーリアン |
| date | timestamp(3) with time zone | text | 日時 |
| point | geometry | text (JSON) | 地理座標 |
| json | jsonb | text (JSON) | JSON データ |
| richText | jsonb | text (JSON) | リッチテキスト |
| select | enum | text (CHECK) | 選択肢 |
| select (hasMany) | 別テーブル | 別テーブル | 複数選択 |
| radio | enum | text (CHECK) | ラジオボタン |
| relationship (single) | (関連ID型)_id | (関連ID型)_id | 単一リレーション |
| relationship (hasMany) | _rels テーブル | _rels テーブル | 複数リレーション |
| relationship (polymorphic) | _rels テーブル | _rels テーブル | 多態リレーション |
| upload (single) | (関連ID型)_id | (関連ID型)_id | 単一アップロード |
| upload (hasMany/polymorphic) | _rels テーブル | _rels テーブル | 複数アップロード |
| array | 別テーブル | 別テーブル | 配列 |
| blocks | 別テーブル(s) | 別テーブル(s) | ブロック |
| blocks (blocksAsJSON) | jsonb | text (JSON) | JSON形式ブロック |
| group | プレフィックス付きカラム | プレフィックス付きカラム | グループ |
| tabs (named) | プレフィックス付きカラム | プレフィックス付きカラム | 名前付きタブ |

### IDタイプ

Payload は以下の ID タイプをサポートしています:

| ID タイプ | PostgreSQL | SQLite | 説明 |
| --- | --- | --- | --- |
| serial | serial (integer) | integer (autoincrement) | 自動増分整数 (デフォルト) |
| uuid | uuid | text | UUID |
| text (カスタム) | varchar | text | カスタムテキストID |
| number (カスタム) | numeric | integer | カスタム数値ID |

## インデックス設計

### 自動生成インデックス

Payload は以下のインデックスを自動的に生成します:

| インデックス名パターン | 対象カラム | 種類 | 条件 |
| --- | --- | --- | --- |
| {table}_{column}_idx | フィールドカラム | 通常 | field.index = true |
| {table}_{column}_idx | フィールドカラム | ユニーク | field.unique = true |
| {table}_locale_parent_id_unique | _locale, _parent_id | ユニーク | ローカライズテーブル |
| {table}_order_parent | order, parent | 通常 | _texts, _numbers テーブル |
| {table}_locale_parent | locale, parent | 通常 | ローカライズ hasMany |
| {table}_order_idx | _order | 通常 | 配列/ブロックテーブル |
| {table}_parent_id_idx | _parent_id | 通常 | 子テーブル |
| {table}_path_idx | _path | 通常 | ブロックテーブル |

### 複合インデックス

コレクション設定で `indexes` オプションを使用して複合インデックスを定義できます:

```typescript
{
  indexes: [
    {
      fields: ['field1', 'field2'],
      unique: true
    }
  ]
}
```

## 外部キー制約

### 基本的な外部キー

| 外部キー名パターン | FROM テーブル | TO テーブル | ON DELETE |
| --- | --- | --- | --- |
| {table}_parent_id_fk | ローカライズテーブル | メインテーブル | CASCADE |
| {table}_parent_fk | _texts, _numbers テーブル | メインテーブル | CASCADE |
| {table}_parent_id_fk | 配列テーブル | 親テーブル | CASCADE |
| {table}_parent_id_fk | ブロックテーブル | ルートテーブル | CASCADE |
| {table}_{relation}_fk | _rels テーブル | 関連テーブル | CASCADE |
| {field}_id | リレーションシップカラム | 関連テーブル | SET NULL |

## MongoDB スキーマ設計

MongoDB アダプターでは、Mongoose を使用してスキーマを定義します。主な特徴:

### ドキュメント構造

- コレクションは MongoDB コレクションに直接マッピング
- ローカライズフィールドはオブジェクト構造でネスト
- 配列/ブロックフィールドはサブドキュメント配列
- リレーションシップは ObjectId 参照

### ローカライズの実装

```javascript
{
  fieldName: {
    en: "English value",
    ja: "日本語の値"
  }
}
```

### リレーションシップの実装

```javascript
// 単一リレーション
{ relatedField: ObjectId("...") }

// hasMany リレーション
{ relatedField: [ObjectId("..."), ObjectId("...")] }

// Polymorphic リレーション
{ relatedField: { relationTo: "collection", value: ObjectId("...") } }
```

## 設定可能なサフィックス

Drizzle アダプターでは以下のサフィックスがカスタマイズ可能です:

| 設定項目 | デフォルト値 | 説明 |
| --- | --- | --- |
| localesSuffix | _locales | ローカライズテーブルのサフィックス |
| relationshipsSuffix | _rels | リレーションシップテーブルのサフィックス |
| versionsSuffix | _v | バージョンテーブルのサフィックス |

## 備考

### blocksAsJSON オプション

PostgreSQL アダプターでは `blocksAsJSON: true` オプションを設定することで、ブロックフィールドを別テーブルではなく JSONB カラムとして格納できます。これにより:

- テーブル数の削減
- シンプルなクエリ
- ただし、ブロック内フィールドへの直接クエリは制限される

### カスタムテーブル名

`dbName` オプションを使用してテーブル名をカスタマイズできます:

```typescript
{
  type: 'array',
  name: 'items',
  dbName: 'custom_items_table'
}
```

### スキーマ名 (PostgreSQL)

PostgreSQL では `schemaName` オプションでカスタムスキーマを使用できます:

```typescript
postgresAdapter({
  schemaName: 'my_schema'
})
```
