@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,265 +1,70 @@
1
1
  ---
2
2
  title: Permissions
3
+ description: The permission catalog, staff roles, and how extensions register their own permissions.
3
4
  ---
4
5
 
5
- Spree uses [CanCanCan](https://github.com/CanCanCommunity/cancancan) for authorization. The permission system allows you to define granular access control for different user roles.
6
+ Staff roles and their permissions are managed as data — in the dashboard under **Settings → Roles**, through the Admin API (`/api/v3/admin/roles`), or in seeds. There is nothing to configure in Ruby for day-to-day permission management. This page covers what extension and host-application developers can plug into.
6
7
 
7
- ## Permission Sets (Recommended)
8
+ ## The permission catalog
8
9
 
9
- Permission Sets provide a clean, modular way to manage permissions. Each permission set is a reusable group of permissions that can be assigned to roles.
10
+ Every grantable capability is a flat key of the form `read_<resource>` or `write_<resource>` — the same vocabulary secret API keys use as scopes. `write_*` implies the matching `read_*`. Discover the catalog at runtime with `GET /api/v3/admin/permissions`; the role editor and the API-key scope picker are both rendered from it.
10
11
 
11
- ### How It Works
12
+ Keys are per resource, not per action. The money-adjacent areas (`payments`, `refunds`, `gift_cards`, `store_credits`) are separate resources from `orders`, so "view orders but don't refund" needs no special casing.
12
13
 
13
- 1. **Roles** - Determine which permission sets govern a user's access (e.g., `admin`, `customer_service`)
14
- 2. **Permission Sets** - Contain the logic defining what actions users can perform on resources
15
- 3. **Role Configuration** - Associates roles with their corresponding permission sets
16
-
17
- ### Configuring Roles
18
-
19
- In your `config/initializers/spree.rb`, configure which permission sets are assigned to each role:
20
-
21
- ```ruby
22
- Rails.application.config.after_initialize do
23
- # Default permissions for all users (guests and logged-in customers)
24
- Spree.permissions.assign(:default, [Spree::PermissionSets::DefaultCustomer])
25
-
26
- # Full admin access
27
- Spree.permissions.assign(:admin, [Spree::PermissionSets::SuperUser])
28
-
29
- # Custom role with specific permissions
30
- Spree.permissions.assign(:customer_service, [
31
- Spree::PermissionSets::DashboardDisplay,
32
- Spree::PermissionSets::OrderManagement,
33
- Spree::PermissionSets::UserDisplay
34
- ])
35
-
36
- # Merchandiser role for product management
37
- Spree.permissions.assign(:merchandiser, [
38
- Spree::PermissionSets::DashboardDisplay,
39
- Spree::PermissionSets::ProductManagement,
40
- Spree::PermissionSets::StockManagement
41
- ])
42
- end
43
- ```
44
-
45
- ### Built-in Permission Sets
46
-
47
- | Permission Set | Description |
48
- |---------------|-------------|
49
- | `SuperUser` | Full admin access with safety restrictions |
50
- | `DefaultCustomer` | Basic storefront permissions (browse, checkout, manage own account) |
51
- | `DashboardDisplay` | View admin dashboard |
52
- | `OrderDisplay` | Read-only access to orders |
53
- | `OrderManagement` | Full order management (view, edit, refund, etc.) |
54
- | `ProductDisplay` | Read-only access to products and catalog |
55
- | `ProductManagement` | Full catalog management (products, variants, taxonomies) |
56
- | `UserDisplay` | Read-only access to users |
57
- | `UserManagement` | Full user management |
58
- | `StockDisplay` | Read-only access to inventory |
59
- | `StockManagement` | Full inventory management |
60
- | `PromotionManagement` | Manage promotions and coupon codes |
61
- | `ConfigurationManagement` | Manage store settings, shipping, taxes, etc. |
62
- | `RoleManagement` | Manage roles (except the protected admin role) |
63
-
64
- ### Creating Custom Permission Sets
65
-
66
- Create a new permission set in `app/models/spree/permission_sets/`:
67
-
68
- ```ruby
69
- # app/models/spree/permission_sets/warehouse_management.rb
70
- module Spree
71
- module PermissionSets
72
- class WarehouseManagement < Base
73
- def activate!
74
- can :manage, Spree::StockItem
75
- can :manage, Spree::StockLocation
76
- can :manage, Spree::StockMovement
77
- can :manage, Spree::Shipment
78
- can [:read, :admin], Spree::Order
79
- end
80
- end
81
- end
82
- end
83
- ```
84
-
85
- Then assign it to a role:
86
-
87
- ```ruby
88
- Spree.permissions.assign(:warehouse_staff, [
89
- Spree::PermissionSets::DashboardDisplay,
90
- Spree::PermissionSets::WarehouseManagement
91
- ])
92
- ```
93
-
94
- ### Permission Set API
95
-
96
- Within a permission set, you have access to:
97
-
98
- - `can(action, subject, conditions = {})` - Grant permission
99
- - `cannot(action, subject, conditions = {})` - Deny permission
100
- - `can?(action, subject)` - Check if permission exists
101
- - `user` - The current user
102
- - `store` - The current store (for multi-store setups)
103
-
104
- ```ruby
105
- module Spree
106
- module PermissionSets
107
- class OrderManagementForOwnOrders < Base
108
- def activate!
109
- # Users can only manage orders they created
110
- can :manage, Spree::Order, created_by_id: user.id
111
-
112
- # But cannot cancel any order
113
- cannot :cancel, Spree::Order
114
-
115
- # Unless it's cancellable
116
- can :cancel, Spree::Order, &:allow_cancel?
117
- end
118
- end
119
- end
120
- end
121
- ```
122
-
123
- ### Managing Permission Configuration
14
+ Roles as code is plain ActiveRecord:
124
15
 
125
16
  ```ruby
126
- # Assign permission sets to a role
127
- Spree.permissions.assign(:customer_service, [
128
- Spree::PermissionSets::OrderDisplay,
129
- Spree::PermissionSets::UserManagement
130
- ])
131
-
132
- # Add more permission sets to an existing role
133
- Spree.permissions.assign(:customer_service, [
134
- Spree::PermissionSets::StockDisplay
135
- ])
136
-
137
- # Clear all permission sets from a role
138
- Spree.permissions.clear(:customer_service)
139
-
140
- # Check what permission sets a role has
141
- Spree.permissions.permission_sets_for(:customer_service)
142
- # => [Spree::PermissionSets::OrderDisplay, ...]
143
-
144
- # Check if a role is configured
145
- Spree.permissions.role_configured?(:customer_service)
146
- # => true
17
+ # db/seeds.rb
18
+ Spree::Role.find_or_create_by!(name: 'support')
19
+ .update!(permissions: %w[read_orders read_customers], description: 'Read-only support')
147
20
  ```
148
21
 
149
- ## Users and Roles
22
+ A role with `mutable: false` (set from seeds or the console) renders read-only in the dashboard — for roles the application does not want store staff to edit. The `admin` role is always protected.
150
23
 
151
- Spree comes with an `admin` role by default. You can create more roles in the Admin Panel or via Rails console:
24
+ ## Registering extension permissions
152
25
 
153
- ```ruby
154
- Spree::Role.find_or_create_by(name: 'customer_service')
155
- Spree::Role.find_or_create_by(name: 'merchandiser')
156
- Spree::Role.find_or_create_by(name: 'warehouse_staff')
157
- ```
158
-
159
- Assign a role to a user:
26
+ Register your models as a catalog resource once; the keys appear in the role editor and become mintable API-key scopes with no further wiring:
160
27
 
161
28
  ```ruby
162
- user = Spree.user_class.find_by(email: 'john@example.com')
163
- role = Spree::Role.find_by(name: 'customer_service')
164
- user.spree_roles << role
29
+ # in your engine's initializer
30
+ Spree.permissions.register_resource(:reviews, group: :catalog, subjects: -> {
31
+ [SpreeReviews::Review]
32
+ })
165
33
  ```
166
34
 
167
- ### Default Role Behavior
35
+ - `group` places the row in the permission pickers (`:orders`, `:catalog`, `:marketing`, `:customers`, `:settings`, `:access`, `:analytics` — or your own).
36
+ - `subjects` is a lambda returning the CanCanCan subjects the keys grant; it resolves lazily, so load order does not matter.
37
+ - Pass `write: false` for read-only resources.
168
38
 
169
- - Users with **no roles assigned** automatically get the `:default` role permissions
170
- - No `RoleUser` records are created for regular customers
171
- - Only users with special permissions need explicit role assignments
39
+ Localize the labels in your engine's locale file under `spree.permissions_catalog.resources.<name>` (`label` and `description`), and declare the same resource on your admin controllers with `scoped_resource :reviews`.
172
40
 
173
- ## Legacy Approach: Custom Ability Classes
41
+ ## Beyond the catalog
174
42
 
175
- > **NOTE:** The permission sets approach above is recommended for new projects. The legacy approach below is supported for backward compatibility.
43
+ The catalog is deliberately flat: it answers "may this role touch this kind of record", and that is the whole grant vocabulary. Two rules that do *not* belong in it:
176
44
 
177
- ### Adding Custom Permissions via Decorator
178
-
179
- Create a new ability class in `app/models/customer_service_ability.rb`:
180
-
181
- ```ruby
182
- class CustomerServiceAbility
183
- include CanCan::Ability
184
-
185
- def initialize(user)
186
- if user.respond_to?(:has_spree_role?) && user.has_spree_role?('customer_service')
187
- can :manage, Spree::Order
188
- end
189
- end
190
- end
191
- ```
192
-
193
- Register it via a decorator in `app/models/spree/ability_decorator.rb`:
194
-
195
- ```ruby
196
- module Spree
197
- module AbilityDecorator
198
- def abilities_to_register
199
- [CustomerServiceAbility]
200
- end
201
- end
202
-
203
- Ability.prepend(AbilityDecorator)
204
- end
205
- ```
206
-
207
- ### Replacing the Ability Class
208
-
209
- You can replace the entire ability class via [Dependencies](dependencies.md):
45
+ - **Record-state rules** ("a completed order cannot be deleted") live on models and workflows, so they bind every caller — including secret API keys, which never consult CanCanCan.
46
+ - **Row-level restrictions** (a support agent limited to one market) are not expressible as keys. Replace the ability class outright:
210
47
 
211
48
  ```ruby
212
49
  # config/initializers/spree.rb
213
- Spree::Dependencies.ability_class = 'CustomAbility'
50
+ Spree::Dependencies.ability_class = 'MyApp::Ability'
214
51
  ```
215
52
 
216
53
  ```ruby
217
- # app/models/custom_ability.rb
218
- class CustomAbility < Spree::Ability
54
+ # app/models/my_app/ability.rb
55
+ class MyApp::Ability < Spree::Ability
219
56
  def initialize(user, options = {})
220
- alias_cancan_delete_action
221
-
222
- @user = user || Spree.user_class.new
223
- @store = options[:store] || Spree::Current.store
224
-
225
- if @user.respond_to?(:has_spree_role?) && @user.has_spree_role?('admin')
226
- apply_admin_permissions(@user, options)
227
- elsif @user.respond_to?(:has_spree_role?) && @user.has_spree_role?(:customer_service)
228
- apply_customer_service_permissions(@user)
229
- else
230
- apply_user_permissions(@user, options)
231
- end
57
+ super
58
+ return unless user.respond_to?(:market_id) && user.market_id
232
59
 
233
- protect_admin_role
234
- end
235
-
236
- protected
237
-
238
- def apply_customer_service_permissions(user)
239
- can :manage, Spree::Order
240
- can [:read, :admin], Spree.user_class
60
+ cannot :manage, Spree::Order
61
+ can [:read, :admin], Spree::Order, market_id: user.market_id
241
62
  end
242
63
  end
243
64
  ```
244
65
 
245
- ## CanCanCan Reference
246
-
247
- Spree's permission system is built on CanCanCan. Key concepts:
66
+ ## How enforcement works
248
67
 
249
- - `can :action, Subject` - Grant permission
250
- - `can :manage, Subject` - Grant all actions (create, read, update, destroy)
251
- - `cannot :action, Subject` - Explicitly deny permission
252
- - `can :action, Subject, conditions` - Conditional permission
253
-
254
- ```ruby
255
- # Examples
256
- can :read, Spree::Product # Can read any product
257
- can :manage, Spree::Order, user_id: user.id # Can manage own orders
258
- can :update, Spree::Order do |order| # Block conditions
259
- order.user == user && !order.completed?
260
- end
261
- cannot :destroy, Spree::Order # Cannot destroy any order
262
- can :destroy, Spree::Order, &:can_be_deleted? # Unless it's deletable
263
- ```
68
+ Every Admin API controller declares its resource (`scoped_resource :orders`). Each request checks the principal's keys — a staff member's role permissions on the current store, or a secret key's scopes — against `read_<resource>` or `write_<resource>` for the action. A missing key produces a 403 naming it in `details.required_permission`. Behind that gate, keys compile to CanCanCan rules for record-level concerns, and `GET /api/v3/admin/me` returns both the rule dump the dashboard mirrors and `permission_keys`, the flat key list.
264
69
 
265
- See the [CanCanCan documentation](https://github.com/CanCanCommunity/cancancan) for more details.
70
+ Storefront customers are not part of this system — customer authorization is ownership, enforced by the Store API's scoped lookups, with nothing to configure. The one swappable piece is `Spree::Storefront::AccessPolicy` (via `Spree::Dependencies.storefront_access_policy_class`): a generic `readable?` / `writable?` / `scope` protocol that defaults to "the caller owns the record", with carts and orders adding guest-token access. Replace it only when access must widen beyond the owner, such as company accounts sharing purchases or wishlists.