vtex-io-service-configuration-apps について
別のアプリからサービスへ構造化設定を渡す VTEX IO 開発者向けのコーディングスキルです。スキーマに基づく契約、ランタイムでの注入、`ctx.vtex.settings` による値の取得を扱います。
主な機能
- 01サービスと設定アプリの責務を分離
- 02JSON Schema による設定定義
- 03VTEX IO コンテキスト経由の値の注入
- 04`ctx.vtex.settings` から設定を取得
- 05設定のエントリーポイントを明示
活用シーン
- 01複数のサービスやアプリで設定を共有
- 02設定変更をサービスのリリース周期から分離
- 03サービスのルートや GraphQL クエリを設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill vtex-io-service-configuration-appsインストール後、Claude Code で/vtex-io-service-configuration-appsを入力して読み込まれたか確認します。
詳細
サービス設定アプリ
このスキルを使う場合
VTEX IO サービスが、ローカルアプリの設定だけに頼るのではなく、configuration ビルダーを通じて別のアプリから構造化された設定を受け取る場合に、このスキルを使います。
configurationビルダーを使った設定アプリの作成- サービスアプリから設定エントリーポイントを公開する
- 複数のサービスやアプリで1つの設定コントラクトを共有する
- 設定のライフサイクルをランタイムアプリのライフサイクルから分離する
ctx.vtex.settingsを通じて注入された設定を読み取る
次の場合には、このスキルを使わないでください。
settingsSchemaだけで管理するシンプルなアプリ内設定contentSchemas.jsonを通じた Store Framework ブロックの設定- 設定に関係しない一般的なサービスのランタイム接続
- 設定に必要な権限を超えるポリシーの設計
判断基準
- サービスアプリと設定アプリは、それぞれ別の役割を担うものとして扱います。
- サービスアプリはランタイム(
node、graphqlなど)を所有し、manifest.jsonでconfigurationビルダーを宣言し、configuration/schema.jsonを定義して、ctx.vtex.settingsを通じて注入された値を読み取ります。 - 設定アプリはサービスのランタイムを所有しません。
nodeやgraphqlビルダーを宣言すべきではなく、通常はconfigurationビルダーだけを使用します。 - 設定アプリは、
configurationフィールドで対象のサービスを指定し、<service-app>/configuration.jsonに具体的な値を設定します。 - 設定コントラクトを、それを使用するアプリから独立して管理する場合は、設定アプリを使います。
- 複数のアプリやサービスで同じ設定モデルを共有する必要がある場合は、設定アプリを優先します。
- サービスアプリでは、
node/service.jsonのルートまたはイベントでsettingsType: "workspace"を指定するか、GraphQL で@settingsを使って、設定エントリーポイントを明示的に公開します。これは、サービスが設定アプリから設定を受け取る場合に適用します。 - 設定アプリでは、
configuration/配下のフォルダー名とconfigurationフィールドのキーを、対象のサービスアプリ ID に一致させます。たとえばvendor.shipping-serviceの場合はshipping-serviceです。 configuration.jsonの構造は、サービスアプリで宣言された JSON Schema に準拠させる必要があります。- 値を取得するためだけに独自の HTTP 呼び出しを行うのではなく、サービスのランタイム内で
ctx.vtex.settingsから受け取った設定を読み取ります。 - ハンドラーとリゾルバーでは、
ctx.vtex.settingsを設定スキーマに合わせてキャストまたは検証し、そのスキーマに沿ったデフォルト値を適用します。 - 設定アプリは、任意の運用データを保存する仕組みの代替ではなく、VTEX IO コンテキストを通じて構造化されたランタイム設定を注入する手段として扱います。
- 設定が1つのアプリ内に限定され、Apps > App Settings で直接編集する場合は
settingsSchemaを使います。コントラクトを共有、バージョン管理、または利用側アプリのライフサイクルから分離する場合は、設定アプリを使います。 - 設定アプリを通じて設定されたサービスが、権限の問題でワークスペースのアプリ設定を解決できない場合は、その状況でマニフェストに
read-workspace-appsポリシーが必要かどうかを明示的に評価します。関係のないサービスに、このポリシーをデフォルトで追加しないでください。 - サービス設定のコントラクトでは、
additionalProperties: falseを使った閉じたスキーマを優先し、構造が複雑になる場合はdefinitionsと$refを使います。
厳守事項
制約:サービスアプリは設定を受け取ることを明示的にオプトインする必要があります
サービスアプリは、node/service.json のルートまたはイベントで settingsType: "workspace" を指定するか、GraphQL で @settings ディレクティブを使用して、設定を注入できる場所を明示する必要があります。
重要な理由
設定アプリがすべてのサービスエントリーポイントに自動的に適用されるわけではありません。サービスは、実行時の設定を解決するルート、イベント、またはクエリを明示的に指定する必要があります。
検出方法
サービスが設定を受け取ることを想定されているにもかかわらず、そのルート、イベント、または GraphQL クエリで settingsType や @settings が宣言されていない場合は、STOP して、まず設定境界を明示してください。
正しい例
{
"routes": {
"status": {
"path": "/_v/status/:code",
"public": true,
"settingsType": "workspace"
}
}
}
誤った例
{
"routes": {
"status": {
"path": "/_v/status/:code",
"public": true
}
}
}
制約:設定の構造は明示的なスキーマファイルで定義する必要があります
設定アプリと、それらが設定するサービスは、暗黙的または文書化されていないペイロードではなく、明示的なスキーマファイルを使用する必要があります。
重要な理由
configuration/schema.json と、それに対応する configuration.json の契約がなければ、アプリ間で共有される設定が曖昧になり、エラーが発生しやすくなります。
検出方法
明確なスキーマファイルがないまま設定アプリが導入されている場合、またはサービスが定義の緩い設定ペイロードを受け入れる場合は、STOP して、まずスキーマを定義してください。
正しい例
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/ServiceConfiguration",
"definitions": {
"ServiceConfiguration": {
"type": "object",
"properties": {
"bank": {
"type": "object",
"properties": {
"account": { "type": "string" },
"workspace": { "type": "string", "default": "master" },
"version": { "type": "string" },
"kycVersion": { "type": "string" },
"payoutVersion": { "type": "string" },
"host": { "type": "string" }
},
"required": ["account", "version", "kycVersion", "payoutVersion", "host"],
"additionalProperties": false
}
},
"required": ["bank"],
"additionalProperties": false
}
}
}
誤った例
{
"anything": true
}
制約:設定を受け取るアプリは、独自の追加フェッチを行わず、実行時コンテキストから注入された設定を読み取る必要があります
サービスが設定アプリを通じて設定される場合、独自の場当たり的な HTTP 呼び出しを作成して同じ設定を取得するのではなく、ctx.vtex.settings から注入された値を読み取る必要があります。
重要な理由
設定アプリの目的は、VTEX IO が構造化された設定をサービスコンテキストに直接注入できるようにすることです。そのうえに独自のフェッチレイヤーを追加すると、複雑さが不必要に増し、ビルダーの主な実行時の利点が失われます。
検出方法
サービスですでに settingsType または @settings を公開しているにもかかわらず、同じ設定を取得するために独自のバックエンドフェッチを実行している場合は、STOP して、読み取りを ctx.vtex.settings に移してください。
正しい例
export async function handleStatus(ctx: Context) {
const settings = ctx.vtex.settings
const code = ctx.vtex.route.params.code
const status = resolveStatus(code, settings)
ctx.body = { status }
}
誤った例
export async function handleStatus(ctx: Context) {
const settings = await ctx.clients.partnerApi.getSettings()
ctx.body = settings
}
推奨パターン
サービスと設定アプリを別々の契約としてモデル化します。
- サービスアプリは、設定を解決できる場所を公開します。
- サービスアプリは、
configuration/schema.jsonで受け付ける構造を定義します。 - 設定アプリは、サービスをビルダーとして宣言し、
configuration.jsonで値を指定します。 - サービスは、
ctx.vtex.settingsを通じて注入された設定を読み取ります。
例:サービスアプリ vendor.shipping-service
manifest.json:
{
"vendor": "vendor",
"name": "shipping-service",
"version": "1.0.0",
"builders": {
"node": "7.x",
"configuration": "1.x"
}
}
configuration/schema.json:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/ShippingConfiguration",
"definitions": {
"ShippingConfiguration": {
"type": "object",
"properties": {
"carrierApi": {
"type": "object",
"properties": {
"baseUrl": { "type": "string" },
"apiKey": { "type": "string", "format": "password" },
"timeoutMs": { "type": "integer", "default": 3000 }
},
"required": ["baseUrl", "apiKey"],
"additionalProperties": false
}
},
"required": ["carrierApi"],
"additionalProperties": false
}
}
}
例:設定アプリ vendor.shipping-config
manifest.json:
{
"vendor": "vendor",
"name": "shipping-config",
"version": "1.0.0",
"builders": {
"configuration": "1.x"
},
"configuration": {
"shipping-service": "1.x"
}
}
configuration/shipping-service/configuration.json:
{
"carrierApi": {
"baseUrl": "https://api.carrier.com",
"apiKey": "secret-api-key-here",
"timeoutMs": 5000
}
}
例:注入された設定を使用する Node サービス
export async function createShipment(ctx: Context, next: () => Promise<void>) {
const settings = ctx.vtex.settings as {
carrierApi: {
baseUrl: string
apiKey: string
timeoutMs?: number
}
}
const timeoutMs = settings.carrierApi.timeoutMs ?? 3000
const response = await ctx.clients.carrier.createShipment({
baseUrl: settings.carrierApi.baseUrl,
apiKey: settings.carrierApi.apiKey,
timeoutMs,
payload: ctx.state.shipmentPayload,
})
ctx.body = response
await next()
}
例:@settings を使用する GraphQL クエリ
type ShippingStatus {
orderId: ID!
status: String!
}
type Query {
shippingStatus(orderId: ID!): ShippingStatus
@settings(type: "workspace")
}
export const resolvers = {
Query: {
shippingStatus: async (_: unknown, args: { orderId: string }, ctx: Context) => {
const settings = ctx.vtex.settings as {
carrierApi: { baseUrl: string; apiKey: string }
}
return ctx.clients.carrier.getStatus({
baseUrl: settings.carrierApi.baseUrl,
apiKey: settings.carrierApi.apiKey,
orderId: args.orderId,
})
},
},
}
サービス設定アプリの最低限の動作チェックリスト:
- サービスアプリが
manifest.jsonでconfigurationビルダーを宣言している。 - サービスアプリが有効な
configuration/schema.jsonを定義している。 - 設定アプリが、スキーマに適合する値を含む
<service-app>/configuration.jsonを提供している。 - 設定が必要なサービスのルートまたはイベントで
settingsType: "workspace"が宣言されている。 - ワークスペースアプリの解決に依存するフローでは、サービスのマニフェストで
read-workspace-appsが必要かどうかを評価している。
場当たり的にサービスコードで取得するのではなく、設定を共有してバージョン管理し、VTEX IO の実行環境から注入したい場合は、この方法を使用してください。
よくある失敗例
- 実際にはアプリ間で共有する設定契約が必要なのに、アプリの設定を使用する。
- 明示的なスキーマファイルを用意せずに設定アプリを作成する。
- 設定を受け取るべきサービスで、
settingsTypeまたは@settingsの指定を忘れる。 - 設定がすでに
ctx.vtex.settingsに注入されているのに、HTTP 経由で取得する。 - 設定アプリを汎用的な運用データストレージとして扱う。
レビューチェックリスト
- 通常の
settingsSchemaではなく、設定アプリが本当に必要ですか? - 別の設定アプリを作らずに、ローカルアプリの設定と
settingsSchemaでこのケースを解決できますか? - サービスで
settingsTypeまたは@settingsを指定し、設定解決を明示的に有効にしていますか? - サービスのルートまたはイベント経由で設定が注入される場合、必要な箇所で
settingsType: "workspace"を宣言していますか? - 設定契約は
configuration/schema.jsonで定義され、configuration.jsonと一致していますか? - 余分な取得処理を追加せず、サービスで
ctx.vtex.settingsから設定を読み取っていますか? - インストール済みのワークスペースアプリまたはその設定の読み取りに依存するフローの場合、
read-workspace-appsをデフォルトで追加するのではなく、意図的に採用するかどうかを検討しましたか? - 設定スキーマは、共有契約として十分に閉じており、明示的ですか?
- 設定契約は、運用データストレージと明確に分離されていますか?
リファレンス
- サービス設定アプリの開発 - サービスアプリと設定アプリの公式ガイド
- ビルダー -
configurationビルダーの概要 - サービス - Node サービスと GraphQL サービスの設定コンテキスト