Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rudis-cms

rudis-cms は、Markdown/YAMLドキュメントをCloudflare D1(SQLite)、R2(オブジェクトストレージ)、KVにコンパイルするヘッドレスCMSです。

特徴

  • スキーマ駆動: YAMLでコンテンツ構造を定義すると、SQLテーブルが自動生成される
  • 画像埋め込みMarkdown: Markdown内の画像は自動的に抽出・最適化され、R2にアップロードされる
  • 複数のストレージバックエンド: R2(オブジェクト)、KV(キーバリュー)、インラインストレージをサポート
  • 差分更新: 変更されたコンテンツのみアップロード、未変更ファイルはスキップ
  • ローカル開発: ローカルのSQLiteとファイルストレージでテスト可能なdumpモード

アーキテクチャ

┌─────────────────┐     ┌──────────────┐     ┌─────────────────┐
│  Markdown/YAML  │────▶│  rudis-cms   │────▶│  Cloudflare D1  │
│     ドキュメント │     │              │     │  (SQLite)       │
└─────────────────┘     │              │     └─────────────────┘
                        │              │     ┌─────────────────┐
                        │              │────▶│  Cloudflare R2  │
                        │              │     │  (オブジェクト)  │
                        └──────────────┘     └─────────────────┘
                                             ┌─────────────────┐
                                        ────▶│  Cloudflare KV  │
                                             │  (キーバリュー)  │
                                             └─────────────────┘

ユースケース

  • 動的コンテンツを持つ静的サイトジェネレーター
  • 構造化メタデータを持つブログプラットフォーム
  • 検索機能を持つドキュメントサイト
  • Cloudflareのエッジで構造化コンテンツを必要とするあらゆるアプリケーション

インストール

ソースからビルド

rudis-cmsはRustで書かれています。ソースからビルドできます:

git clone https://github.com/namachan10777/rudis-cms
cd rudis-cms
cargo install --path .

要件

  • Rust 2024 edition (1.85+)
  • Cloudflareアカウント(以下が必要):
    • D1データベース
    • R2バケット(オプション、オブジェクトストレージ用)
    • KV名前空間(オプション、キーバリューストレージ用)

環境変数

Cloudflareへのデプロイには以下の環境変数が必要です:

変数説明
CF_ACCOUNT_IDCloudflareアカウントID
CF_API_TOKEND1、R2、KVの権限を持つAPIトークン
R2_ACCESS_KEY_IDR2アクセスキーID
R2_SECRET_ACCESS_KEYR2シークレットアクセスキー

Cloudflare APIトークンの作成

  1. Cloudflareダッシュボード > マイプロフィール > APIトークン へ移動
  2. 以下の権限でカスタムトークンを作成:
    • Account > D1 > Edit
    • Account > Workers KV Storage > Edit
    • Account > R2 > Edit

R2認証情報の取得

  1. R2 > R2 APIトークンの管理 へ移動
  2. 読み書きアクセス権を持つ新しいAPIトークンを作成

クイックスタート

このガイドでは、rudis-cmsでシンプルなブログをセットアップする方法を説明します。

1. 設定ファイルの作成

config.yamlファイルを作成します:

glob: "posts/**/*.md"
name: posts
table: posts
database_id: your-d1-database-id
syntax:
  type: markdown
  column: body
schema:
  id:
    type: id
  title:
    type: string
    required: true
  date:
    type: date
    index: true
    required: true
  body:
    type: markdown
    required: true
    storage:
      type: kv
      namespace: your-kv-namespace-id
    image:
      table: post_images
      inherit_ids: [post_id]
      storage:
        type: r2
        bucket: your-bucket-name
        prefix: images

2. コンテンツの作成

posts/hello-world.mdにMarkdownファイルを作成します:

---
id: hello-world
title: Hello World
date: 2024-01-01
---

これは最初の投稿です!

![サンプル画像](./image.png)

3. デプロイ

環境変数を設定して実行します:

