mcpField
C
contentful-migration

contentful-migration

github.com/contentfulデータ・データベース39319 回インストール1 日前に更新
リポジトリ

contentful-migration について

contentful-migrationは、Contentfulのコンテンツモデルやエントリーの変更をTypeScriptのマイグレーションとして記述するスキルです。Contentful CLIまたはプログラムAPIを使い、開発者がスキーマ更新やデータ変換を計画、テスト、実行できます。

主な機能

  1. 01コンテンツタイプの作成、編集、削除
  2. 02フィールド、検証、編集画面の設定
  3. 03エントリー変換とリンクエントリーの生成
  4. 04タグ、注釈、タクソノミー検証の管理
  5. 05Contentful CLIまたはAPIでの実行

活用シーン

  1. 01コンテンツモデルのフィールド追加や変更
  2. 02スキーマ更新時の既存エントリー変換
  3. 03既存コンテンツからリンクエントリーを作成
  4. 04サンドボックス環境でのマイグレーションテスト

MCP 対応

このスキルは、エージェントによる計画やレビュー向けにContentful MCPサーバーを案内します。マイグレーションスクリプトの実行には引き続きcontentful-cliまたはプログラムAPIを使います。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/contentful/skills --skill contentful-migration

インストール後、Claude Code で/contentful-migrationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

package.json
references/
api-reference.md
patterns.md
running-migrations.md

詳細

Contentful の移行

contentful-migration ツールを使うと、コンテンツモデルの変更をコードとして記述し、実行できます。マイグレーションは、コンテンツタイプ、フィールド、エディターインターフェース、エントリーを作成、編集、削除する TypeScript スクリプトです。

インストール:

npm install contentful-migration

GitHub:https://github.com/contentful/contentful-migration

対象範囲

このスキルでは、以下を扱います。

  • コンテンツタイプとフィールドの CRUD 操作
  • フィールドタイプ、検証、エディターインターフェースの設定
  • エントリーの変換(インプレース変換、リンクされたエントリーの生成、タイプ間の変換)
  • タグ、注釈、分類の検証
  • エディターレイアウト、サイドバーウィジェット
  • npx contentful space migration(Contentful CLI)とプログラムによる API を使ったマイグレーションの実行

npx contentful-migration でマイグレーションを実行しないでください。CLI での実行には contentful-cli を使用し、必要に応じて開発用依存関係としてインストールしてから、npx contentful ... で実行してください。

対象外:SDK クライアントのセットアップ(contentful-nextjs スキル)、Contentful の概念と API ルーティング(contentful-guide スキル)。

Contentful MCP に関する注記

  • マイグレーションの計画やレビューにおいて、エージェントと Contentful のやり取りをより簡単にしたいユーザーには、Contentful MCP サーバーのドキュメントを案内してください。https://www.contentful.com/developers/docs/tools/mcp-server/
  • 実際のマイグレーション実行には、引き続き contentful-migration スクリプトと contentful-cli を使用してください。

マイグレーションスクリプトの形式

すべてのマイグレーションファイルは、migration オブジェクトを受け取る関数をエクスポートします。

import type { MigrationFunction } from 'contentful-migration'

const migration: MigrationFunction = (migration) => {
  const blogPost = migration.createContentType('blogPost', {
    name: 'Blog Post',
    description: 'A blog post entry',
    displayField: 'title',
  })

  blogPost.createField('title')
    .name('Title')
    .type('Symbol')
    .required(true)
}

export = migration

この関数は、2 番目のパラメーターとして context オブジェクトも受け取ります。このオブジェクトには、makeRequest(CMA への直接アクセス)、spaceId、accessToken が含まれます。マイグレーション API では取得できないデータが必要な場合は、makeRequest を使用してください。

プロジェクトの状態

echo "=== Existing migrations ===" && ls migrations/ 2>/dev/null || echo "(no migrations/ directory found)"
echo ""
echo "=== Contentful env vars ===" && grep -h CONTENTFUL .env .env.local 2>/dev/null | sed 's/=.*/=<set>/' || echo "(no Contentful env vars found in .env or .env.local)"

ワークフロー

