@mercurjs/docs 2.3.8-canary.2 → 2.3.8-canary.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/content/learn/architecture.mdx +166 -263
  2. package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
  3. package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
  4. package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
  5. package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
  6. package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
  7. package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
  8. package/content/platform/attribute/overview.mdx +37 -33
  9. package/content/platform/attribute/reference/data-models.mdx +53 -38
  10. package/content/platform/attribute/reference/events.mdx +47 -24
  11. package/content/platform/attribute/reference/links.mdx +98 -27
  12. package/content/platform/attribute/reference/service.mdx +71 -32
  13. package/content/platform/attribute/reference/workflows.mdx +158 -28
  14. package/content/platform/catalog/concepts/master-products.mdx +39 -37
  15. package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
  16. package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
  17. package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
  18. package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
  19. package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
  20. package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
  21. package/content/platform/catalog/overview.mdx +39 -35
  22. package/content/platform/catalog/reference/data-models.mdx +154 -43
  23. package/content/platform/catalog/reference/events.mdx +41 -25
  24. package/content/platform/catalog/reference/links.mdx +196 -28
  25. package/content/platform/catalog/reference/service.mdx +57 -35
  26. package/content/platform/catalog/reference/workflows.mdx +124 -30
  27. package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
  28. package/content/platform/commission/concepts/rule-matching.mdx +53 -63
  29. package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
  30. package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
  31. package/content/platform/commission/guides/create-a-rate.mdx +101 -53
  32. package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
  33. package/content/platform/commission/overview.mdx +43 -35
  34. package/content/platform/commission/reference/data-models.mdx +59 -45
  35. package/content/platform/commission/reference/events.mdx +28 -34
  36. package/content/platform/commission/reference/links.mdx +42 -33
  37. package/content/platform/commission/reference/service.mdx +103 -28
  38. package/content/platform/commission/reference/workflows.mdx +101 -27
  39. package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
  40. package/content/platform/offer/concepts/shipping.mdx +28 -29
  41. package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
  42. package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
  43. package/content/platform/offer/guides/create-an-offer.mdx +112 -60
  44. package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
  45. package/content/platform/offer/overview.mdx +39 -32
  46. package/content/platform/offer/reference/data-models.mdx +77 -47
  47. package/content/platform/offer/reference/events.mdx +44 -18
  48. package/content/platform/offer/reference/links.mdx +92 -40
  49. package/content/platform/offer/reference/service.mdx +66 -31
  50. package/content/platform/offer/reference/workflows.mdx +146 -37
  51. package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
  52. package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
  53. package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
  54. package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
  55. package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
  56. package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
  57. package/content/platform/order-group/overview.mdx +42 -32
  58. package/content/platform/order-group/reference/data-models.mdx +48 -31
  59. package/content/platform/order-group/reference/events.mdx +29 -17
  60. package/content/platform/order-group/reference/links.mdx +90 -29
  61. package/content/platform/order-group/reference/service.mdx +55 -31
  62. package/content/platform/order-group/reference/workflows.mdx +83 -24
  63. package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
  64. package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
  65. package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
  66. package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
  67. package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
  68. package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
  69. package/content/platform/payout/overview.mdx +43 -34
  70. package/content/platform/payout/reference/data-models.mdx +63 -36
  71. package/content/platform/payout/reference/events.mdx +56 -30
  72. package/content/platform/payout/reference/links.mdx +52 -22
  73. package/content/platform/payout/reference/service.mdx +72 -33
  74. package/content/platform/payout/reference/workflows.mdx +80 -19
  75. package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
  76. package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
  77. package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
  78. package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
  79. package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
  80. package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
  81. package/content/platform/product-edit/overview.mdx +41 -34
  82. package/content/platform/product-edit/reference/data-models.mdx +73 -47
  83. package/content/platform/product-edit/reference/events.mdx +39 -29
  84. package/content/platform/product-edit/reference/links.mdx +32 -24
  85. package/content/platform/product-edit/reference/service.mdx +45 -26
  86. package/content/platform/product-edit/reference/workflows.mdx +173 -31
  87. package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
  88. package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
  89. package/content/platform/review/concepts/the-review-model.mdx +52 -45
  90. package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
  91. package/content/platform/review/guides/create-a-review.mdx +109 -39
  92. package/content/platform/review/guides/moderate-a-review.mdx +83 -37
  93. package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
  94. package/content/platform/review/overview.mdx +43 -33
  95. package/content/platform/review/reference/data-models.mdx +41 -27
  96. package/content/platform/review/reference/events.mdx +55 -37
  97. package/content/platform/review/reference/links.mdx +80 -22
  98. package/content/platform/review/reference/service.mdx +61 -33
  99. package/content/platform/review/reference/workflows.mdx +80 -24
  100. package/content/platform/store/concepts/lifecycle.mdx +68 -44
  101. package/content/platform/store/concepts/store-entity.mdx +45 -27
  102. package/content/platform/store/concepts/team.mdx +56 -35
  103. package/content/platform/store/guides/create-a-store.mdx +102 -35
  104. package/content/platform/store/guides/manage-the-team.mdx +122 -32
  105. package/content/platform/store/guides/moderate-a-store.mdx +107 -38
  106. package/content/platform/store/overview.mdx +41 -34
  107. package/content/platform/store/reference/data-models.mdx +132 -57
  108. package/content/platform/store/reference/events.mdx +42 -17
  109. package/content/platform/store/reference/links.mdx +67 -49
  110. package/content/platform/store/reference/service.mdx +105 -33
  111. package/content/platform/store/reference/workflows.mdx +304 -24
  112. package/content/references/panel-extensions/layouts.mdx +169 -0
  113. package/llms.txt +112 -111
  114. package/package.json +1 -1