export CF_ACCOUNT_ID=your-account-id
export CF_API_TOKEN=your-api-token
export R2_ACCESS_KEY_ID=your-r2-key
export R2_SECRET_ACCESS_KEY=your-r2-secret

rudis-cms --config config.yaml batch

4. 進捗表示

rudis-cmsはデプロイ中に進捗を表示します:

📋 Loading configuration...
🔧 Compiling schema...
📄 Processing documents...
⬆️ Uploading to storage...
✅ Completed!

📊 Results:
├── ✅ posts/hello-world.md
│   ├── ⬆️ kv://namespace/hello-world
│   └── ⬆️ r2://bucket/images/image.png

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   📄 Entries:    1 total
   ✅ Successful: 1
   ⬆️ Uploads:    2
   ⏱️ Duration:   1.23s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ローカル開発

Cloudflareを使わずにローカルでテストするには、dumpモードを使用します:

rudis-cms --config config.yaml dump --storage ./storage --db ./db

これにより、ローカルのSQLiteデータベースが作成され、ファイルはディスクに保存されます。

設定

rudis-cmsはYAML設定ファイルを使用してコンテンツ構造を定義します。

基本構造

glob: "posts/**/*.md"      # マッチするファイルパターン
name: posts                 # コレクション名
table: posts               # メインテーブル名
database_id: xxx-xxx       # Cloudflare D1データベースID
syntax:
  type: markdown           # または "yaml"
  column: body             # Markdownコンテンツのカラム(markdown専用)
schema:
  # フィールド定義...

トップレベルオプション

オプション必須説明
globはいコンテンツファイルのglobパターン
nameはいコレクション名
tableはいメインデータベーステーブル名
database_idはいCloudflare D1データベースID
preview_database_idいいえプレビュー用の別D1データベース
syntaxはいコンテンツフォーマット設定
schemaはいフィールド定義

シンタックスオプション

Markdown

syntax:
  type: markdown
  column: body    # Markdownコンテンツのフィールド名

Markdownシンタックスでは、フロントマターフィールドがスキーマフィールドにマッピングされ、本文は指定されたカラムに保存されます。

YAML

syntax:
  type: yaml

YAMLシンタックスでは、ファイル全体がYAMLとして解析され、スキーマフィールドにマッピングされます。

プレビューデータベース

プレビュー/下書きコンテンツ用に別のデータベースを指定できます:

database_id: production-db-id
preview_database_id: preview-db-id

--previewフラグを使用すると、本番ではなくプレビューデータベースにデプロイします。

スキーマ定義

スキーマは、コンテンツの構造とデータベースへの保存方法を定義します。

フィールド定義

スキーマ内の各フィールドには名前と設定があります:

schema:
  field_name:
    type: string
    required: true
    index: true

共通オプション

オプションデフォルト説明
typestring-フィールド型(必須)
requiredboolfalseフィールドが必須かどうか
indexboolfalseデータベースインデックスを作成

ネストされたレコード

records型を使用してネストされたテーブルを定義できます:

schema:
  id:
    type: id
  comments:
    type: records
    table: post_comments
    inherit_ids: [post_id]
    schema:
      comment_id:
        type: id
      text:
        type: string

これにより、外部キー関係を持つ別のpost_commentsテーブルが作成されます。

inherit_ids

inherit_idsオプションは、子テーブルに含める親IDを指定します:

comments:
  type: records
  inherit_ids: [post_id]  # post_idを外部キーとして含める

深くネストされたレコードの場合、複数のIDを継承できます:

replies:
  type: records
  inherit_ids: [post_id, comment_id]

schema:
  id:
    type: id
  title:
    type: string
    required: true
  published:
    type: datetime
    index: true
  draft:
    type: boolean
    index: true
  body:
    type: markdown
    storage:
      type: kv
      namespace: content
  tags:
    type: records
    table: post_tags
    inherit_ids: [post_id]
    schema:
      tag:
        type: id

フィールド型

rudis-cmsは様々なデータニーズに対応するフィールド型をサポートしています。

