spree-data-model
Navigate Spree's canonical data model — the Catalog (Product/Variant/OptionType/Taxon/Property/Metafield), Pricing (Price/PriceList), Order graph (Order/LineItem/Adjustment/Shipment/Payment/PaymentSession/Refund/Reimbursement), Inventory (StockLocation/StockItem/StockMovement), Shipping (ShippingMethod/Zone), Promotions, Identity (User/Role/Address/StoreCredit/GiftCard), Taxes, and the v5.4+ Markets + Store multi-region model. Use when designing a feature that touches Spree models, writing decorators, or building admin/storefront UIs.
Best use case
spree-data-model is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Navigate Spree's canonical data model — the Catalog (Product/Variant/OptionType/Taxon/Property/Metafield), Pricing (Price/PriceList), Order graph (Order/LineItem/Adjustment/Shipment/Payment/PaymentSession/Refund/Reimbursement), Inventory (StockLocation/StockItem/StockMovement), Shipping (ShippingMethod/Zone), Promotions, Identity (User/Role/Address/StoreCredit/GiftCard), Taxes, and the v5.4+ Markets + Store multi-region model. Use when designing a feature that touches Spree models, writing decorators, or building admin/storefront UIs.
Teams using spree-data-model should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/spree-data-model/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How spree-data-model Compares
| Feature / Agent | spree-data-model | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Navigate Spree's canonical data model — the Catalog (Product/Variant/OptionType/Taxon/Property/Metafield), Pricing (Price/PriceList), Order graph (Order/LineItem/Adjustment/Shipment/Payment/PaymentSession/Refund/Reimbursement), Inventory (StockLocation/StockItem/StockMovement), Shipping (ShippingMethod/Zone), Promotions, Identity (User/Role/Address/StoreCredit/GiftCard), Taxes, and the v5.4+ Markets + Store multi-region model. Use when designing a feature that touches Spree models, writing decorators, or building admin/storefront UIs.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Spree Data Model
## Before writing code
**Fetch live docs**:
1. Fetch https://spreecommerce.org/docs/developer/core-concepts/architecture for the current model graph.
2. Fetch https://spreecommerce.org/docs/developer/core-concepts/orders for the Order/LineItem/Payment/Shipment graph and state.
3. Fetch https://spreecommerce.org/docs/developer/core-concepts/metafields for Metafield (v5+).
4. Fetch https://spreecommerce.org/docs/use-case/multi-store/model for `Store` and `Market`.
5. Inspect the live `spree` gem source on GitHub for current column names — Spree adds columns between minors.
## Conceptual Architecture
### Catalog
| Model | Purpose | Notes |
|-------|---------|-------|
| `Product` | Top-level catalog item | Has a master `Variant`; many `Image`s, `Property`s, `Taxon`s |
| `Variant` | Concrete SKU | Has `OptionValue`s, `Price`s per currency, `StockItem`s |
| `OptionType` / `OptionValue` | Variant axes (size, color) | An OptionType has many OptionValues |
| `Property` / `ProductProperty` | Free-form spec table | "Material: cotton", "Weight: 250g" |
| `Taxonomy` / `Taxon` | Category trees | `Taxon` is the nested-set node |
| `Image` / `Asset` | Media | Uses ActiveStorage |
| `Metafield` | Custom data on any model (v5+) | Like Shopify metafields |
### Pricing
| Model | Purpose |
|-------|---------|
| `Price` | One row per (Variant × Currency) |
| `PriceList` (v5.3+) | Override prices for a customer group, store, or country |
| `Calculator` | Polymorphic calculator class for shipping/promotion/tax math |
### Order Graph
```
Order
├── LineItem (one per Variant)
│ └── Adjustment[]
├── Shipment (one per StockLocation involved)
│ ├── InventoryUnit
│ ├── ShippingRate
│ └── selected ShippingRate
├── Payment[]
│ ├── PaymentSession (v5.4+, provider-agnostic envelope)
│ └── source (CreditCard, StoreCredit, etc.)
├── Adjustment[] (order-level)
├── Address (bill_address, ship_address)
└── User (optional — guest orders allowed)
```
Plus return-flow models: `ReturnAuthorization` → `CustomerReturn` → `Reimbursement` → `Refund`.
### Inventory
- `StockLocation` — physical / logical warehouse
- `StockItem` — count of a Variant in a StockLocation
- `StockMovement` — append-only ledger of stock changes
- `StockTransfer` — moves stock between locations
### Shipping
- `ShippingMethod` — names a way to ship (UPS Ground, Express)
- `ShippingRate` — computed cost option on a Shipment
- `ShippingCategory` — categorize products by shipping needs
- `Zone` / `ZoneMember` — countries/states a method ships to
### Promotions
`Promotion` + `PromotionRule` + `PromotionAction` + `CouponCode` resulting in `Adjustment`s.
### Identity
| Model | Notes |
|-------|-------|
| `User` | Spree's customer / admin model (Devise-backed in v5+) |
| `Role` | Permissions — `admin`, `customer`, custom |
| `Address` | Bill / ship address, optionally tied to a user |
| `StoreCredit` | Balance on a user, usable as payment |
| `GiftCard` | Tradeable balance, redeemable as payment method |
| `CustomerGroup` | Segments for pricing / promotions |
| `Invitation` | Invite to an account |
| `ApiKey` | Per-user API key for v3 admin API |
### Taxes
- `TaxCategory` — assignable to products (e.g., "Clothing", "Books")
- `TaxRate` — percentage by Zone + TaxCategory
### Multi-Store / Region
| Model | Purpose |
|-------|---------|
| `Store` | One install → many stores, each with own domain/theme/policies |
| `Market` (v5.4+) | Bundles currency + locale + payment methods + shipping per region |
| `CmsPage` | Content pages per store |
| `Theme` | Storefront theme per store |
**Shared across stores**: products, inventory, customers, shipping methods, payment gateways, Markets, admin roles.
**Per-store**: orders, shipments, payments, refunds, store credits, gift cards, themes, blogs, pages, integrations.
### Spree::Metafield (v5+)
A flexible custom-data system attached to any model. Replaces ad-hoc decorators for "I just need one extra field." Use this before adding a column.
### prefixed IDs (v5.4+)
API v3 exposes prefixed IDs (`prod_…`, `ord_…`, `var_…`, `usr_…`, `pay_…`) — these are stable string identifiers separate from the database `id`. Models gain a `prefixed_id` method.
### Polymorphic Adjustments
`Adjustment` belongs to an `adjustable` (Order, LineItem, Shipment) and a `source` (PromotionAction, TaxRate, manual). When sums change, run `order.update_totals` or use `Spree::OrderUpdater` (or its swappable replacement via `Spree::Dependencies`).
## Implementation Guidance
### Querying Safely in Multi-Store
```ruby
# WRONG — leaks across stores
Spree::Order.complete
# RIGHT — always scope by current_store in customer-facing code
current_store.orders.complete
# Admin-side: admin sees all stores by default, but check role scoping
Spree::Order.where(store_id: current_store.id)
```
### Reading Variants With Their Pricing
```ruby
variant = Spree::Variant.find(...)
variant.price_in('USD').amount # raw decimal
variant.price_in('USD').display_price # formatted "$19.99"
variant.amount_in('USD') # alias for price_in(currency).amount
```
For v5.3+ PriceList overrides:
```ruby
price = Spree::Pricing::PriceFinder.new(variant: variant, store: store, user: user, currency: 'USD').call
```
(Verify the live API — pricing service objects are routinely renamed.)
### Order Totals
Don't recompute totals manually. Use the order updater service:
```ruby
Spree::OrderUpdater.new(order).update
# or via Dependencies
Spree::Dependencies.order_updater.call(order)
```
### Adding Custom Data Without a Decorator
Prefer Metafield over adding columns:
```ruby
product.metafields.create!(
namespace: 'my_app',
key: 'launch_date',
value: '2026-06-01',
value_type: 'string'
)
product.metafield('my_app', 'launch_date')
```
Verify the exact API in the live metafields doc.
### Designing for the Order Graph
- **One Order has many Shipments** when items come from different `StockLocation`s.
- **One Shipment has many InventoryUnit**s — one per unit sold.
- **Payments are not necessarily 1:1 with orders** — split tender (store credit + card) creates multiple Payments.
- **PaymentSessions (v5.4+) wrap a Payment** for provider-agnostic checkout flows.
### Common Pitfalls
- **Modifying Order totals directly** — always recompute via the updater service.
- **Adding columns when a Metafield would do** — Metafields don't need migrations and survive upgrades.
- **Ignoring `Store#default`** — most APIs default to it, but explicit scoping is safer.
- **Adjustments on canceled lines** — when a line item is removed mid-order, adjustments tied to it need explicit cleanup. Use service objects, not raw `delete`.
- **Assuming `Variant.is_master` ordering** — the master variant is always present; option-variant ordering follows position columns.
Always cross-check column names and relationships against the live source — the data model evolves between minor releases.Related Skills
woo-data-stores
Work with WooCommerce CRUD data stores — WC_Product, WC_Order, WC_Customer, WC_Coupon data objects, custom data stores, HPOS migration, and getters/setters. Use when creating or modifying WooCommerce data objects or implementing custom data stores.
spree-upgrades
Upgrade a Spree application — version-to-version migration paths (v4 → v5 is a major rewrite; v5.x → v5.y are simpler), Gemfile pinning strategy, decorator brittleness across versions, deprecated gems to remove (`spree_auth_devise`, `deface`, `spree_backend`), API v2 → v3 migration via `spree_legacy_api_v2`, admin Bootstrap → Tailwind transition, the upgrade guide workflow, and rollback strategy. Use when planning a Spree upgrade or auditing technical debt blocking one.
spree-typescript-sdk
Build storefronts and integrations using `@spree/sdk` — the official TypeScript SDK for Spree's API v3 (v5.4+). Covers installation, the resource-builder pattern (`spree.products.list`, `spree.checkout.create`, etc.), Zod schema validation, server-only auth (httpOnly JWTs, never exposing API keys), error handling, typing customizations, and pinning SDK versions to backend Spree releases. Use when integrating Spree into a Next.js / Node.js / TypeScript project.
spree-testing
Test Spree applications and extensions with RSpec — `spree_dev_tools` gem (v5.2+) for factories and helpers, FactoryBot patterns (prefer `build` over `create`), Capybara feature specs, controller/request specs, testing decorators and subscribers, dummy app for extension testing, system specs for the Hotwire admin, and CI patterns. Use when writing Spree tests, setting up CI, or refactoring slow specs.
spree-shipping-fulfillment
Build and customize Spree's shipping and fulfillment — ShippingMethod, ShippingCategory, Zone/ZoneMember, ShippingRate, the Stock::Estimator service, StockLocation/StockItem/StockMovement, multi-shipment orders, ShippingCalculator classes (FlatRate, FlatPercentItemTotal, PerItem, FlexiRate), shipment state machine, returns (ReturnAuthorization → CustomerReturn → Reimbursement → Refund), and integrating carrier APIs (UPS, FedEx, ShipStation). Use when configuring shipping rules, building fulfillment integrations, or debugging shipping-rate calculations.
spree-setup
Bootstrap a new Spree project — `create-spree-app` CLI (v5.2+), `spree-starter` Rails backend, the Next.js storefront repo, `bin/rails g spree:install`, sample data, Docker Compose, and the PostgreSQL + Redis + Sidekiq prerequisites. Use when starting a new Spree project from scratch or onboarding an existing repo.
spree-security
Secure a Spree deployment — Rails credentials and env-var hygiene, Devise auth (Spree v5 ships it in-core; `spree_auth_devise` is archived), CanCanCan authorization rules, Doorkeeper OAuth2 scopes, Storefront publishable key vs admin API key, webhook HMAC verification, OWASP Top 10 for Rails (mass assignment, CSRF, SQL injection via Ransack, XSS, IDOR through prefixed IDs), PCI scope (Spree never touches raw cards thanks to gateway tokenization), and multi-store data isolation. Use when auditing a Spree app, hardening a deploy, or addressing a security incident.
spree-promotions
Build and customize Spree's promotions engine — Promotion + PromotionRule + PromotionAction + CouponCode + Adjustment, the bundled rules (FirstOrder/ItemTotal/Product/Taxon/User/OneUsePerUser/Country/CustomerGroup/etc.), bundled actions (CreateAdjustment/CreateItemAdjustments/FreeShipping/CreateLineItems), Calculator classes, coupon batches with CSV export, the v5.1+ advanced rule-based engine, and authoring custom rules/actions/calculators. Use when modeling promotions, building discount UIs, or extending the promotions engine.
spree-performance
Profile and optimize a Spree application — N+1 queries with bullet/scout, database indexing strategy for Spree's polymorphic associations, Rails fragment + Russian doll caching, ActiveStorage variant pre-generation, Sidekiq queue tuning, MeiliSearch vs Postgres FTS tradeoffs, Puma worker/thread sizing, CDN strategy for catalog pages, asset precompile time, and load testing. Use when Spree is slow, the database is hot, or you're preparing for a traffic spike (Black Friday, launch).
spree-payments
Integrate payment gateways with Spree — PaymentMethod model, the v5.4+ PaymentSession provider-agnostic checkout flow, Stripe via `spree_stripe` (Apple/Google Pay, Link, Connect for marketplaces), Adyen via `spree_adyen`, PayPal via `spree_paypal_checkout`, StoreCredit / GiftCard as payment methods, refunds, payment state machine, and authoring a custom gateway. Use when wiring a payment integration, handling webhooks from a gateway, or debugging payment-state issues.
spree-multi-store
Configure Spree for multi-store and multi-region commerce — one Rails install running many `Store` records, the v5.4+ `Market` model (currency + locale + payment methods + shipping per region), what's shared vs per-store (products+inventory+customers shared; orders+payments+themes per-store), the Marketplace module (Enterprise — vendors/commission/payouts via Stripe Connect), and the Multi-tenant SaaS model. Use when planning a multi-brand or multi-region Spree deployment.
spree-legacy-api-v2
Work with Spree's legacy v2 APIs — JSON:API-style Storefront API at `/api/v2/storefront/*` and Platform API at `/api/v2/platform/*`, Doorkeeper OAuth2 (password grant for storefront, client_credentials + admin scope for platform), the `spree_legacy_api_v2` gem (required in v5+ for backward compatibility), and migration patterns to API v3. Use when maintaining a v2 client during a migration window, integrating an older partner system, or deciding when to cut over to v3.