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

このページ

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

何が何を変更するか

サイトは 4 つの異なるワークフローを経ます。それぞれが別のレイヤーに作用します。

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

シードファイルが関わるのは 3 行目だけです。そのスキーマと構造は、セットアップウィザードが完了する前の最初のリクエストで 1 回だけ適用されます。変更したシードファイルを既存のデータベースに対してデプロイしても何も起こりません。稼働中のサイトのスキーマを進化させるには、常に管理パネルまたは 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 ファイルを読み取ります。オフサイト D1 ダンプを作成するの説明に従って SQL ファイルを作成し、テーブルと行をローカルデータベースに読み込んで、シードをエクスポートします。

sqlite3 prod.db < backup-schema.sql
sqlite3 prod.db < backup-folders.sql
sqlite3 prod.db < backup-data.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. オフサイト D1 ダンプを作成するの説明に従って、本番環境から SQL ファイルを作成し、プレビュー環境の DB バインディングを通じて順番にインポートします。

    npx wrangler d1 execute DB --env preview --remote --file=./backup-schema.sql
    npx wrangler d1 execute DB --env preview --remote --file=./backup-folders.sql
    npx wrangler d1 execute DB --env preview --remote --file=./backup-data.sql
    npx wrangler d1 execute DB --env preview --remote --file=./backup-indexes.sql

    プレビューサイトは、そのセクションで説明しているとおり、検索 API が最初に呼び出されたときに検索インデックスを再構築します。

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