基本型

id

レコードの主キー識別子。

id:
  type: id
  • SQLiteではTEXTとして保存
  • 自動的にインデックス化
  • テーブル内で一意である必要がある

string

テキストコンテンツ。

title:
  type: string
  required: true
  • SQLiteではTEXTとして保存

boolean

真偽値。

published:
  type: boolean
  index: true
  • SQLiteではINTEGER(0/1)として保存

date

時刻なしの日付。

published_date:
  type: date
  index: true
  • ISO 8601形式(YYYY-MM-DD)でTEXTとして保存
  • date()関数を使用してインデックス化

datetime

時刻付きの日付。

created_at:
  type: datetime
  index: true
  • ISO 8601形式でTEXTとして保存
  • datetime()関数を使用してインデックス化

hash

変更検出用のコンテンツハッシュ。

hash:
  type: hash
  • ファイル内容から自動計算
  • キャッシュ無効化に有用

コンテンツ型

markdown

オプションの画像抽出機能付きMarkdownコンテンツ。

body:
  type: markdown
  required: true
  storage:
    type: kv
    namespace: content-namespace
  image:
    table: post_images
    inherit_ids: [post_id]
    embed_svg_threshold: 8192
    storage:
      type: r2
      bucket: my-bucket
      prefix: images
  config: {}

オプション:

  • storage: コンパイル済みMarkdownの保存先
  • image: 抽出された画像の設定
  • image.embed_svg_threshold: これより小さい(バイト)SVGファイルはインライン埋め込み
  • config: 追加のMarkdown処理オプション

image

単一画像フィールド。

og_image:
  type: image
  storage:
    type: r2
    bucket: my-bucket
    prefix: og-images

file

汎用ファイル添付。

attachment:
  type: file
  storage:
    type: r2
    bucket: my-bucket
    prefix: attachments

リレーショナル型

records

複数レコードを持つネストされたテーブル。

tags:
  type: records
  table: post_tags
  inherit_ids: [post_id]
  schema:
    tag:
      type: id

外部キー関係を持つ別テーブルを作成します。

ストレージオプション

rudis-cmsは異なるコンテンツタイプに対応する複数のストレージバックエンドをサポートしています。

R2(オブジェクトストレージ)

画像などのバイナリファイル用のCloudflare R2。

storage:
  type: r2
  bucket: my-bucket
  prefix: images/posts
オプション必須説明
bucketはいR2バケット名
prefixいいえオブジェクトのキープレフィックス

オブジェクトはハッシュに基づくコンテンツアドレスキーで保存され、重複排除が保証されます。

KV(キーバリュー)

コンパイル済みMarkdownなどのテキストコンテンツ用のCloudflare KV。

storage:
  type: kv
  namespace: content-namespace-id
オプション必須説明
namespaceはいKV名前空間ID

Inline

コンテンツをデータベースに直接保存。

storage:
  type: inline

別途ストレージが不要な小さなコンテンツに最適。

Asset

直接配信される静的アセット用。

storage:
  type: asset
  prefix: static

ストレージポインター形式

データベースでは、ストレージ参照はポインター情報を含むJSONとして保存されます:

{
  "hash": "abc123...",
  "pointer": "r2://bucket/prefix/key",
  "content_type": "image/png",
  "size": 12345
}

ポインター形式はストレージタイプを示します:

  • r2://bucket/key - R2オブジェクト
  • kv://namespace/key - KVエントリ
  • asset://path - アセットファイル

重複排除

rudis-cmsはコンテンツハッシュ(BLAKE3)を使用してアップロードを重複排除します:

  1. アップロード前にファイルハッシュを計算
  2. 同じハッシュのオブジェクトが存在する場合、アップロードをスキップ
  3. 進捗表示では新規アップロードは⬆️、スキップは⏭️

すべてのオブジェクトを強制的に再アップロードするには-f / --forceフラグを使用します。

CLIコマンド

グローバルオプション

