vtex-io-app-settings について
VTEX IO 開発者向けに、アプリ設定の境界を設計・レビューするスキルです。スキーマ、実行時の読み取り、検証、機密設定の保護を扱います。
主な機能
- 01アプリ設定とブロック設定の区別
- 02JSON Schema による設定定義
- 03不足設定の検証とデフォルト値適用
- 04シークレットのバックエンド限定
- 05設定と構成アプリの使い分け
活用シーン
- 01マーチャント向けアプリ設定の定義
- 02ページやブロック単位の設定の確認
- 03シークレットの安全な取得と利用
- 04ワークスペース設定の欠落や不一致への対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill vtex-io-app-settingsインストール後、Claude Code で/vtex-io-app-settingsを入力して読み込まれたか確認します。
詳細
アプリの設定と構成の境界
このスキルを使用する場面
VTEX IO アプリで設定可能な設定を公開する方法を決定または実装するときに、このスキルを使用します。
settingsSchemaを定義する- マーチャントが設定可能なアプリの動作を追加する
- 設定をアプリ設定に含めるべきか、カスタムデータに含めるべきかを確認する
- アプリのコードで設定を読み取り、検証する
次の場合には、このスキルを使用しないでください。
service.jsonのランタイムインフラストラクチャ設定- Master Data のエンティティ設計
- ポリシー宣言の詳細
- ルート認証のモデリング
判断基準
- マーチャントや運用担当者が明示的に管理できるようにする安定した設定には、アプリ設定を使用してください。
- VTEX Admin で管理するアプリレベルの設定には
settingsSchemaを使用し、ページやブロックのインスタンスごとに異なる Store Framework ブロックの設定にはstore/contentSchemas.jsonを使用してください。 - 値がアプリまたはアカウント全体で共通する場合は、通常
settingsSchemaに含めます。ページ、ブロック、またはテーマの構成によって異なる場合は、通常contentSchemas.jsonに含めます。 - 大量の運用データを保存する代わりに、アプリ設定を使用しないでください。
- 汎用的なルートの
type: objectだけでなく、properties、required、default、enum、formatなどの制約を使って、JSON Schema を明示的に定義してください。 settingsSchema.access: "public"は、機密性がなく、publicSettingsForAppを通じてフロントエンドコードに公開しても安全な値に限って使用してください。accessが省略されている場合、フロントエンドの GraphQL コンシューマーが設定を読み取れると想定しないでください。フロントエンドへの公開は明示的に選択する必要があります。- API キー、トークン、シークレットには、コードベースにハードコードするのではなく、アプリ設定を使用してください。
- アプリ設定のシークレットを、HTTP レスポンス、GraphQL レスポンス、HTML、またはブラウザー側の props に直接公開しないでください。
- アプリ設定のシークレットをログにも出力しないでください。
- API キーやパスワードなどの機密フィールドは
type: "string"のままにし、format: "password"を指定することを検討してください。Apps GraphQL がhidePasswordsを使用する場合など、一部のプラットフォームのコンシューマーは、このメタデータを使ってレスポンス内の値をマスクすることがあります。これだけをセキュリティ対策として頼らないでください。シークレットは引き続きバックエンド専用として扱い、レスポンスやログに決して公開しないでください。 ui:widget: "password"などの UI 固有のヒントは、一部のレンダラーでサポートされる場合がありますが、コア JSON Schema で保証されているものではありません。標準の VTEX Admin App Settings UI で適用されるとは想定しないでください。- バックエンド設定の読み込みには
ctx.clients.apps.getAppSettings(ctx.vtex.appId ?? process.env.VTEX_APP_ID)を使用し、場当たり的なアクセス方法をハンドラー全体に散在させるのではなく、ヘルパーで正規化または検証を一元管理してください。 - 実行時にこのアプリ自身の設定を読み込む、または保存する場合は、
process.env.VTEX_APP_IDやctx.vtex.appIdなどの正しいアプリ識別子を使用し、アプリトークンと標準のアプリ設定権限を利用してください。403 を「修正」するために、manifest.jsonで余分な License Manager ポリシーを宣言したり、read-workspace-appsのようなワークスペース全体に適用されるポリシーや、文書化されていないwrite-workspace-appsのようなポリシーを追加したりしないでください。 - 設定が必要な Pixel アプリも、Pixel アプリのバックエンド側で
ctx.clients.apps.getAppSettings(...)を通じて設定を取得してください。注入する JavaScript から値を利用できるようにする必要がある場合は、access: "public"とpublicSettingsForAppを通じて機密性のないフィールドだけを公開し、シークレットは厳密にサーバー側に保持してください。 - 設定が欠落または不完全でもコードが動作するよう、使用する箇所で検証するかデフォルト値を適用してください。
- 設定がアカウントやワークスペース間で同一だと想定しないでください。開発、ロールアウト、またはデバッグ中、ワークスペースごとに異なるアプリ設定を持つことがあります。
設定と Configuration Builder の使い分け:
- 設定がこのアプリ固有のもので、マーチャントが Apps > App Settings で編集することを想定している場合は、
settingsSchemaを使用してください。 - 設定の契約を複数のアプリで共有する必要がある場合、実行時のアプリのライフサイクルとは別に管理する場合、または
ctx.vtex.settingsを通じてサービスコンテキストに直接注入する場合は、別のアプリでconfigurationビルダーを使用することを検討してください。 - 主な目的が、アプリ自身が都度取得する設定ではなく、VTEX IO の実行時コンテキストを通じて構造化されたサービス設定を提供することである場合は、Configuration アプリを優先してください。
絶対的な制約
制約:設定可能なアプリの動作にはスキーマが必要です
マーチャントが設定できる項目は、検証されていない場当たり的なオブジェクトではなく、明示的なスキーマを通じてモデル化する必要があります。
重要な理由
スキーマがないと、設定が曖昧になり、検証が難しくなり、環境間で問題が発生しやすくなります。
検出
コードがアプリレベルの設定に依存しているにもかかわらず、スキーマや検証の契約が存在しない場合は、いったん停止して、先に定義してください。
正しい例
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"properties": {
"enableModeration": {
"title": "Enable moderation",
"type": "boolean",
"default": false,
"description": "If true, new content will require approval before going live."
},
"apiKey": {
"title": "External API key",
"type": "string",
"minLength": 1,
"description": "API key for the external moderation service.",
"format": "password"
},
"mode": {
"title": "Mode",
"type": "string",
"enum": ["sandbox", "production"],
"default": "sandbox"
}
},
"required": ["apiKey"]
}
}
誤った例
const settings = ctx.state.anything
制約:機密性の高い設定はバックエンドのみで扱い、フロントエンドに公開してはいけません
API キー、トークン、パスワードなど、アプリ設定に保存されるシークレットは、バックエンドのみで使用する設定として扱う必要があります。
重要な理由
アプリ設定はシークレットを保存するのに自然な場所ですが、HTTP レスポンス、GraphQL ペイロード、HTML、フロントエンドの props で公開すると、設定がセキュリティ上の漏えいにつながります。
検出
ルート、リゾルバー、またはフロントエンド向けレスポンスが設定の生データを返す、もしくは設定の機密フィールドを含む場合は、いったん停止して、外部呼び出しやシークレットの使用をバックエンド境界内に完全に移してください。
正しい例
const { apiKey } = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const result = await externalClient.fetchData({ apiKey })
ctx.body = result
誤った例
const settings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
ctx.body = settings
制約:公開アプリ設定へのアクセスで、機密設定を公開してはいけません
settingsSchema.access が public に設定されている場合、公開される設定には、publicSettingsForApp を通じてフロントエンドコードに渡しても安全な値だけを含める必要があります。
重要な理由
access: "public" は値の提供方法を指定するものであり、セキュリティ制御ではありません。設定が公開されると、ストアフロントやフロントエンドのコードから読み取れるため、シークレットやバックエンドのみで使用する設定を含めてはいけません。
検出
設定スキーマでアクセスが public に指定されているにもかかわらず、API キー、トークン、パスワード、またはバックエンド連携専用の値が含まれている場合は、いったん停止して、それらの設定を非公開のままにしてください。
正しい例
{
"settingsSchema": {
"title": "Public Storefront Settings",
"type": "object",
"access": "public",
"properties": {
"bannerText": {
"title": "Banner text",
"type": "string"
}
}
}
}
誤った例
{
"settingsSchema": {
"title": "My App Settings",
"type": "object",
"access": "public",
"properties": {
"apiKey": {
"title": "External API key",
"type": "string",
"format": "password"
}
}
}
}
制約:設定を運用データの保存に使用してはいけません
アプリ設定は、高頻度で変更される大量のレコードではなく、設定を表す必要があります。
重要な理由
設定は設定境界のためのものであり、トランザクションデータや大規模な運用データのためのものではありません。
検出
設定に注文、レビュー、ログ、キュー項目のように扱われるレコードを保存しようとしている場合は、いったん停止して、その用途に適した別のデータ管理手段に移してください。
正しい例
{
"enableModeration": true
}
誤った例
{
"allReviews": []
}
制約:設定を使用する境界で、設定を検証するかデフォルト値を適用する必要があります
設定に依存するコードは、値が存在しない場合や不完全な場合でも安全に動作する必要があります。
重要な理由
ワークスペースやアカウントによって設定が異なることがあります。すべての設定が存在すると仮定するコードは、壊れやすくなります。
検出
コードが設定を読み取り、検証もデフォルト値もないまま必須フィールドが常に存在すると仮定している場合は、いったん停止して、その依存関係を明示してください。
正しい例
const rawSettings = await ctx.clients.apps.getAppSettings(
ctx.vtex.appId ?? process.env.VTEX_APP_ID
)
const settings = normalizeSettings(rawSettings)
const enabled = settings.enableModeration ?? false
誤った例
const enabled = settings.enableModeration.value
推奨パターン
安定したマーチャント管理の設定には設定機能を使用し、明示的な JSON Schema プロパティで定義したうえで、使用箇所で検証または正規化してください。
シークレットについては、読み取りと外部呼び出しをバックエンドで行い、業務上の結果のみをフロントエンドに返してください。
フロントエンドからの GraphQL アクセスは、意図的に公開する設定にのみ使用し、バックエンド専用の設定は getAppSettings(...) の背後で管理してください。
よくある失敗パターン
- 設定を運用データの保存先として使用する。
- 明示的な
propertiesや検証の詳細を指定せず、type: objectだけを使用する。 - デフォルト値や検証を設定せずに設定を読み込む。
- 生の設定値やシークレットをフロントエンドに公開する。
- バックエンド専用または機密性の高い値を含む設定に
access: "public"を指定する。 - 設定値やシークレットを平文でログに記録する。
- API キーやトークンをアプリ設定に保存せず、ハードコードする。
- アプリ設定の権限エラーに対する汎用的な回避策として、正しい appId と標準のアプリ設定権限を検証する代わりに、
read-workspace-appsなどのワークスペースレベルのポリシーや、write-workspace-appsなどの無効なポリシーを追加する。 - 要件が実際にはブロックレベルの Store Framework 設定であるにもかかわらず、
settingsSchemaを使用する。 - 範囲が広すぎる、または曖昧なスキーマを作成する。
レビューチェックリスト
- このデータは本当にアプリ設定に含めるべきですか?
-
settingsSchemaでは、明確な型を持つpropertiesが明示され、必要な場合に限ってrequiredが指定されていますか? - 機密フィールドは、たとえば
format: "password"を指定したstringフィールドとして安全に表現されていますか?また、Apps GraphQL のhidePasswordsなど、一部のコンシューマーがこのメタデータを使用して出力をマスクする可能性を把握していますか? - 設定を使用するコードは、欠落している値を検証するか、デフォルト値を設定していますか?
- シークレットはバックエンド専用に保たれ、フロントエンドには公開されていませんか?
-
access: "public"を使用する場合、公開されるすべての設定値はフロントエンドで安全に使用できるものですか? - 設定の対象範囲は必要最小限で、意図が明確ですか?
参考資料
- マニフェスト - アプリ設定の契約
- アプリ設定用のインターフェースを作成する -
settingsSchema、access、フロントエンドクエリ、バックエンドでの設定の利用 - アプリ設定を構成する - VTEX IO でアプリ設定を利用する Pixel アプリの例