@spree/docs 0.1.177 → 0.1.178

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/developer/cli/quickstart.md +1 -1
  2. package/dist/developer/contributing/creating-an-extension.md +2 -2
  3. package/dist/developer/core-concepts/addresses.md +3 -3
  4. package/dist/developer/core-concepts/architecture.md +4 -4
  5. package/dist/developer/core-concepts/calculators.md +2 -2
  6. package/dist/developer/core-concepts/carts.md +207 -0
  7. package/dist/developer/core-concepts/channels.md +3 -3
  8. package/dist/developer/core-concepts/customers.md +1 -1
  9. package/dist/developer/core-concepts/events.md +1 -1
  10. package/dist/developer/core-concepts/fulfillments.md +278 -0
  11. package/dist/developer/core-concepts/imports-exports.md +6 -18
  12. package/dist/developer/core-concepts/inventory.md +3 -3
  13. package/dist/developer/core-concepts/media.md +1 -1
  14. package/dist/developer/core-concepts/metafields.md +1 -1
  15. package/dist/developer/core-concepts/orders.md +92 -339
  16. package/dist/developer/core-concepts/payments.md +1 -1
  17. package/dist/developer/core-concepts/promotions.md +68 -195
  18. package/dist/developer/core-concepts/returns-exchanges-claims.md +173 -0
  19. package/dist/developer/core-concepts/store-credits-gift-cards.md +16 -18
  20. package/dist/developer/core-concepts/stores.md +1 -1
  21. package/dist/developer/core-concepts/taxes-discounts-fees.md +199 -0
  22. package/dist/developer/core-concepts/taxes.md +3 -3
  23. package/dist/developer/create-spree-app/quickstart.md +1 -1
  24. package/dist/developer/customization/api.md +36 -11
  25. package/dist/developer/customization/configuration.md +207 -37
  26. package/dist/developer/customization/decorators.md +8 -8
  27. package/dist/developer/customization/permissions.md +34 -229
  28. package/dist/developer/customization/quickstart.md +159 -108
  29. package/dist/developer/customization/validations.md +1 -1
  30. package/dist/developer/dashboard/overview.md +1 -1
  31. package/dist/developer/how-to/build-a-b2b-store.md +21 -0
  32. package/dist/developer/how-to/build-a-marketplace.md +25 -0
  33. package/dist/developer/how-to/custom-api-authentication.md +1 -1
  34. package/dist/developer/how-to/custom-delivery-rate-provider.md +242 -0
  35. package/dist/developer/how-to/custom-document-numbers.md +154 -0
  36. package/dist/developer/how-to/custom-order-routing.md +1 -1
  37. package/dist/developer/how-to/custom-payment-method.md +1 -1
  38. package/dist/developer/how-to/custom-promotion.md +76 -115
  39. package/dist/developer/how-to/custom-report.md +2 -2
  40. package/dist/developer/how-to/custom-stock-splitter.md +5 -5
  41. package/dist/developer/how-to/sell-digital-products.md +20 -0
  42. package/dist/developer/multi-tenant/quickstart.md +1 -1
  43. package/dist/developer/providers/dam.md +14 -0
  44. package/dist/developer/providers/erp.md +31 -0
  45. package/dist/developer/providers/fulfillment.md +25 -0
  46. package/dist/developer/{deployment/telemetry.md → providers/observability.md} +1 -1
  47. package/dist/developer/providers/overview.md +44 -0
  48. package/dist/developer/providers/pim.md +25 -0
  49. package/dist/developer/providers/sso.md +20 -0
  50. package/dist/developer/sdk/admin/extending.md +1 -1
  51. package/dist/developer/sdk/admin/quickstart.md +1 -1
  52. package/dist/developer/sdk/admin/resources.md +1 -1
  53. package/dist/developer/sdk/extending.md +1 -1
  54. package/dist/developer/tutorial/admin-api.md +13 -0
  55. package/dist/developer/tutorial/dashboard-plugin.md +14 -0
  56. package/dist/developer/tutorial/events.md +7 -161
  57. package/dist/developer/tutorial/introduction.md +15 -35
  58. package/dist/developer/tutorial/model.md +7 -98
  59. package/dist/developer/tutorial/store-api.md +13 -0
  60. package/dist/developer/tutorial/storefront.md +12 -0
  61. package/dist/developer/tutorial/testing.md +7 -711
  62. package/dist/developer/upgrades/5.6-to-6.0.md +2 -2
  63. package/package.json +1 -1
  64. package/dist/developer/admin/admin.md +0 -214
  65. package/dist/developer/admin/authentication.md +0 -59
  66. package/dist/developer/admin/components.md +0 -711
  67. package/dist/developer/admin/custom-css.md +0 -256
  68. package/dist/developer/admin/custom-javascript.md +0 -116
  69. package/dist/developer/admin/extending-ui.md +0 -1839
  70. package/dist/developer/admin/form-builder.md +0 -444
  71. package/dist/developer/admin/helper-methods.md +0 -531
  72. package/dist/developer/admin/navigation.md +0 -805
  73. package/dist/developer/admin/tables.md +0 -490
  74. package/dist/developer/advanced/adding_spree_to_rails_app.md +0 -92
  75. package/dist/developer/core-concepts/adjustments.md +0 -113
  76. package/dist/developer/core-concepts/reports.md +0 -208
  77. package/dist/developer/core-concepts/shipments.md +0 -307
  78. package/dist/developer/core-concepts/users.md +0 -303
  79. package/dist/developer/customization/authentication.md +0 -100
  80. package/dist/developer/customization/checkout.md +0 -202
  81. package/dist/developer/customization/emails.md +0 -18
  82. package/dist/developer/customization/routes.md +0 -24
  83. package/dist/developer/multi-vendor/installation.md +0 -61
  84. package/dist/developer/multi-vendor/quickstart.md +0 -17
  85. package/dist/developer/tutorial/admin.md +0 -206
  86. package/dist/developer/tutorial/api.md +0 -606
  87. package/dist/developer/tutorial/extending-models.md +0 -393
  88. package/dist/developer/tutorial/sdk.md +0 -170
  89. package/dist/developer/upgrades/2.0-to-2.1.md +0 -46
  90. package/dist/developer/upgrades/2.1-to-2.2.md +0 -59
  91. package/dist/developer/upgrades/2.2-to-2.3.md +0 -44
  92. package/dist/developer/upgrades/2.3-to-2.4.md +0 -42
  93. package/dist/developer/upgrades/3.0-to-3.1.md +0 -47
  94. package/dist/developer/upgrades/3.1-to-3.2.md +0 -34
  95. package/dist/developer/upgrades/3.2-to-3.3.md +0 -70
  96. package/dist/developer/upgrades/3.3-to-3.4.md +0 -36
  97. package/dist/developer/upgrades/3.4-to-3.5.md +0 -44
  98. package/dist/developer/upgrades/3.5-to-3.6.md +0 -40
  99. package/dist/developer/upgrades/3.6-to-3.7.md +0 -62
  100. package/dist/developer/upgrades/3.7-to-4.0.md +0 -152
  101. package/dist/developer/upgrades/4.0-to-4.1.md +0 -92
  102. package/dist/developer/upgrades/4.1-to-4.2.md +0 -109
  103. package/dist/developer/upgrades/4.10-to-5.0.md +0 -131
  104. package/dist/developer/upgrades/4.2-to-4.3.md +0 -100
  105. package/dist/developer/upgrades/4.3-to-4.4.md +0 -125
  106. package/dist/developer/upgrades/4.4-to-4.5.md +0 -94
  107. package/dist/developer/upgrades/4.5-to-4.6.md +0 -119
  108. package/dist/developer/upgrades/4.6-to-4.7.md +0 -39
  109. package/dist/developer/upgrades/4.8-to-4.9.md +0 -24
  110. package/dist/developer/upgrades/4.9-to-4.10.md +0 -24
  111. package/dist/developer/upgrades/4.x-to-4.8.md +0 -52
  112. package/dist/developer/upgrades/5.0-to-5.1.md +0 -28
  113. package/dist/developer/upgrades/5.1-to-5.2.md +0 -131
  114. package/dist/developer/upgrades/5.2-to-5.3.md +0 -338
  115. package/dist/developer/upgrades/5.3-to-5.4.md +0 -277
  116. package/dist/developer/upgrades/5.4-to-5.5.md +0 -301
  117. package/dist/developer/upgrades/5.5-to-5.6.md +0 -207