rudis-cms --config <CONFIG> <COMMAND>
オプション短縮形説明
--config-c設定ファイルのパス(必須)

コマンド

batch

Cloudflareにコンテンツをデプロイ。

rudis-cms -c config.yaml batch [OPTIONS]
オプション短縮形説明
--force-fすべてのオブジェクトを強制的に再アップロード
--preview-pプレビューデータベースにデプロイ

例:

# 通常のデプロイ
rudis-cms -c config.yaml batch

# すべてを強制的に再アップロード
rudis-cms -c config.yaml batch -f

# プレビューデータベースにデプロイ
rudis-cms -c config.yaml batch --preview

dump

開発/テスト用にローカルファイルにエクスポート。

rudis-cms -c config.yaml dump --storage <PATH> --db <PATH>
オプション説明
--storageストレージファイルのディレクトリ
--dbSQLiteデータベースのディレクトリ

例:

rudis-cms -c config.yaml dump --storage ./local-storage --db ./local-db

show-schema

生成されたスキーマを表示。

rudis-cms -c config.yaml show-schema <SUBCOMMAND>

show-schema sql

SQL DDL文を表示。

rudis-cms -c config.yaml show-schema sql [OPTIONS]
オプション説明
--fetch-objectsオブジェクト取得クエリを含める

show-schema typescript

TypeScript型定義を生成。

rudis-cms -c config.yaml show-schema typescript [OPTIONS]
オプション説明
--save <DIR>ディレクトリに保存
--valibotValibotスキーマを生成

例:

# 標準出力に表示
rudis-cms -c config.yaml show-schema typescript

# Valibotバリデーション付きで保存
rudis-cms -c config.yaml show-schema typescript --save ./generated --valibot

終了コード

コード説明
0成功
1エラー

環境変数

必要な環境変数についてはインストールを参照してください。

SQLスキーマ

rudis-cmsはスキーマ定義に基づいてSQLテーブルを自動生成します。

生成されるテーブル

以下のようなスキーマの場合:

table: posts
schema:
  id:
    type: id
  title:
    type: string
    required: true
  date:
    type: date
    index: true
  body:
    type: markdown
    storage:
      type: kv
      namespace: content
  tags:
    type: records
    table: post_tags
    inherit_ids: [post_id]
    schema:
      tag:
        type: id

以下のSQLが生成されます:

CREATE TABLE IF NOT EXISTS posts (
  id TEXT NOT NULL,
  title TEXT NOT NULL,
  date TEXT NOT NULL,
  body TEXT NOT NULL,
  PRIMARY KEY (id)
);
CREATE INDEX IF NOT EXISTS index_posts_id ON posts(id);
CREATE INDEX IF NOT EXISTS index_posts_date ON posts(date(date));

CREATE TABLE IF NOT EXISTS post_tags (
  post_id TEXT NOT NULL,
  tag TEXT NOT NULL,
  FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
  PRIMARY KEY (post_id, tag)
);
CREATE INDEX IF NOT EXISTS index_post_tags_tag ON post_tags(tag);

型マッピング

rudis-cms型SQLite型備考
idTEXT NOT NULL主キー
stringTEXTrequiredの場合NOT NULL
booleanINTEGER0または1
dateTEXTISO 8601形式
datetimeTEXTISO 8601形式
hashTEXTBLAKE3ハッシュ
markdownTEXTストレージポインター付きJSON
imageTEXTストレージポインター付きJSON
fileTEXTストレージポインター付きJSON

ストレージポインター

コンテンツフィールド(markdown、image、file)はJSONとして保存されます:

{
  "hash": "abc123def456...",
  "size": 12345,
  "content_type": "text/markdown",
  "pointer": "kv://namespace-id/key"
}

外部キー

records型で作成される子テーブルには以下が含まれます:

  • ON DELETE CASCADE付きの外部キー制約
  • 親IDを含む複合主キー

生成されたSQLの確認

CLIを使用して生成されたSQLを確認できます:

rudis-cms -c config.yaml show-schema sql