docs: create docs workspace (#5174)
* docs: migrate ui docs to docs universe * created yarn workspace * added eslint and tsconfig configurations * fix eslint configurations * fixed eslint configurations * shared tailwind configurations * added shared ui package * added more shared components * migrating more components * made details components shared * move InlineCode component * moved InputText * moved Loading component * Moved Modal component * moved Select components * Moved Tooltip component * moved Search components * moved ColorMode provider * Moved Notification components and providers * used icons package * use UI colors in api-reference * moved Navbar component * used Navbar and Search in UI docs * added Feedback to UI docs * general enhancements * fix color mode * added copy colors file from ui-preset * added features and enhancements to UI docs * move Sidebar component and provider * general fixes and preparations for deployment * update docusaurus version * adjusted versions * fix output directory * remove rootDirectory property * fix yarn.lock * moved code component * added vale for all docs MD and MDX * fix tests * fix vale error * fix deployment errors * change ignore commands * add output directory * fix docs test * general fixes * content fixes * fix announcement script * added changeset * fix vale checks * added nofilter option * fix vale error
This commit is contained in:
1 parent
19c5d5ba36
commit
fa7c94b4cc
3209 files changed
+32188
-31018
No files matched your search
@@ -0,0 +1,454 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# B2B Recipe
|
||||
|
||||
This document guides you through the different documentation resources that will help you build a B2B store with Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
In a B2B store, it’s essential to differentiate between customer types to provide them with relevant pricing, products, shopping experience, and more.
|
||||
|
||||
Medusa’s commerce features, including sales channels, customer groups, and price lists, facilitate implementing this setup. Medusa’s architecture and extendible nature allow you to customize your store based on your use case.
|
||||
|
||||
<LearningPath pathName="b2b" />
|
||||
|
||||
---
|
||||
|
||||
## Create B2B Sales Channel
|
||||
|
||||
In Medusa, a sales channel allows you to set product availability per channel. In this case, you can create a B2B sales channel that will include only B2B products.
|
||||
|
||||
You can create a sales channel through the Medusa admin or Admin REST APIs.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/sales-channels/manage',
|
||||
label: 'Option 1: Use Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the sales channel using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/sales-channels/admin/manage',
|
||||
label: 'Option 2: Using the REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the sales channel using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Create a Publishable API Key
|
||||
|
||||
Publishable API keys can be associated with one or more sales channels. Then, in a client such as a storefront, you can pass the publishable API key in the header of your requests to ensure all products retrieved belong to the associated sales channel(s).
|
||||
|
||||
You can create a publishable API key through the Medusa admin or the Admin REST APIs, then associate it with the B2B sales channel. You’ll later use this key when developing your B2B storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/settings/publishable-api-keys',
|
||||
label: 'Option 1: Use Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the publishable API key using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/publishable-api-keys/admin/manage-publishable-api-keys',
|
||||
label: 'Option 2: Using the REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the publishable API key using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Add Products
|
||||
|
||||
Using the Medusa admin or the Admin REST APIs, you can add your B2B products to your store. You can also import your products from an existing CSV file using the Product Import feature.
|
||||
|
||||
After or while you add your products, set the products’ availability to the B2B sales channel you’ve created.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/products/manage',
|
||||
label: 'Add Products Using Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the product using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/products/admin/manage-products',
|
||||
label: 'Add Products Using REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the product using the REST APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/products/import',
|
||||
label: 'Import Products Using Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Import the products using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/products/admin/import-products',
|
||||
label: 'Import Products Using REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Import the product using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Create B2B Customer Groups
|
||||
|
||||
In B2B sales, you often negotiate special prices with each customer or company. So, you need to organize your B2B customers into groups that allow you to set different prices for each.
|
||||
|
||||
You can create a single B2B customer group that all your B2B customers will fall into or create different B2B customer groups for every B2B customer. The second approach is helpful if you apply different prices for each business.
|
||||
|
||||
While creating the customer groups, make sure to add to the `metadata` attribute of the customer group a key `is_b2b` that acts as a flag to indicate that this is a B2B customer group. This is useful for later steps.
|
||||
|
||||
For more advanced customer modeling, you may create custom entities. This is covered in the [Create Custom Entity section](#create-custom-entity).
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/customers/groups',
|
||||
label: 'Option 1: Use Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the customer group using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/customers/admin/manage-customer-groups',
|
||||
label: 'Option 2: Using the REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the customer group using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Add B2B Customers
|
||||
|
||||
After adding your B2B customer group, you can add B2B customers and assign them to the B2B customer group. Alternatively, if you want to allow B2B customers to register themselves, then that will be covered in a later step.
|
||||
|
||||
You can create a customer through the Medusa admin or Admin REST APIs.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/customers/manage',
|
||||
label: 'Option 1: Use Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the customers using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/customers/admin/manage-customers',
|
||||
label: 'Option 2: Using the REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the customers using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Create B2B Price List
|
||||
|
||||
A price list allows you to set different prices on a set of products for various conditions. When building a B2B store, you can use this to assign different prices for B2B customer groups.
|
||||
|
||||
You can use price lists to set the same price for all B2B customers or different prices for different B2B customers if you’ve organized them into separate customer groups.
|
||||
|
||||
You can create a price list through the Medusa admin or Admin REST APIs. You can also import prices into your price list after creating it.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/price-lists/manage',
|
||||
label: 'Add Price List Using Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Create the price list using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/price-lists/admin/manage-price-lists',
|
||||
label: 'Add Price List Using REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create the price list using the REST APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/price-lists/import',
|
||||
label: 'Import Prices Using Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Import the prices using the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/price-lists/admin/import-prices',
|
||||
label: 'Import Prices Using REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Import the prices using the REST APIs.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Create Custom Entity
|
||||
|
||||
If you wish for a more advanced B2B sales flow, you can use Custom Entities to model Companies, Employees, Admins, and Buyers. This gives you more granular control of your B2B sales and allows you to build features like privileges, limits, and more.
|
||||
|
||||
Each of the entities you create can be controlled using custom logic.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/create',
|
||||
label: 'Create Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a custom entity.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/overview',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Find all the development resources to customize Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Create an Endpoint to Check Customers
|
||||
|
||||
On the frontend clients communicating with your store, such as the storefront, you’ll need to check whether the currently logged-in customer is a B2B customer.
|
||||
|
||||
The endpoint’s logic differs based on how you’ve implemented the B2B logic. For example, if you’ve used the `is_b2b` flag in the customer group, your endpoint can check whether that flag is enabled for the logged-in customer.
|
||||
|
||||
Medusa allows you to create custom endpoints exposed as REST APIs.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/create',
|
||||
label: 'Create an Endpoint',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an endpoint in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example Implementation
|
||||
</summary>
|
||||
|
||||
Here’s an example of an endpoint that allows you to check the customer’s group and whether it has the `is_b2b` flag enabled:
|
||||
|
||||
```ts title=src/api/index.ts
|
||||
import { CustomerService } from "@medusajs/medusa"
|
||||
import { Router } from "express"
|
||||
import { requireCustomerAuthentication } from "@medusajs/medusa"
|
||||
import cors from "cors"
|
||||
import { ConfigModule } from "@medusajs/medusa"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
|
||||
export default (rootDirectory) => {
|
||||
const router = Router()
|
||||
const { configModule } = getConfigFile<ConfigModule>(
|
||||
rootDirectory,
|
||||
"medusa-config"
|
||||
)
|
||||
|
||||
const corsOptions = {
|
||||
origin: configModule.projectConfig.store_cors.split(","),
|
||||
credentials: true,
|
||||
}
|
||||
|
||||
router.options("/store/customers/is-b2b", cors(corsOptions))
|
||||
router.get(
|
||||
"/store/customers/is-b2b",
|
||||
cors(corsOptions),
|
||||
requireCustomerAuthentication(),
|
||||
async (req, res) => {
|
||||
const customerService: CustomerService = req.scope.resolve(
|
||||
"customerService"
|
||||
)
|
||||
|
||||
const customer = await customerService
|
||||
.retrieve(req.user.customer_id, {
|
||||
relations: ["groups"],
|
||||
})
|
||||
|
||||
const is_b2b = customer.groups.some(
|
||||
(group) => group.metadata.is_b2b === "true"
|
||||
)
|
||||
|
||||
return res.json({
|
||||
is_b2b,
|
||||
})
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Customize Admin
|
||||
|
||||
Based on your use case, you may need to customize the Medusa admin to add new widgets or pages.
|
||||
|
||||
The Medusa admin plugin can be extended to add widgets, UI routes, and setting pages.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/widgets',
|
||||
label: 'Create Admin Widget',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add widgets into existing admin pages.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/routes',
|
||||
label: 'Create Admin UI Routes',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new pages to your Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/setting-pages',
|
||||
label: 'Create Admin Setting Page',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new page to the Medusa admin settings.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Customize Storefront
|
||||
|
||||
You may want different interfaces for B2B and regular customers on the storefront. You may also want to display products differently for each type of customer.
|
||||
|
||||
Medusa provides a Next.js starter that you can use and customize. You can also build your storefront with any frontend technology. Medusa provides you with different client libraries and REST APIs to use.
|
||||
|
||||
Use the publishable API key you associated with your B2B sales channel in the storefront to ensure only B2B products are retrieved.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Option 1: Use Next.js Starter',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to install and use the Next.js starter template.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Options 2: Build Custom Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to build a custom storefront with your preferred technology.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/publishable-api-keys/storefront/use-in-requests',
|
||||
label: 'Use Publishable API Keys',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to use the publishable API key in client requests.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy B2B Store
|
||||
|
||||
Once you finish your development, you can deploy your B2B backend and storefront to your preferred hosting providers.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Medusa Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your Medusa backend to your preferred hosting provider.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/deployments/storefront',
|
||||
label: 'Deploy Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your storefront to your preferred hosting provider.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your B2B development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -0,0 +1,689 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Commerce automation
|
||||
|
||||
This document guides you on how you can implement different forms of commerce automation within your Medusa project.
|
||||
|
||||
## Overview
|
||||
|
||||
Commerce automation is essential for businesses that want to save costs, provide a better user experience, and avoid manual, repetitive tasks that can lead to human errors. Businesses can utilize it in different domains, including marketing, customer support, order management, and more.
|
||||
|
||||
Medusa provides the necessary architecture and resources to implement commerce automation related to order management, customer service, and more. It mainly utilizes an event bus that allows you to listen to specific event triggers and perform asynchronous actions.
|
||||
|
||||
This document gives a high-level overview of how you can implement different types of commerce automation.
|
||||
|
||||
---
|
||||
|
||||
## Re-Stock Notifications
|
||||
|
||||
Customers may be interested in a product that is currently out of stock.
|
||||
|
||||
Medusa already provides a [Re-stock notifications plugin](../plugins/other/restock-notifications.md). You can also implement this by creating custom entities, triggering custom events, and handling these events with a subscriber.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/other/restock-notifications',
|
||||
label: 'Restock Notifications Plugin',
|
||||
customProps: {
|
||||
icon: Icons['bolt-solid'],
|
||||
description: 'Learn how to install the Restock Notification plugin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/create',
|
||||
label: 'Create an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a custom entity in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/#emitting-events',
|
||||
label: 'Emit Events',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to emit a custom event in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber that handles events.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Automated Customer Support
|
||||
|
||||
Customer support is essential to build a store's brand and customer loyalty. This can include integrating with third-party services or automating notifications sent to customers when changes happen related to their orders, returns, exchanges, and more.
|
||||
|
||||
You can use Medusa's Notification Service to handle notifications triggered by actions on customer orders or profiles.
|
||||
|
||||
For example, when an order's status is updated, the `order.updated` event is triggered. You can create a Notification Service that handles this event by emailing the customer about the status update.
|
||||
|
||||
The [Event reference](../development/events/events-list.md) includes an extensive list of events triggered by the Medusa core.
|
||||
|
||||
Medusa also provides official notification plugins that integrate with third-party services, such as [SendGrid](../plugins/notifications/sendgrid.mdx) or [TwilioSMS](../plugins/notifications/twilio-sms.md).
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/notifications',
|
||||
label: 'Notification Plugins',
|
||||
customProps: {
|
||||
icon: Icons['bolt-solid'],
|
||||
description: 'Check out available notification plugins.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/notification/create-notification-provider',
|
||||
label: 'Create Notification Service',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a notification service.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example: Sending an email for new notes
|
||||
</summary>
|
||||
|
||||
Here’s an example of a subscriber that uses the SendGrid plugin to send an email to the customer when the order has a new note:
|
||||
|
||||
```ts title=src/subscribers/new-note.ts
|
||||
import {
|
||||
EventBusService,
|
||||
NoteService,
|
||||
OrderService,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
sendgridService: any
|
||||
noteService: NoteService
|
||||
orderService: OrderService
|
||||
}
|
||||
|
||||
class NewNoteSubscriber {
|
||||
protected sendGridService_: any
|
||||
protected noteService_: NoteService
|
||||
protected orderService_: OrderService
|
||||
|
||||
constructor({
|
||||
eventBusService,
|
||||
sendgridService,
|
||||
noteService,
|
||||
orderService,
|
||||
}: InjectedDependencies) {
|
||||
this.noteService_ = noteService
|
||||
this.orderService_ = orderService
|
||||
this.sendGridService_ = sendgridService
|
||||
eventBusService.subscribe(
|
||||
"note.created",
|
||||
this.handleNoteCreated
|
||||
)
|
||||
}
|
||||
|
||||
handleNoteCreated = async (data) => {
|
||||
// retrieve note by id
|
||||
const note = await this.noteService_.retrieve(data.id, {
|
||||
relations: ["author"],
|
||||
})
|
||||
|
||||
if (!note || note.resource_type !== "order") {
|
||||
return
|
||||
}
|
||||
|
||||
// retrieve note's order
|
||||
const order = await this.orderService_.retrieve(
|
||||
note.resource_id
|
||||
)
|
||||
|
||||
if (!order) {
|
||||
return
|
||||
}
|
||||
|
||||
this.sendGridService_.sendEmail({
|
||||
templateId: "order-update",
|
||||
from: "hello@medusajs.com",
|
||||
to: order.email,
|
||||
dynamic_template_data: {
|
||||
// any data necessary for your template...
|
||||
note_text: note.value,
|
||||
note_author: note.author.first_name,
|
||||
note_date: note.created_at,
|
||||
order_id: order.display_id,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default NewNoteSubscriber
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Automatic Data Synchronization
|
||||
|
||||
As your commerce store grows, you'll likely need to synchronize data across different systems. For example, you can synchronize data with an ERP system or a data warehouse.
|
||||
|
||||
You can implement automatic synchronization in Medusa using scheduled jobs. A scheduled job runs at a specified date and time interval in the background of your Medusa backend. Within the scheduled job, you can synchronize your internal or external data.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/create',
|
||||
label: 'Create a Scheduled Job',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a scheduled job in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example: Synchronizing products with a third-party service
|
||||
</summary>
|
||||
|
||||
Here’s an example of synchronizing products with a third party service using a [loader](../development/loaders/create.md):
|
||||
|
||||
```ts title=src/loaders/sync-products.ts
|
||||
import {
|
||||
Logger,
|
||||
ProductService,
|
||||
StoreService,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
ProductSelector,
|
||||
} from "@medusajs/medusa/dist/types/product"
|
||||
import { AwilixContainer } from "awilix"
|
||||
|
||||
export default async (
|
||||
container: AwilixContainer,
|
||||
config: Record<string, unknown>
|
||||
): Promise<void> => {
|
||||
const logger = container.resolve<Logger>("logger")
|
||||
logger.info("Synchronizing products...")
|
||||
const productService = container.resolve<ProductService>(
|
||||
"productService"
|
||||
)
|
||||
const storeService = container.resolve<StoreService>(
|
||||
"storeService"
|
||||
)
|
||||
// retrieve store to get last sync date
|
||||
const store = await storeService.retrieve()
|
||||
|
||||
const productFilters: ProductSelector = {}
|
||||
|
||||
if (store.metadata.last_sync_date) {
|
||||
productFilters.updated_at = {
|
||||
gt: new Date(
|
||||
store.metadata.last_sync_date as string
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
const updatedProducts = await productService.list(
|
||||
productFilters
|
||||
)
|
||||
|
||||
updatedProducts.forEach((product) => {
|
||||
// assuming client is an initialized connection
|
||||
// with a third-party service
|
||||
client.sync(product)
|
||||
})
|
||||
|
||||
await storeService.update({
|
||||
metadata: {
|
||||
last_sync_date: new Date(),
|
||||
},
|
||||
})
|
||||
|
||||
logger.info("Finish synchronizing products")
|
||||
}
|
||||
```
|
||||
|
||||
Notice that here it’s assumed that:
|
||||
|
||||
1. The last update date is stored in the `Store`'s metadata object. You can instead use a custom entity to handle this.
|
||||
2. The connection to the third-party service is assumed to be available and handled within the `client` variable.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Order Management Automation
|
||||
|
||||
Using Medusa's architecture and commerce features, you can automate a large amount of order management functionalities.
|
||||
|
||||
Using the event bus service, you can handle events within an order workflow to automate actions. For example, when an order is placed, you can listen to the `order.placed` event and automatically creates a fulfillment if predefined conditions are met.
|
||||
|
||||
Another example is automatically capturing payment when an order is fully shipped, and the `order.shipment_created` is triggered.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events',
|
||||
label: 'Event Bus',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the event architecture system in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber to listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/events-list',
|
||||
label: 'Events Reference',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out triggered events in Medusa and their expected payloads.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Automated RMA Flow
|
||||
|
||||
Businesses must optimize their Return Merchandise Authorization (RMA) flow to ensure a good customer experience and service. By automating the flow, customers can request to return their received items, and businesses can quickly support them.
|
||||
|
||||
Medusa's commerce features are geared towards automating RMA flows and ensuring a good customer experience.
|
||||
|
||||
For example, customers can create returns for their orders without direct involvement from the store operator. The store operator will then receive a notification regarding the return and handle it accordingly. The same applies to order exchanges.
|
||||
|
||||
Medusa also allows the store operator to edit orders, receive customer approval for the edits, and authorize additional payment if necessary, all within a seamless workflow.
|
||||
|
||||
Similar to the examples mentioned earlier, each action triggers events you can listen to and perform additional actions based on your use case.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events',
|
||||
label: 'Event Bus',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the event architecture system in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber to listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/events-list',
|
||||
label: 'Events Reference',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out triggered events in Medusa and their expected payloads.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/returns',
|
||||
label: 'Order Returns',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Returns architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/swaps',
|
||||
label: 'Order Swaps',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Swaps architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/#order-edits',
|
||||
label: 'Order Edits',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Edits architecture and features.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Customer Segmentation
|
||||
|
||||
Businesses use Customer Segmentation to organize customers into different groups and then apply different price rules to these groups. For example, you may group customers by their product preferences, the number of orders they've placed, or geographical location.
|
||||
|
||||
Based on your use case and the segmentation logic, you can use different Medusa automation development tools to detect a customer's segment. Medusa also provides a Customer Groups feature that allows you to segment customers, whether you do it manually or automatically.
|
||||
|
||||
For example, if you're grouping customers with over twenty orders, you can use a Subscriber that listens to the `order.placed` event and checks the number of orders the customer has so far. Then, you can add that customer to the VIP group using Medusa's Customer Groups feature. Finally, you can utilize the Price Lists feature to provide different prices or discounts for customers in the VIP group.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/customers/customer-groups',
|
||||
label: 'Customer Groups',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Customer Groups architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events',
|
||||
label: 'Subscribers and Events',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about events in Medusa and how to listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/price-lists',
|
||||
label: 'Price Lists',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Price Lists architecture and features.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example: Add customer to VIP group
|
||||
</summary>
|
||||
|
||||
Here’s an example of a subscriber that listens to the `order.placed` event and checks if the customer should be added to the VIP customer group based on their number of orders:
|
||||
|
||||
```ts title=src/subscribers/add-custom-to-vip.ts
|
||||
import {
|
||||
CustomerGroupService,
|
||||
CustomerService,
|
||||
EventBusService,
|
||||
OrderService,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
type InjectedDependencies = {
|
||||
orderService: OrderService
|
||||
customerService: CustomerService
|
||||
customerGroupService: CustomerGroupService
|
||||
eventBusService: EventBusService
|
||||
}
|
||||
|
||||
class AddCustomerToVipSubscriber {
|
||||
protected orderService_: OrderService
|
||||
protected customerService_: CustomerService
|
||||
protected customerGroupService_: CustomerGroupService
|
||||
|
||||
constructor({
|
||||
orderService,
|
||||
customerService,
|
||||
customerGroupService,
|
||||
eventBusService,
|
||||
}: InjectedDependencies) {
|
||||
this.orderService_ = orderService
|
||||
this.customerService_ = customerService
|
||||
this.customerGroupService_ = customerGroupService
|
||||
eventBusService.subscribe(
|
||||
"order.placed",
|
||||
this.handleOrderPlaced
|
||||
)
|
||||
}
|
||||
|
||||
handleOrderPlaced = async ({ id }) => {
|
||||
// check if VIP group exists
|
||||
const vipGroup = await this.customerGroupService_.list({
|
||||
name: "VIP",
|
||||
}, {
|
||||
relations: ["customers"],
|
||||
})
|
||||
if (!vipGroup.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// retrieve order and its customer
|
||||
const order = await this.orderService_.retrieve(id)
|
||||
|
||||
if (!order || !order.customer_id ||
|
||||
vipGroup[0].customers.find(
|
||||
(customer) => customer.id === order.customer_id
|
||||
) !== undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
// retrieve orders of this customer
|
||||
const [, count] = await this.orderService_.listAndCount({
|
||||
customer_id: order.customer_id,
|
||||
})
|
||||
|
||||
if (count >= 20) {
|
||||
// add customer to VIP group
|
||||
this.customerGroupService_.addCustomers(
|
||||
vipGroup[0].id,
|
||||
order.customer_id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AddCustomerToVipSubscriber
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Marketing Automation
|
||||
|
||||
In your commerce store, you may utilize marketing strategies that encourage customers to make purchases.
|
||||
|
||||
For example, you may send a newsletter when new products are added to your store. In Medusa, this can be handled by listening to the [product events](../development/events/events-list.md#product-events), such as `product.created`, using a Subscriber, then sending an email to subscribed customers with tools like [SendGrid](../plugins/notifications/sendgrid.mdx) or [Mailchimp](../plugins/notifications/mailchimp.md).
|
||||
|
||||
You can alternatively have a Scheduled Job that checks if the number of new products has exceeded a set threshold, then send out the newsletter.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events',
|
||||
label: 'Events and Subscribers',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about events in Medusa and how to listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/overview',
|
||||
label: 'Scheduled Jobs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about scheduled jobs and how you can create one.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/events-list',
|
||||
label: 'Events Reference',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out triggered events in Medusa and their expected payloads.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example: Sending a newsletter email after adding ten products
|
||||
</summary>
|
||||
|
||||
Here’s an example of listening to the `product.created` event in a subscriber and send a newsletter if the condition is met:
|
||||
|
||||
```ts title=src/subscribers/send-products-newsletter.ts
|
||||
import {
|
||||
CustomerService,
|
||||
EventBusService,
|
||||
NoteService,
|
||||
OrderService,
|
||||
ProductService,
|
||||
StoreService,
|
||||
} from "@medusajs/medusa"
|
||||
import {
|
||||
ProductSelector,
|
||||
} from "@medusajs/medusa/dist/types/product"
|
||||
|
||||
type InjectedDependencies = {
|
||||
eventBusService: EventBusService
|
||||
sendgridService: any
|
||||
productService: ProductService
|
||||
storeService: StoreService
|
||||
customerService: CustomerService
|
||||
}
|
||||
|
||||
class SendProductsNewsletterSubscriber {
|
||||
protected sendGridService_: any
|
||||
protected productService_: ProductService
|
||||
protected storeService_: StoreService
|
||||
protected customerService_: CustomerService
|
||||
|
||||
constructor({
|
||||
eventBusService,
|
||||
sendgridService,
|
||||
productService,
|
||||
storeService,
|
||||
customerService,
|
||||
}: InjectedDependencies) {
|
||||
this.productService_ = productService
|
||||
this.sendGridService_ = sendgridService
|
||||
this.storeService_ = storeService
|
||||
this.customerService_ = customerService
|
||||
eventBusService.subscribe(
|
||||
"product.created",
|
||||
this.handleProductCreated
|
||||
)
|
||||
}
|
||||
|
||||
handleProductCreated = async ({ id }) => {
|
||||
// retrieve store to have access to last send date
|
||||
const store = await this.storeService_.retrieve()
|
||||
|
||||
const productFilters: ProductSelector = {}
|
||||
if (store.metadata.last_send_date) {
|
||||
productFilters.created_at = {
|
||||
gt: new Date(store.metadata.last_send_date as string),
|
||||
}
|
||||
}
|
||||
|
||||
const products = await this.productService_.list(
|
||||
productFilters
|
||||
)
|
||||
|
||||
if (products.length > 10) {
|
||||
// get subscribed customers
|
||||
const customers = await this.customerService_.list({
|
||||
metadata: {
|
||||
is_subscribed: true,
|
||||
},
|
||||
})
|
||||
this.sendGridService_.sendEmail({
|
||||
templateId: "product-newsletter",
|
||||
from: "hello@medusajs.com",
|
||||
to: customers.map((customer) => ({
|
||||
name: customer.first_name,
|
||||
email: customer.email,
|
||||
})),
|
||||
dynamic_template_data: {
|
||||
// any data necessary for your template...
|
||||
products,
|
||||
},
|
||||
})
|
||||
|
||||
await this.storeService_.update({
|
||||
metadata: {
|
||||
last_send_date: new Date(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SendProductsNewsletterSubscriber
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Automation Development Toolkit
|
||||
|
||||
The use cases mentioned in this guide exemplify what commerce automation you can perform or implement with Medusa. Medusa provides the necessary development tools and mechanisms to automate tasks and manual work.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events',
|
||||
label: 'Events and Subscribers',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about events in Medusa and how to listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/notification/overview',
|
||||
label: 'Notification Service',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about notification services and how to create one.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/overview',
|
||||
label: 'Scheduled Jobs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about scheduled jobs and how you can create one.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/notifications',
|
||||
label: 'Notification Plugins',
|
||||
customProps: {
|
||||
icon: Icons['bolt-solid'],
|
||||
description: 'Check out available notification plugins.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,130 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# Ecommerce Recipe
|
||||
|
||||
This document guides you through building an ecommerce store with Medusa and start selling.
|
||||
|
||||
## Overview
|
||||
|
||||
Businesses use an ecommerce store to allow customers to browse their products and make purchases. It also includes accepting payments, managing orders, and more.
|
||||
|
||||
Medusa provides all essential commerce features out-of-the-box. Businesses can go live and start selling without making any adjustments. They can also power-up their store with plugins for payment, fulfillment, and more.
|
||||
|
||||
:::tip
|
||||
|
||||
Recommended read: [How Tekla created an ecommerce store using Medusa](https://medusajs.com/blog/tekla-agilo-pos-case/).
|
||||
|
||||
:::
|
||||
|
||||
<LearningPath pathName="simple-quickstart" />
|
||||
|
||||
---
|
||||
|
||||
## Create a Next.js Starter Storefront
|
||||
|
||||
The Medusa backend can be used with any storefront. All you have to do is connect to its Store APIs to utilize the backend's commerce features.
|
||||
|
||||
You can install, use, and customize the Next.js starter storefront to benefit from all the necessary ecommerce features. Alternatively, you can build your own storefront.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Install Next.js Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to install the Next.js starter storefront.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## (Optional) Install Plugins
|
||||
|
||||
Medusa provides official plugins that you can use for payment, fulfillment, search, and more. These plugins can provide additional functionalities for both your backend and your storefront.
|
||||
|
||||
For example, if you want to accept payment with Stripe, you can install the [Stripe plugin](../plugins/payment/stripe.mdx).
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/plugins/overview',
|
||||
label: 'Explore Plugins',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Explore official plugins and learn how to install them.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy the Backend
|
||||
|
||||
The first step to go live is to deploy the Medusa backend. The deployment guides available in our documentation provide extensive step-by-step guide for different hosting providers, as well as a general deployment guide that you can follow to deploy your backend to other providers.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy the backend to your preferred hosting provider.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy the Storefront
|
||||
|
||||
You can now deploy your storefront. The instructions defer whether you're using the Next.js storefront, a custom storefront, or other forms of storefronts such as a mobile app.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/storefront',
|
||||
label: 'Deploy Next.js Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy the Next.js storefront to your preferred hosting provider.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Explore Features and Development Resources
|
||||
|
||||
Our documentation includes guides related to Medusa's features and how to customize your store. You can learn about how to add new features to your storefront and backend, how to customize existing features, or how to use the Medusa admin to perform different ecommerce functionalities.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/overview',
|
||||
label: 'Commerce Modules',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about Medusa\'s commerce features and check out available guides.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/overview',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about how the Medusa backend works and how you can customize it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide',
|
||||
label: 'Admin User Guide',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn about available admin functionalities and how to use them.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
@@ -0,0 +1,75 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
import Feedback from '@site/src/components/Feedback';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
import LearningPathList from '@site/src/components/LearningPath/List';
|
||||
import LargeCard from '@site/src/components/LargeCard';
|
||||
|
||||
# Medusa Recipes
|
||||
|
||||
This document provides you resources for different paths based on what you're building with Medusa.
|
||||
|
||||
:::note
|
||||
|
||||
These recipes assume you already have a Medusa backend setup. If not, you can create a Medusa project with the following command:
|
||||
|
||||
```bash
|
||||
npx create-medusa-app
|
||||
```
|
||||
|
||||
[Learn more in this guide](../create-medusa-app.mdx).
|
||||
|
||||
:::
|
||||
|
||||
## Recipe: Setup Ecommerce Store
|
||||
|
||||
Follow this recipe if you want to use Medusa for an ecommerce store. This recipe includes three steps that will get you a storefront deployed to Vercel and a backend deployed to Railway.
|
||||
|
||||
<LearningPath pathName="simple-quickstart" />
|
||||
|
||||
---
|
||||
|
||||
## Use-Case Based Recipes
|
||||
|
||||
Explore available recipes for different commerce use cases.
|
||||
|
||||
<DocCardList />
|
||||
|
||||
<Feedback
|
||||
event="survey_use_cases"
|
||||
question="Did your find your use case?"
|
||||
positiveQuestion="Is there anything that should improved?"
|
||||
negativeQuestion="What was your use case?"
|
||||
showLongForm={false}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
<!-- vale docs.HeadingPunctuation = NO -->
|
||||
|
||||
## Can't find your path?
|
||||
|
||||
<!-- vale docs.HeadingPunctuation = YES -->
|
||||
|
||||
Medusa is a customizable commerce solution that can be used to build any custom use case. If you can't find your use case mentioned above, the following guides give you a general understanding of how Medusa can be used and how you can customize it.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/overview',
|
||||
label: 'Commerce Modules',
|
||||
customProps: {
|
||||
icon: Icons['puzzle-solid'],
|
||||
description: "Learn about Medusa's commerce features and how to customize them."
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['server-stack-solid'],
|
||||
description: "Learn how about Medusa's architecture and how to customize it."
|
||||
}
|
||||
},
|
||||
]} />
|
||||
@@ -0,0 +1,460 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# Build a Marketplace
|
||||
|
||||
This document guides you through the different documentation resources that will help you build a marketplace with Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
A marketplace is an online commerce store that allows different vendors to sell their products within the same commerce system. Customers can purchase products from any of these vendors, and vendors can manage their orders separately.
|
||||
|
||||
<LearningPath pathName="marketplace" />
|
||||
|
||||
---
|
||||
|
||||
## Associate Entities with Stores
|
||||
|
||||
:::tip
|
||||
|
||||
Entities represent tables in the database.
|
||||
|
||||
:::
|
||||
|
||||
By default, entities like users, products, or orders aren't associated with a store, as it's assumed there's one store in Medusa. For a marketplace, each of these entities should be associated with their respective stores.
|
||||
|
||||
To associate these entities with the `Store` entity, you need to extend and customize entities created in the Medusa core package `@medusajs/medusa`, such as the `User` entity, to add a relation to the `Store` entity.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/entities/extend-entity',
|
||||
label: 'Extend an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend an entity in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Associate User with Store</summary>
|
||||
|
||||
For example, to associate the `User` entity with the `Store` entity, create the file `src/models/user.ts` with the following content:
|
||||
|
||||
```ts title=src/models/user.ts
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
} from "typeorm"
|
||||
import {
|
||||
User as MedusaUser,
|
||||
} from "@medusajs/medusa"
|
||||
import { Store } from "./store"
|
||||
|
||||
@Entity()
|
||||
export class User extends MedusaUser {
|
||||
@Index("UserStoreId")
|
||||
@Column({ nullable: true })
|
||||
store_id?: string
|
||||
|
||||
@ManyToOne(() => Store, (store) => store.members)
|
||||
@JoinColumn({ name: "store_id", referencedColumnName: "id" })
|
||||
store?: Store
|
||||
}
|
||||
```
|
||||
|
||||
Then, you need to extend the `UserRepository` to point to your extended entity. To do that, create the file `src/repositories/user.ts` with the following content:
|
||||
|
||||
```ts title=src/repositories/user.ts
|
||||
import { User } from "../models/user"
|
||||
import {
|
||||
dataSource,
|
||||
} from "@medusajs/medusa/dist/loaders/database"
|
||||
import {
|
||||
UserRepository as MedusaUserRepository,
|
||||
} from "@medusajs/medusa/dist/repositories/user"
|
||||
|
||||
export const UserRepository = dataSource
|
||||
.getRepository(User)
|
||||
.extend({
|
||||
...Object.assign(
|
||||
MedusaUserRepository,
|
||||
{ target: User }
|
||||
),
|
||||
})
|
||||
|
||||
export default UserRepository
|
||||
```
|
||||
|
||||
Next, you need to create a migration that reflects the changes on the `User` entity in your database. To do that, run the following command to create a migration file:
|
||||
|
||||
```bash
|
||||
npx typeorm migration:create src/migrations/add-user-store-id
|
||||
```
|
||||
|
||||
This creates a file in the `src/migrations` directory of the format `<TIMESTAMP>_add-user-store-id.ts`. Replace the `up` and `down` methods in that file with the methods here:
|
||||
|
||||
```ts title=src/migrations/<TIMESTAMP>_add-user-store-id.ts
|
||||
// ...
|
||||
|
||||
export class AddUserStoreId1681287255173
|
||||
implements MigrationInterface {
|
||||
// ...
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" ADD "store_id" character varying`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "UserStoreId" ON "user" ("store_id")`
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."UserStoreId"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" DROP COLUMN "store_id"`
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Finally, to reflect these changes and start using them, `build` your changes and run migrations with the following commands:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
npx medusa migrations run
|
||||
```
|
||||
|
||||
You can extend other entities in a similar manner to associate them with a store.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Accessing Logged-in User
|
||||
|
||||
Throughout your development, you'll likely need access to the logged-in user. For example, you'll need to know which user is logged in to know which store to associate a new product with.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/example-logged-in-user',
|
||||
label: 'Access Logged-in User',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to access the logged-in user throughout your project using a Middleware.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Customize Data Management Functionalities
|
||||
|
||||
After associating entities with stores, you'll need to customize how certain data management functionalities are implemented in the Medusa core package.
|
||||
|
||||
For example, when a new user is created, you need to ensure that it's associated either with a new store or with the store of the logged-in user. Another example is associating a new product with the logged-in user's store.
|
||||
|
||||
You can customize these functionalities by extending services. Services are classes that contain helper methods specific to an entity. For example, the `UserService` is used to manage functionalities related to the `User` entity, such as creating a user.
|
||||
|
||||
You can also extend services if you need to customize a functionality implemented in a service for other reasons.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/services/extend-service',
|
||||
label: 'Extend a Service',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend a service in Medusa',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Extend User Service</summary>
|
||||
|
||||
You can extend the user service to change how the `create` method is implemented.
|
||||
|
||||
To extend the user service, create the file `src/services/user.ts` with the following content:
|
||||
|
||||
<!-- eslint-disable prefer-rest-params -->
|
||||
|
||||
```ts
|
||||
import { Lifetime } from "awilix"
|
||||
import {
|
||||
UserService as MedusaUserService,
|
||||
} from "@medusajs/medusa"
|
||||
import { User } from "../models/user"
|
||||
import {
|
||||
CreateUserInput as MedusaCreateUserInput,
|
||||
} from "@medusajs/medusa/dist/types/user"
|
||||
import StoreRepository from "../repositories/store"
|
||||
|
||||
type CreateUserInput = {
|
||||
store_id?: string
|
||||
} & MedusaCreateUserInput
|
||||
|
||||
class UserService extends MedusaUserService {
|
||||
static LIFE_TIME = Lifetime.SCOPED
|
||||
protected readonly loggedInUser_: User | null
|
||||
protected readonly storeRepository_: typeof StoreRepository
|
||||
|
||||
constructor(container, options) {
|
||||
super(...arguments)
|
||||
this.storeRepository_ = container.storeRepository
|
||||
|
||||
try {
|
||||
this.loggedInUser_ = container.loggedInUser
|
||||
} catch (e) {
|
||||
// avoid errors when backend first runs
|
||||
}
|
||||
}
|
||||
|
||||
async create(
|
||||
user: CreateUserInput,
|
||||
password: string
|
||||
): Promise<User> {
|
||||
if (!user.store_id) {
|
||||
const storeRepo = this.manager_.withRepository(
|
||||
this.storeRepository_
|
||||
)
|
||||
let newStore = storeRepo.create()
|
||||
newStore = await storeRepo.save(newStore)
|
||||
user.store_id = newStore.id
|
||||
}
|
||||
|
||||
return await super.create(user, password)
|
||||
}
|
||||
}
|
||||
|
||||
export default UserService
|
||||
```
|
||||
|
||||
In the `create` method of this extended service, you create a new store if the user being created doesn't have a store associated with it.
|
||||
|
||||
You can then test out your customization by running the `build` command and starting the backend:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx medusa develop
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Listening to Events
|
||||
|
||||
While implementing your marketplace, you'll typically need to listen to certain events then perform actions asynchronously. For example, you can listen to the `order.placed` event and, when triggered, create child orders of the order, separating ordered items by their associated store.
|
||||
|
||||
To listen to events, you need to create Subscribers that subscribe a handler method to an event. In that handler method, you can implement the desired functionality.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Listen to Order Created Event</summary>
|
||||
|
||||
To listen to the `order.placed` event, create the file `src/subscribers/orderNotifier.ts` with the following content:
|
||||
|
||||
```ts
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ eventBusService }) {
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
|
||||
handleOrder = async (data) => {
|
||||
// TODO perform functionality
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderNotifierSubscriber
|
||||
```
|
||||
|
||||
This subscribes the `handleOrder` method to be executed whenever the `order.placed` event is emitted.
|
||||
|
||||
You can then test out your subscriber by running the `build` command and starting the backend:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx medusa develop
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Add Payment and Fulfillment Providers
|
||||
|
||||
Payment and fulfillment providers can be added through plugins or directly in your project. You can either create your own provider, use one of Medusa's official plugins, or use community plugins.
|
||||
|
||||
:::note
|
||||
|
||||
Payment and fulfillment providers are associated with regions, which are not associated with a store, by default. If you want to allow each store to specify its own payment and fulfillment providers, you'll need to [associate the region with a store](#associate-entities-with-stores).
|
||||
|
||||
:::
|
||||
|
||||
### Option 1: Create your own providers
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create a Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a payment processor.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
|
||||
label: 'Create a Fulfillment Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a fulfillment provider.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Option 2: Install a Plugin
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/overview',
|
||||
label: 'Install an Official Medusa Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available Medusa plugins to install.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://medusajs.com/plugins/',
|
||||
label: 'Install a Community Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available community plugins to install.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Customize Admin
|
||||
|
||||
As you add marketplace features to your store, you'll most likely need to customize the admin to provide an interface to manage these features.
|
||||
|
||||
Medusa's [admin plugin](../admin/quickstart.mdx) can be extended to add widgets or new blocks to existing pages, add UI routes to add new pages, or add setting pages.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/widgets',
|
||||
label: 'Create Admin Widget',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add widgets into existing admin pages.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/routes',
|
||||
label: 'Create Admin UI Routes',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new pages to your Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/setting-pages',
|
||||
label: 'Create Admin Setting Page',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new page to the Medusa admin settings.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Implement Role-Based Access Control
|
||||
|
||||
In your marketplace, you may need to implement role-based access control (RBAC) within stores. This will restrict some users' permissions to specified functionalities or endpoints.
|
||||
|
||||
If you want to implement this functionality, you can follow the RBAC recipe.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/modules/users/backend/rbac',
|
||||
label: 'Implement Role-Based Access Control',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to implement role-based access control (RBAC) in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Build a Storefront
|
||||
|
||||
Medusa provides a Next.js Starter Template that you can use with Medusa. Since you've customized your Medusa project, you'll need to either customize the existing Next.js Starter Template, or create a custom storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Option 1: Use Next.js Starter Template',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Install the Next.js Starter Template to customize it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Option 2: Build Custom Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Find useful resources to build your own storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy Marketplace
|
||||
|
||||
Our documentation includes deployment guides for a basic Medusa backend. You should be able to follow it to deploy your customized marketplace, as well.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your marketplace backend to different hosting providers.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your marketplace development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -0,0 +1,265 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Multi-Regional Store
|
||||
|
||||
This document guides you through Medusa's different features and resources to create a multi-regional store.
|
||||
|
||||
## Overview
|
||||
|
||||
A multi-regional store allows merchants to sell across different countries. This includes supporting each country's tax rules, currency, available shipping and payment options, and more.
|
||||
|
||||
Medusa comes with multi-regional support out of the box. This recipe explains how you can benefit from Medusa's features to create a multi-regional store.
|
||||
|
||||
---
|
||||
|
||||
## Multi-Region Setup
|
||||
|
||||
With Medusa, you can create unlimited regions in your store. Each region has configurations managed through the Medusa Admin Dashboard or the Admin API.
|
||||
|
||||
### Currency
|
||||
|
||||
Merchants can specify the currency of each region. Multiple regions can have the same currency, but a region can have only one currency.
|
||||
|
||||
When customers view your products from a region, they see the prices in the region’s currency. As explained later, this also affects which prices are shown to the customer in a region.
|
||||
|
||||
### Tax rates and providers
|
||||
|
||||
At the regional level, merchants can define a default tax rate and tax rates for specific conditions (for example, for a particular set of products). Each region can also have a different tax provider that calculates the taxes. You can use Medusa's default tax provider or create a custom tax provider.
|
||||
|
||||
During checkout, the taxes are calculated based on the customer's region, tax configurations, and rates.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/taxes/manage',
|
||||
label: 'Manage Taxes in Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn how to manage taxes in Medusa Admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/taxes/admin/manage-tax-settings',
|
||||
label: 'Manage Taxes Using Admin APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to manage tax settings using the Admin APIs.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/taxes/backend/create-tax-provider',
|
||||
label: 'Create Tax Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a tax provider.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Payment and Fulfillment Providers
|
||||
|
||||
Merchants can choose which payment and fulfillment providers are available in each region. For example, one region can use Payment Provider A and B while another only uses Payment Provider B.
|
||||
|
||||
Customers will only be shown the payment providers and shipping options configured for the region during checkout. This lets you give customers a localized experience that feels familiar and instills trust.
|
||||
|
||||
Medusa provides official plugins for payment and fulfillment providers. You can also create custom providers.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/regions/providers',
|
||||
label: 'Manage Providers in Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn how to manage providers in Medusa Admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/payment',
|
||||
label: 'Available Payment Plugins',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available payment plugins',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create Payment Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a payment provider.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
|
||||
label: 'Create Fulfillment Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a fulfillment provider.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Prices Per Region and Currency
|
||||
|
||||
When a merchant sets the price of a product in Medusa, they can specify the price per currency and region. Merchants can also benefit from this pricing mechanism when adding sales or overriding prices for specific conditions using the [Price Lists feature](../modules/price-lists/overview.mdx).
|
||||
|
||||
Then, customers see the price of a product based on the region they're in and the region's currency and whether any special pricing applies to their case. Medusa has a pricing strategy (which you can override) to show the customer the best price based on their context.
|
||||
|
||||
Using the [tax-inclusive beta feature](../beta.md#tax-inclusive-pricing), merchants can specify prices, including taxes per currency and region. Medusa then calculates the tax amount applied to a line item in the cart based on the region's tax configurations.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/products/manage#edit-product-prices-with-bulk-editor',
|
||||
label: 'Setting Product Prices in Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn how to set a product prices in Medusa Admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/payment',
|
||||
label: 'Display Product Price in Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to display the correct product price in a storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Multi-Warehouse Support
|
||||
|
||||
Medusa provides Multi-warehouse features that allow you to manage your inventory across different locations. Merchants can then control which location an item in an order is fulfilled, allowing them to keep a correct inventory count across locations and sales channels.
|
||||
|
||||
A multi-regional setup lets you manage your inventory through Medusa across the different regions you serve. Your products’ inventory and availability aren't bound to a single stock location, and customers are always shown accurate inventory information based on the location associated with their sales channel.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/multiwarehouse/overview',
|
||||
label: 'Multi-warehouse Overview',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Multi-warehouse feature in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/multiwarehouse/locations',
|
||||
label: 'Manage Stock Locations',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn how to manage stock locations in the Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/user-guide/multiwarehouse/inventory',
|
||||
label: 'Manage Inventory',
|
||||
customProps: {
|
||||
icon: Icons['users-solid'],
|
||||
description: 'Learn how to manage inventory in the Medusa admin.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Multi-Lingual Setup with Third-Party CMS
|
||||
|
||||
Medusa can be integrated with third-party services, including Content Management Systems (CMS). You can benefit from rich CMS features with a third-party CMS, including managing your content in multiple languages. This allows you to cater to customers’ different languages in the regions you serve.
|
||||
|
||||
Medusa provides an official Contentful plugin and a community Strapi plugin. You can also create a CMS plugin that integrates with your preferred CMS platform to provide multi-lingual features.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/cms',
|
||||
label: 'CMS Plugins',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about available CMS plugins for the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/plugins/create',
|
||||
label: 'How to Create a Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a plugin for the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Automatic Location Detection
|
||||
|
||||
When you sell across regions, it's essential to be able to detect the customer's region and provide them with the products, prices, and content relevant to them without requiring actions from their side.
|
||||
|
||||
Medusa provides an IP Lookup plugin that lets you detect a customer's location and, ultimately, their region using [ipstack](https://ipstack.com/). You can also create a plugin that detects the location through a different logic.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/other/ip-lookup',
|
||||
label: 'IP Lookup Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to use the IP Lookup plugin in your Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/plugins/create',
|
||||
label: 'How to Create a Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a plugin for the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Features and Development Resources
|
||||
|
||||
Medusa provides other essential commerce features and development resources to help you build your multi-region store.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/overview',
|
||||
label: 'Commerce Modules',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the available commerce features and modules in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/overview',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to customize your Medusa backend for your use case.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Omnichannel Commerce
|
||||
|
||||
This document guides you through the different documentation resources that will help you build omnichannel commerce with Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
Merchants selling across different channels need an efficient way to manage their commerce data and operations across these channels. Omnichannel commerce solves this problem by allowing merchants to support multiple channels through a single system while maintaining layers of separation.
|
||||
|
||||
Omnichannel commerce also provides customers a seamless shopping experience, regardless of where they’re shopping. Whether they’re buying your products from your online store, a marketplace like Amazon, or through social media, you should provide them with a good experience and handle orders consistently.
|
||||
|
||||
Medusa’s headless backend facilitates building omnichannel commerce, as your backend and storefront aren’t tightly coupled. You can also utilize plugins and Medusa’s sales channels feature to expand your business into other avenues like marketplaces and social commerce.
|
||||
|
||||
---
|
||||
|
||||
## Create Multiple Storefronts with One Backend
|
||||
|
||||
You’ll likely build multiple webshops or mobile apps when creating omnichannel commerce. All these storefronts should be able to provide your customers with a similar experience and allow them to browse products and place orders.
|
||||
|
||||
Medusa’s headless backend allows all storefronts to interact with Store REST APIs to provide the same commerce functionalities. This separation also allows you to choose your tech stack for the different storefronts you’re creating.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/fundamentals/architecture-overview',
|
||||
label: 'Medusa’s Architecture',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about Medusa\'s architecture and its ecosystem.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/store',
|
||||
label: 'Store REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available Store REST APIs in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Integrate with Marketplaces and Social Commerce
|
||||
|
||||
Businesses are no longer bound to sell in their stores. They can reach their customers through their different shopping channels.
|
||||
|
||||
One example is marketplaces like Amazon. Customers searching through Amazon to find products are inadvertently searching through many third-party stores connected to Amazon’s marketplace.
|
||||
|
||||
With Medusa, you can use the Sales Channels feature to set different product availability across sales channels. You can then integrate with Amazon’s seller program and use their APIs to push your products on Amazon. This integration can be achieved through a custom plugin you create and install on your Medusa backend.
|
||||
|
||||
Another channel that attracts customer sales is social media. Customers browsing a social media app can now find products and buy them. With an approach similar to what was mentioned above, you can create a plugin in your Medusa backend that integrates with social media apps to show your products and sell them to customers on the app.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/sales-channels/overview',
|
||||
label: 'Sales Channels',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Sales Channel features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/plugins/create',
|
||||
label: 'Create a Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a plugin.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Optimize Customer Experience
|
||||
|
||||
With Medusa’s modular architecture, businesses can focus on bringing their brands to life without restrictions.
|
||||
|
||||
You can implement the customer journey and design for your storefronts that leads to the best customer experience. The backend does not impose any restrictions on how the frontend is built.
|
||||
|
||||
Medusa’s architecture also makes it easier to integrate any third-party services necessary to provide a better customer experience with a plugin. This plugin’s functionality can be accessible to the storefronts connected to the Medusa backend.
|
||||
|
||||
For example, if you’ve integrated a search plugin like Algolia in the Medusa backend, the storefronts can utilize it through the Search Products endpoint. Another example is installing the Stripe payment plugin on the backend and using it in your storefronts to make payments before placing an order.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/plugins/create',
|
||||
label: 'Create a Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a plugin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://medusajs.com/plugins/',
|
||||
label: 'Plugins Library',
|
||||
customProps: {
|
||||
icon: Icons['bolt-solid'],
|
||||
description: 'Check out available community plugins.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your omnichannel development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -0,0 +1,223 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Order Management System (OMS)
|
||||
|
||||
This document guides you through Medusa's different features and resources to use it as an order management system (OMS).
|
||||
|
||||
## Overview
|
||||
|
||||
When you build or integrate an OMS, you face certain challenges, such as accepting orders from different sales channels, tracking inventory across the sales channels, and integrating third-party fulfillment and payment providers with the OMS.
|
||||
|
||||
Medusa provides the building blocks that allow you to integrate it as an OMS within a larger commerce ecosystem. Its commerce features and modular architecture allow businesses to accept orders from any sales channel, benefit from multi-warehouse inventory features, and integrate third-party services for fulfillment, payment, and more.
|
||||
|
||||
:::tip
|
||||
|
||||
Recommended read: [How Siam Makro used Medusa an OMS](https://medusajs.com/blog/makro-omnichannel-order-orchestration/).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Source Orders into Medusa
|
||||
|
||||
Orders from different sales channels in your commerce ecosystem must all route their orders into the OMS.
|
||||
|
||||

|
||||
|
||||
Medusa's [Store REST APIs](https://docs.medusajs.com/api/store) let you integrate a checkout experience in any storefront. Alternatively, you can use Medusa's [Draft Order APIs](https://docs.medusajs.com/api/admin#draft-orders) to place an order without direct involvement from the customer, such as when placing an order through a POS.
|
||||
|
||||
You can implement customizations in your backend if you accept orders through a third-party checkout system and need more flexibility over adding orders to Medusa.
|
||||
|
||||
You can add support for importing orders into Medusa through a custom endpoint that allows batch-inserting orders. Alternatively, you can create a scheduled job that runs at a specified interval and imports orders from an external service.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/store#carts',
|
||||
label: 'Store REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to use the Store REST APIs to create an order.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/create',
|
||||
label: 'Create Endpoint',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a custom endpoint in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/create',
|
||||
label: 'Create Scheduled Jobs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a scheduled job in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Route Orders to Third-party Fulfillment Services
|
||||
|
||||
You can integrate third-party fulfillment providers with Medusa by creating a fulfillment service class or using a fulfillment plugin.
|
||||
|
||||
Medusa uses the fulfillment service whenever a fulfillment action is performed, such as when a fulfillment is created for items in an order. The service's methods interact with the third-party provider to handle the desired fulfillment actions.
|
||||
|
||||

|
||||
|
||||
In addition, Medusa has an event bus that allows you to listen to events and perform a task asynchronously when that event is triggered. So, you can listen to fulfillment-related events, such as the `order.fulfillment_created` event, and handle that event in the subscribed handler method.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
|
||||
label: 'Create a Fulfillment Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a fulfillment provider in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/admin#draft-orders',
|
||||
label: 'Events',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the event bus and how to listen to events.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Process Payment with Third-Party Providers
|
||||
|
||||
Like fulfillment services, you can integrate third-party payment providers with Medusa by creating a payment processor or using payment plugins.
|
||||
|
||||
When a payment action occurs, such as capturing payment, Medusa uses the integrated payment provider to perform these actions. Medusa also emits payment-related events, such as `order.payment_captured`, that can be handled by a subscriber.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/payment',
|
||||
label: 'Payment Plugins',
|
||||
customProps: {
|
||||
icon: Icons['bolt-solid'],
|
||||
description: 'Check out available official payment plugins.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create a Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a payment processor.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Track Inventory Across Sales Channels
|
||||
|
||||
Medusa's multi-warehouse and sales channel features allow merchants to track inventory levels tied to sales channels across stock locations. When an order is placed, the item's quantity is reserved from the stock location associated with the order's sales channel. Once the item is fulfilled, the reserved quantity is deducted from the item's inventory quantity.
|
||||
|
||||
In addition, Medusa's inventory and stock location modules that power its multi-warehouse features can be replaced entirely with a custom implementation. You can then take control of how inventory functionalities are implemented in Medusa.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/multiwarehouse/overview',
|
||||
label: 'Multi-warehouse',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Multi-warehouse architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/sales-channels/overview',
|
||||
label: 'Sales Channels',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Sales Channel architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/plugins/create',
|
||||
label: 'Create a Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a plugin that can be installed in a Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Handle Returns, Exchanges, and Edits
|
||||
|
||||
In Medusa, items in an order can be returned or exchanged; they can be created by the merchant or requested by the customer. A merchant can also edit an order to add, update, or delete items.
|
||||
|
||||
When changes are made to an order by any of the mentioned actions, the changes are reflected on the order's totals and associated inventory. The integrated fulfillment and payment providers are used if fulfillment or payment actions are required, such as fulfilling exchanged items.
|
||||
|
||||
Medusa also emits events related to these actions, such as `order.return_requested`. So, you can listen to these events and perform asynchronous actions, such as communicating with third-party services.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/returns',
|
||||
label: 'Order Returns',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Return architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/swaps',
|
||||
label: 'Exchanges (Swaps)',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Exchange or Swap architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders#order-edits',
|
||||
label: 'Order Edits',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Edit feature and how it works.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/events-list',
|
||||
label: 'Event Reference',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out triggered events in Medusa and their payloads.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development and Commerce Features
|
||||
|
||||
Medusa provides more commerce features that you can learn about in the [Commerce Modules](../modules/overview.mdx) section of this documentation.
|
||||
|
||||
Medusa is also completely customizable, and you can learn more about customizing it in the [Medusa Development](../development/overview.mdx) section of this documentation.
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# Personalized Products
|
||||
|
||||
This document guides you through the different documentation resources to help you build personalized products with Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
Personalized products are products that customers can customize based on their need. For example, they can upload an image to print on a shirt or provide a message to include in a letter.
|
||||
|
||||
Medusa’s customizable architecture allows you to customize its entities or create your own to implement and store personalized products. Also, as the Medusa backend is headless, you have freedom in how you choose to implement the storefront. This is essential for ecommerce stores that provide personalized products, as you typically build a unique experience around your products.
|
||||
|
||||
---
|
||||
|
||||
## Store Personalized Data
|
||||
|
||||
Most of the entities in Medusa’s core include a `metadata` attribute. This attribute helps store custom data in the core entities.
|
||||
|
||||
The `Product` entity represents the main product, whereas the `ProductVariant` is the different saleable options of that product. For example, a shirt is a `Product`, and each different color of the shirt is the `ProductVariant`. The `LineItem` entity is the product variant added to the cart.
|
||||
|
||||
So, you can use the `metadata` attribute of the `LineItem` entity to store the customer’s personalization. Optionally, you can use the `metadata` attribute in the `Product` or `ProductVariant` to store the expected format of personalized data. This depends on your use case and how basic or complex it is.
|
||||
|
||||
For example, if you’re asking customers to enter a message to put in a letter they’re purchasing, you can use the `metadata` attribute of the `LineItem` entity to set the personalized information entered by the customer.
|
||||
|
||||
Note that two Line Items in the cart having different `metadata` attributes are not considered the same item. So, each Line Item is managed separately and can have its own quantity.
|
||||
|
||||
In more complex cases, you can extend entities from the core, such as the `Product` entity, to add more attributes. You can also create new custom entities to hold your personalized data and logic.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/overview#metadata-attribute',
|
||||
label: 'Metadata Attribute',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the metadata attribute and how to use it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/create',
|
||||
label: 'Create an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an entity in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/extend-entity',
|
||||
label: 'Extend an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend an entity in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Build a Custom Storefront
|
||||
|
||||
Medusa provides a headless backend that can be accessed through REST APIs. So, there are no restrictions on what language or framework you use to build the storefront or what design or experience you provide customers.
|
||||
|
||||
You can build a unique experience around your products that focuses on the customer’s personalization capabilities.
|
||||
|
||||
Medusa provides a Next.js storefront starter with basic ecommerce functionalities that can be used and modified. You can also build your own storefront by using Medusa’s client libraries or REST APIs to communicate with the backend from the storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Next.js Starter',
|
||||
customProps: {
|
||||
icon: Icons['nextjs'],
|
||||
description: 'Learn about the Next.js starter and how to install it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Build Your Own Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Follow this roadmap to learn how to create a storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Pass Personalized Data to the Order
|
||||
|
||||
If you followed the basic approach of using the `metadata` attribute to store the personalized data, you can pass the personalization data when you add an item to the cart in the storefront using the [Add a Line Item](https://docs.medusajs.com/api/store#carts_postcartscartlineitems) endpoint. This endpoint accepts a `metadata` request body parameter that will be stored in the created Line Item’s `metadata` attribute.
|
||||
|
||||
In the case that you’ve created a custom entity or extended a core entity, you can create a custom endpoint that handles saving the personalization data. You can then call that endpoint from the storefront before or after adding the item to the cart.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/store#carts_postcartscartlineitems',
|
||||
label: 'Add a Line Item Endpoint',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the expected request parameters and response.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/create',
|
||||
label: 'Create Endpoint',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an endpoint in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Access Personalized Data in the Order
|
||||
|
||||
If you stored the personalized data in the `metadata` of the Line Items, those same Line Items are associated with the placed order. So, by expanding the `items` relation on the `Order` entity, you can retrieve the `metadata` attribute of the Line Items.
|
||||
|
||||
In the case that you’ve created a custom entity or extended a core entity, you can create a custom endpoint that handles retrieving the personalization data. If the entity you’ve created or customized is associated with the Order entity, you can alternatively expand it similarly to the `items` relation.
|
||||
|
||||
If you want to show the personalized data in the Medusa admin, you can extend the Medusa admin to add a widget, a UI route, or a setting page and show the personalized data.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/store#expanding-fields',
|
||||
label: 'Expanding Relations in API Requests',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to expand relations in API requests.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/services/create-service#pagination-filtering-and-relations',
|
||||
label: 'Expanding Relations in Services',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to expand relations in services.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/widgets',
|
||||
label: 'Extending Medusa Admin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend the Medusa admin with widgets and more.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Fulfill Personalized Products in Orders
|
||||
|
||||
Once a customer places an order, the `order.placed` event is emitted in the backend. You can listen to this event with a Subscriber to access the order’s details and fulfill its personalized products.
|
||||
|
||||
For example, if the customer personalizes a shirt to include an image or message, you can listen to the `order.placed` event to send their request to the printing fulfillment machine or service.
|
||||
|
||||
You can also listen to other [Order-related events](../development/events/events-list.md#order-events) to perform this action at a different point if necessary, such as when the `order.fulfillment_created` is triggered.
|
||||
|
||||
Alternatively, you can create a fulfillment service that integrates a third-party service or mechanism to fulfill the personalized product. This is useful if you want the fulfillment of personalized products to be embedded into Medusa’s existing order fulfillment.
|
||||
|
||||
- Create a Subscriber
|
||||
- Create a Fulfillment Service
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber and listen to events.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
|
||||
label: 'Create a Fulfillment Service',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a fulfillment provider in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your personalized products development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -0,0 +1,295 @@
|
||||
---
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import Icons from '@theme/Icon';
|
||||
|
||||
# POS
|
||||
|
||||
This document guides you through Medusa's different features and resources to create a point-of-sale (POS) system.
|
||||
|
||||
## Overview
|
||||
|
||||
Building a POS system on top of an ecommerce engine introduces challenges related to the tech stack used, data sync across channels, and feature availability relevant to offline sales in a POS, not just online sales.
|
||||
|
||||
Medusa's modular architecture solves these challenges. Any frontend can utilize Medusa's commerce features through its REST APIs. Medusa's commerce features include multi-warehouse and sales channel features that facilitate integrating a POS system.
|
||||
|
||||
:::tip
|
||||
|
||||
Recommended read: [How Tekla built a POS system with Medusa](https://medusajs.com/blog/tekla-agilo-pos-case/).
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Freedom in Choosing Your POS Tech Stack
|
||||
|
||||
When you build a POS system, you must choose which programming framework, language, or tool you want to use.
|
||||
|
||||
Medusa's modular architecture removes any restrictions you may have while making this choice. Any client or front end can connect to the Medusa backend using its headless REST APIs.
|
||||
|
||||

|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/fundamentals/architecture-overview',
|
||||
label: 'Medusa’s Architecture',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about Medusa\'s architecture and its ecosystem.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://docs.medusajs.com/api/admin',
|
||||
label: 'Admin REST APIs',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available Admin REST APIs in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/js-client/overview',
|
||||
label: 'JavaScript Client',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the JavaScript client and to use it.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Integrate a Barcode Scanner
|
||||
|
||||
POS systems make the checkout process smoother by integrating a barcode scanner. Merchants can scan a product by its barcode to check its details or add it to the customer's purchase.
|
||||
|
||||
Medusa’s [Product Variant entity](../references/entities/classes/ProductVariant.md) includes the necessary attributes to implement this integration, mainly the `barcode` attribute. Other notable attributes include `ean`, `upc`, and `hs_code`, among others.
|
||||
|
||||
To search through product variants by their barcode, you can create a custom endpoint and call it within your POS.
|
||||
|
||||

|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/products',
|
||||
label: 'Products',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Product architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/create',
|
||||
label: 'Create Endpoint',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an endpoint in the Medusa backend.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
Example: Search Products By Barcode Endpoint
|
||||
</summary>
|
||||
|
||||
Here’s an example of creating a custom endpoint that searches product variants by a barcode:
|
||||
|
||||
```ts title=src/api/index.ts
|
||||
import { Request, Response, Router } from "express"
|
||||
import cors from "cors"
|
||||
import {
|
||||
ConfigModule,
|
||||
errorHandler,
|
||||
ProductVariantService,
|
||||
wrapHandler,
|
||||
} from "@medusajs/medusa"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
|
||||
export default (rootDirectory: string): Router | Router[] => {
|
||||
// Read currently-loaded medusa config
|
||||
const { configModule } = getConfigFile<ConfigModule>(
|
||||
rootDirectory,
|
||||
"medusa-config"
|
||||
)
|
||||
const { projectConfig } = configModule
|
||||
|
||||
// Set up our CORS options objects, based on config
|
||||
const storeCorsOptions = {
|
||||
origin: projectConfig.store_cors.split(","),
|
||||
credentials: true,
|
||||
}
|
||||
|
||||
// Set up express router
|
||||
const router = Router()
|
||||
|
||||
router.get(
|
||||
"/pos/search-barcode",
|
||||
cors(storeCorsOptions),
|
||||
wrapHandler(
|
||||
async (req: Request, res: Response) => {
|
||||
const barcode = (req.query.barcode as string) || ""
|
||||
if (!barcode) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
"Barcode is required"
|
||||
)
|
||||
}
|
||||
// get product service
|
||||
const productVariantService = req.scope.resolve<
|
||||
ProductVariantService
|
||||
>("productVariantService")
|
||||
|
||||
// retrieve product variants by barcode
|
||||
const productVariants = await productVariantService
|
||||
.list({
|
||||
barcode,
|
||||
})
|
||||
|
||||
res.json({
|
||||
product_variants: productVariants,
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
router.use(errorHandler())
|
||||
|
||||
return router
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Access Accurate Inventory Details
|
||||
|
||||
As you manage an online and offline store, it's essential to separate inventory quantity across different locations.
|
||||
|
||||
Using Medusa's multi-warehouse features, merchants can manage the inventory items and their availability across locations and sales channels. They can create a sales channel for their online store and a sales channel for their POS system, then manage the inventory quantity of product variants in each channel.
|
||||
|
||||

|
||||
|
||||
This also opens the door for other business opportunities, such as an endless aisle experience. Suppose a product isn't available in-store but is available in different warehouses. In that case, you can allow customers to purchase that item in-store and deliver it to their address.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/multiwarehouse/overview',
|
||||
label: 'Multi-Warehouse',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Multi-warehouse architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/sales-channels/overview',
|
||||
label: 'Sales Channels',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Sales Channel architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/multiwarehouse/admin/manage-inventory-items',
|
||||
label: 'Manage Inventory Items',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to use the Admin REST APIs to manage inventory items.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Build an Omni-channel Customer Experience
|
||||
|
||||
Using Medusa's Customer APIs and features, you can retrieve a customer's details from the backend and place an order on the POS under their account. The customer can then view their order details on their online profile as if they had placed the order online.
|
||||
|
||||
In addition, using Medusa's dynamic discounts feature, store operators can create discounts on the fly for customers using the POS system and apply them to their orders. You can also extend Medusa to provide features for a better customer experience, such as a rewards system or loyalty points.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/customers/overview',
|
||||
label: 'Customers',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Customer architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/discounts/overview',
|
||||
label: 'Discounts',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Discount architecture and features.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Accept Payment, Place Order, and Use RMA Features
|
||||
|
||||
Medusa's architecture allows you to integrate any third-party payment processor for your POS and online storefront. For example, you can integrate [Stripe Terminal](https://stripe.com/terminal) to accept in-store payments.
|
||||
|
||||
Once you accept the payment, you can place an order in the POS system using the [Draft Order APIs](https://docs.medusajs.com/api/admin#draft-orders). Draft orders provide similar features to an online checkout experience, including discounts, payment processing, and more.
|
||||
|
||||
Then, merchants can view all orders coming from different sales channels using the Medusa admin dashboard. This keeps logistics and order handling consistent and allows businesses to provide return and exchange features to online and in-store customers.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create a Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a payment processor.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/draft-orders',
|
||||
label: 'Draft Orders',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Draft Order architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/returns',
|
||||
label: 'Order Returns',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Return architecture and features.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/orders/swaps',
|
||||
label: 'Order Swaps',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn about the Order Swap architecture and features.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your POS development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -0,0 +1,205 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# Build Subscription-based Purchases
|
||||
|
||||
This document guides you through the different documentation resources that will help you build subscription-based purchasing in Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
Subscription-based purchase allows customers to purchase products for a specified period, and the payment and fulfillment is processed within a regular interval in that period.
|
||||
|
||||
For example, a customer can purchase a book subscription box for a period of three months. Each month, the payment will be captured for that order and, if the payment is successful, the fulfillment will be processed.
|
||||
|
||||
:::tip
|
||||
|
||||
Recommended read: [How Goodchef built subscription-based purchases with Medusa](https://medusajs.com/blog/goodchef-webbers-powering-subscriptions-with-medusas-commerce-modules/).
|
||||
|
||||
:::
|
||||
|
||||
<LearningPath pathName="subscriptions" />
|
||||
|
||||
---
|
||||
|
||||
## Save Subscription Details in the Database
|
||||
|
||||
Subscriptions have details related to the subscription interval, subscription period, and more.
|
||||
|
||||
Based on the approach you choose to implement the subscription logic (which is discussed in the next section), you might need to store different data in your backend.
|
||||
|
||||
If you want to store the subscription details in a new table in the database, you can do that by creating an entity. If you want to extend an existing entity in Medusa's core, such as the `Order` entity, to add details related to the subscription, you can extend an entity.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/create',
|
||||
label: "Create an Entity",
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an entity in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/extend-entity',
|
||||
label: 'Extend an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend an entity in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Decide on Subscription Approach
|
||||
|
||||
There are different ways to implement subscriptions in your Medusa backend. This document discusses two options: using Stripe subscriptions, or implementing subscriptions logic within the backend, independent of a specific payment provider.
|
||||
|
||||
### Option 1: Using Stripe Subscriptions
|
||||
|
||||
Stripe provides a [subscription payments](https://stripe.com/docs/billing/subscriptions/overview) that allows you to authorize payment on a subscription basis within Stripe. Stripe then handles checking for recurring payments and capturing payment at the specified interval.
|
||||
|
||||
This approach allows you to delegate the complications of implementing the subscription logic to Stripe, but does not support using other payment providers.
|
||||
|
||||
Medusa provides a Stripe plugin, however, it doesn't handle subscriptions. You can either use that plugin to add the subscription feature on top of it, or create a custom Stripe Subscription payment provider.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://github.com/medusajs/medusa/tree/develop/packages/medusa-payment-stripe',
|
||||
label: "Use Medusa's Stripe Plugin",
|
||||
customProps: {
|
||||
icon: Icons['github'],
|
||||
description: "Check out Medusa's stripe plugin to build subscription on top of it.",
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create a Stripe Subscription payment processor from scratch.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Option 2: Implement Subscription Logic
|
||||
|
||||
By implementing the subscription logic within your backend, you can have full control over the subscription logic. You'll also be independent of payment providers, allowing you to provide customers with more than payment provider option.
|
||||
|
||||
Implementing the logic depends on your use case, but you'll mainly need to do two things:
|
||||
|
||||
1. Perform an action when an order is placed, such as saving subscription details. This can be done using subscribers, which register handler methods to be triggered when an event is emitted. When an order is placed, the `order.placed` event is emitted.
|
||||
2. Check daily for subscriptions that need renewal. This can be done using a scheduled job, which is a cron job that can be executed on a defined interval. Within that job, you can define your renewal logic.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/create',
|
||||
label: 'Create a Scheduled Job',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a scheduled job in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Customize Admin
|
||||
|
||||
As you add subscription features to your store, you'll most likely need to customize the admin to provide an interface to manage these features.
|
||||
|
||||
Medusa's [admin plugin](../admin/quickstart.mdx) can be extended to add widgets or new blocks to existing pages, add UI routes to add new pages, or add setting pages.
|
||||
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/widgets',
|
||||
label: 'Create Admin Widget',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add widgets into existing admin pages.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/routes',
|
||||
label: 'Create Admin UI Routes',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new pages to your Medusa admin.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/setting-pages',
|
||||
label: 'Create Admin Setting Page',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to add new page to the Medusa admin settings.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Build a Storefront
|
||||
|
||||
Medusa provides a Next.js Starter Template that you can use with Medusa. Since you've customized your Medusa project, you'll need to either customize the existing Next.js Starter Template, or create a custom storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Option 1: Use Next.js Starter Template',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Install the Next.js Starter Template to customize it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Option 2: Build Custom Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Find useful resources to build your own storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy Backend
|
||||
|
||||
Our documentation includes deployment guides for a basic Medusa backend. You should be able to follow it to deploy your customized backend, as well.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your subscription-based backend to different hosting providers.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
Reference in new issue
Block a user