デプロイ済みサイトのスキーマを進化させる

このページ

EmDash は、コレクション、フィールド、タクソノミーを、コンテンツと並べてデータベースに保存します。このガイドでは、この稼働中のコンテンツモデルを変更する方法を、コードのデプロイ、初回のシード、EmDash コアのマイグレーションと混同しないように説明します。例では Cloudflare D1 を使いますが、同じ区別はすべてのデータベースアダプターに当てはまります。

何が何を変更するか

サイトには、4 つの異なるワークフローがあります。それぞれが異なるレイヤーに影響します。

ワークフロー変わるもの方法
コンテンツ編集エントリ、メディア、設定管理画面またはコンテンツ API
コードのデプロイテンプレート、設定、EmDash のバージョンwrangler deploy — EmDash が管理するデータベーステーブルをマイグレーションする場合があります
初回のブートストラップすべて(空の状態から)マイグレーション + シードファイル + セットアップウィザード。初回起動時に自動
スキーマの進化コレクション、フィールド、タクソノミー稼働中のサイトに対して管理画面または emdash schema(このページ)

シードファイルが関わるのは 3 行目だけです。そのスキーマと構造は、セットアップウィザードが完了する前の最初のリクエストで一度だけ適用されます。変更したシードファイルを既存のデータベースに対してデプロイしても、何も起こりません。稼働中のサイトのスキーマの進化は、常に管理画面または API を通じて行います。

管理画面でスキーマを変更する

管理画面は、デプロイ済みサイトを進化させるための主要な方法です。管理画面で Content Types を開き、コレクションとフィールドを追加、編集、削除します。変更はすぐに反映されます。コンテンツ API、ローダー、編集 UI はいずれも、実行時にデータベースからスキーマを読み取るためです。

利用できるフィールドタイプ、バリデーションルール、ウィジェットのオプションについては、コレクションとフィールドを参照してください。

スキーマを変更したら、テンプレートが使用する TypeScript の型を再生成します。emdash types コマンドは実行中のインスタンスからスキーマを読み取るため、デプロイ済みのサイトを直接指定できます。

npx emdash types --url https://example.com

CLI からスキーマを変更する

emdash schema コマンドは、REST API を通じて実行中のインスタンスと通信するため、ローカル開発に対して使うのと同じ方法でデプロイ済みのサイトに対しても使えます。まず、デバイスフローで一度認証します。

npx emdash login --url https://example.com

あるいは、管理画面の Settings → API Tokens で API トークンを作成し、--token または環境変数 EMDASH_TOKEN で渡すこともできます。CI で便利です。

その後は、ローカルで使うのと同じコマンドでスキーマを進化させます。

npx emdash schema add-field posts subtitle --type string --label "Subtitle" --url https://example.com
npx emdash schema remove-field posts legacy_field --url https://example.com
npx emdash schema create projects --label Projects --url https://example.com

これらのコマンドはスクリプトにしてチェックインしておくと、すべての環境に同じ順序で変更を適用できます。コマンドは自動的に冪等になるわけではありません。すでに存在するオブジェクトに対して create や add-field を再実行すると、失敗する場合があります。emdash schema list または get で対象を確認し、各ステップをどの環境で完了したかを記録して、最初のエラーで止めてください。

コマンドの完全な一覧については、CLI リファレンスを参照してください。

シードファイルを同期する

ビルドに埋め込まれたシードファイルは、新しいデータベースが何に初期化されるかを決めます。たとえば、新しいプレビュー環境、障害復旧のための再構築、同じサイトの 2 つ目のデプロイです。シードがスターターブログのままで、本番環境が別のものへと進化している場合、新しい環境はすべて誤ったモデルでブートストラップされます。

ビルドは、.emdash/seed.json、package.json#emdash.seed に指定されたパス、seed/seed.json の順で最初に見つかったシードファイルを埋め込みます。どれも存在しない場合は、組み込みのデフォルトシード(スターターブログのモデル)が埋め込まれ、astro dev が警告をログに出力します。

デプロイ済みサイトのスキーマを進化させたら、稼働中のモデルをリポジトリにエクスポートし直します。emdash export-seed はローカルの SQLite ファイルを読み取り、wrangler d1 export はデプロイ済みの D1 データベースからそのファイルを生成します。

npx wrangler d1 export emdash-db --remote --output=./prod.sql
sqlite3 prod.db < prod.sql
npx emdash export-seed --database prod.db > .emdash/seed.json

エクスポートされたシードには、稼働中のサイトの設定、コレクション、タクソノミー、メニュー、リダイレクト、ウィジェットエリア、セクションが含まれます。エントリも含めるには --with-content を追加します。更新した .emdash/seed.json は、新しいスキーマに依存するコードと一緒にコミットしてください。そうすれば、新しい環境は常にコードが理解できるモデルでブートストラップされます。

プレビュー環境で変更をリハーサルする

破壊的なスキーマ変更(フィールドの削除、コレクションの再構成)は、本番環境の使い捨てのコピーでリハーサルするのが最も安全です。

  1. 別のプレビュー用 D1 データベースを作成し、Wrangler に preview 環境へ追加させます。

    npx wrangler d1 create emdash-db-preview \
      --binding DB --env preview --update-config

    env.preview.d1_databases に新しいデータベース名と UUID が含まれていることを確認します。バインディングは、最上位の Wrangler 設定から継承されません。

  2. 本番環境をエクスポートし、その SQL をプレビュー環境の DB バインディング経由でインポートします。

    npx wrangler d1 export emdash-db --remote --output=./prod.sql
    npx wrangler d1 execute DB --env preview --remote --file=./prod.sql
  3. プロジェクトをビルドしてプレビュー環境にデプロイし、プレビュー URL に対してスキーマ変更を実行します。

    npm run build
    npx wrangler deploy --env preview
    npx emdash schema remove-field posts legacy_field --url https://preview.example.com
  4. 公開ページ、管理画面のフォーム、生成された型、変更したフィールドを読み取るテンプレートを確認します。本番データベースの新しいバックアップを取ってから、同じコマンドを本番環境に対して一度だけ実行します。

間違いから回復する

  • フィールドを誤って削除した。 列とそのデータは稼働中のデータベースから失われています。D1 の Time Travel による特定時点のバックアップから復元するか、フィールドを再度追加して、以前の wrangler d1 export からその値を復元してください。
  • 新しい環境が誤ったモデルでブートストラップされた。 埋め込まれたシードが古かったか、存在しませんでした。.emdash/seed.json を更新し(シードファイルを同期するを参照)、再ビルドして、空のデータベースを指すようにデプロイし直し、ブートストラップをやり直してください。
  • スキーマとテンプレートが一致しない。 デプロイとスキーマ変更は独立しているため、順序を意図的に決めてください。追加のスキーマ変更(新しいコレクション、新しい任意フィールド)を先に行い、その後でそれらを使うコードを展開します。削除の場合は、先にそのフィールドを使わなくなったコードをデプロイし、その後でフィールドを削除してください。