docs: updated marketplace recipe + added example (#8061)

- Moved recipes into its own section of the learning resources
- Updated the marketplace recipe overview
- Added an example implementation of the marketplace recipe

Closes DOCS-791
This commit is contained in:
Shahed Nasser
2024-07-11 15:56:41 +00:00
committed by GitHub
parent b5a44ef6b1
commit 78f49286d0
6 changed files with 1467 additions and 730 deletions
File diff suppressed because it is too large Load Diff
@@ -8,17 +8,11 @@ export const metadata = {
This recipe provides the general steps to implement a marketplace in your Medusa application.
<Note type="soon" title="In Development">
This recipe is a work in progress, as some features are not ready yet in Medusa V2.
</Note>
## 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.
In Medusa, you can create a Marketplace Module that establishes the relations between a store, users, products, and orders. Using these relations, you can implement different stores for different users, with products and orders associated with that store.
In Medusa, you can create a Marketplace Module that implements custom data models, such as vendors or sellers, and link those data models to existing ones such as products and orders. You also expose custom features using API routes, and implement complex flows using workflows.
<Note title="Related use-case">
@@ -28,783 +22,107 @@ In Medusa, you can create a Marketplace Module that establishes the relations be
---
## Create Relationships Between Data Models
## Create Custom Module with Data Models
In a marketplace, an admin user has a store where they manage their products and orders, among other details.
In a marketplace, a business or a vendor has a user, and they can use that user to authenticate and manage the vendor's data.
Create a Marketplace Module that holds and manages these relationships.
<Note type="soon">
Module Relationships is coming soon.
</Note>
You can create a marketplace module that implements data models for vendors, their admins, anything else that fits your use case.
<CardList items={[
{
href: "!docs!/basics/modules-and-services",
title: "Create a Module",
text: "Learn how to create a module",
text: "Learn how to create a module.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
{
href: "!docs!/advanced-development/modules/module-relationships",
title: "Module Relationships",
text: "Create relationships between modules.",
href: "!docs!/basics/data-models",
title: "Create Data Models",
text: "Create data models in the module.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
]} />
<Details summaryContent="Example">
In this section, youll create a Marketplace Module with the necessary relationships and functionalities in the main service.
Start by creating the directory `src/modules/marketplace`.
Then, create the file `src/modules/marketplace/models/store-user.ts` with the following content:
```ts title="src/modules/marketplace/models/store-user.ts"
import { model } from "@medusajs/utils"
const StoreUser = model.define("store_user", {
id: model.id().primaryKey(),
store_id: model.text(),
user_id: model.text(),
})
export default StoreUser
```
This creates a `StoreUser` data model with the `store_id` and `user_id` properties.
{/* These properties will be used later to establish relationships to the Store and User modules. */}
Next, create the file `src/modules/marketplace/models/store-product.ts` with the following content:
```ts title="src/modules/marketplace/models/store-product.ts"
import { model } from "@medusajs/utils"
const StoreProduct = model.define("store_product", {
id: model.id().primaryKey(),
store_id: model.text(),
product_id: model.text(),
})
export default StoreProduct
```
This creates a `StoreProduct` data model with the `store_id` and `product_id` properties.
{/* These properties will be used later to establish relationships to the Store and Product modules. */}
Finally, create the file `src/modules/marketplace/models/store-order.ts` with the following content:
```ts title="src/modules/marketplace/models/store-order.ts"
import { model } from "@medusajs/utils"
const StoreOrder = model.define("store_order", {
id: model.id().primaryKey(),
store_id: model.text(),
order_id: model.text(),
parent_order_id: model.text(),
})
export default StoreOrder
```
This creates a `StoreOrder` data model with the `store_id`, `order_id`, and `parent_order_id` properties.
{/* The `store_id` and `order_id` properties will be used to establish relationships to the Store and Order modules. Youll learn about the use of `parent_order_id` in a later section. */}
To reflect these changes on the database, create the migration `src/modules/marketplace/migrations/Migration20240514143248.ts` with the following content:
```ts title="src/modules/marketplace/migrations/Migration20240514143248.ts"
import { Migration } from "@mikro-orm/migrations"
export class Migration20240514143248 extends Migration {
async up(): Promise<void> {
this.addSql("create table if not exists \"store_order\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"order_id\" text not null, \"parent_order_id\" text not null, constraint \"store_order_pkey\" primary key (\"id\"));")
this.addSql("create table if not exists \"store_product\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"product_id\" text not null, constraint \"store_product_pkey\" primary key (\"id\"));")
this.addSql("create table if not exists \"store_user\" (\"id\" varchar(255) not null, \"store_id\" text not null, \"user_id\" text not null, constraint \"store_user_pkey\" primary key (\"id\"));")
}
async down(): Promise<void> {
this.addSql("drop table if exists \"store_order\" cascade;")
this.addSql("drop table if exists \"store_product\" cascade;")
this.addSql("drop table if exists \"store_user\" cascade;")
}
}
```
Youll run the migration after registering the module in the Medusa configurations.
Then, create the modules main service at `src/modules/marketplace/service.ts` with the following content:
export const mainServiceHighlights = [
["6", "MedusaService", "Extends the service factory to generate data management features."]
]
```ts title="src/modules/marketplace/service.ts" highlights={mainServiceHighlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
import { MedusaService } from "@medusajs/utils"
import StoreUser from "./models/store-user"
import StoreProduct from "./models/store-product"
import StoreOrder from "./models/store-order"
class MarketplaceModuleService extends MedusaService({
StoreUser,
StoreProduct,
StoreOrder,
}){
// TODO add custom methods
}
export default MarketplaceModuleService
```
The modules main service extends the service factory to generate data management features for the `StoreUser`, `StoreProduct`, and `StoreOrder` data models.
Finally, create the module definition at `src/modules/marketplace/index.ts` with the following content:
```ts title="src/modules/marketplace/index.ts"
import MarketplaceModuleService from "./service"
import { Module } from "@medusajs/utils"
export default Module("marketplace", {
service: MarketplaceModuleService,
})
```
To use the module, add it to the `modules` object in `medusa-config.js`:
```js title="medusa-config.js"
module.exports = defineConfig({
// ...
modules: {
marketplaceModuleService: {
resolve: "./modules/marketplace",
definition: {
isQueryable: true,
},
},
},
})
```
Then, run the migrations of the module:
```bash npm2yarn
npx medusa migrations run
```
</Details>
---
## Attach Users to Stores
## Define Module Links
To attach admin users to their own stores, create a subscriber that listens to the `user.created` event and attaches the user to the store.
Since a vendor has products, orders, and other models based on your use case, define module links between your module's data models and the commerce module's data models.
<Note type="soon">
- The `user.created` event is currently not emitted.
- Module Relationships is coming soon.
</Note>
For example, if you defined a vendor data model in a marketplace module, you can define a module link between the vendor and the Product Module's product data model.
<Card
href="!docs!/basics/events-and-subscribers"
title="Create a Subscriber"
text="Learn how to create a subscriber in Medusa."
href="!docs!/advanced-development/modules/module-links"
title="Define a Module Link"
text="Learn how to define a module link."
startIcon={<AcademicCapSolid />}
showLinkIcon={false}
/>
{/* <Details summaryContent="Example">
Create the file `src/subscribers/user-created.ts` with the following content:
export const userSubscriberHighlights = [
["13", "data", "The event data payload with the created user's ID."],
["27", "retrieveUser", "Retrieve the created user."],
["29", "createStores", "Create a store for that user using the Store Module."],
["33", "createStoreUsers", "Create a relationship between the user and the store by creating a `StoreUser` record."]
]
```ts title="src/subscribers/user-created.ts" highlights={userSubscriberHighlights} collapsibleLines="1-11" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/utils"
import {
IUserModuleService,
IStoreModuleService,
} from "@medusajs/types"
import MarketplaceModuleService from "../modules/marketplace/service"
export default async function userCreatedHandler({
data,
container,
}: SubscriberArgs<{ id: string }>) {
const { id } = "data" in data ? data.data : data
const userModuleService: IUserModuleService = container.resolve(
ModuleRegistrationName.USER
)
const storeModuleService: IStoreModuleService = container.resolve(
ModuleRegistrationName.STORE
)
const marketplaceModuleService: MarketplaceModuleService = container.resolve(
"marketplaceModuleService"
)
const user = await userModuleService.retrieveUser(id)
const store = await storeModuleService.createStores({
name: `${user.first_name}'s Store`,
})
const storeUser = await marketplaceModuleService.createStoreUsers({
store_id: store.id,
user_id: user.id,
})
console.log(`Created StoreUser ${storeUser.id}`)
}
export const config: SubscriberConfig = {
event: "user.created",
}
```
This adds a subscriber to the `user.created` event. In the subscriber, you:
- Retrieve the created user. The created users ID is passed in the events data payload.
- Create a store for that user using the Store Module.
- Create a relationship between the user and the store by creating a `StoreUser` record.
To test it out, use the `medusa user` command to create a user:
```bash npm2yarn
npx medusa user -e my-admin@medusa-test.com -p supersecret
```
At the end of the output, you should see the message `Created StoreUser {store_user_id}` where the `{store_user_id}` is the ID of the created `StoreUser`.
</Details> */}
---
## Attach Products to Stores
## Allow Vendor Admins to Authenticate
Similar to the previous section, to attach products to stores, create a subscriber that listens to the `product.created` event. In the subscriber, you attach the product to the store its created in.
If your marketplace module implements admins for sellers or vendors, you can create an actor type for it.
<Note type="soon">
- The `product.created` event is currently not emitted.
- Module Relationships is coming soon.
</Note>
Then, you guard custom API routes to only allow authenticated vendor admins.
<Card
href="!docs!/basics/events-and-subscribers"
title="Create a Subscriber"
text="Learn how to create a subscriber in Medusa."
href="/commerce-modules/auth/create-actor-type"
title="Create an Actor Type"
text="Learn how to create an actor type and authenticate it."
startIcon={<AcademicCapSolid />}
showLinkIcon={false}
/>
{/* <Details summaryContent="Example">
Create the file `src/subscribers/product-created.ts` with the following content:
export const productSubscriberHighlights = [
["24", "retrieveProduct", "Retrieve the created product."],
["26", "", "This subscriber requires the store ID to be set in `product.metadata.store_id`. If not, the subscriber ends execution."],
["30", "createStoreProducts", "Create a relationship between the product and the store by creating a `StoreProduct` record."]
]
```ts title="src/subscribers/product-created.ts" highlights={productSubscriberHighlights} collapsibleLines="1-10" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/utils"
import {
IProductModuleService,
} from "@medusajs/types"
import MarketplaceModuleService from "../modules/marketplace/service"
export default async function productCreateHandler({
data,
container,
}: SubscriberArgs<{ id: string }>) {
const { id } = "data" in data ? data.data : data
const productModuleService: IProductModuleService = container.resolve(
ModuleRegistrationName.PRODUCT
)
const marketplaceModuleService: MarketplaceModuleService = container.resolve(
"marketplaceModuleService"
)
const product = await productModuleService.retrieveProduct(id)
if (!product.metadata?.store_id) {
return
}
await marketplaceModuleService.createStoreProducts({
store_id: product.metadata.store_id as string,
product_id: id,
})
}
export const config: SubscriberConfig = {
event: "product.created",
}
```
This adds a subscriber to the `product.created` event. In the subscriber, you:
- Retrieve the created product.
- This subscriber requires the store ID to be set in `product.metadata.store_id`. If not, the subscriber ends execution.
- If the store ID is found, create a relationship between the product and the store by creating a `StoreProduct` record.
To test it out, start the Medusa application:
```bash npm2yarn
npm run dev
```
Then, send an authenticated `POST` request to `/admin/products`:
```bash
curl -X POST 'http://localhost:9000/admin/products' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer {jwt_token}' \
--data '{
"title": "My Shirt 13",
"metadata": {
"store_id": "store_01HXV74JCCAHA3F2X3EWZTZG5R"
}
}'
```
This returns the created product. In the next section, youll implement the API route to fetch the products of a store.
</Details> */}
---
## Retrieve Stores Products
## Create Vendor API Routes
To allow admin users to view their stores products, create an API route that uses the remote query to fetch the products based on the logged-in users store.
<Note type="soon">
Retrieving module relationship data using the remote query is coming soon.
</Note>
If you provide vendor or sellers with custom features, or a different way of managing products and orders, create API routes only accessible by vendors exposing your custom features.
<CardList items={[
{
href: "!docs!/basics/api-routes",
title: "API Routes",
title: "Create API Routes",
text: "Learn how to create an API Route in Medusa.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
{
href: "!docs!/advanced-development/modules/remote-query",
title: "Remote Query",
text: "Use the remote query to fetch data across modules.",
href: "!docs!/advanced-development/api-routes/protected-routes",
title: "Protect Routes",
text: "Learn how to guard routes to allow authenticated users only.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
]} />
{/* <Details summaryContent="Example">
Create the file `src/api/admin/marketplace/products/route.ts` with the following content:
export const productRoutesHighlights = [
["26", "storeUsers", "Retrieve the store of the logged-in user."],
["38", "query", "Build a query that retrieves the products of that store."],
["50", "remoteQuery", "Retrieve the products using remote query."]
]
```ts title="src/api/admin/marketplace/products/route.ts" highlights={productRoutesHighlights} collapsibleLines="1-13" expandButtonLabel="Show Imports"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { RemoteQueryFunction } from "@medusajs/modules-sdk"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
MedusaError,
} from "@medusajs/utils"
import MarketplaceModuleService
from "../../../../modules/marketplace/service"
export async function GET(
req: AuthenticatedMedusaRequest,
res: MedusaResponse
): Promise<void> {
const marketplaceModuleService: MarketplaceModuleService =
req.scope.resolve(
"marketplaceModuleService"
)
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
const storeUsers = await marketplaceModuleService
.listStoreUsers({
user_id: req.auth_context.actor_id,
})
if (!storeUsers.length) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
"This user doesn't have an associated store."
)
}
const query = remoteQueryObjectFromString({
entryPoint: "store_product",
fields: [
"product.*",
],
variables: {
filters: {
store_id: storeUsers[0].store_id,
},
},
})
const result = await remoteQuery(query)
res.json({
store_id: storeUsers[0].store_id,
products: result.map((data) => data.product),
})
}
```
This creates a `GET` API route at `/admin/marketplace/products`. In the API route, you:
- Retrieve the store of the logged-in user.
- Build a query that retrieves the products of that store.
- Retrieve the products using remote query and return them.
Next, create the file `src/api/middlewares.ts` with the following content:
```ts title="src/api/middlewares.ts"
import {
MiddlewaresConfig,
authenticate,
} from "@medusajs/medusa"
export const config: MiddlewaresConfig = {
routes: [
{
matcher: "/admin/marketplace*",
middlewares: [
authenticate(
"admin",
["session", "bearer", "api-key"]
),
],
},
],
}
```
This ensures that only authenticated admin users can access your API route.
To test it out, start the Medusa application. Then, send a `GET` request to `/admin/marketplace/products`:
```bash
curl 'localhost:9000/admin/marketplace/products' \
-H 'Authorization: Bearer {jwt_token}'
```
This will return the product you created in the previous section, if the `{jwt_token}` belongs to the user of the same store ID.
</Details> */}
---
## Split Orders Based on Stores
## Split Orders Based on Vendors
An order may contain items from different stores. To ensure that users can only view and manage their orders, create a subscriber that listens to the `order.placed` event and handles splitting the order into multiple orders based on the items stores.
If your use case allows a customer's orders to have items from different vendors, you can override the [Complete Cart API route](https://docs.medusajs.com/v2/api/store#carts_postcartsidcomplete) to change how the order should be created.
<Note type="soon">
The `order.placed` event is still not emitted in Medusa V2.
</Note>
If your flow requires different steps, such as creating a parent order then creating a child order, create a workflow and execute it from the API route.
<Card
href="!docs!/basics/events-and-subscribers"
title="Create a Subscriber"
text="Learn how to create a subscriber in Medusa."
href="!docs!/basics/workflows"
title="Create a Workflow"
text="Learn how to create a workflow in Medusa."
startIcon={<AcademicCapSolid />}
showLinkIcon={false}
/>
{/* <Details summaryContent="Example">
Create the file `src/subscribers/order-created.ts` with the following content:
export const orderSubscriberHighlights = [
["35", "", "Loop over the created orders items."],
["57", "", "Group the items by their store ID."],
["72", "createStoreOrders", "If the items have the same store ID, then associate the created order with the store."],
["88", "createStoreOrders", "If there are items from more than one store in the order, create child orders and associate each of them with the store."],
["91", "parent_order_id", "The `parent_order_id` property in the `StoreOrder` data model points to the original order."]
]
```ts title="src/subscribers/order-created.ts" highlights={orderSubscriberHighlights} collapsibleLines="1-13" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,
} from "@medusajs/medusa"
import { ModuleRegistrationName } from "@medusajs/utils"
import {
IOrderModuleService,
CreateOrderDTO,
} from "@medusajs/types"
import MarketplaceModuleService
from "../modules/marketplace/service"
import { createOrdersWorkflow } from "@medusajs/core-flows"
export default async function orderCreatedHandler({
data,
container,
}: SubscriberArgs<{ id: string }>) {
const { id } = "data" in data ? data.data : data
const orderModuleService: IOrderModuleService =
container.resolve(
ModuleRegistrationName.ORDER
)
const marketplaceModuleService: MarketplaceModuleService =
container.resolve(
"marketplaceModuleService"
)
const storeToOrders: Record<string, CreateOrderDTO> = {}
const order = await orderModuleService.retrieveOrder(id, {
relations: ["items"],
})
await Promise.all(order.items?.map(async (item) => {
const storeProduct = await marketplaceModuleService
.listStoreProducts({
product_id: item.product_id,
})
if (!storeProduct.length) {
return
}
const storeId = storeProduct[0].store_id
if (!storeToOrders[storeId]) {
const { id, ...orderDetails } = order
storeToOrders[storeId] = {
...orderDetails,
items: [],
}
}
const { id, ...itemDetails } = item
storeToOrders[storeId].items.push(itemDetails)
}))
const storeToOrdersKeys = Object.keys(storeToOrders)
if (!storeToOrdersKeys.length) {
return
}
if (
storeToOrdersKeys.length === 1 &&
storeToOrders[0].items.length === order.items.length
) {
// The order is composed of items from one store, so
// associate the order as-is with the store.
await marketplaceModuleService.createStoreOrders({
store_id: storeToOrdersKeys[0],
order_id: order.id,
})
return
}
// create store orders for each child order
await Promise.all(
storeToOrdersKeys.map(async (storeId) => {
const { result } = await createOrdersWorkflow(container)
.run({
input: storeToOrders[storeId],
})
await marketplaceModuleService.createStoreOrders({
store_id: storeId,
order_id: result.id,
parent_order_id: order.id,
})
})
)
}
export const config: SubscriberConfig = {
event: "order.placed",
}
```
This adds a subscriber to the `order.placed` event. In the subscriber, you:
- Loop over the created orders items.
- Group the items by their store ID.
- If the items have the same store ID, then associate the created order with the store.
- If there are items from more than one store in the order, create child orders and associate each of them with the store. Here, you use the `parent_order_id` property in the `StoreOrder` data model to point to the original order.
To test this out, create an order in your store. That will run the subscriber and create the child orders.
The next section covers how to retrieve the stores orders.
</Details> */}
---
## Retrieve Stores Orders
Similar to products, to allow admin users to view their stores orders, create an API route that uses the remote query to fetch the orders based on the logged-in users store.
<Note type="soon">
Retrieving module relationship data using the remote query is coming soon.
</Note>
<CardList items={[
{
href: "!docs!/basics/api-routes",
title: "API Routes",
text: "Learn how to create an API Route in Medusa.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
{
href: "!docs!/advanced-development/modules/remote-query",
title: "Remote Query",
text: "Use the remote query to fetch data across modules.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
]} />
{/* <Details summaryContent="Example">
Create the file `src/api/admin/marketplace/orders/route.ts` with the following content:
export const orderRoutesHighlights = [
["25", "", "Retrieve the store of the logged-in user."],
["29", "", "Build a query that retrieves the orders of that store."],
["41", "", "Retrieve the orders using remote query."]
]
```ts title="src/api/admin/marketplace/orders/route.ts" highlights={orderRoutesHighlights} collapsibleLines="1-12" expandButtonLabel="Show Imports"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import { RemoteQueryFunction } from "@medusajs/modules-sdk"
import {
remoteQueryObjectFromString,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import MarketplaceModuleService
from "../../../../modules/marketplace/service"
export async function GET(
req: AuthenticatedMedusaRequest,
res: MedusaResponse
): Promise<void> {
const marketplaceModuleService: MarketplaceModuleService =
req.scope.resolve(
"marketplaceModuleService"
)
const remoteQuery: RemoteQueryFunction = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_QUERY
)
const storeUsers = await marketplaceModuleService.listStoreUsers({
user_id: req.auth_context.actor_id,
})
const query = remoteQueryObjectFromString({
entryPoint: "store_order",
fields: [
"order.*",
],
variables: {
filters: {
store_id: storeUsers[0].store_id,
},
},
})
const result = await remoteQuery(query)
res.json({
orders: result.map((data) => data.order),
})
}
```
This creates a `GET` API route at `/admin/marketplace/orders`. In the API route, you:
- Retrieve the store of the logged-in user.
- Build a query that retrieves the orders of that store.
- Retrieve the orders using remote query and return them.
To test it out, start the Medusa application. Then, send a `GET` request to `/admin/marketplace/orders`:
```bash
curl 'localhost:9000/admin/marketplace/orders' \
-H 'Authorization: Bearer {jwt_token}'
```
This will return the orders you created in the previous section if the `{jwt_token}` belongs to the user of the same store ID.
</Details> */}
---
## Customize Storefront
Medusa provides a Next.js storefront to use with your application. You can either customize it or build your own to represent your marketplace features.
Medusa provides a Next.js Starter storefront that you can customize for your use case.
For example, you can create an API route that retrieves available stores and another API route that retrieves the products of each store using the remote query as done in previous sections.
You can also create a custom storefront from scratch.
<CardList items={[
{
@@ -815,10 +133,18 @@ For example, you can create an API route that retrieves available stores and ano
showLinkIcon: false
},
{
href: "!docs!/storefront-development/tips",
title: "Storefront Tips",
text: "Find tips on developing a custom storefront.",
href: "/storefront-development",
title: "Storefront Development",
text: "Find useful guides for creating a custom storefront.",
startIcon: <AcademicCapSolid />,
showLinkIcon: false
},
]} />
---
## Customize Admin
The Medusa Admin is extendable, allowing you to add widgets to existing pages or create new pages.
If your use case requires bigger customizations to the admin, such as showing different products and orders based on the logged-in vendor, use the [admin API routes](!api!/admin) to build a custom admin.
+11
View File
@@ -0,0 +1,11 @@
import { ChildDocs } from "docs-ui"
export const metadata = {
title: `Recipes`,
}
# {metadata.title}
This section of the documentation provides recipes for common use cases with example implementations.
<ChildDocs onlyTopLevel />
@@ -731,6 +731,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/recipes/integrate-ecommerce-stack/page.mdx",
"pathname": "/recipes/integrate-ecommerce-stack"
},
{
"filePath": "/www/apps/resources/app/recipes/marketplace/examples/vendors/page.mdx",
"pathname": "/recipes/marketplace/examples/vendors"
},
{
"filePath": "/www/apps/resources/app/recipes/marketplace/page.mdx",
"pathname": "/recipes/marketplace"
@@ -747,6 +751,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/recipes/oms/page.mdx",
"pathname": "/recipes/oms"
},
{
"filePath": "/www/apps/resources/app/recipes/page.mdx",
"pathname": "/recipes"
},
{
"filePath": "/www/apps/resources/app/recipes/personalized-products/page.mdx",
"pathname": "/recipes/personalized-products"
+17 -7
View File
@@ -6159,9 +6159,26 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"path": "/recipes",
"title": "Recipes",
"hasTitleStyling": true,
"isChildSidebar": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/recipes/marketplace",
"title": "Marketplace",
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/recipes/marketplace/examples/vendors",
"title": "Example: Vendors",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
@@ -6197,13 +6214,6 @@ export const generatedSidebar = [
"title": "Integrate Ecommerce Stack",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"path": "/recipes/marketplace",
"title": "Marketplace",
"children": []
},
{
"loaded": true,
"isPathHref": true,
+12 -4
View File
@@ -1280,9 +1280,21 @@ export const sidebar = sidebarAttachHrefCommonOptions([
},
{
path: "/recipes",
title: "Recipes",
hasTitleStyling: true,
isChildSidebar: true,
children: [
{
path: "/recipes/marketplace",
title: "Marketplace",
children: [
{
path: "/recipes/marketplace/examples/vendors",
title: "Example: Vendors",
},
],
},
{
path: "/recipes/b2b",
title: "B2B",
@@ -1303,10 +1315,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([
path: "/recipes/integrate-ecommerce-stack",
title: "Integrate Ecommerce Stack",
},
{
path: "/recipes/marketplace",
title: "Marketplace",
},
{
path: "/recipes/multi-region-store",
title: "Multi-Region Store",