@mercurjs/docs 2.3.8-canary.3 → 2.3.9-canary.1

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 (120) hide show
  1. package/content/learn/architecture.mdx +166 -263
  2. package/content/learn/introduction.mdx +9 -1
  3. package/content/learn/use-cases.mdx +70 -0
  4. package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
  5. package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
  6. package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
  7. package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
  8. package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
  9. package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
  10. package/content/platform/attribute/overview.mdx +37 -33
  11. package/content/platform/attribute/reference/data-models.mdx +53 -38
  12. package/content/platform/attribute/reference/events.mdx +47 -24
  13. package/content/platform/attribute/reference/links.mdx +98 -27
  14. package/content/platform/attribute/reference/service.mdx +71 -32
  15. package/content/platform/attribute/reference/workflows.mdx +158 -28
  16. package/content/platform/catalog/concepts/master-products.mdx +39 -37
  17. package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
  18. package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
  19. package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
  20. package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
  21. package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
  22. package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
  23. package/content/platform/catalog/overview.mdx +39 -35
  24. package/content/platform/catalog/reference/data-models.mdx +154 -43
  25. package/content/platform/catalog/reference/events.mdx +41 -25
  26. package/content/platform/catalog/reference/links.mdx +196 -28
  27. package/content/platform/catalog/reference/service.mdx +57 -35
  28. package/content/platform/catalog/reference/workflows.mdx +124 -30
  29. package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
  30. package/content/platform/commission/concepts/rule-matching.mdx +53 -63
  31. package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
  32. package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
  33. package/content/platform/commission/guides/create-a-rate.mdx +101 -53
  34. package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
  35. package/content/platform/commission/overview.mdx +43 -35
  36. package/content/platform/commission/reference/data-models.mdx +59 -45
  37. package/content/platform/commission/reference/events.mdx +28 -34
  38. package/content/platform/commission/reference/links.mdx +42 -33
  39. package/content/platform/commission/reference/service.mdx +103 -28
  40. package/content/platform/commission/reference/workflows.mdx +101 -27
  41. package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
  42. package/content/platform/offer/concepts/shipping.mdx +28 -29
  43. package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
  44. package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
  45. package/content/platform/offer/guides/create-an-offer.mdx +112 -60
  46. package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
  47. package/content/platform/offer/overview.mdx +39 -32
  48. package/content/platform/offer/reference/data-models.mdx +77 -47
  49. package/content/platform/offer/reference/events.mdx +44 -18
  50. package/content/platform/offer/reference/links.mdx +92 -40
  51. package/content/platform/offer/reference/service.mdx +66 -31
  52. package/content/platform/offer/reference/workflows.mdx +146 -37
  53. package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
  54. package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
  55. package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
  56. package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
  57. package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
  58. package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
  59. package/content/platform/order-group/overview.mdx +42 -32
  60. package/content/platform/order-group/reference/data-models.mdx +48 -31
  61. package/content/platform/order-group/reference/events.mdx +29 -17
  62. package/content/platform/order-group/reference/links.mdx +90 -29
  63. package/content/platform/order-group/reference/service.mdx +55 -31
  64. package/content/platform/order-group/reference/workflows.mdx +83 -24
  65. package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
  66. package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
  67. package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
  68. package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
  69. package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
  70. package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
  71. package/content/platform/payout/overview.mdx +43 -34
  72. package/content/platform/payout/reference/data-models.mdx +63 -36
  73. package/content/platform/payout/reference/events.mdx +56 -30
  74. package/content/platform/payout/reference/links.mdx +52 -22
  75. package/content/platform/payout/reference/service.mdx +72 -33
  76. package/content/platform/payout/reference/workflows.mdx +80 -19
  77. package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
  78. package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
  79. package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
  80. package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
  81. package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
  82. package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
  83. package/content/platform/product-edit/overview.mdx +41 -34
  84. package/content/platform/product-edit/reference/data-models.mdx +73 -47
  85. package/content/platform/product-edit/reference/events.mdx +39 -29
  86. package/content/platform/product-edit/reference/links.mdx +32 -24
  87. package/content/platform/product-edit/reference/service.mdx +45 -26
  88. package/content/platform/product-edit/reference/workflows.mdx +173 -31
  89. package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
  90. package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
  91. package/content/platform/review/concepts/the-review-model.mdx +52 -45
  92. package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
  93. package/content/platform/review/guides/create-a-review.mdx +109 -39
  94. package/content/platform/review/guides/moderate-a-review.mdx +83 -37
  95. package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
  96. package/content/platform/review/overview.mdx +43 -33
  97. package/content/platform/review/reference/data-models.mdx +41 -27
  98. package/content/platform/review/reference/events.mdx +55 -37
  99. package/content/platform/review/reference/links.mdx +80 -22
  100. package/content/platform/review/reference/service.mdx +61 -33
  101. package/content/platform/review/reference/workflows.mdx +80 -24
  102. package/content/platform/store/concepts/lifecycle.mdx +68 -44
  103. package/content/platform/store/concepts/store-entity.mdx +45 -27
  104. package/content/platform/store/concepts/team.mdx +56 -35
  105. package/content/platform/store/guides/create-a-store.mdx +102 -35
  106. package/content/platform/store/guides/manage-the-team.mdx +122 -32
  107. package/content/platform/store/guides/moderate-a-store.mdx +107 -38
  108. package/content/platform/store/overview.mdx +41 -34
  109. package/content/platform/store/reference/data-models.mdx +132 -57
  110. package/content/platform/store/reference/events.mdx +42 -17
  111. package/content/platform/store/reference/links.mdx +67 -49
  112. package/content/platform/store/reference/service.mdx +105 -33
  113. package/content/platform/store/reference/workflows.mdx +304 -24
  114. package/content/references/api/conventions.mdx +20 -0
  115. package/content/resources/integrations/magento2.mdx +162 -0
  116. package/content/resources/integrations/overview.mdx +10 -0
  117. package/content/resources/integrations/stripe-connect.mdx +1 -1
  118. package/content/resources/tutorials/custom-api-route.mdx +3 -2
  119. package/llms.txt +113 -111
  120. package/package.json +1 -1
