sales-app-extensibility について
FastStore プロジェクトで VTEX Sales App の拡張機能を開発・デプロイするためのスキルです。環境確認から計画、コード生成、検証、デプロイまでを順に案内します。
主な機能
- 01FastStore と Sales App の前提条件確認
- 027段階の拡張開発ワークフロー
- 03拡張ポイントとフックの選択
- 04UI・API 拡張テンプレート
- 05TypeScript と静的解析による検証
- 06ドキュメントとデプロイの案内
活用シーン
- 01カートのプロモーション拡張の作成
- 02商品詳細へのバッジやおすすめ表示の追加
- 03Sales App 拡張への API 組み込み
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill sales-app-extensibilityインストール後、Claude Code で/sales-app-extensibilityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/code-templates-and-patterns.mddesign-guidelines.mddiscovery-and-use-cases.mddocumentation-template.mdextension-points-hooks-and-types.mdlocal-dev-build-and-deploy.mdstatic-analysis-rules.md詳細
Sales App の拡張性
このスキルを使用する場面
VTEX Sales App 向けの拡張機能を構築、カスタマイズ、またはデプロイする場合に、このスキルを使用してください。
- カートページへの機能追加(プロモーション、ロイヤルティ、サービス)
- 商品詳細ページへの機能追加(バッジ、おすすめ商品、保証)
- メニューへの機能追加(ユーザープロフィール、ナビゲーション、指標)
- Sales App の拡張機能への外部 API の統合
- Sales App 用の拡張機能コードの生成、スキャフォールディング、または検証
次の場合は、このスキルを使用しないでください。
- 通常の FastStore ストアフロントのカスタマイズ(
faststore-storefrontを使用してください) - VTEX IO アプリの構築(
vtex-io-*スキルを使用してください) - Sales App のコア開発またはフレームワークの変更
前提条件:FastStore プロジェクト
プロジェクトのルートに次のファイルが必要です:biome.json、faststore.json、package.json、tsconfig.json、turbo.json。
いずれかが見つからない場合は、STOP。ユーザーは先に FastStore をインストールする必要があります。
npx @vtex/fsp-cli init
# Prompt: "What is the application name?" → enter name or press Enter for default
cd <application-name> && yarn
ドキュメント:https://beta.fast.store/getting-started
前提条件:Sales App モジュール
FastStore プロジェクト内に、src/、package.json、tsconfig.json を含む Sales App ワークスペースが必要です(通常は packages/sales-app)。ルートの package.json にある "workspaces" で、sales-app を含むパスを確認してください。見つからない場合は、STOP。
yarn add @vtex/sales-app -D -W
npx fsp create
# Prompts: account name → "Sales App" → path (default or custom)
# Then add the path to root package.json "workspaces" array
yarn install
ドキュメント:https://beta.fast.store/sales-app/setting-up
両方の前提条件が確認されるまで、ディスカバリーやコード生成に進まないでください。
判断ルール
必須の 7 ステップのワークフロー(ステップ 0~6)を順番に実行してください。ステップを省略しないでください。
| ステップ | 目的 | ゲート |
|---|---|---|
| 0 | 前提条件の確認 | FastStore と Sales App がインストール済み → 続行。それ以外の場合は STOP |
| 1 | ディスカバリー | ユーザーが構築したいものを理解する |
| 2 | 要件と計画 | 要件を整理 → 計画を生成 → ユーザーの承認を待つ |
| 3 | コード生成と検証 | Component.tsx + Component.css(プレーン CSS。.module.css は使用しない)+ index.tsx を生成 → 検証 |
| 4 | ドキュメント | 拡張機能を説明する docs/<ExtensionName>.md を生成 |
| 5 | ローカルテスト | 開発コマンドと URL を提示 |
| 6 | ビルドとデプロイ | ビルドコマンド → デプロイガイド |
拡張ポイントの選択
| 拡張ポイント | カテゴリー | 利用可能なフック | レイアウトシフト |
|---|---|---|---|
cart.cart-list.after | カート | useCart、useExtension | いいえ |
cart.cart-item.after | カート | useCart、useCartItem、useExtension | はい |
cart.order-summary.after | カート | useCart、useExtension | はい |
pdp.sidebar.before | PDP | usePDP、useCart、useExtension | はい |
pdp.sidebar.after | PDP | usePDP、useCart、useExtension | はい |
pdp.content.after | PDP | usePDP、useCart、useExtension | はい |
menu.item | メニュー | useExtension | いいえ |
menu.drawer-content | メニュー | useCurrentUser、useExtension | いいえ |
フックの利用可否
- useCart → すべてのカートおよび PDP の拡張機能
- useCartItem →
cart.cart-item.afterのみ - useCurrentUser →
menu.drawer-contentのみ - usePDP → PDP の拡張機能のみ
- useExtension → すべての拡張ポイント
テンプレートの選択
- API なし + フックなし → シンプルテンプレート
- API なし + フックあり → フックテンプレート
- API あり + 認証なし → API テンプレート
- API あり + VTEX IO プロキシ → IO プロキシテンプレート(推奨)
- API あり + 直接認証 → 直接認証テンプレート(安全ではありません。ユーザーに警告してください)
- API ドキュメントあり → 抽出したレスポンスの形状から TypeScript インターフェースを生成。API ドキュメントなし →
${DATA_INTERFACE}プレースホルダーを使用
API 認証戦略
- 推奨:VTEX IO プロキシアプリ — IO アプリがキーをサーバー側に保存します。拡張機能では、相対パス(
/_v/my-api/data)とともにcredentials: 'include'を使用します。 - 安全ではない方法:直接認証 — キーがフロントエンドのコードに含まれ、ブラウザー上で確認できます。テストと開発にのみ使用してください。
厳守事項
制約:コンポーネントは null ではなく JSX.Element を返す必要があります
defineExtensions が求める ExtensionPointComponent は、Element | null ではなく Element を返します。
重要な理由
null を返すと TypeScript のコンパイルエラーが発生し、ビルドに失敗します。
検出方法
defineExtensions に登録されたコンポーネント内で return null を使用している。
正しい例
export function MyExtension(): JSX.Element {
if (!data) return (<></>);
return <div>{data.value}</div>;
}
誤った例
export function MyExtension(): JSX.Element | null {
if (!data) return null;
return <div>{data.value}</div>;
}
制約:使用前にオプションのプロパティを確認する必要があります
CartItem.manualPrice(number | undefined)、CartItem.productRefId(string | undefined)、CartItem.attachments(Attachment[] | undefined)は、使用前に確認する必要があります。
重要な理由 TypeScript の strict モードでは、値が undefined の可能性があるプロパティへのアクセスが拒否されます。
検出方法
item.manualPrice、item.productRefId、item.attachments を ?.、??、&&、!= null を使わずに参照している。
正しい例
const price = item.manualPrice ?? item.sellingPrice;
const refId = item.productRefId ?? 'N/A';
const count = item.attachments?.length ?? 0;
誤った例
const price = item.manualPrice;
const refId = item.productRefId.toUpperCase();
const count = item.attachments.length;
制約:useCartItem().item は undefined の可能性があります
useCartItem() から取得した item は CartItem | undefined です。
重要な理由
undefined に対してプロパティにアクセスすると、実行時エラーが発生します。
検出方法
useCartItem() から分割代入した item を、if (!item) のガードなしで使用している。
正しい例
const { item } = useCartItem();
if (!item) return (<></>);
return <div>{item.name}</div>;
誤った例
const { item } = useCartItem();
return <div>{item.name}</div>;
制約:index.tsx では defineExtensions が必須です
エントリーポイントでは、@vtex/sales-app の defineExtensions を使用する必要があります。
重要な理由 これがない場合、ビルドは成功しますが、拡張機能は何もレンダリングされません。
検出方法
index.tsx に defineExtensions のインポートまたは呼び出しがない。
正しい例
import { defineExtensions } from '@vtex/sales-app';
import { MyExtension } from './components/MyExtension';
export default defineExtensions({ 'cart.cart-list.after': MyExtension });
誤った例
import { MyExtension } from './components/MyExtension';
export default { 'cart.cart-list.after': MyExtension };
制約:エクステンションポイント名は完全に一致させる必要があります
ID は固定の一覧です。存在しない名前を指定しても、エラーは表示されません。
重要な理由 拡張機能はどこにもレンダリングされません。ビルドエラーは発生せず、実行時には表示されません。
検出方法
次の一覧にない名前を使用している:cart.cart-list.after、cart.cart-item.after、cart.order-summary.after、pdp.sidebar.before、pdp.sidebar.after、pdp.content.after、menu.item、menu.drawer-content。
正しい例
defineExtensions({ 'cart.cart-list.after': MyExtension });
誤った例
defineExtensions({ 'cart.list.after': MyExtension });
制約:フックは対応するエクステンションポイントで使用する必要があります
各フックには available_in の制限があります。
重要な理由 フックのコンテキストがマウントされるのは、特定のエクステンションポイントのみです。それ以外で使用すると、実行時エラーが発生します。
検出方法
PDP またはメニューで useCartItem を使用している。カートで useCurrentUser を使用している。メニューまたは cart-list で usePDP を使用している。
正しい例
// useCartItem in cart.cart-item.after ✓
defineExtensions({ 'cart.cart-item.after': ItemWarranty });
誤った例
// useCartItem in pdp.sidebar.after ✗ — will fail at runtime
defineExtensions({ 'pdp.sidebar.after': ItemWarranty });
推奨パターン
ワークフローの概要
Step 0 — FastStore と Sales App の前提条件を確認します。不足している場合は STOP します。
Step 1 — ディスカバリー。キーワードからユースケースを検出し、追加の質問をして、API 認証戦略を決定します。ユーザーが API ドキュメント(URL、OpenAPI/Swagger ファイル、Markdown、またはインラインテキスト)を提供した場合は、それを取り込んでエンドポイントの詳細とレスポンスの形式を抽出します。同等の手動での質問は省略します。抽出した情報をユーザーと確認します。詳細な質問の流れと API ドキュメントの取り込みに関するセクションについては、ディスカバリーのリファレンスを読み込みます。
Step 2 — 要件を拡張ポイント、フック、テンプレートに対応付けます。作成するファイルを一覧にした計画を提示します:components/<ComponentName>.tsx、components/<ComponentName>.css(プレーン CSS — .module.css は決して使用しないでください)、および index.tsx。承認を待ちます。
Step 3 — <ComponentName>.tsx、<ComponentName>.css(プレーン CSS、.module.css は決して使用しないでください)、および index.tsx を生成します。
このステップで必要なリファレンス(生成前に読み込みます):
- code-templates-and-patterns.md — すべてのコンポーネントテンプレート、CSS テンプレート(Sales App のデザインシステム全体をインラインで含みます:トークン、タイポグラフィ、間隔、レスポンシブ対応)、
index.tsxテンプレート、型生成ルール、およびカスタム fetch フックのパターン。 - extension-points-hooks-and-types.md — フックの戻り値の型と TypeScript の型定義。
- static-analysis-rules.md —
@vtex/fsp-analyzerによるサンドボックスのセキュリティ、CSS の分離、および React のパフォーマンスに関するルール。生成したすべてのファイルに対して、これらのチェックを実行します。 - design-guidelines.md — 拡張機能が UI テキストを表示する場合(文頭のみ大文字にするルール)、またはアイコン(Phosphor Icons)を使用する場合に読み込みます。
Step 1 で API ドキュメントを取り込んだ場合は、抽出したレスポンスの形式から TypeScript インターフェイスを生成し、コンポーネント内で ${DATA_INTERFACE} プレースホルダーの代わりに使用します。拡張機能が 2 つ以上のエンドポイントを呼び出す場合は、fetch ロジックをカスタムフックに切り出します。code-templates-and-patterns.md の 12 項目チェックリストに照らして検証します。コードを提示する前に、違反をすべて修正し、警告をユーザーに伝えます。
Step 4 — Sales App パッケージ内に docs/<ExtensionName>.md を生成します(必要に応じて docs/ フォルダーを作成します)。必須の 9 セクション構成と記入する Markdown のひな形については、ドキュメントテンプレートのリファレンスを読み込みます。
Step 5 — ローカル開発コマンドとテスト URL を提示します。開発/ビルド/デプロイのリファレンスを読み込みます。
Step 6 — ビルドコマンドとデプロイガイドを提示します。開発/ビルド/デプロイのリファレンスを読み込みます。
参照ファイル
タスクで必要になった時点で読み込んでください。最初にすべてを読み込まないでください。
| ファイル | 読み込むタイミング |
|---|---|
| references/extension-points-hooks-and-types.md | 拡張ポイントの選択、フックの選定、TypeScript の型(CartItem、ProductSku、Totalizers、Attachment)の確認、または拡張ポイントごとのフックの戻り値と利用可否の確認 |
| references/code-templates-and-patterns.md | 拡張コードの生成時 — シンプル、フック、API、IO Proxy、Direct Auth のテンプレート、Sales App のデザインシステム全体をインライン化した CSS テンプレート(トークン、タイポグラフィ、余白、レスポンシブ対応)、defineExtensions を含む index.tsx、フックの初期化、検証チェックリスト |
| references/discovery-and-use-cases.md | ステップ 1(ディスカバリー)の実行時 — ユースケースの検出キーワード、追加質問、API 認証の判断ツリー、IO Proxy と Direct Auth のフロー |
| references/local-dev-build-and-deploy.md | ステップ 5〜6 の実行時 — 開発サーバーのコマンド、テスト URL、ビルドコマンド、一般的なビルドエラー、FastStore WebOps のデプロイ、監視、ロールバック |
| references/static-analysis-rules.md | 生成コードの検証時(ステップ 3)— サンドボックスのセキュリティ、CSS の包含、@vtex/fsp-analyzer の React パフォーマンスルール、違反 ID、検出パターン、正しい例と誤った例を含む全ルールカタログ |
| references/design-guidelines.md | UI テキストの作成時(文頭大文字のルール)またはアイコン(Phosphor Icons)の使用時。CSS 関連のデザインルール(トークン、タイポグラフィ、余白、レスポンシブ対応)は code-templates-and-patterns.md 内の CSS テンプレートに直接記載されているため、CSS の生成にこのファイルは不要です。 |
| references/documentation-template.md | ステップ 4 で docs/<ExtensionName>.md ファイルを作成するとき — 9 セクションの構成と Markdown のひな形 |
よくある失敗
- 前提条件の確認を省略する — FastStore/Sales App がインストールされていない状態でコードを生成する。ステップ 1 の前に、必ず両方を確認してください。
- 計画を提示しない — ユーザーが別の方法を希望している場合があります。コードを生成する前に、必ずステップ 2 で確認してください。
- ドキュメントを省略する —
docs/<ExtensionName>.mdを作成せずに拡張機能を生成する。必要な構成については、documentation-template.mdを読み込んでください。 - API レスポンスの型をでっち上げる — 生成したインターフェースが実際の API と一致しない。ドキュメントが提供されている場合は、そこから型を導出してください。提供されていない場合は、ユーザーに JSON レスポンスのサンプルを依頼してください。
- 提供された API ドキュメントを無視する — ユーザーが URL またはファイルを提供したにもかかわらず、エージェントが手動で質問してしまう。必ず先にドキュメントを確認し、API ドキュメント取り込みフローを使用してください。
- 2 つ以上のエンドポイントに対するインライン
fetch— コンポーネント本体内に複数のfetch呼び出しがある。hooks/use{Purpose}.tsにカスタムフックとして切り出してください。 packages/sales-app/src/の外にコードを配置する — このパスの外にあるファイルはビルドに含まれません。
コードレベルの違反(DOM API、Node のインポート、eval、CSS の包含、React のパフォーマンス、デザイントークン)は
@vtex/fsp-analyzerによって適用され、ステップ 3 の検証時に検出されます。static-analysis-rules.md と design-guidelines.md を参照してください。
レビューチェックリスト
ワークフローのゲート
- FastStore がインストールされていますか(biome.json、faststore.json、package.json、tsconfig.json、turbo.json)?
- Sales App モジュールがインストールされていますか(sales-app ディレクトリ内の src/、package.json、tsconfig.json)?
- 調査が完了し、ユースケースが特定されていますか?
- 実行計画はユーザーに承認されていますか?
- 拡張ポイントは有効ですか(8 項目のリファレンスに記載されていますか)?
- フックは選択した拡張ポイントと互換性がありますか?
- ドキュメントは
docs/<ExtensionName>.mdに生成されていますか(documentation-template.md を使用した 9 つのセクション)? - API ドキュメントが提供されている場合、TypeScript インターフェースはドキュメントに記載されたレスポンスの形式と一致していますか?
- 2 つ以上の API エンドポイントを使用する場合、フェッチロジックは
hooks/内のカスタムフックに切り出されていますか? - ビルドは成功しますか:
yarn fsp build {account} sales-app? - ローカルでテストしましたか:
yarn fsp dev {account}?
TypeScript / 実行時のガード(fsp-analyzer では検出されません)
- コンポーネントは JSX.Element を返し、null を返していませんか?
- オプショナルなプロパティ(manualPrice、productRefId、attachments)はガードされていますか?
- useCartItem().item が undefined かどうか確認していますか?
- defineExtensions は index.tsx で設定されていますか?
その他すべてのコードレベルのルール(サンドボックス API、CSS の包含、React のパフォーマンス、デザイントークン)は
@vtex/fsp-analyzerによって適用され、ステップ 3 でチェックされます。static-analysis-rules.md と design-guidelines.md を参照してください。
関連スキル
faststore-storefront— Sales App 外でのストアフロントのカスタマイズvtex-io-app-contract— セキュアな API 統合のための VTEX IO プロキシアプリの構築
リファレンス
- Sales App のセットアップ:https://beta.fast.store/sales-app/setting-up
- FastStore の入門ガイド:https://beta.fast.store/getting-started
- VTEX Sales App のドキュメント:https://help.vtex.com/en/tracks/instore-getting-started-and-setting-up
- VTEX IO アプリの開発:https://developers.vtex.com/docs/guides/vtex-io-documentation-developing-an-app