@@ -1,70 +1,146 @@
1
1
  ---
2
- title: "Create a master product"
2
+ title: "Create a master product from server code"
3
3
  sidebarTitle: "Create a master product"
4
- description: "Create a master product programmatically with createProductsWorkflow."
4
+ description: "Add a product to the shared catalog with Mercur's createProductsWorkflow, including attributes, variants, and an allowlist."
5
5
  ---
6
6
 
7
- In this guide, you'll learn how to add a product to the shared catalog from your
8
- own server code, for example in a seed script, a custom API route, or an import
9
- flow.
7
+ Run `createProductsWorkflow` to add a product to the shared catalog from a custom route, a seed script, or an import job. It creates the product and its variants, attaches attributes, links any stores you name, and records the submission.
10
8
 
11
- Mercur exposes a `createProductsWorkflow` that creates the `Product` record,
12
- attaches attributes and variants, records the submission for audit, and
13
- optionally allowlists the submitting store. Run it from any place that has access
14
- to the Medusa container.
9
+ ## Before you begin
15
10
 
16
- ## Run the workflow
11
+ You need the following in place:
17
12
 
18
- ```ts title="src/api/custom/route.ts"
19
- import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
20
- import { createProductsWorkflow } from "@mercurjs/core/workflows"
13
+ - A Mercur server with `@mercurjs/core` installed
14
+ - The ids of any [attributes](/platform/attribute/overview) and stores you want to reference
15
+
16
+ <Warning>
17
+ Import `createProductsWorkflow` from `@mercurjs/core/workflows`, not `@medusajs/medusa/core-flows`. Medusa's workflow has the same name but skips attributes, the allowlist, and the audit record.
18
+ </Warning>
19
+
20
+ ## Create the product
21
+
22
+ <Steps>
23
+ <Step title="Add a route that runs the workflow">
24
+ Create an admin route. The workflow returns the created `ProductDTO` objects in input order.
25
+
26
+ ```ts title="src/api/admin/supplier-products/route.ts"
27
+ import type {
28
+ AuthenticatedMedusaRequest,
29
+ MedusaResponse,
30
+ } from "@medusajs/framework/http"
31
+ import { createProductsWorkflow } from "@mercurjs/core/workflows"
32
+
33
+ export async function POST(
34
+ req: AuthenticatedMedusaRequest,
35
+ res: MedusaResponse
36
+ ) {
37
+ const { result } = await createProductsWorkflow(req.scope).run({
38
+ input: {
39
+ products: [{ title: "Aeron Chair", status: "proposed" }],
40
+ created_by: req.auth_context.actor_id,
41
+ },
42
+ })
43
+
44
+ res.status(201).json({ product: result[0] })
45
+ }
46
+ ```
21
47
 
22
- export async function POST(req: MedusaRequest, res: MedusaResponse) {
23
- const { result } = await createProductsWorkflow(req.scope).run({
24
- input: {
25
- products: [
48
+ `created_by` is required. Mercur stores it on the `PRODUCT_ADD` change as the submitter. Without a `status`, the product starts as `draft`.
49
+ </Step>
50
+ <Step title="Add attributes and variants">
51
+ Pass `attributes` instead of native `options`. A `multi_select` attribute with `is_variant_axis` becomes the option that variants bind to by title.
52
+
53
+ ```ts
54
+ const product = {
55
+ title: "Aeron Chair",
56
+ status: "proposed" as const,
57
+ attributes: [
26
58
  {
27
- title: "Aeron Chair",
28
- status: "proposed",
29
- seller_ids: ["sel_123"],
59
+ id: "pattr_01JD8Q1234567",
60
+ value_ids: ["pattrval_01JD8Q1234567"],
30
61
  },
62
+ { title: "Size", is_variant_axis: true, values: ["B", "C"] },
31
63
  ],
32
- created_by: req.auth_context.actor_id,
33
- },
34
- })
35
-
36
- res.status(201).json({ product: result[0] })
37
- }
38
- ```
64
+ variants: [
65
+ { title: "Size B", options: { Size: "B" } },
66
+ { title: "Size C", options: { Size: "C" } },
67
+ ],
68
+ }
69
+ ```
39
70
 
