@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.
- package/content/learn/architecture.mdx +166 -263
- package/content/learn/introduction.mdx +9 -1
- package/content/learn/use-cases.mdx +70 -0
- package/content/platform/attribute/concepts/attribute-types.mdx +73 -46
- package/content/platform/attribute/concepts/global-vs-inline.mdx +54 -32
- package/content/platform/attribute/concepts/variant-axes.mdx +54 -32
- package/content/platform/attribute/guides/attach-attributes-to-a-product.mdx +96 -53
- package/content/platform/attribute/guides/create-a-variant-axis.mdx +106 -57
- package/content/platform/attribute/guides/create-an-attribute.mdx +105 -56
- package/content/platform/attribute/overview.mdx +37 -33
- package/content/platform/attribute/reference/data-models.mdx +53 -38
- package/content/platform/attribute/reference/events.mdx +47 -24
- package/content/platform/attribute/reference/links.mdx +98 -27
- package/content/platform/attribute/reference/service.mdx +71 -32
- package/content/platform/attribute/reference/workflows.mdx +158 -28
- package/content/platform/catalog/concepts/master-products.mdx +39 -37
- package/content/platform/catalog/concepts/product-seller-allowlist.mdx +56 -35
- package/content/platform/catalog/concepts/status-lifecycle.mdx +55 -49
- package/content/platform/catalog/concepts/variants-categories-collections.mdx +55 -35
- package/content/platform/catalog/guides/allowlist-stores.mdx +100 -37
- package/content/platform/catalog/guides/create-a-master-product.mdx +124 -48
- package/content/platform/catalog/guides/publish-or-reject-a-product.mdx +120 -55
- package/content/platform/catalog/overview.mdx +39 -35
- package/content/platform/catalog/reference/data-models.mdx +154 -43
- package/content/platform/catalog/reference/events.mdx +41 -25
- package/content/platform/catalog/reference/links.mdx +196 -28
- package/content/platform/catalog/reference/service.mdx +57 -35
- package/content/platform/catalog/reference/workflows.mdx +124 -30
- package/content/platform/commission/concepts/order-commission-lines.mdx +54 -52
- package/content/platform/commission/concepts/rule-matching.mdx +53 -63
- package/content/platform/commission/concepts/rules-and-rates.mdx +61 -59
- package/content/platform/commission/guides/batch-update-rules.mdx +69 -41
- package/content/platform/commission/guides/create-a-rate.mdx +101 -53
- package/content/platform/commission/guides/refresh-order-commission-lines.mdx +104 -35
- package/content/platform/commission/overview.mdx +43 -35
- package/content/platform/commission/reference/data-models.mdx +59 -45
- package/content/platform/commission/reference/events.mdx +28 -34
- package/content/platform/commission/reference/links.mdx +42 -33
- package/content/platform/commission/reference/service.mdx +103 -28
- package/content/platform/commission/reference/workflows.mdx +101 -27
- package/content/platform/offer/concepts/pricing-and-inventory.mdx +63 -49
- package/content/platform/offer/concepts/shipping.mdx +28 -29
- package/content/platform/offer/concepts/what-is-an-offer.mdx +48 -45
- package/content/platform/offer/guides/bulk-create-offers.mdx +97 -61
- package/content/platform/offer/guides/create-an-offer.mdx +112 -60
- package/content/platform/offer/guides/manage-offer-inventory.mdx +78 -38
- package/content/platform/offer/overview.mdx +39 -32
- package/content/platform/offer/reference/data-models.mdx +77 -47
- package/content/platform/offer/reference/events.mdx +44 -18
- package/content/platform/offer/reference/links.mdx +92 -40
- package/content/platform/offer/reference/service.mdx +66 -31
- package/content/platform/offer/reference/workflows.mdx +146 -37
- package/content/platform/order-group/concepts/computed-totals.mdx +40 -37
- package/content/platform/order-group/concepts/order-splitting.mdx +41 -39
- package/content/platform/order-group/concepts/the-order-group.mdx +39 -32
- package/content/platform/order-group/guides/list-order-groups.mdx +96 -56
- package/content/platform/order-group/guides/retrieve-an-order-group.mdx +93 -42
- package/content/platform/order-group/guides/split-a-cart.mdx +115 -40
- package/content/platform/order-group/overview.mdx +42 -32
- package/content/platform/order-group/reference/data-models.mdx +48 -31
- package/content/platform/order-group/reference/events.mdx +29 -17
- package/content/platform/order-group/reference/links.mdx +90 -29
- package/content/platform/order-group/reference/service.mdx +55 -31
- package/content/platform/order-group/reference/workflows.mdx +83 -24
- package/content/platform/payout/concepts/account-lifecycle.mdx +64 -67
- package/content/platform/payout/concepts/accounts-and-onboarding.mdx +50 -40
- package/content/platform/payout/concepts/payout-pipeline.mdx +70 -73
- package/content/platform/payout/guides/create-a-payout-account.mdx +65 -41
- package/content/platform/payout/guides/process-a-provider-webhook.mdx +84 -38
- package/content/platform/payout/guides/start-provider-onboarding.mdx +90 -46
- package/content/platform/payout/overview.mdx +43 -34
- package/content/platform/payout/reference/data-models.mdx +63 -36
- package/content/platform/payout/reference/events.mdx +56 -30
- package/content/platform/payout/reference/links.mdx +52 -22
- package/content/platform/payout/reference/service.mdx +72 -33
- package/content/platform/payout/reference/workflows.mdx +80 -19
- package/content/platform/product-edit/concepts/change-actions.mdx +52 -45
- package/content/platform/product-edit/concepts/change-pipeline.mdx +60 -52
- package/content/platform/product-edit/concepts/status-and-auto-confirm.mdx +43 -46
- package/content/platform/product-edit/guides/confirm-or-decline-a-change.mdx +104 -56
- package/content/platform/product-edit/guides/edit-a-product.mdx +126 -46
- package/content/platform/product-edit/guides/request-a-revision.mdx +99 -39
- package/content/platform/product-edit/overview.mdx +41 -34
- package/content/platform/product-edit/reference/data-models.mdx +73 -47
- package/content/platform/product-edit/reference/events.mdx +39 -29
- package/content/platform/product-edit/reference/links.mdx +32 -24
- package/content/platform/product-edit/reference/service.mdx +45 -26
- package/content/platform/product-edit/reference/workflows.mdx +173 -31
- package/content/platform/review/concepts/product-vs-seller-reviews.mdx +42 -41
- package/content/platform/review/concepts/ratings-and-moderation.mdx +45 -44
- package/content/platform/review/concepts/the-review-model.mdx +52 -45
- package/content/platform/review/guides/compute-aggregate-ratings.mdx +62 -37
- package/content/platform/review/guides/create-a-review.mdx +109 -39
- package/content/platform/review/guides/moderate-a-review.mdx +83 -37
- package/content/platform/review/guides/respond-to-a-review.mdx +85 -40
- package/content/platform/review/overview.mdx +43 -33
- package/content/platform/review/reference/data-models.mdx +41 -27
- package/content/platform/review/reference/events.mdx +55 -37
- package/content/platform/review/reference/links.mdx +80 -22
- package/content/platform/review/reference/service.mdx +61 -33
- package/content/platform/review/reference/workflows.mdx +80 -24
- package/content/platform/store/concepts/lifecycle.mdx +68 -44
- package/content/platform/store/concepts/store-entity.mdx +45 -27
- package/content/platform/store/concepts/team.mdx +56 -35
- package/content/platform/store/guides/create-a-store.mdx +102 -35
- package/content/platform/store/guides/manage-the-team.mdx +122 -32
- package/content/platform/store/guides/moderate-a-store.mdx +107 -38
- package/content/platform/store/overview.mdx +41 -34
- package/content/platform/store/reference/data-models.mdx +132 -57
- package/content/platform/store/reference/events.mdx +42 -17
- package/content/platform/store/reference/links.mdx +67 -49
- package/content/platform/store/reference/service.mdx +105 -33
- package/content/platform/store/reference/workflows.mdx +304 -24
- package/content/references/api/conventions.mdx +20 -0
- package/content/resources/integrations/magento2.mdx +162 -0
- package/content/resources/integrations/overview.mdx +10 -0
- package/content/resources/integrations/stripe-connect.mdx +1 -1
- package/content/resources/tutorials/custom-api-route.mdx +3 -2
- package/llms.txt +113 -111
- package/package.json +1 -1
|
@@ -1,350 +1,253 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Architecture"
|
|
3
|
-
description: "
|
|
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
|
|
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
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
models differ, not because their data does.
|
|
27
|
+
## Backend packages
|
|
94
28
|
|
|
95
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
39
|
+
```ts medusa-config.ts
|
|
40
|
+
import { withMercur } from "@mercurjs/core"
|
|
120
41
|
|
|
121
|
-
|
|
42
|
+
module.exports = withMercur({
|
|
43
|
+
projectConfig: {
|
|
44
|
+
databaseUrl: process.env.DATABASE_URL,
|
|
45
|
+
redisUrl: process.env.REDIS_URL,
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
```
|
|
122
49
|
|
|
123
|
-
|
|
50
|
+
Everything else in this file is standard Medusa configuration.
|
|
124
51
|
|
|
125
|
-
|
|
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
|
-
###
|
|
54
|
+
### `@mercurjs/payout-stripe-connect`
|
|
131
55
|
|
|
132
|
-
A
|
|
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
|
-
|
|
58
|
+
[Source](https://github.com/mercurjs/mercur/tree/main/packages/providers/payout-stripe-connect) · [Stripe Connect guide](/resources/integrations/stripe-connect)
|
|
140
59
|
|
|
141
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64
|
+
## Providers
|
|
151
65
|
|
|
152
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
```
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
208
|
-
|
|
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
|
-
|
|
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
|
-
[
|
|
137
|
+
[Source](https://github.com/mercurjs/mercur/tree/main/packages/dashboard-sdk) · [Panel extensions](/references/panel-extensions/overview)
|
|
217
138
|
|
|
218
|
-
###
|
|
139
|
+
### `@mercurjs/dashboard-shared`
|
|
219
140
|
|
|
220
|
-
|
|
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
|
-
|
|
143
|
+
[Source](https://github.com/mercurjs/mercur/tree/main/packages/dashboard-shared)
|
|
227
144
|
|
|
228
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
244
|
-
|
|
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
|
-
###
|
|
168
|
+
### `@mercurjs/types`
|
|
247
169
|
|
|
248
|
-
|
|
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
|
-
|
|
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
|
-
|
|
259
|
-
summary on the order detail screen without owning that screen:
|
|
174
|
+
## Tooling packages
|
|
260
175
|
|
|
261
|
-
|
|
262
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
188
|
+
### `create-mercur-app`
|
|
271
189
|
|
|
272
|
-
|
|
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 @
|
|
193
|
+
bunx create-mercur-app@latest
|
|
279
194
|
```
|
|
280
195
|
|
|
281
|
-
[
|
|
196
|
+
[Source](https://github.com/mercurjs/mercur/tree/main/packages/create-mercur-app)
|
|
197
|
+
|
|
198
|
+
### Blocks
|
|
282
199
|
|
|
283
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
+
### `@mercurjs/docs`
|
|
295
205
|
|
|
296
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
210
|
+
## Where your code goes
|
|
305
211
|
|
|
306
|
-
|
|
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
|
-
|
|
309
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
227
|
+
## Design decisions
|
|
320
228
|
|
|
321
|
-
|
|
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
|
|
332
|
-
|
|
333
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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>
|