docs: add keywords to cloud, fixes to installation and Index Module docs (#14129)
* docs: add keywords to cloud, fixes to installation and Index Module docs * fix vale error
This commit is contained in:
@@ -28,7 +28,7 @@ The Index Module solves this problem by ingesting data into a central data store
|
||||
|
||||
### Ingested Data Models
|
||||
|
||||
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
|
||||
Data models are ingested if they're linked to other data models with the `filterable` property set, as you'll learn in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Medusa also ingests some core data models by default, such as `Product`, `ProductVariant`, `Price`, and `SalesChannel`.
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -68,7 +68,7 @@ npx medusa db:migrate
|
||||
|
||||
### Ingest Data
|
||||
|
||||
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
|
||||
The Index Module only ingests data when you start your Medusa server. So, to [ingest data models](#ingested-data-models), start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
@@ -177,7 +177,7 @@ The `index` method accepts an object with the same properties as the `graph` met
|
||||
|
||||
## How to Ingest Custom Data Models
|
||||
|
||||
Aside from the [core data models](#ingested-data-models), you can also ingest your own custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
|
||||
You can ingest core and custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
|
||||
|
||||
<Note>
|
||||
|
||||
@@ -185,7 +185,7 @@ Read-only links are not supported by the Index Module.
|
||||
|
||||
</Note>
|
||||
|
||||
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](../../../customization/custom-features/module/page.mdx)), you can ingest it into the Index Module using the `filterable` property in its link definition to the Product data model:
|
||||
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](../../../customization/custom-features/module/page.mdx)), you can ingest it into the Index Module using the `filterable` property in its link definition to the `Product` data model:
|
||||
|
||||
export const filterableHighlights = [
|
||||
["12", "filterable", "Ingest Brand by setting its filterable properties."]
|
||||
|
||||
@@ -10,15 +10,15 @@ In this chapter, you'll learn how to install and run a Medusa application.
|
||||
|
||||
## Get Started with Cloud
|
||||
|
||||
Cloud is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
|
||||
[Cloud](!cloud!) is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
|
||||
|
||||
Refer to the [Sign Up](!cloud!/sign-up) guide to create your first Medusa project in minutes.
|
||||
[Sign up](http://cloud.medusajs.com/signup) with Cloud and create your first Medusa project in minutes.
|
||||
|
||||
---
|
||||
|
||||
## Create Medusa Application Locally
|
||||
|
||||
A Medusa application is made up of a Node.js server and an admin dashboard. You can optionally install the [Next.js Starter Storefront](!resources!/nextjs-starter) separately either while installing the Medusa application or at a later point.
|
||||
A Medusa application is made up of a Node.js server and a Vite admin dashboard. You can optionally install the [Next.js Starter Storefront](!resources!/nextjs-starter) separately either while installing the Medusa application or at a later point.
|
||||
|
||||
<Note>
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export const generatedEditDates = {
|
||||
"app/learn/build/page.mdx": "2025-10-27T09:30:26.957Z",
|
||||
"app/learn/deployment/general/page.mdx": "2025-10-21T07:39:08.998Z",
|
||||
"app/learn/fundamentals/workflows/multiple-step-usage/page.mdx": "2025-08-01T14:59:59.501Z",
|
||||
"app/learn/installation/page.mdx": "2025-10-24T09:22:44.583Z",
|
||||
"app/learn/installation/page.mdx": "2025-11-26T12:14:47.372Z",
|
||||
"app/learn/fundamentals/data-models/check-constraints/page.mdx": "2025-07-25T13:50:21.065Z",
|
||||
"app/learn/fundamentals/module-links/link/page.mdx": "2025-04-07T08:03:14.513Z",
|
||||
"app/learn/fundamentals/workflows/store-executions/page.mdx": "2025-04-17T08:29:10.166Z",
|
||||
@@ -121,7 +121,7 @@ export const generatedEditDates = {
|
||||
"app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z",
|
||||
"app/learn/fundamentals/api-routes/override/page.mdx": "2025-05-09T08:01:24.493Z",
|
||||
"app/learn/fundamentals/module-links/index/page.mdx": "2025-05-23T07:57:58.958Z",
|
||||
"app/learn/fundamentals/module-links/index-module/page.mdx": "2025-10-30T11:31:29.704Z",
|
||||
"app/learn/fundamentals/module-links/index-module/page.mdx": "2025-11-26T11:20:25.961Z",
|
||||
"app/learn/introduction/build-with-llms-ai/page.mdx": "2025-10-02T15:10:49.394Z",
|
||||
"app/learn/installation/docker/page.mdx": "2025-10-24T08:53:46.445Z",
|
||||
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
|
||||
|
||||
@@ -14684,7 +14684,7 @@ The Index Module solves this problem by ingesting data into a central data store
|
||||
|
||||
### Ingested Data Models
|
||||
|
||||
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
|
||||
Data models are ingested if they're linked to other data models with the `filterable` property set, as you'll learn in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section. Medusa also ingests some core data models by default, such as `Product`, `ProductVariant`, `Price`, and `SalesChannel`.
|
||||
|
||||
Prior to [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2), only the `Product`, `ProductVariant`, `Price`, and `SalesChannel` data models were ingested. Make sure to update to the latest version to ingest all core data models.
|
||||
|
||||
@@ -14720,7 +14720,7 @@ npx medusa db:migrate
|
||||
|
||||
### Ingest Data
|
||||
|
||||
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
|
||||
The Index Module only ingests data when you start your Medusa server. So, to [ingest data models](#ingested-data-models), start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
@@ -14825,11 +14825,11 @@ The `index` method accepts an object with the same properties as the `graph` met
|
||||
|
||||
## How to Ingest Custom Data Models
|
||||
|
||||
Aside from the [core data models](#ingested-data-models), you can also ingest your own custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
|
||||
You can ingest core and custom data models into the Index Module. You can do so by defining a link between your custom data model and one of the core data models, and setting the `filterable` property in the link definition.
|
||||
|
||||
Read-only links are not supported by the Index Module.
|
||||
|
||||
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](https://docs.medusajs.com/learn/customization/custom-features/module/index.html.md)), you can ingest it into the Index Module using the `filterable` property in its link definition to the Product data model:
|
||||
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](https://docs.medusajs.com/learn/customization/custom-features/module/index.html.md)), you can ingest it into the Index Module using the `filterable` property in its link definition to the `Product` data model:
|
||||
|
||||
```ts title="src/links/product-brand.ts" highlights={filterableHighlights}
|
||||
import BrandModule from "../modules/brand"
|
||||
@@ -24296,15 +24296,15 @@ In this chapter, you'll learn how to install and run a Medusa application.
|
||||
|
||||
## Get Started with Cloud
|
||||
|
||||
Cloud is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
|
||||
[Cloud](https://docs.medusajs.com/cloud/index.html.md) is Medusa's PaaS platform that allows you to deploy and manage production-ready Medusa applications with ease. Benefit from features like zero-configuration deployments, automatic scaling, and GitHub integration to streamline your development workflow.
|
||||
|
||||
Refer to the [Sign Up](https://docs.medusajs.com/cloud/sign-up/index.html.md) guide to create your first Medusa project in minutes.
|
||||
[Sign up](http://cloud.medusajs.com/signup) with Cloud and create your first Medusa project in minutes.
|
||||
|
||||
***
|
||||
|
||||
## Create Medusa Application Locally
|
||||
|
||||
A Medusa application is made up of a Node.js server and an admin dashboard. You can optionally install the [Next.js Starter Storefront](https://docs.medusajs.com/resources/nextjs-starter/index.html.md) separately either while installing the Medusa application or at a later point.
|
||||
A Medusa application is made up of a Node.js server and a Vite admin dashboard. You can optionally install the [Next.js Starter Storefront](https://docs.medusajs.com/resources/nextjs-starter/index.html.md) separately either while installing the Medusa application or at a later point.
|
||||
|
||||
While this is the recommended way to create a Medusa application, you can alternatively [install a Medusa application with Docker](https://docs.medusajs.com/learn/installation/docker/index.html.md).
|
||||
|
||||
@@ -65737,7 +65737,7 @@ export const TierRule = model.define("tier_rule", {
|
||||
{
|
||||
on: ["tier_id", "currency_code"],
|
||||
unique: true,
|
||||
}
|
||||
},
|
||||
])
|
||||
```
|
||||
|
||||
@@ -65876,7 +65876,7 @@ import CustomerModule from "@medusajs/medusa/customer"
|
||||
export default defineLink(
|
||||
{
|
||||
linkable: TierModule.linkable.tier,
|
||||
filterable: ["id"]
|
||||
filterable: ["id"],
|
||||
},
|
||||
{
|
||||
linkable: CustomerModule.linkable.customer,
|
||||
@@ -66018,7 +66018,7 @@ export const createTierRulesStep = createStep(
|
||||
const tierModuleService = container.resolve(TIER_MODULE)
|
||||
|
||||
const createdRules = await tierModuleService.createTierRules(
|
||||
input.tier_rules.map(rule => ({
|
||||
input.tier_rules.map((rule) => ({
|
||||
tier_id: input.tier_id,
|
||||
min_purchase_value: rule.min_purchase_value,
|
||||
currency_code: rule.currency_code,
|
||||
@@ -66033,7 +66033,7 @@ export const createTierRulesStep = createStep(
|
||||
}
|
||||
|
||||
const tierModuleService = container.resolve(TIER_MODULE)
|
||||
await tierModuleService.deleteTierRules(createdRules.map(rule => rule.id))
|
||||
await tierModuleService.deleteTierRules(createdRules.map((rule) => rule.id))
|
||||
}
|
||||
)
|
||||
```
|
||||
@@ -66082,7 +66082,7 @@ export const createTierWorkflow = createWorkflow(
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
// Create the tier
|
||||
@@ -67005,7 +67005,7 @@ export const deleteTierRulesStep = createStep(
|
||||
const tierModuleService: TierModuleService = container.resolve(TIER_MODULE)
|
||||
// Restore deleted rules
|
||||
await tierModuleService.createTierRules(
|
||||
compensationData.map(rule => ({
|
||||
compensationData.map((rule) => ({
|
||||
tier_id: rule.tier_id,
|
||||
min_purchase_value: rule.min_purchase_value,
|
||||
currency_code: rule.currency_code,
|
||||
@@ -67060,7 +67060,7 @@ export const updateTierWorkflow = createWorkflow(
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
// Validate promotion if provided
|
||||
when({ input }, (data) => !!data.input.promo_id)
|
||||
@@ -67073,7 +67073,7 @@ export const updateTierWorkflow = createWorkflow(
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
}
|
||||
},
|
||||
}).config({ name: "retrieve-promotion" })
|
||||
})
|
||||
// Update the tier
|
||||
@@ -67089,10 +67089,10 @@ export const updateTierWorkflow = createWorkflow(
|
||||
const ids = transform({
|
||||
tiers,
|
||||
}, (data) => {
|
||||
return (data.tiers[0].tier_rules?.map(rule => rule?.id) || []) as string[]
|
||||
return (data.tiers[0].tier_rules?.map((rule) => rule?.id) || []) as string[]
|
||||
})
|
||||
deleteTierRulesStep({
|
||||
ids
|
||||
ids,
|
||||
})
|
||||
return createTierRulesStep({
|
||||
tier_id: input.id,
|
||||
@@ -67205,8 +67205,8 @@ export default defineMiddlewares({
|
||||
matcher: "/admin/tiers/:id",
|
||||
methods: ["POST"],
|
||||
middlewares: [validateAndTransformBody(UpdateTierSchema)],
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -67288,7 +67288,7 @@ export default defineMiddlewares({
|
||||
}),
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -67319,8 +67319,8 @@ export default config({
|
||||
// ...
|
||||
{
|
||||
resolve: "@medusajs/index",
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -67426,7 +67426,7 @@ const { data: storeData } = useQuery({
|
||||
|
||||
const updateTierMutation = useMutation({
|
||||
mutationFn: async (data: EditTierFormData) => {
|
||||
if (!tier) return
|
||||
if (!tier) {return}
|
||||
return await sdk.client.fetch(`/admin/tiers/${tier.id}`, {
|
||||
method: "POST",
|
||||
body: data,
|
||||
@@ -67984,7 +67984,7 @@ In `src/admin/routes/tiers/page.tsx`, find the `onRowClick` handler and replace
|
||||
```tsx title="src/admin/routes/tiers/page.tsx"
|
||||
onRowClick: (_event, row) => {
|
||||
navigate(`/tiers/${row.id}`)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
You navigate to the tier details page when the user clicks on a tier in the tiers list.
|
||||
@@ -68042,12 +68042,12 @@ class TierModuleService extends MedusaService({
|
||||
}) {
|
||||
async calculateQualifyingTier(
|
||||
currencyCode: string,
|
||||
purchaseValue: number,
|
||||
purchaseValue: number
|
||||
) {
|
||||
const rules = await this.listTierRules(
|
||||
{
|
||||
currency_code: currencyCode,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!rules || rules.length === 0) {
|
||||
@@ -68205,7 +68205,7 @@ export const updateCustomerTierOnOrderWorkflow = createWorkflow(
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const validatedCustomer = validateCustomerStep({
|
||||
@@ -68223,8 +68223,8 @@ export const updateCustomerTierOnOrderWorkflow = createWorkflow(
|
||||
$nin: [
|
||||
OrderStatus.CANCELED,
|
||||
OrderStatus.DRAFT,
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
}).config({ name: "completed-orders" })
|
||||
|
||||
@@ -68638,8 +68638,8 @@ updateCartPromotionsWorkflow.hooks.validate(async ({ input, cart }, { container
|
||||
entity: "tier",
|
||||
fields: ["id", "promo_id"],
|
||||
filters: {
|
||||
promo_id: promotions.map((p) => p.id)
|
||||
}
|
||||
promo_id: promotions.map((p) => p.id),
|
||||
},
|
||||
})
|
||||
|
||||
// Validate each promotion being added
|
||||
@@ -68714,8 +68714,8 @@ completeCartWorkflow.hooks.validate(async ({ cart }, { container }) => {
|
||||
entity: "tier",
|
||||
fields: ["id", "promo_id"],
|
||||
filters: {
|
||||
promo_id: detailedCart.promotions.map((p) => p?.id).filter(Boolean) as string[]
|
||||
}
|
||||
promo_id: detailedCart.promotions.map((p) => p?.id).filter(Boolean) as string[],
|
||||
},
|
||||
})
|
||||
|
||||
// Validate that if a tier promotion is applied, the customer belongs to that tier
|
||||
@@ -68761,7 +68761,7 @@ class TierModuleService extends MedusaService({
|
||||
// ...
|
||||
async calculateNextTierUpgrade(
|
||||
currencyCode: string,
|
||||
currentPurchaseValue: number,
|
||||
currentPurchaseValue: number
|
||||
) {
|
||||
const rules = await this.listTierRules(
|
||||
{
|
||||
@@ -68866,7 +68866,7 @@ export async function GET(
|
||||
|
||||
// Get currency code from cart or region context
|
||||
// Try to get from cart first, then region
|
||||
let regionId = req.validatedQuery.region_id
|
||||
const regionId = req.validatedQuery.region_id
|
||||
|
||||
// Calculate total purchase value
|
||||
const { data: orders } = await query.graph({
|
||||
@@ -68879,7 +68879,7 @@ export async function GET(
|
||||
$nin: [
|
||||
OrderStatus.CANCELED,
|
||||
OrderStatus.DRAFT,
|
||||
]
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -68911,7 +68911,7 @@ export async function GET(
|
||||
const currentTier = customer.tier || null
|
||||
|
||||
// Determine next tier upgrade
|
||||
let nextTierUpgrade = await tierModuleService.calculateNextTierUpgrade(
|
||||
const nextTierUpgrade = await tierModuleService.calculateNextTierUpgrade(
|
||||
currencyCode as string,
|
||||
totalPurchaseValue
|
||||
)
|
||||
@@ -69018,9 +69018,9 @@ export const retrieveCustomerNextTier =
|
||||
const authHeaders = await getAuthHeaders()
|
||||
const region = await getRegion(countryCode)
|
||||
|
||||
if (!region) return null
|
||||
if (!region) {return null}
|
||||
|
||||
if (!authHeaders) return null
|
||||
if (!authHeaders) {return null}
|
||||
|
||||
const headers = {
|
||||
...authHeaders,
|
||||
@@ -69037,7 +69037,7 @@ export const retrieveCustomerNextTier =
|
||||
next,
|
||||
query: {
|
||||
region_id: region.id,
|
||||
}
|
||||
},
|
||||
})
|
||||
.then((data) => data)
|
||||
.catch(() => null)
|
||||
@@ -94107,7 +94107,7 @@ To create the workflow, create the file `src/workflows/sync-products.ts` with th
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowResponse
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
|
||||
import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products"
|
||||
@@ -94123,11 +94123,11 @@ export const syncProductsWorkflow = createWorkflow(
|
||||
"sync-products",
|
||||
({ filters, limit, offset }: SyncProductsWorkflowInput) => {
|
||||
const productFilters = transform({
|
||||
filters
|
||||
filters,
|
||||
}, (data) => {
|
||||
return {
|
||||
status: ProductStatus.PUBLISHED,
|
||||
...data.filters
|
||||
...data.filters,
|
||||
}
|
||||
})
|
||||
const { data, metadata } = useQueryGraphStep({
|
||||
@@ -101971,7 +101971,7 @@ To create the workflow, create the file `src/workflows/sync-products.ts` with th
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowResponse
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
|
||||
import { syncProductsStep, SyncProductsStepInput } from "./steps/sync-products"
|
||||
@@ -101987,11 +101987,11 @@ export const syncProductsWorkflow = createWorkflow(
|
||||
"sync-products",
|
||||
({ filters, limit, offset }: SyncProductsWorkflowInput) => {
|
||||
const productFilters = transform({
|
||||
filters
|
||||
filters,
|
||||
}, (data) => {
|
||||
return {
|
||||
status: ProductStatus.PUBLISHED,
|
||||
...data.filters
|
||||
...data.filters,
|
||||
}
|
||||
})
|
||||
const { data, metadata } = useQueryGraphStep({
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
---
|
||||
keywords:
|
||||
- email
|
||||
- mail
|
||||
- medusa mail
|
||||
- transactional email
|
||||
- marketing email
|
||||
- email service
|
||||
- cloud email
|
||||
- medusa cloud email
|
||||
- medusa emails
|
||||
---
|
||||
|
||||
import { CodeTabs, CodeTab, Prerequisites, InlineIcon } from "docs-ui"
|
||||
import { ChevronUpDown } from "@medusajs/icons"
|
||||
|
||||
|
||||
@@ -26,6 +26,6 @@ export const generatedEditDates = {
|
||||
"app/billing/plans/page.mdx": "2025-10-08T14:49:27.009Z",
|
||||
"app/cache/page.mdx": "2025-11-12T14:37:24.809Z",
|
||||
"app/deployments/troubleshooting/page.mdx": "2025-10-17T14:44:22.894Z",
|
||||
"app/emails/page.mdx": "2025-11-12T15:41:36.777Z",
|
||||
"app/emails/page.mdx": "2025-11-26T11:07:58.083Z",
|
||||
"app/emails/react-email/page.mdx": "2025-11-12T15:41:56.365Z"
|
||||
}
|
||||
Reference in New Issue
Block a user