40
- <Note>
41
- Passing `seller_ids` allowlists those stores for the product as it's created,
42
- so the submitting store can immediately create an
43
- [offer](/platform/offer/overview) against it. `created_by` records who
44
- submitted the product for the audit trail.
45
- </Note>
71
+ The first entry attaches a global attribute with a chosen value. The second creates a product-scoped axis. New variants get `manage_inventory: false` unless you set it, since stock lives on [offers](/platform/offer/overview).
72
+ </Step>
73
+ <Step title="Restrict the product to stores">
74
+ Add `seller_ids` to a product to put those stores on its [allowlist](/platform/catalog/concepts/product-seller-allowlist).
46
75
 
47
- ## Default status
76
+ ```ts
77
+ const product = {
78
+ title: "Aeron Chair",
79
+ seller_ids: ["sel_01JD8Q1234567", "sel_01JD8Q1234568"],
80
+ }
81
+ ```
48
82
 
49
- A product created without an explicit `status` follows the marketplace's review
50
- flow. Vendor-created products default to **`proposed`**, submitted for operator
51
- review rather than published outright. Set `status: "draft"` to keep a product
52
- private until it's ready, or `status: "published"` from a trusted operator flow
53
- to skip review. See the
54
- [status lifecycle](/platform/catalog/concepts/status-lifecycle).
83
+ Only these 2 stores can see and sell the product once it's published. Leave `seller_ids` out to open it to every store.
84
+ </Step>
85
+ </Steps>
55
86
 
56
- ## Attach custom data
87
+ ## Submit on behalf of a store
57
88
 
58
- The workflow accepts an `additional_data` payload passed to its hooks, letting
59
- you persist marketplace-specific data alongside the product without forking the
60
- workflow.
89
+ Pass the store's seller id as `created_by` to make the product a submission from that store. That's what the vendor API does, and it's how Mercur lets a store see its own `draft` and `proposed` products.
61
90
 
