mcpField
S
storefront-builder

storefront-builder

github.com/saleor開発2384 回インストール12 週間前に更新
リポジトリ

storefront-builder について

storefront-builder は、Saleor のストアフロント構築を段階ごとに案内するエージェントスキルです。既存プロジェクトの規約に従い、指定されたステップだけを実行します。

主な機能

  1. 01Saleor GraphQL APIへの接続
  2. 02コード生成とクライアントの設定
  3. 03ストアフロントのデザイントークン定義
  4. 04商品一覧・詳細ページの構築
  5. 05価格・画像・在庫データの処理

活用シーン

  1. 01既存プロジェクトをSaleorに接続
  2. 02ストアフロントの配色と書体を決定
  3. 03商品一覧とバリエーション選択ページを作成

インストール

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

$npx skills add https://github.com/saleor/agent-skills --skill storefront-builder

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

詳細

Saleor Storefront Playbook

このスキルは Saleor のデータコントラクトと、UX/データレイヤーの動作を担当します。フレームワークの足場作り、CSS の設定、環境変数の読み込み方法は担当しません。エージェントは、これらをローカルプロジェクトから確認します。

$ARGUMENTS を解析して、実行するステップを特定してください。

ステップの振り分け

$ARGUMENTS の最初の単語をステップ番号として読み取り、該当するセクションに進んでください。そのステップだけを実行してから停止し、ユーザーが次のステップを依頼するまで待ってください。ステップを自動的に連続実行してはいけません。

ステップが指定されていない場合、または認識できない場合は、次を出力してください。

Saleor Storefront Builder

Usage: /storefront-builder <step>

Steps:
  1   Bootstrap — wire GraphQL client, codegen, Saleor API connection
  2   Design & aesthetic — color palette, typography, accent color
  3   Catalog — product list page + product detail page with variant selection

Example: /storefront-builder 1

ステップ 1:プロジェクトの初期設定

既存のプロジェクトを Saleor の GraphQL API に接続し、クライアントを適切に分離してコード生成を設定します。

0. Saleor インスタンスの確認

ユーザーに尋ねてください。

「Saleor インスタンスの準備はできていますか?

  • いいえ — https://cloud.saleor.io/ で作成してください(無料プランを利用できます)。その後、API URL を持って戻ってきてください。
  • はい — ストアフロント/API の URL を貼り付けてください。作業を開始します。」

続行する前にユーザーの返答を待ってください。まだインスタンスを用意していない場合は、ここで停止し、ユーザーが設定を完了するまで待ってください。URL が提供された場合は、ステップ 6 で使うために控えておいてください。

1. プロジェクトを調べる

