spree-providers について
Spree 6 に外部システムを接続する開発者向けスキルです。Provider の契約や登録方法に加え、設定、認証情報、各機能の実装要件を解説します。
主な機能
- 01各種コマース機能の Provider 契約
- 02レジストリ設定と登録時期の説明
- 03店舗ごとの連携認証情報
- 04実装インターフェースの参照
- 05連携時の注意点
活用シーン
- 01税務または決済 Provider の追加
- 02配送レートやフルフィルメントの接続
- 03外部検索や売上金支払いの連携
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ spree/ agent-skills --skill spree-providersインストール後、Claude Code で/spree-providersを入力して読み込まれたか確認します。
詳細
Spree プロバイダー — 外部システムとの接続
Spree 6 では、プロバイダーコントラクトを通じて外部システムに接続します。サブクラス化する基底クラス、登録先となるレジストリ、そしてマーチャント(または設定)が選択する場所で構成されています。各コントラクトには Spree 自身のデータを使う組み込みのデフォルトがあるため、何も接続しなくても動作は変わりません。コアの処理フローをフォークしたりデコレートしたりする必要はありません。
以下のパスでは、
create-spree-appプロジェクトのserver/プレフィックスを使用しています。従来型の Rails アプリでは省略してください。
全体像
| 対象 | 基底クラス | 登録方法 | 選択方法 | デフォルト |
|---|---|---|---|---|
| 税金 | Spree::TaxProvider::Base | Spree.tax_providers << MyTax | market.tax_provider、または Spree.default_tax_provider = | Spree::TaxProvider::Internal |
| 配送料金 | Spree::DeliveryRateProvider::Base | Spree.delivery_rate_providers << MyRates | delivery_method.rate_provider | …::Internal(計算機)、…::Freight |
| フルフィルメント/ラベル/WMS | Spree::FulfillmentProvider::Base | Spree.fulfillment_providers << MyWms ⚠ after_initialize | delivery_method.fulfillment_provider | …::Manual、Digital、Pickup、PickupPoint |
| 決済 | Spree::PaymentMethod(または Spree::Gateway)+Spree::PaymentSession STI | Spree.payment_methods << MyGateway ⚠ after_initialize | 決済方法のレコード(設定 → 決済) | Check、StoreCredit、Bogus |
| 検索 | Spree::SearchProvider::Base | Spree.search_provider = 'My::Provider'(グローバルで1つ) | — | Spree::SearchProvider::Database |
| 出品者への支払い | Spree::PayoutProvider::Base | Spree.payout_providers << MyPayouts | ストア設定 payout_provider、または Spree.default_payout_provider | Spree::PayoutProvider::System |
| デジタル商品の納品物 | Spree::DigitalAssetProvider::Base | Spree.digital_asset_providers << 'My::Provider' | digital_asset.provider_type | …::File |
| 認証ストラテジー(SSO、外部 JWT) | Spree::Authentication::Strategies::BaseStrategy/OidcStrategy.configure(...) | Spree.{store,admin,seller}_authentication_strategies.add(:key, klass) ⚠ after_initialize | ログインリクエスト(provider パラメーター) | :email(EmailPasswordStrategy) |
| 上記いずれかの認証情報 | Spree::Integration | Spree.integrations << 'My::Integration' ⚠ after_initialize | ストアごとに設定 → インテグレーション | — |
| オブザーバビリティ | —(gem) | gem 'spree_opentelemetry' + OTEL_* 環境変数 | — | 無効 |
トランザクションメールはプロバイダーではありません。 Spree はデプロイメント全体に対して SMTP_* 環境変数で設定された通常の SMTP 経由でメールを送信します。管理画面でストアごとに設定するものではなく、インストールするプロバイダー gem もありません。どの SMTP サービスでも利用できます(Resend、Postmark、SendGrid、Mailgun、Amazon SES にはセットアップガイドがあります)。STARTTLS ポート(587)を使用してください。465 などの暗黙的 TLS ポートでは接続できません。Spree はバウンスや苦情を処理しないため、プロバイダー独自の Webhook で対応してください。spree-deployment を参照してください。
同じ方法で利用できますが、「プロバイダー」ではない関連プラグインポイント:Spree.order_routing.rules/.strategies(基底クラス Spree::OrderRoutingRule、Spree::OrderRouting::Strategy::Base)、Spree.stock_splitters ⚠、Spree.number_generators[:order] = 'My::Numbers'、Spree.promotions.rules/.actions ⚠、Spree.adjusters ⚠、Spree.tracking_carriers['my_courier'] = { name:, url: } ⚠。spree-fulfillment、spree-promotions、spree-order-totals を参照してください。
近日対応予定(ロードマップ。インターフェースが変更される可能性があります): ERP 在庫同期、PIM 価格フィード、外部ホスト型 DAM メディア。コアにはすでに Spree::PricingProvider::Base/Spree::InventoryProvider::Base と、Spree.pricing_providers/Spree.inventory_providers、およびストア設定 pricing_provider/inventory_provider(デフォルトは 'internal')が含まれていますが、ドキュメントではロードマップ扱いです。現在のソースを確認せずに、これらを使った本番用インテグレーションを構築しないでください。
⚠ 登録のタイミング
Core は独自の config.after_initialize 内で payment_methods、fulfillment_providers、integrations、stock_splitters、adjusters、promotions.actions、tracking_carriers および3つの認証レジストリを割り当てます。その前に追加したものはすべて、config/initializers/spree.rb の先頭や、起動時に after_initialize より先に実行される to_prepare に追加したものも含め、何も通知されずに消去されます。その他のプロバイダーレジストリは早い段階で初期化され、要素が追加されるため、どのタイミングでも問題ありません。統一ルールは、すべてのプロバイダーを after_initialize 内で登録することです。
# server/config/initializers/spree.rb
Rails.application.config.after_initialize do
Spree.integrations << 'MyApp::AcmeIntegration'
Spree.delivery_rate_providers << MyApp::AcmeRates
Spree.fulfillment_providers << MyApp::AcmeFulfillment
Spree.payment_methods << MyApp::AcmeGateway
end
Spree.search_provider = 'MyApp::SearchProvider::Typesense' # plain assignment, any time
gem 内では、エンジンで config.after_initialize を使用してください(spree-extensions を参照)。誤った場合の症状として、ダッシュボードの選択欄にプロバイダーが表示されない、または保存時に「must be registered」や包含検証のエラーが発生します。レジストリは検証時の許可リストも兼ねています(delivery_method.rate_provider、market.tax_provider、digital_asset.provider_type、integration.type はすべてレジストリに対して検証されます)。
認証情報:Spree::Integration
ストアごとの認証情報を ENV に保存してはいけません。マルチストアアプリやマーケットプレイスアプリでは、ストアごとに異なるアカウントを使用するためです。インテグレーションを作成してください。
module MyApp
class AcmeIntegration < Spree::Integration
preference :api_key, :password # :password = masked on read, guarded on write
preference :test_mode, :boolean, default: true
def self.integration_group = 'shipping' # gallery grouping
# Called when the merchant activates it; false blocks activation with the message.
def can_connect?
client.ping
true
rescue StandardError => e
self.connection_error_message = e.message
false
end
def client = @client ||= Acme::Client.new(api_key: preferred_api_key)
end
end
プロバイダーは def self.integration_class = 'MyApp::AcmeIntegration' でインテグレーションに紐づけます(配送レート、フルフィルメント、価格設定、在庫の各プロバイダーは Spree::IntegrationBackedProvider を含みます)。ストアごとの利用可否はこの設定から導出され、integration はストアの有効なレコードを返します。税金と支払いプロバイダーは、それぞれ独自に self.available_for_store?(store) をオーバーライドします。
コントラクト早見表
税金(spree-taxes)— estimate(owner, items = nil, tax_date:, tax_identifier:, exemptions:, context:) は、アイテムごとに置換方式で Spree::TaxLine レコードを書き込みます。リモート台帳がない限り、commit(order)、void(order)、refund(order, return_items, amount:, tax_date:) は何もしません。クラスレベルの display_name、available_for_store?、unsupported_capabilities を実装します。プロバイダーはステートレスで、引数なしで構築されます。
配送レート(spree-fulfillment)— estimates(package) は Spree::DeliveryRateProvider::Estimate.new(cost:, currency:, carrier:, service_level:, estimated_delivery_date:, metadata:) の配列を返します。単一の見積もりの場合は estimate(package) を使用します。nil/[] を返すと、配送方法は非表示になります。例外を発生させないでください。例外を捕捉し、Rails.error.report を呼び出して、[] を返してください。リクエストごとのキャッシュには Spree::Current.provider_cache[key] ||= を使用します。任意で self.service_catalog(integration) → ServiceCatalog.listing/none/unavailable を実装できます。book/release は存在しますが、Core からはまだ呼び出されません。
フルフィルメント — クラス述語は generates_labels?、digital?、pickup?。インスタンスメソッドは can_fulfill?、auto_fulfill?、requires_address?、serves_location?(delivery_method, stock_location)、purchase_label(owner)、refund_label(label)、create_fulfillment(fulfillment)(冪等)、cancel_fulfillment、tracking_url、documents です。ラベルを生成するプロバイダーは、フルフィルメントを出荷済みとしてマークする前にラベルを購入します。実装例:spree_easypost(SpreeEasyPost::DeliveryRateProvider、SpreeEasyPost::FulfillmentProvider、SpreeEasyPost::Integration)。
支払い(spree-payments)— Spree::PaymentMethod をサブクラス化し、一致する Spree::PaymentSession の STI サブクラス(および任意の Spree::PaymentSetupSession)で支払いセッションのメソッドを実装して、ウェブフックを処理します。実装例:SpreeStripe::Gateway。
検索 — search_and_filter(scope:, query:, filters:, sort:, page:, limit:)、filters(...)、index(product)、remove(product)、remove_by_id(prefixed_id)、index_batch(documents)、reindex(scope)、self.indexing_required?。ドキュメントの形式は Spree::Dependencies.search_product_presenter から取得します(spree_meilisearch gem は SpreeMeilisearch::ProductPresenter を登録します)。Meilisearch の場合:gem 'spree_meilisearch'、MEILISEARCH_URL/MEILISEARCH_API_KEY、Spree.search_provider = 'SpreeMeilisearch::SearchProvider' を設定し、次に spree task search:reindex を実行します。
支払い(spree-marketplace)— transfer!(seller_transfer)、pay!(seller_payout)(ID は reference に保存し、完了状態にはしないでください。Webhook と Spree.seller_payout_complete_workflow で確認します)、reverse!(seller_transfer)。オンボーディング用の onboarding_url、onboarded?、onboarding_state、onboarding_message。クラス用の display_name、reference_system、requires_payout_account?、available_for_store?。provider_key はオーバーライドしないでください。タイムアウト時は Spree::Core::AmbiguousGatewayError、確定した失敗時は Spree::Core::GatewayError を発生させてください。参考:SpreeStripe::PayoutProvider(Stripe Connect)。
デジタルアセット — deliver(digital_link, expires_in:) は Spree::DigitalDelivery.new(redirect_url:) または .new(inline_value:, content_type:) を返します。空の場合は拒否されたものとして扱い、お客様のダウンロード可能回数は消費しません。アセットごとの設定には setting :pool_name, :string(ダッシュボードのフォームとして表示)を使用します。生成される納品物では self.requires_attachment? は false です。
SSO/外部 ID(spree-auth-permissions)— OpenID Connect はコアに含まれています。
Rails.application.config.after_initialize do
Spree.admin_authentication_strategies.add(
:entra,
Spree::Authentication::Strategies::OidcStrategy.configure(
issuer: 'https://login.microsoftonline.com/<tenant>/v2.0',
client_id: ENV['ENTRA_CLIENT_ID'],
client_secret: ENV['ENTRA_CLIENT_SECRET'],
redirect_uri: 'https://shop.example.com/api/v3/admin/auth/callback/entra',
label: 'Microsoft Entra ID'
)
)
end
あらゆる OIDC 発行者(Okta、Google Workspace、Keycloak、Auth0)で動作します。パスワードログインを無効にするには .remove(:email) を使用します。OIDC 以外の JWT 発行者の場合は、BaseStrategy をサブクラス化します(authenticate、provider、success(user)、failure(msg)、find_or_create_user_from_oauth)。
可観測性(spree-deployment、spree-performance)— gem 'spree_opentelemetry' を追加し、OTEL_SERVICE_NAME と OTEL_EXPORTER_OTLP_ENDPOINT を設定します。OTEL_SDK_DISABLED=true で無効になります。すべてのワークフロー実行/ステップ/フック、イベントのディスパッチ、Webhook の配信、ゲートウェイの呼び出しについてスパンを記録します。SpreeOpenTelemetry.configure { |c| c.use/skip/with_sdk } で調整できます。エクスポーターとして Sentry を使用できます(OTEL_TRACES_EXPORTER=none)。
注意点
- レートプロバイダーとフルフィルメントプロバイダーは、チェックアウトを決して中断してはなりません。 これらの呼び出しはワークフロー内で実行されるため、ベンダーエラーを捕捉して、例外を発生させるのではなく、オプションを非表示にする、フォールバックするなどの方法で縮退させます。ただし、契約でゲートウェイエラーを発生させると定められている場合は除きます。
- 税プロバイダーはフェイルクローズにします。
estimateで完全なSpree::TaxLine行を計算できない場合は、例外を発生させます。再計算(または完了処理)が中断され、不足した税額のまま注文が確定することはありません。フォールバックするのは、フォールバック先(例:Spree::TaxProvider::Internal)が完全で監査可能な税行一式を書き込む場合に限ります。 - プロバイダーはステートレスです。 引数なしでインスタンス化します(配送レートプロバイダーには
delivery_methodが渡されます)。リクエスト固有の情報はすべてパラメーターとして渡されます。ストアごとのデータをクラスにメモ化しないでください。 - レジストリ内のクラス名は開発時のリロード後も維持されます。コアはリロード時に
delivery_rate_providers/fulfillment_providersを再解決します。文字列エントリー('My::Provider')を受け付けるレジストリでは、これが最もリロードに強い形式です。 - gem を削除すると、未登録のクラスを参照する行が残ります。 これらの行は残存します(バリデーションは変更時にのみ実行されます)。支払いプロバイダーがなくなったストアは組み込みプロバイダーにフォールバックしますが、そのプロバイダーを参照する配送方法やマーケットはクリーンアップしてください。
- プロバイダーからの受信 Webhook は、レコードのストア内で実行されます。
POST /api/v3/webhooks/{payments,payouts}/:payment_method_idと/webhooks/fulfillments/:integration_idは、プレフィックス付き ID のみで支払い方法/インテグレーションを検索し(API キーやストアヘッダーは不要)、そのストアをSpree::Current.storeに設定します。また、Spree::Payments::HandleWebhookJobも同様に処理します。そのレコード固有のシークレットに対する署名検証だけが認証手段です。これを決して省略せず、シークレットが設定されていない場合は値を返すのではなく例外を発生させてください。さらに、プロバイダーの有効期間ルール(署名付きタイムスタンプと許容範囲。例:Stripe のconstruct_eventにおける5分間のウィンドウ)も適用してください。コアの支払い処理は支払い単位で冪等ですが、独自に作成するハンドラーもプロバイダーの安定したキー(イベント ID またはオブジェクト ID)を使って冪等にし、再配信されても何も起きないようにしてください。 - 税プロバイダーと税率は別物です。 内部プロバイダーはゾーン/税率を使用し、外部エンジンはマーケットごとの計算を置き換えます。確定済みの注文では金額が固定されるため、プロバイダーの
commit/refundがリモートの台帳を処理します。
詳細を読むには
- 概要:
node_modules/@spree/docs/dist/developer/providers/overview.md - ガイド:
node_modules/@spree/docs/dist/developer/how-to/{custom-delivery-rate-provider,custom-payment-method,custom-search-provider,custom-digital-asset-provider,custom-api-authentication,custom-order-routing,custom-stock-splitter,custom-document-numbers}.md - プロバイダー:
node_modules/@spree/docs/dist/developer/providers/{fulfillment,payouts,sso,observability,erp,pim,dam}.md - インテグレーションカタログ:https://spreecommerce.org/docs/integrations (決済:Stripe、Adyen、PayPal、Razorpay、マーケットプレイス:Stripe Connect、配送:EasyPost、税金:Avalara、検索:Meilisearch、マーケティング/分析:Klaviyo、GA、GTM) — セットアップガイドは
node_modules/@spree/docs/dist/integrations/<category>/<name>.mdにあります - 関連スキル:
spree-extensions、spree-taxes、spree-fulfillment、spree-payments、spree-marketplace、spree-auth-permissions、spree-customization