62
91
  ```ts
63
- await createProductsWorkflow(req.scope).run({
92
+ await createProductsWorkflow(container).run({
64
93
  input: {
65
- products: [{ title: "Aeron Chair", seller_ids: ["sel_123"] }],
66
- created_by: "usr_123",
67
- additional_data: { source: "supplier-feed" },
94
+ products: [{ title: "Desk lamp", status: "proposed" }],
95
+ created_by: "sel_01JD8Q1234567",
68
96
  },
69
97
  })
70
98
  ```
99
+
100
+ The product appears in that store's product list as a proposed submission, and stays hidden from other stores until it's published.
101
+
102
+ ## Validate input with the validate hook
103
+
104
+ The workflow runs a `validate` hook before it creates anything. Throw from the handler to stop the run.
105
+
106
+ ```ts title="src/workflows/hooks/validate-products.ts"
107
+ import { createProductsWorkflow } from "@mercurjs/core/workflows"
108
+ import { MedusaError } from "@medusajs/framework/utils"
109
+
110
+ createProductsWorkflow.hooks.validate(async ({ products }) => {
111
+ const missing = products.find((p) => !p.description)
112
+ if (missing) {
113
+ throw new MedusaError(
114
+ MedusaError.Types.INVALID_DATA,
115
+ `Product "${missing.title}" needs a description`
116
+ )
117
+ }
118
+ })
119
+ ```
120
+
121
+ The hook receives the raw `input` and its `products` array, so you can check any field before Medusa writes rows.
122
+
123
+ ## Attach custom data with additional_data
124
+
125
+ Pass `additional_data` to carry extra values through the run. Mercur forwards it to Medusa's product and variant workflows and to the `productsCreated` hook.
126
+
127
+ ```ts title="src/workflows/hooks/products-created.ts"
128
+ import { createProductsWorkflow } from "@mercurjs/core/workflows"
129
+
130
+ createProductsWorkflow.hooks.productsCreated(
131
+ async ({ products, additional_data }, { container }) => {
132
+ const logger = container.resolve("logger")
133
+ const source = additional_data?.source
134
+
135
+ logger.info(`Imported ${products.length} products from ${source}`)
136
+ }
137
+ )
138
+ ```
139
+
140
+ Call the workflow with `additional_data: { source: "supplier_feed" }` and the handler receives it next to the created products.
141
+
142
+ ## Next steps
143
+
144
+ - [Publish or reject a product](/platform/catalog/guides/publish-or-reject-a-product) to review what you created
145
+ - [Allowlist stores](/platform/catalog/guides/allowlist-stores) to change the store list later
146
+ - [Create an offer](/platform/offer/guides/create-an-offer) so a store can sell the product
@@ -1,79 +1,144 @@
1
1
  ---
2
- title: "Publish or reject a product"
2
+ title: "Publish or reject a proposed product"
3
3
  sidebarTitle: "Publish or reject"
4
- description: "Move a proposed master product to published or rejected from server code."
4
+ description: "Review a store's product submission from server code: publish it, reject it, or ask for a revision."
5
5
  ---
6
6
 
7
- In this guide, you'll learn how to review a submitted product from your own
8
- server code. Each transition has a dedicated workflow so the audit trail, events,
9
- and side effects run consistently.
7
+ Run Mercur's review workflows to decide on a `proposed` product from a custom route, a subscriber, or a scheduled job. Each one checks the status, records who reviewed the product, and emits an event.
10
8
 
11
- A product enters review as `proposed`. From there you can publish it, reject it,
12
- or ask the submitter for a revision. Every workflow validates that the product is
13
- currently `proposed` before it runs.
9
+ ## Before you begin
14
10
 
15
- ## Publish a product
11
+ You need the following in place:
16
12
 
17
- Move one or more `proposed` products to `published` with
18
- `confirmProductsWorkflow`:
13
+ - A product in `proposed` status, such as a store submission
14
+ - The id of the operator or system acting, for the audit record
19
15
 
