@spree/docs 0.1.0
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.
- package/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- package/package.json +27 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Multi-Store Setup
|
|
3
|
+
sidebarTitle: Setup
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Root domain
|
|
7
|
+
|
|
8
|
+
You need to set a wildcard `root_domain` on the store to enable multi-store setup
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
Spree.root_domain = ENV.fetch('SPREE_ROOT_DOMAIN', 'lvh.me')
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This will be used to generate the store URLs, eg. `store1.lvh.me`, `store2.lvh.me`, etc.
|
|
15
|
+
|
|
16
|
+
`store1` part is the unique store `code` identifier, which is auto-generated based on the store name. You can change it in the admin panel in **Settings -> Domains**.
|
|
17
|
+
|
|
18
|
+
> **INFO:** If you later change the `root_domain`, you will need to run:
|
|
19
|
+
>
|
|
20
|
+
> ```ruby
|
|
21
|
+
Spree::Store.all.each(&:save)
|
|
22
|
+
```
|
|
23
|
+
>
|
|
24
|
+
> to update the store URLs.
|
|
25
|
+
|
|
26
|
+
## Creating new stores
|
|
27
|
+
|
|
28
|
+
After you restart your application, you will see a new option in the admin panel, under new item menu:
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
You can also create a new store from the rails console:
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
Spree::Store.create!(name: 'New Store')
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This will create a new store with the given name, code and URL.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spree Multi Tenant Configuration
|
|
3
|
+
sidebarTitle: Configuration
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Multi-tenant applications include additional configuration options. All configuration should be placed in `config/initializers/spree_multi_tenant.rb` file.
|
|
7
|
+
|
|
8
|
+
### Root domain
|
|
9
|
+
|
|
10
|
+
To make multi-tenant, you need a root/wildcard domain, eg. `*.example.com`. Tenant stores are usually accessed via subdomains, eg. `store1.example.com`, `store2.example.com`, etc.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
Spree.root_domain = 'example.com'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Still your tenants will be able to add custom domains, eg. `myflowerstore.com` via the Spree admin panel. Tenant subdomains are used only for admin panel access.
|
|
17
|
+
|
|
18
|
+
### App subdomain
|
|
19
|
+
|
|
20
|
+
Application subdomains is used to access the application, eg. `app.example.com`. By default for existing tenants it will redirect them to their tenant subdomain, eg. `store1.example.com`. If you want, you can also use this as a tenant signup/store setup page, this is available under `app.example.com/tenants/new`.
|
|
21
|
+
|
|
22
|
+
You can customize the app subdomain by:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
SpreeMultiTenant::Config[:app_subdomain] = 'admin'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This will change `app.example.com` to `admin.example.com`.
|
|
29
|
+
|
|
30
|
+
### Emails
|
|
31
|
+
|
|
32
|
+
Usually email providers, such as SendGrid, require emails to be send from a valid / verified email address, which will be your root domain.
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
SpreeMultiTenant::Config[:mail_from_name] = ENV.fetch('MAIL_FROM_NAME', 'Your SaaS Name')
|
|
36
|
+
SpreeMultiTenant::Config[:mail_from_address] = ENV.fetch('MAIL_FROM_ADDRESS', "support@#{Spree.root_domain}")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> **INFO:** `mail_from_name` is only used in admin emails, such as admin staff invitations, exports, etc. For consumer facing emails, this will be your tenant store name, eg. 'My Flower Store` (or whatever they set in the store settings).
|
|
40
|
+
>
|
|
41
|
+
> Also, customer facing emails will use the tenant email address in `Reply-To` header.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Multi-Tenant Core Concepts
|
|
3
|
+
sidebarTitle: Core Concepts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Tenant class
|
|
7
|
+
|
|
8
|
+
The center of the multi-tenant architecture is the `Spree::Tenant` class. This is the highest level class in the multi-tenant system.
|
|
9
|
+
|
|
10
|
+
Every tenanted model includes a `tenant_id` column. This is used to identify which tenant a record belongs to. It's row-level multi-tenancy.
|
|
11
|
+
|
|
12
|
+
After creating a new tenant it will automatically create store and run [Spree seeds](https://github.com/spree/spree/tree/main/core/app/services/spree/seeds) to populate data such as countries, zones, tax rates, etc.
|
|
13
|
+
|
|
14
|
+
## Tenanted models
|
|
15
|
+
|
|
16
|
+
All models that are tenanted inherit from `SpreeMultiTenant::Base` class. `spree_multi_tenant` automatically sets the `Spree.base_class` to `SpreeMultiTenant::Base` so all standard Spree models will be tenanted (with an exclusion of `Spree::CustomDomain`).
|
|
17
|
+
|
|
18
|
+
When creating a new model that you want to be tenanted remember to inherit from `SpreeMultiTenant::Base` and not from `Spree::Base` and add `tenant_id` column to the table, eg.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bin/rails g model Spree::NewModel tenant:references name:string --parent SpreeMultiTenant::Base
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> **INFO:** You don't need to add `belongs_to :tenant` to the model, it's handled by gem.
|
|
25
|
+
|
|
26
|
+
## Tenant selector
|
|
27
|
+
|
|
28
|
+
By default the current tenant is selected based on the subdomain or `Spree::CustomDomain`. The selector works in tandem with the default [Spree::Stores::FindCurrent](https://github.com/spree/spree/blob/main/core/app/finders/spree/stores/find_current.rb) finder.
|
|
29
|
+
|
|
30
|
+
First it finds the current store, and later sets the current tenant based on the store's `tenant_id`.
|
|
31
|
+
|
|
32
|
+
Tenant record is accessible in views and controllers as `current_tenant`. In models you can access it via `SpreeMultiTenant.current_tenant`.
|
|
33
|
+
|
|
34
|
+
> **INFO:** One tenant can have multiple stores. Calling `Spree::Store.default` will return the default store for the first tenant.
|
|
35
|
+
|
|
36
|
+
## Code isolation
|
|
37
|
+
|
|
38
|
+
All code run when `SpreeMultiTenant.current_tenant` is set will be executed in the context of the tenant, what that means:
|
|
39
|
+
|
|
40
|
+
* all finder queries will always attach `tenant_id = <current_tenant.id>` to the query
|
|
41
|
+
* all writes will automatically set `tenant_id` to the current tenant ID (you don't need to do it manually)
|
|
42
|
+
|
|
43
|
+
> **WARNING:** [insert_all](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-insert_all) / [upsert_all](https://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-upsert_all) methods will require you to manually set `tenant_id` to the desired value.
|
|
44
|
+
|
|
45
|
+
## Background jobs
|
|
46
|
+
|
|
47
|
+
Background jobs enqueued when `SpreeMultiTenant.current_tenant` is set will be executed in the context of the tenant.
|
|
48
|
+
|
|
49
|
+
## Enforce tenant context
|
|
50
|
+
|
|
51
|
+
Sometimes when you're not sure if the tenant context is active you can use `SpreeMultiTenant.with_tenant` to enforce it, eg.
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
SpreeMultiTenant.with_tenant(tenant) do
|
|
55
|
+
# all operations here will be executed in the context of the tenant
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Excluding tenant context
|
|
60
|
+
|
|
61
|
+
Sometimes you want to run a piece of code outside of the tenant context, for that you can use `SpreeMultiTenant.without_tenant`
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
SpreeMultiTenant.without_tenant do
|
|
65
|
+
# all operations here will be executed outside of the tenant context
|
|
66
|
+
end
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Command line
|
|
70
|
+
|
|
71
|
+
When using `bin/rails console` or `bin/rails runner` you can set the tenant context by:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
SpreeMultiTenant.current_tenant = Spree::Store.find_by(code: 'my_store').tenant
|
|
75
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spree Multi Tenant Installation
|
|
3
|
+
sidebarTitle: Installation
|
|
4
|
+
description: Learn how to setup a multi-tenant eCommerce (SaaS) with Spree
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
> **WARNING:** This installation instructions assume you have a clean Spree Starter installation and you've purchased the [Spree Enterprise Edition license](https://spreecommerce.org/pricing).
|
|
8
|
+
>
|
|
9
|
+
> For migrating existing application from single-tenant to multi-tenant, please contact us at [support@spreecommerce.org](mailto:support@spreecommerce.org).
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
* You need to be on Spree 5.1+, we recommend using [spree_starter](https://github.com/spree/spree_starter) as a base for your application
|
|
14
|
+
* You need to have 2 environment variables set:
|
|
15
|
+
* `KEYGEN_ACCOUNT_ID`
|
|
16
|
+
* `KEYGEN_LICENSE_KEY`
|
|
17
|
+
* We support both PostgreSQL and MySQL databases
|
|
18
|
+
|
|
19
|
+
> **INFO:** Environment variables will be provided to you after purchasing the [Spree Enterprise Edition license](https://spreecommerce.org/pricing).
|
|
20
|
+
|
|
21
|
+
> **WARNING:** You will need to add these environment variables to your CI/CD pipeline and production environments.
|
|
22
|
+
|
|
23
|
+
## Customer User Class
|
|
24
|
+
|
|
25
|
+
Please follow [Authentication](/docs/developer/customization/authentication) documentation to create a new user class.
|
|
26
|
+
|
|
27
|
+
Now we will need to make slight adjustments to the generated user class so it can work in a multi-tenant environment.
|
|
28
|
+
|
|
29
|
+
If you're using Devise, you will need to remove `:validatable` module. This module is responsible for validating the user's email uniqueness. We need to change it to validate it in the scope of the tenant.
|
|
30
|
+
|
|
31
|
+
Spree Multi-Tenant gem injects `SpreeMultiTenant::CustomerUserConcern` that handles that instead.
|
|
32
|
+
|
|
33
|
+
## Admin User Class
|
|
34
|
+
|
|
35
|
+
For our multi-tenant setup we will need a separate Admin user class. Our standard User class will be only used for customer accounts which will be isolated by tenant.
|
|
36
|
+
Admin user classes will be shared across tenants allowing them to manage multiple tenants from a single admin panel.
|
|
37
|
+
|
|
38
|
+
Let's create a new model with Devise (unless you already have one):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
rails g devise Spree::AdminUser
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Replace the generated Devise code with the following:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
class Spree::AdminUser < Spree::Base
|
|
48
|
+
# Include default devise modules. Others available are:
|
|
49
|
+
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
|
50
|
+
devise :database_authenticatable, :registerable,
|
|
51
|
+
:recoverable, :rememberable, :validatable
|
|
52
|
+
|
|
53
|
+
# Spree modules
|
|
54
|
+
include Spree::UserMethods
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If you already have a custom Admin user class, you can add the following code to it:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
# Spree modules
|
|
62
|
+
include Spree::UserMethods
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This will make sure that the Admin user class works well with Spree ecosystem.
|
|
66
|
+
|
|
67
|
+
Register new model in `config/initializers/spree.rb`:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
Spree.admin_user_class = "Spree::AdminUser"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Installing gems
|
|
74
|
+
|
|
75
|
+
1. Add the following code to your `Gemfile`:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
source "https://license:#{ENV['KEYGEN_LICENSE_KEY']}@rubygems.pkg.keygen.sh/#{ENV['KEYGEN_ACCOUNT_ID']}" do
|
|
79
|
+
gem 'spree_enterprise'
|
|
80
|
+
gem 'spree_multi_tenant'
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
2. Install gems:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
bundle install
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. Run generators:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
bundle exec rails g spree_enterprise:install && bundle exec rails g spree_multi_tenant:install
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
> **INFO:** This will copy and run migrations for `spree_enterprise` and `spree_multi_tenant` gems.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Building a Multi-Tenant Spree Application
|
|
3
|
+
sidebarTitle: Quickstart
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Spree out of the box is a single-tenant application. You can have multiple stores on the same instance of Spree, but they share the same products, admin user accounts and other resources.
|
|
7
|
+
Multi-Store Spree setup is recommended for running multiple brands or multiple language versions of the same brand on the same instance.
|
|
8
|
+
|
|
9
|
+
If you want to have a true multi-tenant application, you will need to purchase [Enterprise Edition license](https://spreecommerce.org/pricing) which includes `spree_multi_tenant` gem providing full multi-tenant support.
|
|
10
|
+
|
|
11
|
+
## Multi-Store vs Multi-Tenant
|
|
12
|
+
|
|
13
|
+
To sum it up:
|
|
14
|
+
|
|
15
|
+
* Multi-Store setup is recommended for running multiple brands or multiple language versions of the same store
|
|
16
|
+
* Multi-Tenant allows you to create a SaaS application with multiple tenants, each of them with their own Spree instance
|
|
17
|
+
|
|
18
|
+
## Setup SaaS application
|
|
19
|
+
|
|
20
|
+
[Follow the installation instructions](/developer/multi-tenant/installation) to setup a multi-tenant Spree application.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spree Multi Vendor Installation
|
|
3
|
+
sidebarTitle: Installation
|
|
4
|
+
description: Learn how to setup a multi-vendor marketplace with Spree
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
> **WARNING:** This installation instructions assume you have purchased the [Spree Enterprise Edition license](https://spreecommerce.org/pricing).
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
* You need to be on Spree 5.1+, we recommend using [spree_starter](https://github.com/spree/spree_starter) as a base for your application
|
|
12
|
+
* You need to have 2 environment variables set:
|
|
13
|
+
* `KEYGEN_ACCOUNT_ID`
|
|
14
|
+
* `KEYGEN_LICENSE_KEY`
|
|
15
|
+
* We support both PostgreSQL and MySQL databases
|
|
16
|
+
* Redis/Valkey for background jobs
|
|
17
|
+
|
|
18
|
+
> **INFO:** Environment variables will be provided to you after purchasing the [Spree Enterprise Edition license](https://spreecommerce.org/pricing).
|
|
19
|
+
|
|
20
|
+
> **WARNING:** You will need to add these environment variables to your CI/CD pipeline and production environments.
|
|
21
|
+
|
|
22
|
+
## Installing gems
|
|
23
|
+
|
|
24
|
+
1. Add the following code to your `Gemfile`:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
source "https://license:#{ENV['KEYGEN_LICENSE_KEY']}@rubygems.pkg.keygen.sh/#{ENV['KEYGEN_ACCOUNT_ID']}" do
|
|
28
|
+
gem 'spree_enterprise'
|
|
29
|
+
gem 'spree_multi_vendor'
|
|
30
|
+
end
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. Install gems:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
bundle install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
3. Run generators:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bundle exec rails g spree_enterprise:install && bundle exec rails g spree_multi_vendor:install
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
> **INFO:** This will copy and run migrations for `spree_enterprise` and `spree_multi_vendor` gems.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Building a Multi-Vendor Marketplace with Spree
|
|
3
|
+
sidebarTitle: Quickstart
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
If you want to have a true multi-vendor marketplace, you will need to purchase [Enterprise Edition license](https://spreecommerce.org/pricing) which includes `spree_multi_vendor` gem providing full multi-vendor support.
|
|
7
|
+
|
|
8
|
+
## What is included in `spree_multi_vendor`
|
|
9
|
+
|
|
10
|
+
1. **Ability to invite and manage vendors**, their products and orders
|
|
11
|
+
2. Full fledged **vendor dashboard** where vendors can self-serve orders, products, manage their team, etc.
|
|
12
|
+
3. White-label **Shopify Sales Channel application** allowing vendors to connect their Shopify stores, import products, shipping rates and receive orders to fulfill them like a regular order in their Shopify store.
|
|
13
|
+
4. White-label **WooCommerce application** allowing vendors to connect their WooCommerce stores, import products, shipping rates and receive orders to fulfill them like a regular order in their WooCommerce store
|
|
14
|
+
5. **Stripe Connect** integration allowing vendors to receive payments directly to their Stripe accounts, split payments between marketplace and vendors, automated payouts and more
|
|
15
|
+
6. **Multi-party checkout** allowing customers to checkout with multiple vendors, split payments between them and receive separate invoices for each vendor
|
|
16
|
+
7. **Flexible permission system** to tailor the marketplace to your needs (eg. disable/enable vendor panel features)
|
|
17
|
+
8. **Vendor API** endpoints to allow vendors to manage their products, orders, etc.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Admin API
|
|
3
|
+
description: Manage your store programmatically with the Spree Admin SDK
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **INFO:** The Admin API SDK is coming soon. The `client.admin` namespace is ready and will provide full access to administrative endpoints for managing products, orders, customers, and store settings.
|
|
7
|
+
|
|
8
|
+
## Preview
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
import { createClient } from '@spree/sdk';
|
|
12
|
+
|
|
13
|
+
const client = createClient({
|
|
14
|
+
baseUrl: 'https://api.mystore.com',
|
|
15
|
+
secretKey: 'spree_sk_xxx', // Admin API requires a secret key
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Admin endpoints will be available under client.admin.*
|
|
19
|
+
// client.admin.products.list()
|
|
20
|
+
// client.admin.orders.list()
|
|
21
|
+
// client.admin.customers.list()
|
|
22
|
+
```
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Authentication
|
|
3
|
+
description: Authentication modes and guest checkout with the Spree SDK
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The SDK supports multiple authentication modes depending on your use case. For a full overview of the API authentication methods, see the [Store API Authentication](/api-reference/store-api/authentication) reference.
|
|
7
|
+
|
|
8
|
+
## Publishable Key Only (Guest/Public Access)
|
|
9
|
+
|
|
10
|
+
Use a publishable API key for public endpoints like browsing products:
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { createClient } from '@spree/sdk'
|
|
14
|
+
|
|
15
|
+
const client = createClient({
|
|
16
|
+
baseUrl: 'http://localhost:3000',
|
|
17
|
+
publishableKey: 'spree_pk_xxx',
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// Public endpoints work without user authentication
|
|
24
|
+
const products = await client.products.list()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Publishable Key + JWT (Authenticated Customer)
|
|
28
|
+
|
|
29
|
+
For authenticated customer actions like viewing orders or managing addresses:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Login to get a JWT token
|
|
33
|
+
const { token, user } = await client.auth.login({
|
|
34
|
+
email: 'customer@example.com',
|
|
35
|
+
password: 'password123',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Use the token for authenticated requests
|
|
39
|
+
const orders = await client.customer.orders.list({}, { token })
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// Refresh token when needed
|
|
45
|
+
const newTokens = await client.auth.refresh({ token })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Register New Customer
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const { token, user } = await client.customers.create({
|
|
52
|
+
email: 'new@example.com',
|
|
53
|
+
password: 'password123',
|
|
54
|
+
password_confirmation: 'password123',
|
|
55
|
+
first_name: 'John',
|
|
56
|
+
last_name: 'Doe',
|
|
57
|
+
})
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Guest Checkout
|
|
61
|
+
|
|
62
|
+
For guest checkout, use the `token` returned when creating a cart. The SDK automatically sends it via the `x-spree-token` header:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Create a cart (guest)
|
|
66
|
+
const cart = await client.carts.create()
|
|
67
|
+
|
|
68
|
+
// Use spreeToken for all cart and checkout operations
|
|
69
|
+
const options = { spreeToken: cart.token }
|
|
70
|
+
|
|
71
|
+
// Add items
|
|
72
|
+
await client.carts.items.create(cart.id, {
|
|
73
|
+
variant_id: 'variant_abc123',
|
|
74
|
+
quantity: 1,
|
|
75
|
+
}, options)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const options = { spreeToken: cart.token }
|
|
81
|
+
|
|
82
|
+
// Update cart with email
|
|
83
|
+
await client.carts.update(cart.id, {
|
|
84
|
+
email: 'guest@example.com',
|
|
85
|
+
}, options)
|
|
86
|
+
|
|
87
|
+
// Complete checkout
|
|
88
|
+
await client.carts.complete(cart.id, options)
|
|
89
|
+
```
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Configuration
|
|
3
|
+
description: Localization, error handling, TypeScript types, and custom fetch
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Localization & Currency
|
|
7
|
+
|
|
8
|
+
Pass locale and currency headers with any request. For full details, see the [Localization](/api-reference/store-api/localization) reference.
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// Set locale and currency per request
|
|
12
|
+
const products = await client.products.list({}, {
|
|
13
|
+
locale: 'fr',
|
|
14
|
+
currency: 'EUR',
|
|
15
|
+
country: 'FR',
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// Works with all endpoints
|
|
22
|
+
const category = await client.categories.get('clothing/shirts', {
|
|
23
|
+
expand: ['ancestors'],
|
|
24
|
+
}, {
|
|
25
|
+
locale: 'de',
|
|
26
|
+
currency: 'EUR',
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Error Handling
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { SpreeError } from '@spree/sdk';
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
await client.products.get('non-existent');
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error instanceof SpreeError) {
|
|
39
|
+
console.log(error.code); // 'record_not_found'
|
|
40
|
+
console.log(error.message); // 'Product not found'
|
|
41
|
+
console.log(error.status); // 404
|
|
42
|
+
console.log(error.details); // Validation errors (if any)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Custom Fetch
|
|
48
|
+
|
|
49
|
+
You can provide a custom fetch implementation:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { createClient } from '@spree/sdk';
|
|
53
|
+
|
|
54
|
+
const client = createClient({
|
|
55
|
+
baseUrl: 'https://api.mystore.com',
|
|
56
|
+
publishableKey: 'spree_pk_xxx',
|
|
57
|
+
fetch: customFetchImplementation,
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Monetary Amounts
|
|
62
|
+
|
|
63
|
+
All monetary values in the API are returned as **strings** (e.g., `"29.99"`, `"0.0"`), not numbers. This preserves decimal precision and avoids floating-point rounding issues.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const order = await client.orders.get('or_abc123', {}, { token });
|
|
67
|
+
|
|
68
|
+
// Monetary fields are strings
|
|
69
|
+
order.total; // "129.99"
|
|
70
|
+
order.item_total; // "99.99"
|
|
71
|
+
order.delivery_total; // "10.00"
|
|
72
|
+
order.tax_total; // "20.00"
|
|
73
|
+
|
|
74
|
+
// Display fields include currency formatting
|
|
75
|
+
order.display_total; // "$129.99"
|
|
76
|
+
|
|
77
|
+
// Convert to number when needed for calculations
|
|
78
|
+
const total = parseFloat(order.total);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This applies to all monetary fields across all types: `Order`, `LineItem`, `Fulfillment`, `Payment`, `GiftCard`, `Price`, etc.
|
|
82
|
+
|
|
83
|
+
## TypeScript Support
|
|
84
|
+
|
|
85
|
+
The SDK includes full TypeScript support with generated types from the API serializers:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import type {
|
|
89
|
+
Product,
|
|
90
|
+
Order,
|
|
91
|
+
Cart,
|
|
92
|
+
Variant,
|
|
93
|
+
Category,
|
|
94
|
+
LineItem,
|
|
95
|
+
Address,
|
|
96
|
+
Customer,
|
|
97
|
+
PaginatedResponse,
|
|
98
|
+
} from '@spree/sdk';
|
|
99
|
+
|
|
100
|
+
// All responses are fully typed
|
|
101
|
+
const products: PaginatedResponse<Product> = await client.products.list();
|
|
102
|
+
const category: Category = await client.categories.get('clothing');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Available Types
|
|
106
|
+
|
|
107
|
+
All types are exported as unprefixed names (e.g., `Product`, `Order`). Legacy `Store*` prefixed aliases (e.g., `StoreProduct`) are still available for backward compatibility.
|
|
108
|
+
|
|
109
|
+
### Core Types
|
|
110
|
+
- `Product` - Product data
|
|
111
|
+
- `Variant` - Variant data
|
|
112
|
+
- `Cart` - Cart data (uses `cart_` prefixed IDs)
|
|
113
|
+
- `Order` - Completed order data (uses `or_` prefixed IDs)
|
|
114
|
+
- `LineItem` - Line item in cart
|
|
115
|
+
- `Category` - Category
|
|
116
|
+
- `Country` - Country with states
|
|
117
|
+
- `State` - State/province
|
|
118
|
+
- `Address` - Customer address
|
|
119
|
+
- `Customer` - Customer profile
|
|
120
|
+
- `Market` - Market configuration (currency, locales, countries)
|
|
121
|
+
|
|
122
|
+
### Commerce Types
|
|
123
|
+
- `Payment` - Payment record
|
|
124
|
+
- `PaymentMethod` - Payment method
|
|
125
|
+
- `PaymentSession` - Provider-agnostic payment session
|
|
126
|
+
- `Fulfillment` - Fulfillment record
|
|
127
|
+
- `DeliveryRate` - Delivery rate option
|
|
128
|
+
- `DeliveryMethod` - Delivery method
|
|
129
|
+
- `CreditCard` - Saved credit card
|
|
130
|
+
- `GiftCard` - Gift card
|
|
131
|
+
- `Discount` - Discount applied to a cart or order
|
|
132
|
+
|
|
133
|
+
### Product Types
|
|
134
|
+
- `Media` - Product media (images, videos)
|
|
135
|
+
- `Price` - Price data
|
|
136
|
+
- `OptionType` - Option type (e.g., Size, Color)
|
|
137
|
+
- `OptionValue` - Option value (e.g., Small, Red)
|
|
138
|
+
- `DigitalLink` - Digital download link
|
|
139
|
+
- `Metafield` - Custom metafield data
|
|
140
|
+
|
|
141
|
+
### Wishlist Types
|
|
142
|
+
- `Wishlist` - Wishlist
|
|
143
|
+
- `WishlistItem` - Wishlist item
|
|
144
|
+
|
|
145
|
+
### Client Types
|
|
146
|
+
- `Client` - Main client interface
|
|
147
|
+
- `StoreClient` - Store API client class
|
|
148
|
+
- `ClientConfig` - Client configuration
|
|
149
|
+
- `RequestOptions` - Per-request options
|
|
150
|
+
- `RetryConfig` - Retry behavior configuration
|
|
151
|
+
|
|
152
|
+
### Utility Types
|
|
153
|
+
- `PaginatedResponse<T>` - Paginated API response
|
|
154
|
+
- `ListResponse<T>` - List API response
|
|
155
|
+
- `AuthTokens` - JWT tokens from login
|
|
156
|
+
- `AddressParams` - Address input parameters
|
|
157
|
+
- `UpdateCartParams` - Cart update parameters
|
|
158
|
+
- `CreatePaymentParams` - Direct payment creation parameters
|
|
159
|
+
- `CreatePaymentSessionParams` - Payment session creation parameters
|
|
160
|
+
- `UpdatePaymentSessionParams` - Payment session update parameters
|
|
161
|
+
- `CompletePaymentSessionParams` - Payment session completion parameters
|
|
162
|
+
- `ProductFiltersResponse` - Product filters response
|
|
163
|
+
- `CheckoutRequirement` - Checkout requirement (`{ step, field, message }`)
|
|
164
|
+
|
|
165
|
+
## Extending Types
|
|
166
|
+
|
|
167
|
+
All generated SDK types are TypeScript `interface`s, which means you can extend them via [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) when you customize API serializers on the backend.
|
|
168
|
+
|
|
169
|
+
### Example: Adding a Brand to Products
|
|
170
|
+
|
|
171
|
+
If you've customized the `ProductSerializer` in your app to include a `brand_id` attribute:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
# app/serializers/my_store/product_serializer.rb
|
|
175
|
+
module MyStore
|
|
176
|
+
class ProductSerializer < Spree::Api::V3::ProductSerializer
|
|
177
|
+
typelize brand_id: :string
|
|
178
|
+
|
|
179
|
+
attribute :brand_id do |product|
|
|
180
|
+
product.brand&.prefixed_id
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# config/initializers/spree.rb
|
|
186
|
+
Spree.api.product_serializer = MyStore::ProductSerializer
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
You can extend the SDK type in your frontend code so TypeScript knows about the new field:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// types/spree.d.ts
|
|
193
|
+
declare module '@spree/sdk' {
|
|
194
|
+
interface Product {
|
|
195
|
+
brand_id: string;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Now `brand_id` is available on every `Product` across your app — no type casting needed:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const products = await client.products.list();
|
|
204
|
+
products.data.forEach((product) => {
|
|
205
|
+
console.log(product.brand_id); // fully typed
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Extending Zod Schemas
|
|
210
|
+
|
|
211
|
+
If you use the SDK's Zod schemas for runtime validation, extend them with `.extend()`:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { z } from 'zod';
|
|
215
|
+
import { ProductSchema } from '@spree/sdk/zod';
|
|
216
|
+
|
|
217
|
+
const MyProductSchema = ProductSchema.extend({
|
|
218
|
+
brand_id: z.string(),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Use for runtime validation
|
|
222
|
+
const product = MyProductSchema.parse(apiResponse);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
> **NOTE:** Declaration merging only affects TypeScript types (compile-time). Zod schemas perform runtime validation and must be extended separately if you need validation of custom fields.
|