Skip to main content
The Product Edit module owns the product change — the request/approval record through which sellers propose edits to the shared catalog. Products in Mercur are master records that no seller owns; any seller may request a change to any product, and the operator confirms, declines, or lets the platform auto-confirm it.

The master products model

A product row is a shared catalog entry — it has no owner column. Three rules follow:
  • Selling eligibility is a separate allowlist: the product_seller link. One or more rows restrict the product to those sellers; zero rows mean the product is unrestricted.
  • Creator attribution lives on the change record (product_change.created_by plus a PRODUCT_ADD action), and is used only for scoping vendor list views — a seller sees products they created, plus published products not restricted to other sellers.
  • Edits are requests. Vendor product update endpoints stage a change instead of writing directly; there is no ownership gate on requesting a change.

Data models

ProductChange

Table product_change, ID prefix prodch.
FieldTypeNotes
product_idtextTarget product
statusenumProductChangeStatus, default pending
created_bytextNullable; requesting actor
internal_note / external_notetextNullable
confirmed_by / confirmed_attext / dateTimeNullable; audit trail
declined_by / declined_at / declined_reasontext / dateTime / textNullable
canceled_by / canceled_attext / dateTimeNullable
requires_action_by / requires_action_at / requires_action_reasontext / dateTime / textNullable; “changes requested” state
metadatajsonNullable
Relations: actions (one-to-many, deleted with the change).

ProductChangeAction

Table product_change_action, ID prefix prodchact. The ordered operations a change applies:
FieldTypeNotes
product_idtext
orderingautoincrementApply order
actiontextOperation type (e.g. PRODUCT_ADD, update, variant, attribute operations)
detailsjsonDefault {}; the operation payload
appliedbooleanDefault false
internal_notetextNullable

Enums

enum ProductChangeStatus {
  PENDING = "pending",
  CONFIRMED = "confirmed",
  DECLINED = "declined",
  CANCELED = "canceled",
}
LinkPurpose
changes (read-only)Product → its change records via product_id

Service

ProductChangeModuleService extends MedusaService with auto-generated CRUD only — the lifecycle logic lives in workflows: createProductChangeWorkflow, stageProductChangeWorkflow, confirmProductChangeWorkflow, autoConfirmProductChangeWorkflow, cancelProductChangeWorkflow, rejectProductChangeWorkflow, and the applyProductChangeActionsWorkflow family that replays the staged actions onto the product. See Workflows.
  • Vendor: POST /vendor/products/:id and variant/attribute sub-routes stage changes; GET /vendor/products/:id/preview shows the product with pending changes applied; POST /vendor/products/:id/cancel withdraws a request.
  • Admin: GET /admin/products/:id/preview, POST /admin/products/:id/confirm, POST /admin/products/:id/reject, POST /admin/products/:id/request-changes, plus POST /admin/product-changes/:id/confirm and /cancel.

Next steps

Product Attribute module

Offer module