@@ -1,350 +1,253 @@
1
1
  ---
2
2
  title: "Architecture"
3
- description: "How Mercur is put together: the runtime layers, the boundary between the marketplace platform and your own code, and the zones you extend."
3
+ description: "What runs where in a Mercur project, which package does what, and where your own code goes."
4
4
  ---
5
5
 
6
- Mercur is an open-source marketplace platform. It gives you a multi-vendor
7
- commerce backend, an admin panel, and a vendor portal that you deploy on your own
8
- infrastructure and change at the source level.
9
-
10
- It is not a hosted service you integrate with, and it is not a starter kit you
11
- finish yourself. Mercur is a running system on day one, with defined seams for
12
- the parts every marketplace does differently: onboarding rules, commission logic,
13
- approval policy, back-office integrations, and the screens your teams work in.
14
-
15
- This page describes those layers and those seams. If you are evaluating Mercur,
16
- the two questions it answers are **what runs where** and **where does my code go**.
17
-
18
- ## Design principles
19
-
20
- Everything below follows from four decisions.
21
-
22
- - **You run it.** MIT-licensed, PostgreSQL, Node. No vendor in the request path, no GMV fee, no proprietary runtime. Self-host, or deploy to any cloud that runs a Node process and a database.
23
- - **Extension over configuration.** Instead of hundreds of settings, the platform exposes typed extension zones: workflow hooks, API routes, modules, custom fields, pages, and widgets. When a zone isn't enough, the source is yours to change.
24
- - **Marketplace on top of commerce, not instead of it.** Products, carts, orders, payments, and fulfillment are handled by [Medusa](https://medusajs.com), a mature commerce engine. Mercur adds only what multi-vendor requires: sellers, offers, order splitting, commissions, payouts, and governance.
25
- - **Governance is structural.** Role scoping, the product change pipeline, and exact-precision money arithmetic are properties of the architecture, not features you enable.
26
-
27
- ## The layers
28
-
29
- Mercur is a single deployable backend with three API surfaces, plus two panel
30
- applications that are ordinary clients of those APIs.
31
-
32
- ```mermaid
33
- graph TD
34
- subgraph Clients
35
- A[Admin Panel<br/>React]
36
- B[Vendor Portal<br/>React]
37
- C[Storefront<br/>any framework]
38
- D[Your services<br/>ERP · PIM · agents]
39
- end
40
-
41
- subgraph "Backend — one Node process"
42
- E["/admin/*"]
43
- F["/vendor/*"]
44
- G["/store/*"]
45
- H[Marketplace domain<br/>sellers · offers · commissions · payouts · governance]
46
- I[Commerce domain<br/>products · carts · orders · payments · fulfillment]
47
- end
48
-
49
- J[(PostgreSQL)]
50
- K[Redis · event bus, workflow engine, cache]
51
- L[Providers<br/>payment · payout · fulfillment · notification · search]
52
-
53
- A --> E
54
- B --> F
55
- C --> G
56
- D --> E
57
- E --> H
58
- F --> H
59
- G --> H
60
- H --> I
61
- I --> J
62
- H --> J
63
- H --> K
64
- H --> L
65
- ```
66
-
67
- ### Data
6
+ Mercur is a [Medusa](https://medusajs.com) application with a marketplace layer on top. One Node process serves three HTTP APIs, two React panels and your storefront call it through a typed client, and PostgreSQL stores all data. This page lists each piece, the package it ships in, and where your own code fits.
68
7
 
69
- One PostgreSQL database. Every domain owns its own tables and never reaches into
70
- another's; relationships across domains are declared explicitly as links (see
71
- [Links](#links)). That isolation is what makes a domain replaceable, and what
72
- keeps a schema change local instead of platform-wide.
8
+ <img className="block dark:hidden" src="/images/figures/architecture-layers-light.svg" alt="Mercur's architecture: the admin and vendor panels, a storefront, and your services call the backend through @mercurjs/client. The backend exposes /admin, /vendor, and /store and runs marketplace modules from @mercurjs/core beside Medusa's commerce modules and your own code, over PostgreSQL, Redis, and providers." />
9
+ <img className="hidden dark:block" src="/images/figures/architecture-layers-dark.svg" alt="Mercur's architecture: the admin and vendor panels, a storefront, and your services call the backend through @mercurjs/client. The backend exposes /admin, /vendor, and /store and runs marketplace modules from @mercurjs/core beside Medusa's commerce modules and your own code, over PostgreSQL, Redis, and providers." />
73
10
 
74
- Redis backs the event bus, the workflow engine, and caching in production. In
75
- development both fall back to in-memory implementations, so a laptop needs
76
- nothing but Postgres.
11
+ ## How a request runs
77
12
 
78
- ### Domain
13
+ Mercur keeps Medusa’s layers as they are, so [Medusa’s architecture guide](https://docs.medusajs.com/learn/introduction/architecture) applies to every Mercur project. A request passes through four layers:
79
14
 
80
- The domain layer is where marketplace behaviour lives: seller accounts and
81
- members, offers against a shared product catalog, commission rules and their
82
- resolution, payout accounts and transfers, order groups, the product change
83
- pipeline. It calls into the commerce domain for anything commerce already does.
15
+ 1. **API route**: an HTTP handler under `/admin`, `/vendor`, or `/store`. Middleware authenticates the caller first; on `/vendor` it also resolves the caller’s seller before any handler runs, including handlers you add.
16
+ 2. **Workflow**: the handler runs a workflow for every write. Each step has a compensation function, so when a step fails, the steps before it roll back.
17
+ 3. **Module**: workflow steps call module services. A module owns its tables and never imports another module.
18
+ 4. **Data**: every module stores its tables in the same PostgreSQL database. Links record relationships between modules without foreign keys between their tables.
84
19
 
85
- Two things about this layer matter to an architect:
20
+ Reads skip the workflow layer. Handlers call Medusa’s [Query](https://docs.medusajs.com/learn/fundamentals/module-links/query), which follows links across modules in one call.
86
21
 
87
- - **It is not a wrapper.** Mercur does not proxy or re-implement commerce endpoints. Marketplace concepts are first-class records with their own lifecycle, joined to commerce records through links.
88
- - **Your own domains sit beside it.** A module you write, a module Mercur ships, and a module Medusa ships are the same kind of object, registered the same way, with the same access to the container, the event bus, and the workflow engine. There is no privileged inner ring.
22
+ Checkout uses all four layers in a single request. `completeCartWithSplitOrdersWorkflow` groups the cart’s items by seller, creates one order per seller under an order group, and refreshes each order’s commission lines. If a step fails, the workflow rolls back and the cart stays open.
89
23
 
90
- ### API
24
+ <img className="block dark:hidden" src="/images/figures/order-split-light.svg" alt="A cart with items from two sellers becomes order group #G98, split into order #100 for ACME and order #99 for GLOBEX, each with its own status, commission, and payout." />
25
+ <img className="hidden dark:block" src="/images/figures/order-split-dark.svg" alt="A cart with items from two sellers becomes order group #G98, split into order #100 for ACME and order #99 for GLOBEX, each with its own status, commission, and payout." />
91
26
 
92
- Three HTTP surfaces, one per audience, separated because their authorization
93
- models differ, not because their data does.
27
+ ## Backend packages
94
28
 
95
- | Surface | Path | Audience | Scoping |
96
- | ---------- | ----------- | --------------------- | ------------------------------------------------------------------ |
97
- | **Admin** | `/admin/*` | Marketplace operators | Platform-wide, gated by role |
98
- | **Vendor** | `/vendor/*` | Sellers | Every request is narrowed to the caller's seller before the handler |
99
- | **Store** | `/store/*` | Customers, storefront | Public catalog and the caller's own cart, orders, and account |
29
+ The backend is one Medusa server. Mercur adds a plugin and providers to it; it doesn’t replace or fork the framework.
100
30
 
101
- A route is a thin adapter: middleware authenticates and scopes, a Zod validator
102
- checks the payload, and the handler runs a workflow for writes or the query
103
- engine for reads. Business logic does not live in routes, which is why adding
104
- one is cheap and overriding one is safe. See the
105
- [API conventions](/references/api/conventions).
31
+ ### Medusa
106
32
 
107
- ### Clients
33
+ Medusa is the commerce engine: products, pricing, carts, orders, payments, fulfillment, promotions, and the module, workflow, and event system the rest of Mercur is built on. Anything in [Medusa’s documentation](https://docs.medusajs.com/learn) works in a Mercur project.
108
34
 
109
- The admin panel and the vendor portal are separate React applications, not a
110
- templated back office. They talk to the backend through `@mercurjs/client`, a
111
- typed fetch wrapper generated from the real route definitions — including routes
112
- you add — so a backend change that breaks a caller fails at `tsc`, not in
113
- production.
35
+ ### `@mercurjs/core`
114
36
 
115
- The storefront is deliberately not shipped as a fixed application. Anything that
116
- speaks HTTP consumes the Store API; a reference Next.js storefront is available
117
- to start from.
37
+ The marketplace plugin. It contains the marketplace modules (sellers and members, offers, commissions, payouts, product attributes, the product change pipeline, reviews, and custom fields), the workflows that connect them to commerce, the `/vendor` API, and the marketplace routes on `/admin` and `/store`. You register it by wrapping your Medusa config with `withMercur()`:
118
38
 
119
- ## The building blocks
39
+ ```ts medusa-config.ts
40
+ import { withMercur } from "@mercurjs/core"
120
41
 
121
- Four primitives compose the domain layer. You use the same four to extend it.
42
+ module.exports = withMercur({
43
+ projectConfig: {
44
+ databaseUrl: process.env.DATABASE_URL,
45
+ redisUrl: process.env.REDIS_URL,
46
+ },
47
+ })
48
+ ```
122
49
 
123
- ### Modules
50
+ Everything else in this file is standard Medusa configuration.
124
51
 
125
- A module owns one domain: its data models, its service, its migrations. Modules
126
- never import each other. That constraint is what lets you swap Mercur's
127
- commission logic for your own, or drop a module you don't use, without a
128
- refactor rippling outward. [Modules →](/resources/best-practices/modules)
52
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/core) · [Platform modules](/platform/store/overview)
129
53
 
130
- ### Links
54
+ ### `@mercurjs/payout-stripe-connect`
131
55
 
132
- A link declares a relationship between records in two modules without either
133
- module knowing about the other. The product–seller link, for example, is what
134
- allowlists which sellers may sell a given product — expressed as a link rather
135
- than a foreign key, so neither the product model nor the seller model is
136
- modified. Your modules link to built-in entities exactly the same way.
137
- [Links →](/resources/best-practices/module-links)
56
+ A payout provider built on Stripe Connect. It creates a connected account per seller, returns onboarding links, transfers each seller’s share, and maps Stripe webhooks to payout account statuses.
138
57
 
139
- ### Workflows
58
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/providers/payout-stripe-connect) · [Stripe Connect guide](/resources/integrations/stripe-connect)
140
59
 
141
- A workflow is a multi-step operation with automatic compensation: if step five
142
- fails, steps one through four roll back. Anything that crosses domains or must
143
- not half-happen is a workflow — seller approval, payout transfer, and above all
144
- cart completion, which validates the cart, splits it by seller, creates an order
145
- each, allocates payment, and computes commission lines as one atomic unit.
60
+ ### PostgreSQL and Redis
146
61
 
147
- Workflows also expose **hooks**, which is the primary backend extension zone.
148
- [Workflows →](/resources/best-practices/workflows)
62
+ PostgreSQL is the only supported database. The starter `medusa-config.ts` uses Redis for the event bus, the workflow engine, locking, and the cache; Medusa also ships in-memory versions of these modules for development.
149
63
 
150
- ### Events and subscribers
64
+ ## Providers
151
65
 
152
- Workflows emit events; subscribers react asynchronously. Notifications, webhooks
153
- to your systems, search indexing, and payout side effects all hang off this,
154
- which keeps the transactional path short and lets you add behaviour without
155
- touching the workflow that triggered it.
156
- [Subscribers and jobs →](/resources/best-practices/subscribers-and-jobs)
66
+ Mercur doesn’t choose your payment gateway, carrier, email service, or search engine. Each integration sits behind a provider interface, and you pick the implementation in `medusa-config.ts`:
157
67
 
158
- ## Extension zones
68
+ | Concern | Provider interface | Available implementations |
69
+ | --- | --- | --- |
70
+ | Payments | Medusa payment module | Stripe, or your own provider |
71
+ | Seller payouts | Mercur payout module | `@mercurjs/payout-stripe-connect`, a `system` provider for development |
72
+ | Fulfillment | Medusa fulfillment module | Manual, or a carrier provider |
73
+ | Notifications | Medusa notification module | Local, SendGrid |
74
+ | Files | Medusa file module | Local, S3 |
75
+ | Authentication | Medusa auth module | Email and password, Google, GitHub |
76
+ | Search | Blocks | `algolia`, `meilisearch` |
77
+ | Events, workflows, locking, cache | Medusa infrastructure modules | In-memory, Redis |
159
78
 
160
- This is the part that determines what a build actually costs. Mercur exposes six
161
- zones. Each one is typed, each one is additive, and none of them require forking
162
- or patching platform code.
79
+ Swapping a provider doesn’t touch marketplace code. A payout provider implements `IPayoutProvider` from `@mercurjs/types`, which has four methods: `createPayoutAccount`, `createOnboarding`, `createPayout`, and `getWebhookActionAndData`. You register it on the payout module:
163
80
 
164
- ```mermaid
165
- graph LR
166
- subgraph Backend
167
- A[Workflow hooks<br/>inject steps into existing flows]
168
- B[API routes<br/>add or override endpoints]
169
- C[Modules and links<br/>add domains]
170
- D[Custom fields<br/>extra data on built-in entities]
171
- end
172
- subgraph Panels
173
- E[Pages<br/>new routes]
174
- F[Widgets<br/>components in named zones]
175
- G[Custom field UI<br/>forms · rows · columns]
176
- H[Navigation<br/>reorder · relabel · hide]
177
- end
81
+ ```ts medusa-config.ts
82
+ {
83
+ resolve: "@mercurjs/core/modules/payout",
84
+ options: {
85
+ providers: [
86
+ {
87
+ resolve: "./src/providers/my-payout",
88
+ id: "my-payout",
89
+ options: { apiKey: process.env.PAYOUT_API_KEY },
90
+ },
91
+ ],
92
+ },
93
+ }
178
94
  ```
179
95
 
180
- ### 1. Workflow hooks — change what happens
96
+ For the Medusa provider types, see [Medusa’s integrations](https://docs.medusajs.com/resources/integrations).
97
+
98
+ ## Panel packages
99
+
100
+ The admin panel and the vendor panel are React 18 apps built with Vite and [Medusa UI](https://docs.medusajs.com/ui). They ship as packages that your host apps render, so you upgrade them by bumping a version.
181
101
 
182
- The default way to change platform behaviour. A hook is a declared point inside
183
- an existing workflow where you register your own step. Your step runs inside the
184
- original transaction and participates in its rollback, so you are not
185
- reimplementing the flow to add one rule.
102
+ ### `@mercurjs/admin` and `@mercurjs/vendor`
186
103
 
187
- ```ts src/workflows/hooks/seller-approved.ts
188
- import { approveSellerWorkflow } from "@mercurjs/core/workflows"
104
+ `@mercurjs/admin` is the operator panel and `@mercurjs/vendor` is the seller panel. A host app renders the panel and adds its stylesheet:
189
105
 
190
- approveSellerWorkflow.hooks.sellerApproved(
191
- async ({ seller_id }, { container }) => {
192
- await container.resolve("erp").createVendorAccount(seller_id)
193
- }
194
- )
106
+ ```tsx apps/admin/src/main.tsx
107
+ import { createRoot } from "react-dom/client"
108
+ import App from "@mercurjs/admin"
109
+ import "@mercurjs/admin/index.css"
110
+
111
+ createRoot(document.getElementById("root")!).render(<App />)
195
112
  ```
196
113
 
197
- Reach for a hook when the answer is "the standard flow, plus something."
198
- [Extend a workflow →](/resources/customization/extend-a-workflow)
114
+ In development, the host apps run on ports 7000 and 7001. In production you can deploy them as static sites, or serve them from the backend with the `admin-ui` and `vendor-ui` modules of `@mercurjs/core`.
199
115
 
200
- ### 2. API routes — add endpoints
116
+ [Admin source](https://github.com/mercurjs/mercur/tree/main/packages/admin) · [Vendor source](https://github.com/mercurjs/mercur/tree/main/packages/vendor)
201
117
 
202
- Drop a `route.ts` under `src/api/**` and the endpoint exists. Routes nest under
203
- the built-in ones, so a new resource can hang off an existing entity rather than
204
- living off to the side.
118
+ ### `@mercurjs/dashboard-sdk`
205
119
 
206
- ```
207
- src/api/vendor/sellers/documents/route.ts → GET/POST /vendor/sellers/documents
208
- src/api/vendor/sellers/documents/[id]/route.ts → GET/DELETE /vendor/sellers/documents/:id
120
+ A Vite plugin that turns files in a host app into panel extensions. Pages come from `src/routes/**/page.tsx`, widgets from `src/widgets/`, custom-field UI from `src/custom-fields/`, and sidebar changes from `src/_navigation.ts`:
121
+
122
+ ```ts vite.config.ts
123
+ import react from "@vitejs/plugin-react"
124
+ import { defineConfig } from "vite"
125
+ import { mercurDashboardPlugin } from "@mercurjs/dashboard-sdk/vite"
126
+
127
+ export default defineConfig({
128
+ plugins: [
129
+ react(),
130
+ mercurDashboardPlugin({ medusaConfigPath: "../api/medusa-config.ts" }),
131
+ ],
132
+ })
209
133
  ```
210
134
 
211
- Your routes get the same treatment as the built-in ones: vendor requests are
212
- already scoped to the caller's seller by the surrounding middleware, and codegen
213
- picks the route up so it appears on the typed client with real request and
214
- response types.
135
+ The plugin also writes `extension-targets.d.ts` with every zone id and model name, so a widget that targets a missing zone fails type-checking.
215
136
 
216
- [Create an API route →](/resources/best-practices/api-routes)
137
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/dashboard-sdk) · [Panel extensions](/references/panel-extensions/overview)
217
138
 
218
- ### 3. Modules and links — add domains
139
+ ### `@mercurjs/dashboard-shared`
219
140
 
220
- When the data has its own lifecycle — subscriptions, RMAs, contracts, quotas —
221
- it is a module, not a field. You define the models and service, link the module
222
- to the built-in entities it relates to, and it becomes queryable in the same
223
- graph as everything else. This is how substantial vertical features get built,
224
- and it is the same mechanism Mercur's own domains use.
141
+ The UI primitives both panels are built from: forms, tabbed create flows, data tables, route modals and drawers, and query-key helpers. Use them in your own pages so they match the built-in screens.
225
142
 
226
- ### 4. Custom fields — add data to built-in entities
143
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/dashboard-shared)
227
144
 
228
- For one plain property on an existing record — `is_featured` on a product,
229
- `tier` on a customer — you declare the field in configuration and the storage,
230
- link, and migration are generated for you.
145
+ ## Client packages
231
146
 
232
- ```ts medusa-config.ts
233
- {
234
- resolve: "@mercurjs/core/modules/custom-fields",
235
- options: {
236
- customFields: {
237
- Product: { is_featured: { type: "boolean", nullable: true } },
238
- },
239
- },
240
- }
147
+ Every Mercur client, the panels included, talks to the backend over HTTP through the same typed client.
148
+
149
+ ### `@mercurjs/client`
150
+
151
+ A typed fetch wrapper. `mercurjs codegen` reads your backend’s API routes, including the ones you add, and writes a `Routes` type. The client turns property access on that type into requests:
152
+
153
+ ```ts src/lib/client.ts
154
+ import { createClient, type InferClient } from "@mercurjs/client"
155
+ import type { Routes } from "@acme/api/_generated"
156
+
157
+ export const client: InferClient<Routes> = createClient({
158
+ baseUrl: "http://localhost:9000",
159
+ })
160
+
161
+ const { sellers } = await client.admin.sellers.query({ limit: 20 })
241
162
  ```
242
163
 
243
- One row per parent, no lifecycle of its own; anything more is a module.
244
- [Custom fields →](/resources/best-practices/custom-fields)
164
+ `.query()` sends a `GET`, `.mutate()` sends a `POST`, and `.delete()` sends a `DELETE`. Because the panels use this client too, a backend change that breaks a caller fails at `tsc` instead of at runtime.
165
+
166
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/client) · [Add a typed API route](/resources/tutorials/custom-api-route)
245
167
 
246
- ### 5. Panel pages and widgets — change what teams see
168
+ ### `@mercurjs/types`
247
169
 
248
- The panels are extended by file convention. A file's folder decides what it does,
249
- and there is no manifest to maintain.
170
+ Mercur’s entity and HTTP types (sellers, offers, commissions, payouts, order groups), plus re-exports of Medusa’s types. A storefront can type its responses with this package without importing the backend.
250
171
 
251
- | Path | Adds |
252
- | ------------------------ | ------------------------------------- |
253
- | `src/routes/**/page.tsx` | A new page and its route |
254
- | `src/widgets/**` | A component in a named zone on a built-in page |
255
- | `src/custom-fields/**` | Form fields, detail rows, and list columns on a built-in model |
256
- | `src/_navigation.ts` | Sidebar order, labels, and visibility |
172
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/types)
257
173
 
258
- A widget targets a slot on an existing page, which is how you put a payout
259
- summary on the order detail screen without owning that screen:
174
+ ## Tooling packages
260
175
 
261
- ```tsx apps/vendor/src/widgets/payout-summary.tsx
262
- export const config = defineWidgetConfig({ zone: "orders.detail.side.after" })
176
+ These packages run on your machine or in CI. None of them run in production.
177
+
178
+ ### `@mercurjs/cli`
179
+
180
+ The `mercurjs` command. It installs and updates blocks (`add`, `diff`, `search`, `view`), generates route types (`codegen`), and builds plugins and registries:
181
+
182
+ ```bash
183
+ bunx @mercurjs/cli@latest add wishlist
263
184
  ```
264
185
 
265
- Zone ids, model names, and field ids are generated per panel into
266
- `extension-targets.d.ts`, so a mistargeted extension fails type-checking instead
267
- of silently not rendering.
268
- [Panel extensions →](/references/panel-extensions/overview)
186
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/cli)
269
187
 
270
- ### 6. Blocks — install features as source
188
+ ### `create-mercur-app`
271
189
 
272
- Larger features ship as blocks. The CLI copies the source into your project
273
- rather than adding a dependency, so a block is yours from the moment it lands:
274
- readable, debuggable, and modifiable without waiting on an upstream release.
275
- Updates are explicit — `diff` against the registry and take what you want.
190
+ Creates a new project: the API, the admin host app, and the vendor host app in one Turborepo workspace.
276
191
 
277
192
  ```bash
278
- bunx @mercurjs/cli@latest add reviews
193
+ bunx create-mercur-app@latest
279
194
  ```
280
195
 
281
- [Blocks →](/learn/blocks)
196
+ [Source](https://github.com/mercurjs/mercur/tree/main/packages/create-mercur-app)
197
+
198
+ ### Blocks
282
199
 
283
- ### Choosing a zone
200
+ Blocks are features that the CLI copies into your project as source code: modules, workflows, API routes, and panel extensions. Once installed, a block is your code. `mercurjs diff` shows what changed upstream, and you decide what to take. The official registry includes `wishlist`, `algolia`, `meilisearch`, `vendor-chat`, and `requests`, and you can host your own registry.
284
201
 
285
- | You want to… | Use |
286
- | --------------------------------------------------- | ----------------------- |
287
- | Add a rule or side effect to an existing operation | Workflow hook |
288
- | Expose new data or a new operation over HTTP | API route |
289
- | Model something with its own lifecycle | Module and link |
290
- | Store one extra property on a built-in entity | Custom field |
291
- | Show or capture something in the panels | Page, widget, or custom-field UI |
292
- | Adopt a whole feature and own it | Block |
202
+ [Blocks](/learn/blocks) · [Registry](/learn/registry)
293
203
 
294
- ## Governance
204
+ ### `@mercurjs/docs`
295
205
 
296
- Multi-vendor means untrusted writers, so the guarantees operators need are built
297
- into the layers rather than layered on.
206
+ These docs, bundled into `node_modules` with an `llms.txt` index. Coding agents read them to get the contracts for the Mercur version you installed.
298
207
 
299
- - **Scoping before handling.** Vendor requests are narrowed to the caller's seller in middleware, ahead of any handler. A route cannot accidentally leak across sellers, including a route you add.
300
- - **An immutable change pipeline.** Product edits are recorded as `ProductChange` entries — who changed what, who approved it, when. Low-risk edits auto-confirm; the rest queue for review. The audit trail is the mechanism, not a log written beside it.
301
- - **Exact money.** Commission and payout arithmetic uses arbitrary-precision numbers throughout, so splitting a payment across sellers stays exact.
302
- - **Agents inside the same guardrails.** The typed client, exposed workflows, `llms.txt`, and the MCP server give AI agents structured contracts — subject to the same roles and the same review pipeline as human users.
208
+ [Build with AI](/resources/ai/overview)
303
209
 
304
- ## How a multi-vendor order flows
210
+ ## Where your code goes
305
211
 
306
- One cart, several sellers. This is the path that touches every layer.
212
+ Your code lives next to Mercur’s in the same project, and nothing requires a fork. Each kind of change has one place to go:
307
213
 
308
- 1. The customer adds items from multiple sellers to a single cart (Store API).
309
- 2. Cart completion starts the split-order workflow.
310
- 3. Items are grouped by seller and an order is created per seller, all under one order group.
311
- 4. Commission lines are computed per order from the matching rules.
312
- 5. Payment is allocated proportionally across the seller orders.
313
- 6. Each seller's share is credited to its payout account, net of commission.
314
- 7. Events fire: notifications, webhooks, indexing, and any hook you registered.
315
- 8. Sellers fulfill their own orders in the vendor portal; the operator sees all of it in the admin panel.
214
+ <img className="block dark:hidden" src="/images/figures/extension-zones-light.svg" alt="Stacked panels for Blocks, Panels, and Backend, with an Extensions table in front listing one file per zone: a workflow hook, an API route, a module, a custom field, a page, and a widget, each with its typed target." />
215
+ <img className="hidden dark:block" src="/images/figures/extension-zones-dark.svg" alt="Stacked panels for Blocks, Panels, and Backend, with an Extensions table in front listing one file per zone: a workflow hook, an API route, a module, a custom field, a page, and a widget, each with its typed target." />
316
216
 
317
- Steps 2 through 6 are a single workflow. If any of it fails, none of it happened.
217
+ | You want to | Use | Location |
218
+ | --- | --- | --- |
219
+ | Add a rule or side effect to an existing flow | [Workflow hook](/resources/customization/extend-a-workflow) | `src/workflows/hooks/` |
220
+ | Expose data or an operation over HTTP | [API route](/resources/best-practices/api-routes) | `src/api/**/route.ts` |
221
+ | Model something with its own lifecycle | [Module](/resources/best-practices/modules) and [link](/resources/best-practices/module-links) | `src/modules/`, `src/links/` |
222
+ | Store one extra property on a built-in entity | [Custom field](/resources/best-practices/custom-fields) | `medusa-config.ts` |
223
+ | React to something that happened | [Subscriber](/resources/best-practices/subscribers-and-jobs) | `src/subscribers/` |
224
+ | Show something in a panel | [Page or widget](/references/panel-extensions/overview) | `src/routes/`, `src/widgets/` |
225
+ | Adopt a whole feature | [Block](/learn/blocks) | `bunx @mercurjs/cli@latest add` |
318
226
 
319
- ## Stack
227
+ ## Design decisions
320
228
 
321
- | Concern | Technology |
322
- | ------------------ | -------------------------------------------- |
323
- | Runtime | Node.js 20+, TypeScript |
324
- | Commerce engine | Medusa v2 |
325
- | Database | PostgreSQL |
326
- | Events, cache | Redis (in-memory fallback in development) |
327
- | Panels | React 18, Vite, Medusa UI, TanStack Query |
328
- | Validation, forms | Zod, React Hook Form |
329
- | Build | Turborepo, Bun, tsup |
229
+ These decisions explain the shape of the packages above:
330
230
 
331
- Mercur's own code is distributed as `@mercurjs/core`, a Medusa plugin registered
332
- by `withMercur()` in your `medusa-config.ts`. That packaging matters when you
333
- upgrade; it does not change any of the above.
231
+ - **A Mercur project is a Medusa project**: Mercur adds modules, routes, and workflows to Medusa and changes none of its layers
232
+ - **Modules don’t import each other**: links connect them, so you can replace Mercur’s commission module or remove a module you don’t use
233
+ - **Integrations are providers**: payments, payouts, fulfillment, notifications, files, and search each sit behind an interface you implement or swap
234
+ - **Seller scoping runs before handlers**: `/vendor` middleware resolves the seller before your code runs
235
+ - **Types come from the backend**: codegen reads your routes, the client reads the generated types, and the panels use the client
236
+ - **Panels are packages, features are source**: you upgrade the panels by bumping a version, and you own every block you install
334
237
 
335
238
  ## Next steps
336
239
 
337
240
  <CardGroup cols={2}>
338
241
  <Card title="Platform modules" href="/platform/store/overview">
339
- Data models, workflows, and events for each marketplace domain.
340
- </Card>
341
- <Card title="Panel extensions" href="/references/panel-extensions/overview">
342
- Pages, widgets, custom fields, and navigation.
242
+ Data models, workflows, and events for each marketplace module.
343
243
  </Card>
344
244
  <Card title="Extend a workflow" href="/resources/customization/extend-a-workflow">
345
- Inject a step into an existing flow through a hook.
245
+ Run your own step inside an existing flow through a hook.
246
+ </Card>
247
+ <Card title="Panel extensions" href="/references/panel-extensions/overview">
248
+ Add pages, widgets, custom fields, and navigation to the panels.
346
249
  </Card>
347
- <Card title="API reference" href="/references/api/conventions">
250
+ <Card title="API conventions" href="/references/api/conventions">
348
251
  Authentication, seller scoping, and the three API surfaces.
349
252
  </Card>
350
253
  </CardGroup>
@@ -18,11 +18,19 @@ Mercur focuses on the marketplace domain on top.
18
18
 
19
19
  ## Requirements
20
20
 
21
- - [Node.js v20+](https://nodejs.org/en/download) (LTS)
21
+ - [Node.js v24.22.1+](https://nodejs.org/en/download) (LTS, recommended) or v22.23.4+
22
22
  - [Bun v1.3+](https://bun.sh) (recommended package manager)
23
23
  - [Git](https://git-scm.com/downloads)
24
24
  - PostgreSQL v14+
25
25
 
26
+ <Warning>
27
+ The [October 2026 Node.js security releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases)
28
+ fix several high-severity vulnerabilities, including a remote code execution
29
+ bug in the Brotli decoder and TLS certificate hostname bypasses. We recommend
30
+ running Mercur on **Node.js v24.22.1** or later. If you stay on Node.js 22,
31
+ use v22.23.4 or later.
32
+ </Warning>
33
+
26
34
  <Tip>
27
35
  The quickest way to run PostgreSQL locally is with Docker:
28
36
 
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: "Use cases"
3
+ sidebarTitle: "Use cases"
4
+ description: "Two ways to run Mercur: as the whole marketplace, with its own storefront, admin and vendor panels, or as the marketplace layer inside a store you already run, selling seller offers next to your own products."
5
+ ---
6
+
7
+ Mercur fits two kinds of business. Pick the one that matches yours; the modules underneath are the same.
8
+
9
+ <Tabs>
10
+ <Tab title="Marketplace platform">
11
+ You are building a marketplace from scratch, or replacing one. Mercur runs everything: the storefront, the operator admin, the vendor panel sellers log into, and the backend that splits every checkout into one order per seller, computes commissions and pays sellers out.
12
+
13
+ <img className="block dark:hidden" src="/images/figures/use-case-platform-light.svg" alt="Three Mercur surfaces stacked back to front: the admin Sellers list, the vendor panel's Offers table for ACME, and the storefront product page for the Linen shirt listing the offers a shopper can buy." />
14
+ <img className="hidden dark:block" src="/images/figures/use-case-platform-dark.svg" alt="Three Mercur surfaces stacked back to front: the admin Sellers list, the vendor panel's Offers table for ACME, and the storefront product page for the Linen shirt listing the offers a shopper can buy." />
15
+
16
+ **Pick this when**
17
+
18
+ - You don't have a store yet, or you want the marketplace to be the product
19
+ - Sellers should get their own panel: offers, orders, fulfillment, payouts
20
+ - You want one shared catalog that every seller lists against
21
+
22
+ **What you get**
23
+
24
+ | Surface | Who uses it | Package |
25
+ | --- | --- | --- |
26
+ | Storefront | Shoppers | Any framework on the Store API, or the starter storefront |
27
+ | Admin panel | Operators | `@mercurjs/admin` |
28
+ | Vendor panel | Sellers | `@mercurjs/vendor` |
29
+ | Backend | Everyone | `@mercurjs/core` on Medusa |
30
+
31
+ <CardGroup cols={2}>
32
+ <Card title="Install Mercur" icon="rocket" href="/learn/introduction">
33
+ Create a marketplace project and run it locally.
34
+ </Card>
35
+ <Card title="Architecture" icon="sitemap" href="/learn/architecture">
36
+ How the panels, the API and the modules fit together.
37
+ </Card>
38
+ </CardGroup>
39
+ </Tab>
40
+ <Tab title="Marketplace inside your store">
41
+ You already sell your own products on a platform like Magento. You want third-party sellers next to them, in the same product page and the same checkout, without moving your catalog or your payments. Your store stays the storefront; Mercur becomes the marketplace layer behind it.
42
+
43
+ <img className="block dark:hidden" src="/images/figures/use-case-hybrid-light.svg" alt="A product page in your own store lists your warehouse next to two seller offers from ACME and GLOBEX. A wire leads from the seller rows to a Mercur order group with one order per seller; your own line never leaves your store." />
44
+ <img className="hidden dark:block" src="/images/figures/use-case-hybrid-dark.svg" alt="A product page in your own store lists your warehouse next to two seller offers from ACME and GLOBEX. A wire leads from the seller rows to a Mercur order group with one order per seller; your own line never leaves your store." />
45
+
46
+ **Pick this when**
47
+
48
+ - Your store, checkout and payment provider are already live and should stay
49
+ - You sell first-party stock and want sellers to compete on the same SKUs
50
+ - Sellers need a panel, but shoppers should never notice a second system
51
+
52
+ **Who runs what**
53
+
54
+ | Concern | Your store | Mercur |
55
+ | --- | --- | --- |
56
+ | Catalog, prices, stock of your own products | ✔ | |
57
+ | Storefront, cart, checkout, payment capture | ✔ | |
58
+ | Sellers, their offers, their panel | | ✔ |
59
+ | One order per seller, commissions, payouts | | ✔ |
60
+
61
+ <CardGroup cols={2}>
62
+ <Card title="Magento 2 integration" icon="store" href="/resources/integrations/magento2">
63
+ Install the connector and run a mixed first-party and seller order.
64
+ </Card>
65
+ <Card title="Order Group module" icon="layer-group" href="/platform/order-group/overview">
66
+ How one checkout becomes one order per seller.
67
+ </Card>
68
+ </CardGroup>
69
+ </Tab>
70
+ </Tabs>