package.json と、存在するフレームワーク設定ファイル(nuxt.config.ts、next.config.*、svelte.config.js、remix.config.js、vite.config.* など)を読み取り、次の内容を確認してください。

  • フレームワークとバージョン
  • 使用中のパッケージマネージャー(ロックファイルを確認:pnpm-lock.yaml、yarn.lock、package-lock.json)
  • 既存の GraphQL 設定(ある場合)
  • インポートエイリアスの規則(例:@/、~/、#)
  • ソースディレクトリの構成(src/、app/、ルート直下)

上記について質問してはいけません。プロジェクトから判断してください。必要な情報を特定できず、作業の続行に必要な場合にのみ質問してください。

2. AGENTS.md を作成する

リポジトリのルートに AGENTS.md がまだ存在しない場合は、ここで作成してください。これにより、このリポジトリで今後やり取りする際に、Saleor 固有のルールが AI ハーネスに適用されます。

インストール済みのスキルを確認してください。

ls .agent-skills/saleor-storefront/AGENTS.md 2>/dev/null && echo "STOREFRONT" || echo ""
ls .agent-skills/saleor-configurator/AGENTS.md 2>/dev/null && echo "CONFIGURATOR" || echo ""

存在するスキルへの @ 参照だけを含めて、AGENTS.md を記述してください。

# Saleor Storefront

This is a Saleor-powered storefront.

## Workflow

When running `/storefront-builder`, execute only the requested step, then stop and wait for the user to ask for the next one. Never chain steps automatically.

## Saleor rules


@.agent-skills/saleor-storefront/AGENTS.md


@.agent-skills/saleor-configurator/AGENTS.md

AGENTS.md がすでに存在する場合は、このステップ全体をスキップしてください。上書きしてはいけません。

3. GraphQL の依存関係をインストールする

ステップ 1 で確認したパッケージマネージャーを使ってください。

graphql-request graphql
@graphql-codegen/cli @graphql-codegen/client-preset  (dev)
4. コード生成の設定を作成する

プロジェクトルートにコード生成設定ファイルを作成してください(ファイル名は、プロジェクトの規則に応じて codegen.ts または codegen.js)。設定する主な値は次のとおりです。

  • schema:Saleor GraphQL API の URL。プロジェクトで使用している環境変数から読み込みます(設定されていない場合は SALEOR_API_URL)。
  • documents:ローカルの規則に従い、プロジェクトの GraphQL ファイルディレクトリを指す glob
  • generates:gqlTagName: "graphql" を指定して client プリセットを使用

package.json に codegen スクリプトを追加してください。

5. Saleor API クライアントを作成する

2 クライアントパターン — これは Saleor の正しい実装に必須のルールです。省略できません。

プロジェクトのライブラリ/ユーティリティの規則に合う場所にクライアントモジュールを作成してください。2 つのクライアントをエクスポートします。

saleorClient      — anonymous, no auth headers — safe for RSC, SSG, public product queries
saleorAuthClient  — server-only, reads app token from env — NEVER use in browser bundles

**2 つのクライアントが重要な理由:**公開クエリやキャッシュ対象のクエリにアプリトークンを渡すと、特権アクセスが漏えいし、顧客データが露出する可能性があります。匿名クエリは匿名のままにしてください。

認証クライアントでは、トークンの環境変数が設定されている場合にのみ Authorization ヘッダーを含めてください(フロントエンド環境で変数が未設定でもモジュールがエラーにならないよう、条件分岐で保護してください)。

6. 環境を設定する

プロジェクトで使用している環境変数の命名規則を確認します(例:Next.js ではブラウザーからアクセスできる変数に NEXT_PUBLIC_* を使用し、Nuxt では NUXT_PUBLIC_* を使用します)。

必須の変数:

  • [PUBLIC_PREFIX]_SALEOR_API_URL — Saleor GraphQL エンドポイント
  • [PUBLIC_PREFIX]_SALEOR_CHANNEL — デフォルトのチャネルスラッグ
  • SALEOR_APP_TOKEN(パブリックプレフィックスなし — サーバーサイド専用)

プロジェクトの環境ファイル(.env.local、.env など)に、プレースホルダー値とコメントを記述するか、既存のファイルを更新します。入力する Saleor API URL とチャネルスラッグがあるか、ユーザーに確認します。

ヒント — Configurator で既存のストアを調査する 既存の Saleor インスタンスにアクセスでき、設定されているチャネル、カテゴリ、商品がわからない場合は、Configurator CLI を使用します。

export SALEOR_URL=https://your-store.saleor.cloud/graphql/
export SALEOR_TOKEN=YOUR_TOKEN
pnpm dlx @saleor/configurator introspect

生成された config.yml を確認すると、正確なチャネルスラッグ、公開済みの商品、カテゴリ構造がわかります。これらの値を環境変数とクエリにそのまま使用します。

7. 検証する

API URL が設定されている場合は、コード生成を実行してスキーマに接続できることを確認します。

[package-manager] codegen 2>&1 | head -20

ネットワークエラーが発生した場合は、問題の原因を調査します(URL の誤り、認証情報の不足など)。

8. まとめ
[✓/–] AGENTS.md: [created / already existed]
✓ Framework: [detected framework]
✓ Package manager: [pm]
✓ Deps: graphql-request, @graphql-codegen/cli, @graphql-codegen/client-preset
✓ Clients: [path] (public + authenticated)
✓ Codegen: codegen.ts
[✓/⚠] API URL: [set / not set]
[✓/⚠] Channel: [slug / placeholder]

Next: /storefront-builder 2

まとめを出力したら、そこで停止してください。ユーザーから明示的に依頼されない限り、ステップ 2 に進まないでください。


ステップ 2:デザインと美的方向性

UI コードを書く前に、ストアフロントのビジュアルアイデンティティを定義します。このステップでは、以降のすべてのステップで読み込むテーマモジュールとデザイントークンを作成します。ファイルパスとトークン形式は、プロジェクトの既存の規約に従います。

1. プロジェクトのスタイリング設定を確認する

プロジェクトを読み、次の点を確認します。

  • 使用している CSS フレームワーク(Tailwind、CSS Modules、styled-components、UnoCSS、vanilla CSS など)
  • 既存のデザイントークンの規約(CSS カスタムプロパティ、theme.* ファイル、Tailwind 設定など)
  • 共通スタイルの配置場所

Tailwind や特定の CSS の手法を決めつけず、プロジェクトから判断します。

2. 美的方向性について質問する

1 つのメッセージで、ユーザーに 3 つの質問を会話形式で尋ねます。フォームのような聞き方は避けてください。

「ストアフロントの見た目を決めましょう。いくつか簡単に質問します。

  1. 参考にしたいものはありますか?(ブランド、URL、スクリーンショットなど。なくてもかまいません)
  2. 全体的な雰囲気はどのようなものがよいですか?たとえば、ミニマルで明るい、ダークで高級感のある、大胆でカラフル、柔らかく温かみのある、クラシックでエディトリアルな雰囲気などです。ご自身の言葉で説明していただいてもかまいません。
  3. アクセントカラーの希望はありますか?ボタンやリンクに使います。16 進数、色名で指定するか、お任せください。」

ユーザーからの情報が少ない場合は、先に進む前に追加で 1 つ質問します。

3. トークンを決める

背景、サーフェス、ボーダー、テキスト(プライマリ)、テキスト(セカンダリ)、アクセント、アクセント(ホバー時)、ボーダー半径、見出しフォント、本文フォントの値を決めます。

4. テーマトークンを記述する

プロジェクトの規約に沿った場所にテーマモジュールを記述します。次の情報を含むコメントブロックを追加します。

  • スタイルプリセット名
  • 参考にしたもの(あれば)
  • アクセントカラーを選んだ理由
  • タイポグラフィの選択理由

プロジェクトの既存の規約に従って、トークンをスタイリングシステムに組み込みます。

  • Tailwind:トークンの値を使って tailwind.config.* を拡張する
  • CSS カスタムプロパティ:プロジェクトのグローバル CSS ファイルに記述する
  • その他:既存の方式に従う

グローバル CSS またはベース CSS を更新し、背景とテキストのデフォルトを適用します。

5. まとめ
✓ Style: [preset name]
✓ Accent: [color]
✓ Typography: [font choice]
✓ Theme tokens: [path]
✓ Styling system updated: [tailwind.config / globals.css / etc.]

Next: /storefront-builder 3

まとめを出力したら、そこで停止してください。ユーザーから明示的に依頼されない限り、ステップ 3 に進まないでください。


ステップ 3:カタログ — 商品一覧と商品詳細ページ(PDP)

バリエーション選択機能を備えた商品一覧ページと商品詳細ページを作成します。

前提条件の確認

Saleor クライアントモジュールが存在することを確認します(Step 1 で設定した内容をもとに検索してください)。存在しない場合は、まず /storefront-builder 1 を実行するようユーザーに伝えます。

プロジェクトの env ファイルにチャネルスラッグがあるか確認します。見つからず、引数としても渡されていない場合は、次のように尋ねます。

"Saleor のチャネルスラッグは何ですか?(Saleor Dashboard → Channels、または Enter キーで 'default-channel')"

プロジェクトのフレームワークとルーティング規約を調べ、ページの作成場所とデータ取得の方法(サーバーコンポーネント、getStaticProps、ローダー、load 関数、asyncData など)を確認します。

1. GraphQL クエリ — Saleor のデータ契約

プロジェクトの GraphQL ドキュメントディレクトリに products.graphql ファイルを作成します。

ProductCard フラグメント

商品一覧に必要なフィールド:

fragment ProductCard on Product {
  id
  name
  slug
  thumbnail {
    url
    alt
  }
  pricing {
    priceRange {
      start {
        gross {
          amount
          currency
        }
      }
    }
  }
  category {
    name
    slug
  }
}

これらのフィールドが必要な理由:

  • thumbnail は null の場合があるため、必ず代替画像またはプレースホルダーを用意してください
  • pricing.priceRange.start は null の場合があるため、価格の表示前にチェックしてください
  • category は null の場合があるため、カテゴリラベルの表示前にチェックしてください
ProductDetails フラグメント

商品詳細ページに必要なフィールド:

fragment ProductDetails on Product {
  id
  name
  slug
  description
  thumbnail {
    url
    alt
  }
  media {
    url
    alt
    type
  }
  pricing {
    priceRange {
      start {
        gross {
          amount
          currency
        }
      }
    }
  }
  category {
    name
    slug
  }
  variants {
    id
    name
    sku
    pricing {
      price {
        gross {
          amount
          currency
        }
      }
      priceUndiscounted {
        gross {
          amount
          currency
        }
      }
    }
    selectionAttributes: attributes(variantSelection: VARIANT_SELECTION) {
      attribute {
        name
        slug
      }
      values {
        name
        slug
      }
    }
    quantityAvailable
  }
}

これらのフィールドが必要な理由:

  • 商品詳細ページでは thumbnail より media 配列を優先し、media が空の場合は thumbnail を使用してください
  • variants.pricing は null の場合があるため、amount にアクセスする前にチェックしてください
  • 匿名ユーザーの場合、quantityAvailable は null になることがあります。null の場合は在庫ありとして扱ってください(在庫数を 1 とみなします)
  • selectionAttributes は variantSelection: VARIANT_SELECTION フィルターを使用します。これにより、商品レベルの属性ではなく、バリアントを区別する属性(サイズ、色など)のみが返されます
クエリ
query ProductList($channel: String!, $first: Int = 20, $after: String) {
  products(channel: $channel, first: $first, after: $after) {
    edges {
      node {
        ...ProductCard
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

query ProductBySlug($slug: String!, $channel: String!) {
  product(slug: $slug, channel: $channel) {
    ...ProductDetails
  }
}

チャネルは常に必須です — channel を指定しないクエリでは、価格や在庫状況のデータが返されません。

クエリを作成したら、codegen を実行します。

2. Saleor のデータ処理ルール

ページとコンポーネントを実装する際は、以下のルールに従ってください。

説明の解析

Saleor は description を EditorJS JSON として保存します。生のまま表示せず、安全に解析してください。

function extractDescriptionText(description: unknown): string {
  try {
    const parsed = typeof description === "string" ? JSON.parse(description) : description;
    return parsed?.blocks
      ?.map((b: { data?: { text?: string } }) => b.data?.text ?? "")
      .filter(Boolean)
      .join(" ") ?? "";
  } catch {
    return "";
  }
}
価格のフォーマット

通貨記号をハードコードせず、レスポンスの通貨を使って、常に Intl.NumberFormat を使用してください。

function formatPrice(amount: number, currency: string) {
  return new Intl.NumberFormat(undefined, { style: "currency", currency }).format(amount);
}

ユーザーのブラウザーのロケールを尊重するには、ロケールに undefined を指定してください(または、プロジェクトにロケールシステムがある場合はロケールを渡してください)。

画像の処理
  • 商品詳細ページでは、thumbnail より product.media[0] を優先し、media が空の場合は thumbnail を使用してください
  • 画像が欠けていないか必ず確認し、壊れた <img> タグではなく、ニュートラルなプレースホルダーを表示してください
  • alt テキストがない場合は、alt ?? product.name を代替テキストとして使用してください
在庫/購入可能状況の意味
  • quantityAvailable === null → 購入可能として扱います(匿名ユーザーには在庫情報が表示されません)
  • quantityAvailable === 0 → 在庫切れです。選択できないようにし、視覚的なインジケーター(取り消し線または薄い表示)を付けてください
  • quantityAvailable > 0 → 在庫ありです
バリアント選択の UX
  • すべてのバリアントを表示し、在庫切れのものは非表示にせず選択できないようにしてください。表示することで、ユーザーはどの選択肢があるか把握できます
  • 属性がある場合は、selectionAttributes を使用してバリアントにラベル(例:「サイズ:M」「色:赤」)を付けてください
  • 商品にバリアントが 1 つしかなく、選択属性もない場合は、セレクターを省略して「カートに追加」に進んでください
  • 選択したバリアントの pricing.price は、商品レベルの pricing.priceRange より優先されます。選択時に表示価格を更新してください
空の状態/エラー状態
  • 商品一覧に結果がない場合:問題解決のヒント(チャネルスラッグが間違っている、または商品が公開されていないなど)を添えた明確なメッセージを表示してください
  • 商品が見つからない場合(ProductBySlug が null):フレームワークの not-found/404 の仕組みを使用してください
  • 価格情報がない場合:$0 や NaN を表示せず、価格全体を省略してください
3. 共通ナビゲーションの作成

プロジェクトのコンポーネントディレクトリに、ローカルの命名規約に従ってナビゲーション/ヘッダーコンポーネントを作成します。ナビゲーションには、Step 2 で設定したテーマトークンを使用してください(Step 2 を省略した場合は、適切なニュートラルなデフォルト値を使用します)。

プロジェクトで確認したフレームワークの規約に従って、ナビゲーションをルートレイアウト/アプリシェルに組み込みます。

4. 商品一覧ページを作成する

プロジェクトのルーティング規則に合ったパス(例:app/page.tsx、pages/index.tsx、pages/index.vue、src/routes/+page.svelte、app/routes/_index.tsx)に商品一覧ページを作成します。

データ取得のパターン:フレームワークが提供する方法を使用します(非同期サーバーコンポーネント、getStaticProps/ISR、load 関数、asyncData、Remix loader など)。SSG に対応したフレームワークでは、適切な再検証間隔(例:60s)を設定します。

セクション 2 のすべてのデータ処理ルールを適用します。null 許容値のチェック、価格の適切なフォーマット、空状態の表示を行います。

5. PDP を作成する

ルーティング規則に合ったパス(例:app/p/[slug]/page.tsx、pages/p/[slug].tsx、pages/p/[slug].vue、src/routes/p/[slug]/+page.svelte)に PDP を作成します。

セクション 2 のすべてのデータ処理ルールを適用します。

6. VariantSelector コンポーネントを作成する

プロジェクトのコンポーネントディレクトリに VariantSelector コンポーネントを作成します。クライアント側で操作できるようにしてください(React state、Vue ref、Svelte store など、フレームワークのインタラクティビティ機能を使用します)。

動作:

  • すべてのバリエーションを表示し、在庫切れのものは無効にします(非表示にはしません)。
  • 選択中のバリエーションを強調表示します。
  • バリエーションを選択すると、表示価格を更新します(バリエーションの pricing.price が優先されます)。
  • バリエーションの選択が必須の場合、選択するまで「カートに追加」ボタンを無効にします。
  • 単一バリエーションの商品/属性のない商品では、セレクターを省略し、「カートに追加」を直接表示します。
  • この段階では「カートに追加」は機能しません。プレースホルダーのみとし、その旨をコメントで明記します。
7. 実行して確認する

プロジェクトの開発コマンドで開発サーバーを起動します。データが正しく読み込まれることを確認するため、商品一覧と PDP の URL をユーザーに案内します。

よくある問題:

  • 一覧が空:チャンネルのスラッグが間違っているか、そのチャンネルで商品が公開されていません。configurator introspect を実行してストアを調べるよう提案します。
  • コード生成エラー:API URL が設定されていないか、アクセスできません。
  • どのスラッグでも商品が見つからない:チャンネルが一致していないか、そのチャンネルで商品が公開されていません。
概要
✓ GraphQL queries: [path]/products.graphql
✓ Types generated
✓ Navigation: [path] (wired into root layout)
✓ Product list: [route]
✓ Product detail: [route]
✓ VariantSelector: [path]

Note: "Add to Cart" is present but non-functional — checkout is not covered by this skill

This is the last step currently available in this skill.

概要を出力した後、停止してください。


Saleor の正確性に関するルール(常に適用)

これらのルールは、すべての手順と今後のストアフロント作業に適用されます。

  1. 必ず channel を渡す — 商品/価格/在庫状況に関するすべてのクエリで必要です。省略するとデータが返されません。
  2. description を安全に解析する — これは EditorJS の JSON であり、プレーンテキストや HTML ではありません。
  3. SALEOR_APP_TOKEN をブラウザーに絶対に公開しない — 2 クライアントパターンを使用します。認証クライアントはサーバー側でのみ使用します。
  4. quantityAvailable が null の場合は購入可能 — 匿名ユーザーには在庫数が返されません。null は「購入を制限しない」という意味です。
  5. すべての階層で pricing は null になり得る — amount にアクセスする前に、pricing、pricing.price、pricing.priceRange、gross をチェックします。
  6. 価格には Intl.NumberFormat を使用する — 通貨記号をハードコードしたり、ロケールを決めつけたりしてはいけません。
  7. PDP のメディアの優先順位:media[0] → thumbnail → プレースホルダー
  8. 在庫切れのバリエーションは非表示にせず、無効にする — 非表示にすると、商品の選択肢についてユーザーを混乱させます。

コメント