20
- ```ts title="src/api/custom/publish/route.ts"
21
- import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
16
+ The workflows fail with a `NOT_ALLOWED` error for any product that isn't `proposed`.
17
+
18
+ ## Review a product
19
+
20
+ <Steps>
21
+ <Step title="Publish it">
22
+ `confirmProductsWorkflow` publishes one or more products in a single run. `internal_note` is stored on each audit record for operators.
23
+
24
+ ```ts title="src/api/admin/reviews/publish/route.ts"
25
+ import type {
26
+ AuthenticatedMedusaRequest,
27
+ MedusaResponse,
28
+ } from "@medusajs/framework/http"
29
+ import { confirmProductsWorkflow } from "@mercurjs/core/workflows"
30
+
31
+ type Body = { product_ids: string[] }
32
+
33
+ export async function POST(
34
+ req: AuthenticatedMedusaRequest<Body>,
35
+ res: MedusaResponse
36
+ ) {
37
+ await confirmProductsWorkflow(req.scope).run({
38
+ input: {
39
+ product_ids: req.body.product_ids,
40
+ actor_id: req.auth_context.actor_id,
41
+ internal_note: "Checked against the supplier sheet",
42
+ },
43
+ })
44
+
45
+ res.json({ published: req.body.product_ids })
46
+ }
47
+ ```
48
+
49
+ If any product isn't `proposed`, the run fails and none of them change.
50
+ </Step>
51
+ <Step title="Or reject it">
52
+ `rejectProductWorkflow` handles one product. `message` is stored as the change's `external_note`, the note the store can read.
53
+
54
+ ```ts
55
+ import { rejectProductWorkflow } from "@mercurjs/core/workflows"
56
+
57
+ await rejectProductWorkflow(container).run({
58
+ input: {
59
+ product_id: "prod_01JD8Q1234567",
60
+ message: "Images don't match the description",
61
+ actor_id: "user_01JD8Q1234567",
62
+ },
63
+ })
64
+ ```
65
+
66
+ The product moves to `rejected` and leaves the store's product list.
67
+ </Step>
68
+ <Step title="Or ask for a revision">
69
+ `requestProductChangeWorkflow` keeps the product `proposed` and records a `CHANGE_REQUESTED` action with your message.
70
+
71
+ ```ts
72
+ import { requestProductChangeWorkflow } from "@mercurjs/core/workflows"
73
+
74
+ await requestProductChangeWorkflow(container).run({
75
+ input: {
76
+ product_id: "prod_01JD8Q1234567",
77
+ message: "Add a size B variant",
78
+ actor_id: "user_01JD8Q1234567",
79
+ },
80
+ })
81
+ ```
82
+
83
+ The product stays in the review queue, and your message is stored as the change's `external_note`.
84
+ </Step>
85
+ </Steps>
86
+
87
+ ## Run a review from a subscriber
88
+
89
+ Review products automatically by running a workflow when they're created. This subscriber publishes products from one trusted store.
90
+
91
+ ```ts title="src/subscribers/auto-publish-trusted.ts"
92
+ import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework"
22
93
  import { confirmProductsWorkflow } from "@mercurjs/core/workflows"
23
94
 