@@ -1,215 +1,242 @@
1
1
  ---
2
2
  title: Quickstart
3
3
  og:title: Spree Customization Quickstart
4
- description: Recommended ways to customize Spree store settings, configuration, events, webhooks, dependencies, admin extensions, and decorators as a last resort.
4
+ description: Recommended ways to customize the Spree 6 backend configuration, workflow hooks, events, checkout steps, providers, dependencies, and decorators as a last resort.
5
5
  ---
6
6
 
7
- Spree is a flexible platform allowing you to customize every part of it to suit your business needs. This guide presents customization options **in order of recommendation** - start from the top and only move down if simpler options don't meet your needs.
7
+ Spree is designed to be customized without forking it. This guide presents the options **in order of recommendation** start at the top and only move down when a simpler option doesn't fit.
8
8
 
9
- ## Quick Reference
9
+ > **NOTE:** Business logic is extended through **workflow hooks** rather than by replacing classes wholesale, and the admin is a React application with its own extension points rather than a Rails engine extended through partials.
10
+
11
+ ## Quick reference
10
12
 
11
13
  | What you want to do | Recommended approach |
12
- |---------------------|---------------------|
13
- | Change store settings (currency, zones, languages) | [Store Settings](#store-settings) |
14
+ |---|---|
15
+ | Change store settings (currency, markets, languages) | [Store settings](#store-settings) |
14
16
  | Tweak Spree behavior globally | [Configuration](#configuration) |
15
- | React to model changes (sync, notifications) | [Events & Subscribers](#events-and-subscribers) |
17
+ | Run your own logic inside checkout, cancellation, refunds | [Workflow hooks](#workflow-hooks) |
18
+ | Block an operation from happening | [Workflow hooks](#workflow-hooks) — `validate` |
19
+ | React after something happened (sync, notifications) | [Events & subscribers](#events-and-subscribers) |
20
+ | Add or reorder checkout steps | [Checkout registry](#checkout-steps) |
21
+ | Swap tax, delivery rate, search or fulfillment behavior | [Providers](#providers) |
22
+ | Add searchable/filterable fields | [Search & filtering](#search-and-filtering) |
23
+ | Use your own user model or identity provider | [Authentication](#authentication) |
16
24
  | Notify external services | [Webhooks](#webhooks) |
17
- | Swap core services (cart, checkout, etc.) | [Dependencies](#dependencies) |
18
- | Add admin menu items | [Admin Navigation](#admin-extensions) |
19
- | Add sections to admin forms | [Admin Partials](#admin-extensions) |
20
- | Add searchable/filterable fields | [Ransack Configuration](#search-and-filtering) |
25
+ | Replace a whole workflow or service | [Dependencies](#dependencies) |
21
26
  | Add associations/validations to models | [Decorators](#decorators) (last resort) |
22
27
 
23
- **Best for:** Changing currency, shipping zones, languages, and other business settings.
24
-
25
- There's a lot of Store settings you can change in the admin panel without touching the code.
28
+ > **INFO:** **Customizing the admin?** This page covers the backend — models, API and business logic. The Spree 6 admin is a separate React application with its own extension points. See [Dashboard Customization](../dashboard/customization/quickstart.md).
26
29
 
27
- Go to **Admin > Settings**
28
-
29
- <img src="/images/spree_admin_store_settings.png" alt="Spree Admin Store Settings" />
30
+ **Best for:** currency, markets, delivery zones, languages, and other business settings.
30
31
 
32
+ Most day-to-day configuration is data, not code. Change it in the dashboard under **Settings** — no deploy required.
31
33
  <details>
32
34
  <summary>Configuration</summary>
33
35
 
34
- **Best for:** Tweaking Spree's behavior globally without modifying source code.
35
-
36
- Global application configuration allows you to customize various aspects of Spree:
36
+ **Best for:** tweaking Spree's behavior globally.
37
37
 
38
38
  ```ruby config/initializers/spree.rb
39
39
  Spree.config do |config|
40
- config.allow_guest_checkout = false
41
- config.products_per_page = 20
40
+ config.minimum_password_length = 10
42
41
  end
43
42
  ```
44
43
 
45
- Please see [Configuration](configuration.md) section for more information.
44
+ See [Configuration](configuration.md).
46
45
 
47
46
  </details>
48
47
 
49
-
50
48
  <details>
51
- <summary>Events and Subscribers</summary>
49
+ <summary>Workflow hooks</summary>
52
50
 
53
- **Best for:** Reacting to model changes, syncing with external services, sending notifications, audit logging.
51
+ **Best for:** running your own logic *inside* a core flow — checkout completion, order cancellation, refunds, fulfillment creation.
54
52
 
55
- > **INFO:** Events are the **recommended way** to add behavior when something happens in Spree, replacing the need for decorator callbacks.
53
+ > **INFO:** Hooks are the **headline extension point in Spree 6**. Before them, customizing a flow meant replacing the entire class and keeping your copy in sync with core forever.
56
54
 
57
- Spree's event system lets you subscribe to events like `order.completed`, `product.updated`, `payment.paid`, etc.:
55
+ Register a handler against a hook key `<workflow key>.<hook name>`:
58
56
 
59
- ```ruby app/subscribers/order_completed_subscriber.rb
60
- class OrderCompletedSubscriber < Spree::Subscriber
61
- subscribes_to 'order.completed'
57
+ ```ruby config/initializers/spree.rb
58
+ Spree.hooks.register('carts.complete.validate') do |flow|
59
+ flow.reject!('We cannot deliver to this region') unless deliverable?(flow.cart)
60
+ end
61
+ ```
62
62
 
63
- def handle(event)
64
- order = Spree::Order.find_by_prefix_id(event.payload['id'])
65
- return unless order
63
+ Pass a class instead of a block for anything longer than a line:
66
64
 
67
- # Sync to external service, send notification, etc.
68
- ExternalService.notify_order_placed(order)
69
- end
70
- end
65
+ ```ruby
66
+ Spree.hooks.register('carts.complete.after_finalize', 'MyApp::PushOrderToERP')
71
67
  ```
72
68
 
73
- **Key benefits:**
74
- - Loose coupling - your code doesn't depend on Spree internals
75
- - Async by default - keeps requests fast
76
- - Easier testing and upgrades
69
+ There are three families of hook:
77
70
 
78
- Please see [Events](../core-concepts/events.md) section for more information.
71
+ | Family | Naming | What it can do |
72
+ |---|---|---|
73
+ | **validate** | `validate` | Veto the operation with `flow.reject!(message)` |
74
+ | **lifecycle** | past tense — `after_finalize`, `after_cancel` | React to what happened; read-only |
75
+ | **context** | `set_*_context`, `get_provider_data` | Return a hash that gets merged into the flow's data |
79
76
 
80
- </details>
77
+ Hook keys are validated after boot, so a typo fails startup rather than silently never running.
81
78
 
79
+ See [Services & Workflows](workflows.md) for the full list of flows and their hooks.
80
+
81
+ </details>
82
82
 
83
83
  <details>
84
- <summary>Webhooks</summary>
84
+ <summary>Events and subscribers</summary>
85
+
86
+ **Best for:** reacting *after* something happened — syncing to external systems, notifications, audit logging.
85
87
 
86
- **Best for:** Notifying external services (ERPs, CRMs, fulfillment systems) when events occur.
88
+ ```ruby app/subscribers/spree/order_placed_subscriber.rb
89
+ module Spree
90
+ class OrderPlacedSubscriber < Spree::Subscriber
91
+ subscribes_to 'order.placed'
87
92
 
88
- Webhooks send HTTP POST requests to external URLs when Spree events happen:
93
+ def handle(event)
94
+ order = Spree::Order.find_by_prefix_id(event.payload['id'])
95
+ return unless order
89
96
 
90
- - Order completed → Notify fulfillment system
91
- - Product updated → Sync with PIM
92
- - Customer created → Add to CRM
97
+ MyApp::ERP.push(order)
98
+ end
99
+ end
100
+ end
101
+ ```
93
102
 
94
- Configure webhooks in **Admin > Developers > Webhooks** or via the API.
103
+ **Events or hooks?** A hook runs *inside* the flow and can influence or block it. An event fires *after* the fact and cannot. Reach for an event unless you need to change the outcome.
95
104
 
96
- Please see [Webhooks](../core-concepts/webhooks.md) section for more information.
105
+ See [Events](../core-concepts/events.md).
97
106
 
98
107
  </details>
99
108
 
100
-
101
109
  <details>
102
- <summary>Dependencies</summary>
110
+ <summary>Checkout steps</summary>
103
111
 
104
- **Best for:** Swapping core services, serializers, and abilities with your own implementations.
112
+ **Best for:** adding, removing or reordering checkout steps.
105
113
 
106
- Spree allows you to replace core classes without modifying them:
114
+ Spree 6 has no checkout state machine. A cart reports what it still needs, and you can add to that list:
107
115
 
108
116
  ```ruby config/initializers/spree.rb
109
- Spree::Dependencies.cart_add_item_service = "MyCartAddItemService"
110
- Spree::Dependencies.cart_remove_item_service = "MyCartRemoveItemService"
117
+ Spree::Checkout::Registry.register_step(
118
+ name: :loyalty,
119
+ before: :payment,
120
+ satisfied: ->(cart) { cart.metadata['loyalty_number'].present? },
121
+ requirements: ->(cart) {
122
+ [{ step: 'loyalty', field: 'loyalty_number', message: 'Loyalty number is required' }]
123
+ }
124
+ )
111
125
  ```
112
126
 
113
- This is cleaner than decorating services because you provide a complete replacement rather than patching behavior.
127
+ Or attach a requirement to an existing step:
114
128
 
115
- Please see [Dependencies](dependencies) section for more information.
129
+ ```ruby
130
+ Spree::Checkout::Registry.add_requirement(
131
+ step: :payment,
132
+ field: :po_number,
133
+ message: 'PO number is required',
134
+ satisfied: ->(cart) { cart.metadata['po_number'].present? }
135
+ )
136
+ ```
116
137
 
117
- </details>
138
+ Registered requirements appear in the Cart API's `requirements` array, so your storefront renders them without duplicating any rules.
139
+
140
+ See [Carts](../core-concepts/carts.md#checkout-requirements).
118
141
 
142
+ </details>
119
143
 
120
144
  <details>
121
- <summary>Admin Extensions</summary>
145
+ <summary>Providers</summary>
122
146
 
123
- **Best for:** Adding menu items, form sections, dashboard widgets, and other UI elements to the admin panel.
147
+ **Best for:** swapping a whole area of behavior for your own implementation.
124
148
 
125
- Spree provides declarative APIs for extending the admin without decorators or view overrides:
149
+ Spree 6 exposes pluggable providers for the domains that vary most between businesses:
126
150
 
127
- **Navigation API** - Add menu items:
128
- ```ruby config/initializers/spree.rb
129
- Rails.application.config.after_initialize do
130
- Spree.admin.navigation.sidebar.add :brands,
131
- label: :brands,
132
- url: :admin_brands_path,
133
- icon: 'award',
134
- position: 35
135
- end
136
- ```
151
+ | Provider | Controls |
152
+ |---|---|
153
+ | Tax provider | How tax is calculated, per market |
154
+ | Delivery rate provider | How delivery is priced — flat rates or live carrier rates |
155
+ | Fulfillment provider | How a delivery type behaves — shipping, digital, pickup |
156
+ | Search provider | Database or Meilisearch |
157
+ | Payout provider | Where marketplace payouts go |
137
158
 
138
- **Partials API** - Add sections to forms:
139
- ```ruby config/initializers/spree.rb
140
- Spree.admin.partials.product_form << 'spree/admin/products/erp_section'
141
- ```
159
+ Each is a class you register and select on the relevant record, so no conditional code lands in core.
142
160
 
143
- Please see:
144
- - [Admin Navigation](../admin/navigation.md) - For adding menu items
145
- - [Admin Partials](../admin/extending-ui.md) - For extending UI
146
- - [Admin Tables](../admin/tables.md) - For customizing list views
161
+ See [Fulfillments](../core-concepts/fulfillments.md#delivery-types) and [Taxes](../core-concepts/taxes.md).
147
162
 
148
163
  </details>
149
164
 
150
-
151
165
  <details>
152
- <summary>Search and Filtering</summary>
166
+ <summary>Search and filtering</summary>
153
167
 
154
- **Best for:** Making custom fields searchable/sortable in the admin and API.
155
-
156
- Instead of decorating models to add `ransackable_attributes`, use the Ransack configuration API:
168
+ **Best for:** making custom fields searchable and sortable in the dashboard and API.
157
169
 
158
170
  ```ruby config/initializers/spree.rb
159
- Spree.ransack.add_attribute :product, :erp_id
160
- Spree.ransack.add_association :product, :brand
171
+ Spree.ransack.add_attribute(Spree::Product, :erp_id)
172
+ Spree.ransack.add_association(Spree::Product, :brand)
173
+ Spree.ransack.add_scope(Spree::Product, :featured)
161
174
  ```
162
175
 
163
- Please see [Search & Filtering](../core-concepts/search-filtering.md#extending-ransackable-configuration) section for more information.
176
+ See [Search & Filtering](../core-concepts/search-filtering.md).
164
177
 
165
178
  </details>
166
179
 
167
-
168
180
  <details>
169
181
  <summary>Authentication</summary>
170
182
 
171
- **Best for:** Using your own user model or authentication system.
183
+ **Best for:** using your own user model or identity provider.
172
184
 
173
- Spree allows you to use your own authentication system instead of the default Devise-based one.
185
+ Spree 6 owns its authentication stack rather than depending on Devise, and separates the customer identity from the staff identity. Point Spree at your own classes with `Spree.user_class` and `Spree.admin_user_class`.
174
186
 
175
- You can find more information in the [Authentication](authentication) section.
187
+ See [Authentication](../providers/sso.md).
176
188
 
177
189
  </details>
178
190
 
179
-
180
191
  <details>
181
- <summary>Checkout flow</summary>
192
+ <summary>Webhooks</summary>
182
193
 
183
- **Best for:** Customizing checkout steps and flow.
194
+ **Best for:** notifying external services ERPs, CRMs, fulfillment systems — without writing Ruby.
184
195
 
185
- With Spree you can change the checkout flow to fit your business needs - add steps, remove steps, or change the order.
196
+ Configure them in the dashboard under **Settings Webhooks**, or through the Admin API.
186
197
 
187
- Please see [Checkout flow customization section](checkout) for more information.
198
+ See [Webhooks](../core-concepts/webhooks.md).
188
199
 
189
200
  </details>
190
201
 
202
+ <details>
203
+ <summary>Dependencies</summary>
204
+
205
+ **Best for:** replacing an entire workflow or service with your own class.
206
+
207
+ ```ruby config/initializers/spree.rb
208
+ Spree::Dependencies.cart_add_item_workflow = 'MyApp::Carts::AddItem'
209
+ ```
210
+
211
+ > **WARNING:** Seam names end in `_workflow` in Spree 6. The old `*_service` names still resolve for one release with a warning, but **writes to them are ignored** — a class written against the old service contract isn't interchangeable with a workflow. Update the key when you upgrade.
212
+
213
+ Prefer a hook when you only need to add behavior. Replace the class only when you need to change what the flow fundamentally does.
214
+
215
+ See [Dependencies](dependencies.md).
216
+
217
+ </details>
191
218
 
192
219
  <details>
193
220
  <summary>Decorators</summary>
194
221
 
195
- **Best for:** Adding associations, validations, scopes, and methods to Spree models. Use as a last resort.
222
+ **Best for:** adding associations, validations and scopes to Spree models. Use as a last resort.
196
223
 
197
- > **WARNING:** Decorators should be used **only when no other option works**. They tightly couple your code to Spree internals and can break during upgrades.
224
+ > **WARNING:** Decorators couple your code to Spree internals and are the most common cause of painful upgrades.
198
225
  >
199
- > **Do NOT use decorators for:**
200
- > - After-save callbacksUse [Events](../core-concepts/events.md) instead
201
- > - External service sync Use [Webhooks](../core-concepts/webhooks.md) instead
202
- > - Custom service logicUse [Dependencies](dependencies) instead
203
- > - Admin UI changesUse [Admin Extensions](#admin-extensions) instead
226
+ > **Do not use decorators for:**
227
+ > - Logic inside a core flow use [workflow hooks](#workflow-hooks)
228
+ > - After-save callbacksuse [events](#events-and-subscribers)
229
+ > - External service syncuse [webhooks](#webhooks)
230
+ > - Replacing a serviceuse [dependencies](#dependencies)
231
+ > - Admin UI changes → use [dashboard customization](../dashboard/customization/quickstart.md)
204
232
 
205
- Decorators are still appropriate for structural changes:
233
+ They remain appropriate for structural additions:
206
234
 
207
235
  ```ruby app/models/spree/product_decorator.rb
208
236
  module Spree
209
237
  module ProductDecorator
210
238
  def self.prepended(base)
211
239
  base.belongs_to :brand, class_name: 'MyApp::Brand', optional: true
212
- base.validates :external_id, presence: true
213
240
  base.scope :featured, -> { where(featured: true) }
214
241
  end
215
242
 
@@ -222,6 +249,30 @@ Spree is a flexible platform allowing you to customize every part of it to suit
222
249
  end
223
250
  ```
224
251
 
225
- Please see [Decorators](decorators) section for more information.
252
+ See [Decorators](decorators.md).
226
253
 
227
254
  </details>
255
+
256
+
257
+ ## Choosing between hooks, events and dependencies
258
+
259
+ These three overlap, and picking the wrong one is the most common source of upgrade pain:
260
+
261
+ **Step 1: Do you need to block or change the outcome?**
262
+
263
+ Use a **workflow hook**. Only `validate` hooks can stop an operation, and only they run early enough to do so safely — before money moves.
264
+
265
+ **Step 2: Do you just need to know it happened?**
266
+
267
+ Use an **event subscriber**. It's decoupled, testable, and survives upgrades untouched.
268
+
269
+ **Step 3: Do you need the flow to do something fundamentally different?**
270
+
271
+ Use **dependencies** to replace the class — and accept that you now own keeping it current.
272
+
273
+
274
+ ## Related
275
+
276
+ - [Services & Workflows](workflows.md) — the workflow model and every hook
277
+ - [Carts](../core-concepts/carts.md) — checkout requirements and completion
278
+ - [Dashboard Customization](../dashboard/customization/quickstart.md) — extending the admin
@@ -162,7 +162,7 @@ Spree::Checkout::Registry.add_requirement(
162
162
  )
163
163
  ```
164
164
 
165
- See the [Spree 6 quickstart](/v6/developer/customization/quickstart) for the full registry API.
165
+ See the [Spree 6 quickstart](quickstart.md) for the full registry API.
166
166
 
167
167
  ## Custom field values
168
168
 
@@ -102,4 +102,4 @@ When in doubt, customize in-app first. The migration path to a plugin is mechani
102
102
  - [Plugin scaffolding](plugins/scaffolding.md)
103
103
  - [Slots catalog](slots-catalog.md) — every named slot the dashboard exposes
104
104
  - [`@spree/dashboard-core` README](https://github.com/spree/spree/tree/main/packages/dashboard-core) — full extension API reference
105
- - [Classic Admin extension model](../admin/extending-ui.md) — for Spree 5.x
105
+ - [Classic Admin extension model](customization/quickstart.md) — for Spree 5.x
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Build a B2B Store
3
+ description: Wholesale pricing, customer groups, companies with tax exemption, and gated storefront access — assembling Spree's B2B capabilities into a working wholesale channel.
4
+ ---
5
+
6
+ Spree's B2B capabilities are core features composed together rather than a separate product: price lists give buyers negotiated and volume pricing, customer groups segment who sees what, companies carry the legal and tax identity of the buyer, and channel access controls gate the storefront to signed-in buyers.
7
+
8
+ ## What you will build
9
+
10
+ - **Wholesale pricing** — price lists scoped to customer groups, volume tiers, and regional pricing per market.
11
+ - **Companies** — buyer organizations with locations and contacts, tax identifiers validated per jurisdiction, and tax exemption certificates applied at checkout.
12
+ - **Gated access** — a storefront channel restricted to approved buyers, with guest checkout disabled.
13
+ - **B2B checkout** — orders carrying the buying company and location, priced and taxed accordingly.
14
+
15
+ ## Outline
16
+
17
+ 1. Model your buyer segments as customer groups
18
+ 2. Build wholesale price lists and volume tiers
19
+ 3. Register companies, locations and tax exemptions
20
+ 4. Gate a sales channel for wholesale buyers
21
+ 5. Take a wholesale order end to end
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Build a Multi-Vendor Marketplace
3
+ description: Marketplace capabilities are part of Spree 6 core — sellers, order splitting, commissions and payouts, without a separate extension.
4
+ ---
5
+
6
+ > **NOTE:** Marketplace features are a headline capability of the Spree 6.0 release and are documented here as they land. This guide covers the open-source core.
7
+
8
+ Spree 6 brings multi-vendor marketplace support into the open-source core: sellers as first-class records, orders split per seller at completion, a commission engine, and a payout ledger with pluggable payout providers.
9
+
10
+ ## What you will build
11
+
12
+ - **Sellers** — onboard sellers with an operator-configured requirements checklist, review submissions, and approve them for selling.
13
+ - **Order splitting** — a customer checks out once; completion produces per-seller orders grouped under one purchase.
14
+ - **Commissions** — the platform's cut computed per seller, with EU commission taxation handled.
15
+ - **Payouts** — a transfer and payout ledger, with Stripe Connect payouts (Express onboarding, on-fulfillment transfers) shipping in the open-source monorepo.
16
+ - **Seller operations** — sellers work through their own dedicated API surface, scoped so a seller only ever sees their own trade.
17
+
18
+ ## Outline
19
+
20
+ 1. Enable marketplace capabilities and configure the store
21
+ 2. Define seller onboarding requirements
22
+ 3. Invite and approve sellers
23
+ 4. Assign catalog to sellers and take a multi-seller order through checkout
24
+ 5. Configure commissions
25
+ 6. Connect Stripe for payouts
@@ -378,4 +378,4 @@ end
378
378
  - `Spree::Api::V3::Store::AuthController` — `spree/api/app/controllers/spree/api/v3/store/auth_controller.rb`
379
379
  - `Spree::Api::V3::Admin::AuthController` — `spree/api/app/controllers/spree/api/v3/admin/auth_controller.rb`
380
380
  - `Spree::Api::V3::JwtAuthentication` — `spree/api/app/controllers/concerns/spree/api/v3/jwt_authentication.rb`
381
- - See also: [Staff & Roles](../core-concepts/staff-roles.md) for the admin login flow, [Customers](../core-concepts/customers.md) for storefront auth, and [Authentication](../customization/authentication.md) for `Spree.user_class` integration.
381
+ - See also: [Staff & Roles](../core-concepts/staff-roles.md) for the admin login flow, [Customers](../core-concepts/customers.md) for storefront auth, and [Authentication](../providers/sso.md) for `Spree.user_class` integration.