DocsDeveloper SectionMedusaJS 2.0 Engine Connection

Comprehensive Architecture and Integration of MedusaJS 2.0 Engine

The MedusaJS 2.0 (v2.15.5) e-commerce engine manages all operations related to the product catalog, regional pricing, shopping cart, checkout process, Module Links, and customer accounts.

Crucial Note on Publishable API Key Configuration
After generating a key in the Medusa Admin panel, you must attach the created key to the **Main Sales Channel**; otherwise, products will not be displayed on the frontend.

Medusa v2 Module Links Architecture

In Medusa v2, modules are completely isolated, and database communication between independent module models (like reviews, questions, wishlists, and Strapi) is established via defineLink in the store-admin/src/links/ folder:

product-strapi.tsMapping between Medusa product ID and Strapi CMS content IDs.
review-product.tsConnection between buyer reviews and the corresponding Medusa product.
wishlist-customer.tsConnection between wishlist and the customer's profile.
question-product.tsConnecting submitted Q&As to catalog products.
store-admin/src/links/review-product.ts
typescript
import { defineLink } from "@medusajs/framework/modules-sdk"
import ProductModule from "@medusajs/medusa/product"
import ProductReviewModule from "../modules/product-review"
export default defineLink(
ProductModule.linkable.product,
ProductReviewModule.linkable.productReview
)

Useful Server & Seed Scripts for Database and Catalog Management

In the store-admin/src/scripts/ folder, there is a collection of ready-made scripts for seeding and managing products:

Initial database seed script (regions, shipping, products)
bash
npm run seed
Inject 30 complete sample products with variants and prices
bash
npx medusa exec ./src/scripts/seed-30-products.ts
Manual and forced synchronization of product index in Meilisearch
bash
npx medusa exec ./src/scripts/sync-meilisearch.ts
Complete cleanup of products to start from scratch
bash
npx medusa exec ./src/scripts/delete-all-products.ts

Frontend Product Fetching Layer (products.ts)

src/lib/data/products.ts
typescript
import { sdk } from "@lib/config"
import { HttpTypes } from "@medusajs/types"
import { getAuthHeaders, getCacheOptions } from "./cookies"
import { getLocaleHeader } from "@lib/util/get-locale-header"
import { getRegion, retrieveRegion } from "./regions"
import { isNetworkFetchError, warnMedusaUnreachable } from "@lib/util/medusa-fetch"
export const listProducts = async ({
pageParam = 1,
queryParams,
countryCode,
regionId,
disableAuth = false,
}: {
pageParam?: number
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams
countryCode?: string
regionId?: string
disableAuth?: boolean
}): Promise<{
response: { products: HttpTypes.StoreProduct[]; count: number }
nextPage: number | null
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams
}> => {
if (!countryCode && !regionId) {
throw new Error("Country code or region ID is required")
}
const limit = queryParams?.limit || 12
const _pageParam = Math.max(pageParam, 1)
const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit
let region: HttpTypes.StoreRegion | undefined | null
if (countryCode) {
region = await getRegion(countryCode, disableAuth)
} else {
region = await retrieveRegion(regionId!, disableAuth)
}
if (!region) {
return { response: { products: [], count: 0 }, nextPage: null }
}
const headers = {
...(disableAuth ? {} : await getAuthHeaders()),
...(await getLocaleHeader(disableAuth)),
} as Record<string, string>
const next = {
...(disableAuth
? { tags: ["store-products"] }
: await getCacheOptions("store-products")),
revalidate: 3600,
}
try {
return await sdk.client
.fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
`/store/products`,
{
method: "GET",
query: {
limit,
offset,
region_id: region?.id,
fields:
"*variants.calculated_price,+variants.inventory_quantity,*variants.images,*options,*options.values,*variants.options,+metadata,+tags",
...queryParams,
},
headers,
next,
cache: "force-cache",
}
)
.then(({ products, count }) => {
const nextPage = count > offset + limit ? pageParam + 1 : null
return {
response: { products, count },
nextPage,
queryParams,
}
})
} catch (error) {
if (isNetworkFetchError(error)) {
warnMedusaUnreachable("listProducts")
return {
response: { products: [], count: 0 },
nextPage: null,
queryParams,
}
}
throw error
}
}

Email and Notification Service (Nodemailer SMTP & SendPulse)

The system for sending notification emails, contact forms, and order confirmations is implemented using Nodemailer (SMTP) and SendPulse with responsive templates:

Email service configuration in .env
env
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM_ADDRESS=noreply@yourdomain.com
CONTACT_FORM_RECIPIENT=info@yourdomain.com
SENDPULSE_API_ID=your_sendpulse_id
SENDPULSE_API_SECRET=your_sendpulse_secret