24
- export async function POST(req: MedusaRequest, res: MedusaResponse) {
25
- await confirmProductsWorkflow(req.scope).run({
26
- input: {
27
- product_ids: [req.params.id],
28
- actor_id: req.auth_context.actor_id,
29
- internal_note: "Looks good",
30
- },
95
+ export default async function autoPublish({
96
+ event,
97
+ container,
98
+ }: SubscriberArgs<{ id: string }>) {
99
+ const query = container.resolve("query")
100
+ const { data: [action] } = await query.graph({
101
+ entity: "product_change_action",
102
+ fields: ["product_change.created_by"],
103
+ filters: { product_id: event.data.id, action: "PRODUCT_ADD" },
31
104
  })
105
+ if (action?.product_change?.created_by !== "sel_01JD8Q1234567") return
32
106
 
33
- res.sendStatus(200)
107
+ await confirmProductsWorkflow(container).run({
108
+ input: { product_ids: [event.data.id], actor_id: "system" },
109
+ })
34
110
  }
111
+
112
+ export const config: SubscriberConfig = { event: "product.created" }
35
113
  ```
36
114
 
37
- ## Reject a product
115
+ The handler reads the `PRODUCT_ADD` record to find the submitter, then publishes. `product.created` fires twice for each product created through Mercur's workflow, so the second run fails the `proposed` check. Catch that error, or check the status first.
38
116
 
39
- ```ts
40
- import { rejectProductWorkflow } from "@mercurjs/core/workflows"
117
+ ## React to the outcome with hooks
41
118
 
42
- await rejectProductWorkflow(container).run({
43
- input: {
44
- product_id: "prod_123",
45
- message: "Images don't match the description",
46
- actor_id: "usr_123",
47
- },
48
- })
49
- ```
119
+ Each review workflow exposes a hook that runs after the status change. Use it for side effects that must happen inside the same run.
50
120
 
51
- ## Request a revision
121
+ | Workflow | Hook | Hook input |
122
+ | --- | --- | --- |
123
+ | `confirmProductsWorkflow` | `productsConfirmed` | `product_ids`, `internal_note`, `additional_data` |
124
+ | `rejectProductWorkflow` | `productRejected` | `product_id`, `message`, `additional_data` |
125
+ | `requestProductChangeWorkflow` | `productChangeRequested` | `product_id`, `message`, `additional_data` |
52
126
 
53
- To send the submission back for changes without rejecting it, use
54
- `requestProductChangeWorkflow`. The product stays `proposed` and a
55
- `CHANGE_REQUESTED` action is recorded for the submitter to act on:
56
-
57
- ```ts
58
- import { requestProductChangeWorkflow } from "@mercurjs/core/workflows"
127
+ ```ts title="src/workflows/hooks/product-rejected.ts"
128
+ import { rejectProductWorkflow } from "@mercurjs/core/workflows"
59
129
 
60
- await requestProductChangeWorkflow(container).run({
61
- input: {
62
- product_id: "prod_123",
63
- message: "Please add a size variant",
64
- actor_id: "usr_123",
65
- },
66
- })
130
+ rejectProductWorkflow.hooks.productRejected(
131
+ async ({ product_id, message }, { container }) => {
132
+ const logger = container.resolve("logger")
133
+ logger.info(`Rejected ${product_id}: ${message ?? "no reason"}`)
134
+ }
135
+ )
67
136
  ```
68
137
 
69
- <Warning>
70
- These workflows require the product to be `proposed`. Running them against a
71
- `draft`, `published`, or `rejected` product fails validation rather than
72
- forcing the transition.
73
- </Warning>
138
+ For work that can run later, subscribe to `product.published`, `product.rejected`, or `product.change-requested` instead.
74
139
 
75
- ## React to review outcomes
140
+ ## Next steps
76
141
 
77
- To run your own side effects when a product is published or rejected, subscribe
78
- to the events these workflows emit rather than polling. See the
79
- [Event reference](/platform/catalog/reference/events) for the event names.
142
+ - [Event reference](/platform/catalog/reference/events) for payloads
143
+ - [Status lifecycle](/platform/catalog/concepts/status-lifecycle) for every transition
144
+ - [Request a revision](/platform/product-edit/guides/request-a-revision) for edits to published products
@@ -1,90 +1,94 @@
1
1
  ---
2
2
  title: "Catalog"
3
3
  sidebarTitle: "Overview"
4
- description: "Master products, variants, categories, and the store allowlist that governs who may sell what."
4
+ description: "Keep one shared product catalog, decide which stores may sell each product, and review what stores submit."
5
5
  ---
6
6
 
7
- Use Mercur to govern one shared product catalog and control which stores are
8
- allowed to sell what.
7
+ Use Mercur to keep one product catalog for the whole marketplace and control which stores can sell each product.
9
8
 
10
- Master-data governance lives here. The Catalog domain keeps products as a single
11
- shared source of truth, controls access to it through an allowlist over who may
12
- sell each product, and holds every submission to an approval lifecycle before it
13
- goes live. On top of that governance layer it holds master products, variants,
14
- categories, collections, tags, and types. A store never owns a product. It sells
15
- against a shared master product through an [offer](/platform/offer/overview).
9
+ The catalog is Medusa's Product module (`Modules.PRODUCT`) with a marketplace layer on top. Products, variants, categories, collections, tags, and types are native Medusa models. Mercur adds the `product_seller` allowlist, a review flow over the product `status`, an audit record for every submission, and its own product workflows. No store owns a product: a store sells a master product through an [offer](/platform/offer/overview) that carries its own SKU, price, and stock.
10
+
11
+ <img className="block dark:hidden" src="/images/figures/catalog-overview-light.svg" alt="A product_seller link table behind a Products list of the shared catalog: each master product shows its status, the stores on its allowlist, and its offer count, with the Linen shirt restricted to ACME highlighted." />
12
+ <img className="hidden dark:block" src="/images/figures/catalog-overview-dark.svg" alt="A product_seller link table behind a Products list of the shared catalog: each master product shows its status, the stores on its allowlist, and its offer count, with the Linen shirt restricted to ACME highlighted." />
16
13
 
17
14
  <Note>
18
- **Catalog = Medusa's Product module + Mercur's marketplace layer.** Products,
19
- variants, categories, and collections are Medusa's native `Product` module.
20
- Mercur adds the `product_seller` allowlist (which stores may sell a product),
21
- the `draft` → `proposed` → `published` / `rejected` status lifecycle, and its
22
- own product workflows. Products are **shared master products**, not
23
- seller-owned, and a store sells one via an [offer](/platform/offer/overview).
15
+ There's no Mercur catalog module. Resolve the service with `Modules.PRODUCT` from `@medusajs/framework/utils`, and run Mercur's product workflows from `@mercurjs/core/workflows`. Mercur's `createProductsWorkflow` has the same name as Medusa's, so check the import path.
24
16
  </Note>
25
17
 
26
18
  ## Key features
27
19
 
28
- - **Shared master data:** products live in one catalog, not owned by any store. Creating a product adds it to the shared catalog.
29
- - **Allowlist access control:** the `product_seller` link governs which stores may sell a given master product.
30
- - **Approval governance:** a `draft` → `proposed` → `published` / `rejected` lifecycle, with vendor-created products defaulting to `proposed`.
31
- - **Attribution, not ownership:** the creator of an unreviewed submission is recorded for audit, but the product still belongs to the shared catalog.
32
- - **Native Medusa structure:** variants, categories, collections, tags, and types come straight from Medusa's Product module.
33
- - **Sold via offers:** a store lists a master product by creating an offer that carries its SKU, price, and inventory.
20
+ The catalog layer covers how products enter the marketplace and who can sell them:
21
+
22
+ - **Shared master products**: one `Product` record per item, sold by any number of stores through offers
23
+ - **Store allowlist**: the `product_seller` link restricts a product to the stores on it; a product with no rows is open to every store
24
+ - **Review flow**: vendor submissions start as `proposed` and an operator publishes or rejects them
25
+ - **Submission audit**: every create and review step writes a confirmed `ProductChange` record with the actor who did it
26
+ - **Attribute-driven variants**: products take Mercur attributes on create, and variant-axis attributes become the options variants bind to
27
+ - **Native structure**: variants, categories, collections, tags, and types come straight from Medusa's Product module
28
+
29
+ ## How it works
30
+
31
+ A product moves through the catalog in a fixed order:
32
+
33
+ 1. A store or an operator runs `createProductsWorkflow`. Vendor submissions default to `proposed`.
34
+ 2. The workflow records a `PRODUCT_ADD` change with the creator as `created_by`, and links any `seller_ids` to the product.
35
+ 3. An operator runs `confirmProductsWorkflow`, `rejectProductWorkflow`, or `requestProductChangeWorkflow` on the proposed product.
36
+ 4. Once `published`, the product shows in the Store API and to every store its allowlist permits.
37
+ 5. Each store that sells it creates an offer against one of its variants.
34
38
 
35
39
  ## Get started
36
40
 
37
- Learn how the domain fits together.
41
+ Learn how master products, the allowlist, and statuses fit together.
38
42
 
39
43
  <CardGroup cols={2}>
40
44
  <Card title="Master products" icon="box" href="/platform/catalog/concepts/master-products">
41
- The shared catalog, why products aren't seller-owned, and submission attribution.
45
+ Why products belong to the catalog and how Mercur records who submitted them.
42
46
  </Card>
43
47
  <Card title="The store allowlist" icon="user-lock" href="/platform/catalog/concepts/product-seller-allowlist">
44
- The `product_seller` link that controls who may sell a product.
48
+ How the `product_seller` link decides which stores see and sell a product.
45
49
  </Card>
46
50
  <Card title="Status lifecycle" icon="arrows-rotate" href="/platform/catalog/concepts/status-lifecycle">
47
- Draft, proposed, published, and rejected, plus how products move between them.
51
+ The four statuses and the workflow behind each transition.
48
52
  </Card>
49
53
  <Card title="Variants & categories" icon="sitemap" href="/platform/catalog/concepts/variants-categories-collections">
50
- Variants, categories, collections, tags, and types from Medusa's Product module.
54
+ The Medusa models that structure the catalog, and where Mercur extends them.
51
55
  </Card>
52
56
  </CardGroup>
53
57
 
54
58
  ## Examples
55
59
 
56
- Build against the Catalog domain in your own code.
60
+ Build against the catalog in your own server code.
57
61
 
58
62
  <CardGroup cols={2}>
59
63
  <Card title="Create a master product" icon="plus" href="/platform/catalog/guides/create-a-master-product">
60
- Run `createProductsWorkflow` from a route or seed script.
64
+ Run `createProductsWorkflow` with attributes, variants, and an allowlist.
61
65
  </Card>
62
66
  <Card title="Allowlist stores" icon="user-plus" href="/platform/catalog/guides/allowlist-stores">
63
- Grant and revoke a store's right to sell a product in code.
67
+ Restrict a product to chosen stores, or open it to all of them again.
64
68
  </Card>
65
69
  <Card title="Publish or reject" icon="gavel" href="/platform/catalog/guides/publish-or-reject-a-product">
66
- Move a proposed product to published or rejected.
70
+ Review a proposed product from a route or a subscriber.
67
71
  </Card>
68
72
  </CardGroup>
69
73
 
70
74
  ## Resources
71
75
 
72
- Data models, workflows, service methods, and events for the Catalog domain.
76
+ The data models, links, workflows, service methods, and events behind the catalog.
73
77
 
74
78
  <CardGroup cols={2}>
75
79
  <Card title="Data models" icon="table" href="/platform/catalog/reference/data-models">
76
- The `Product`, `ProductVariant`, `ProductCategory`, and the `product_seller` table.
80
+ `Product`, `ProductVariant`, `ProductCategory`, and the other Product module models.
77
81
  </Card>
78
82
  <Card title="Links" icon="link" href="/platform/catalog/reference/links">
79
- How the catalog links to sellers, offers, attributes, and media.
83
+ How products and categories link to stores, offers, attributes, changes, and media.
80
84
  </Card>
81
85
  <Card title="Workflows" icon="diagram-project" href="/platform/catalog/reference/workflows">
82
- Mercur's product create, review, and allowlist workflows.
86
+ Mercur's create, review, allowlist, and category workflows with their hooks.
83
87
  </Card>
84
88
  <Card title="Service" icon="gear" href="/platform/catalog/reference/service">
85
89
  Medusa's Product module service, resolved with `Modules.PRODUCT`.
86
90
  </Card>
87
91
  <Card title="Events" icon="bell" href="/platform/catalog/reference/events">
88
- Events emitted as products are created and reviewed.
92
+ The events Mercur emits when products are created and reviewed.
89
93
  </Card>
90
94
  </CardGroup>