マイグレーションを作成する際は、以下の手順に従ってください。

  1. まず必要な環境変数を確認します。 値が不足している場合は、先にユーザーにローカルの .env ファイルへ追加するよう依頼してください。
  2. 変更内容を評価します。 変更が必要なコンテンツタイプとフィールドを特定します。Contentful のウェブアプリまたは CMA を使って、現在のコンテンツモデルを確認してください。
  3. マイグレーションスクリプトを作成します。 以下の操作を使用してください。行番号付きのより適切なエラーメッセージが表示されるため、オブジェクト表記よりもチェーンを優先してください。
  4. サンドボックス環境でテストします。 テストしていないマイグレーションを本番環境に対して実行しないでください。まずサンドボックス環境を作成します。contentful environment create --name sandbox --source master
  5. マイグレーションを実行します。 CLI とプログラムによる実行方法については、マイグレーションの実行を参照してください。
  6. 確認します。 ウェブアプリでコンテンツモデルを確認し、エントリーが損なわれていないことを確認してください。

必要な環境変数

  • CONTENTFUL_SPACE_ID - Space ID。Contentful のウェブアプリの URL(/spaces/<SPACE_ID>/...)または Space settings -> API keys で確認できます。
  • CONTENTFUL_MANAGEMENT_ACCESS_TOKEN - マイグレーションに使用する CMA トークン。Account settings -> CMA tokens(https://app.contentful.com/account/profile/cma_tokens)またはスペースに限定された CMA トークンのページ(https://app.contentful.com/spaces/<SPACE_ID>/api/cma_tokens)で作成してください。
  • CONTENTFUL_ENVIRONMENT_ID(任意)- --environment-id の指定を省略したい場合に使う対象環境の ID(例:master または sandbox)。

必要な値が不足している場合は、不足している値を明示してユーザーに尋ね、それぞれの確認場所を伝えてください。

コンテンツタイプの操作

コンテンツタイプを作成する:

const page = migration.createContentType('page', {
  name: 'Page',
  description: 'A generic page',
  displayField: 'title',
})

既存のコンテンツタイプを編集する:

const page = migration.editContentType('page')
page.description('Updated description')
page.displayField('internalName')

コンテンツタイプを削除する:

migration.deleteContentType('page')

削除するコンテンツタイプにはエントリーが 1 つもあってはなりません。すべてのエントリーを先に削除するか、transformEntriesToType を使って移動してください。

フィールドの操作

フィールドを作成する:

page.createField('title')
  .name('Title')
  .type('Symbol')
  .required(true)
  .localized(true)

既存のフィールドを編集する:

page.editField('title')
  .name('Page Title')
  .required(false)

フィールドを削除する:

page.deleteField('legacyField')

フィールドを削除すると、すべてのエントリーからそのコンテンツが完全に削除されます。

フィールド ID を変更する:

page.changeFieldId('oldName', 'newName')

既存のコンテンツは保持され、ID のみが変更されます。

フィールドを移動する:

page.moveField('slug').afterField('title')
page.moveField('featured').toTheTop()
page.moveField('metadata').toTheBottom()
page.moveField('author').beforeField('publishDate')

フィールドタイプのクイックリファレンス

タイプ説明追加設定
Symbol短いテキスト(最大256文字)—
Text長いテキスト(最大50,000文字)—
Integer整数—
Number小数—
DateISO 8601 の日付/時刻—
Boolean真/偽—
Object任意の JSON—
Location緯度/経度の座標—
RichText構造化されたリッチテキストenabledNodeTypes、enabledMarks のバリデーション
Array値または参照のリストitems が必要です:{ type, linkType?, validations? }
Link単一の参照linkType が必要です:'Asset' または 'Entry'
ResourceLinkスペース間の参照allowedResources が必要です

設定の詳細は、API リファレンス — フィールドタイプをご覧ください。

バリデーションのクイックリファレンス

バリデーション適用対象例
inSymbol、Integer、Number{ in: ['draft', 'published', 'archived'] }
uniqueSymbol、Integer、Number{ unique: true }
sizeArray、Text、Symbol{ size: { min: 1, max: 5 } }
rangeInteger、Number{ range: { min: 0, max: 100 } }
regexpSymbol、Text{ regexp: { pattern: '^[a-z0-9-]+$' } }
dateRangeDate{ dateRange: { min: '2020-01-01', max: '2030-12-31' } }
linkContentTypeLink、Link の Array{ linkContentType: ['author', 'organization'] }
linkMimetypeGroupLink(Asset){ linkMimetypeGroup: ['image', 'video'] }
assetFileSizeLink(Asset){ assetFileSize: { min: 0, max: 5242880 } }
assetImageDimensionsLink(Asset){ assetImageDimensions: { width: { min: 100, max: 2000 } }

フィールドに .validations([...]) を指定してバリデーションを適用します。すべてのオプションについては、API リファレンス — バリデーションをご覧ください。

エントリーの変換

エントリーをその場で変換します:

migration.transformEntries({
  contentType: 'blogPost',
  from: ['firstName', 'lastName'],
  to: ['fullName'],
  transformEntryForLocale: (fields, locale) => {
    const first = fields.firstName[locale]
    const last = fields.lastName[locale]
    if (!first && !last) return
    return { fullName: `${first || ''} ${last || ''}`.trim() }
  },
})

オプション:shouldPublish(true、false、または 'preserve'。デフォルトは 'preserve')。

リンクされたエントリーを派生させます:

migration.deriveLinkedEntries({
  contentType: 'blogPost',
  derivedContentType: 'author',
  from: ['authorName'],
  toReferenceField: 'authorRef',
  derivedFields: ['name'],
  identityKey: (fields) =>
    fields.authorName['en-US'].toLowerCase().replace(/\s+/g, '-'),
  deriveEntryForLocale: (fields, locale) => {
    if (locale !== 'en-US') return
    return { name: fields.authorName[locale] }
  },
})

これにより、既存の blogPost.authorName データから新しい author エントリーを作成し、authorRef を介してリンクします。

その他の例については、パターン — エントリーの変換とパターン — リンクされたエントリーの派生をご覧ください。

エディターインターフェース

フィールドのウィジェットを変更します:

const page = migration.editContentType('page')

page.changeFieldControl('slug', 'builtin', 'slugEditor', {
  helpText: 'URL-friendly identifier',
  trackingFieldId: 'title',
})

page.changeFieldControl('category', 'builtin', 'dropdown')
page.changeFieldControl('publishDate', 'builtin', 'datePicker', { format: 'dateonly' })

ウィジェットの名前空間:builtin、extension(UI 拡張機能)、app(カスタムアプリ)。

組み込みウィジェットとその設定については、API リファレンス — エディターインターフェースをご覧ください。

ベストプラクティス

  1. マイグレーションファイルには連番を付けます: 001-create-blog-post.ts、002-add-author-field.ts、003-transform-categories.ts。
  2. 1つのマイグレーションにつき、論理的な変更は1つにします。 デバッグ、取り消し、レビューが容易になります。
  3. 本番環境で実行する前に、必ずサンドボックス環境でテストします。
  4. 変換中に既存の公開状態を維持するには、shouldPublish: 'preserve'(デフォルト)を使用します。
  5. オブジェクト形式よりもチェーンを優先します — チェーンを使うと、行単位のエラーメッセージが表示されます。
  6. データ変換とスキーマ変更を分けます。 最初のマイグレーションでスキーマを変更し、2つ目でデータを変換します。これにより、各手順を個別に検証できます。
  7. context.makeRequest の使用は必要最小限にします — マイグレーション API でユースケースに対応できない場合にのみ使用してください。

よくある間違い

  • 配列フィールドにitemsを設定し忘れる。 type: 'Array'には、要素の型を指定するitemsプロパティが必要です。
  • エントリーがあるコンテンツタイプを削除する。 先にすべてのエントリーを削除するか、transformEntriesToTypeを使って移動する必要があります。
  • リンクフィールドにlinkTypeがない。 type: 'Link'には、linkType: 'Asset'またはlinkType: 'Entry'が必要です。
  • masterに対して実行する。 必ずサンドボックス環境でテストしてください。CLIでは--environment-id sandboxを使用します。
  • 変換時にロケールの欠落に対応しない。 transformEntryForLocaleはすべてのロケールで呼び出されます。スキップするにはundefinedを返します。
  • displayFieldにSymbol以外のフィールドを設定する。 表示フィールドの型はSymbolである必要があります。

参考資料

関連スキル

  • contentful-guideスキル — Contentfulの概念、用語、APIルーティング
  • contentful-nextjsスキル — ContentfulとのNext.js連携

コメント