diff --git a/muse-cloud/muse-module-market/muse-module-market-server/pom.xml b/muse-cloud/muse-module-market/muse-module-market-server/pom.xml
index cf315ece..3c67b0c8 100644
--- a/muse-cloud/muse-module-market/muse-module-market-server/pom.xml
+++ b/muse-cloud/muse-module-market/muse-module-market-server/pom.xml
@@ -22,6 +22,11 @@
muse-module-market-api
${revision}
+
+ cn.iocoder.cloud
+ muse-module-events-api
+ ${revision}
+
cn.iocoder.cloud
muse-module-member-server
diff --git a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/AdminMarketGovernanceServiceImpl.java b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/AdminMarketGovernanceServiceImpl.java
index 99834755..305b4120 100644
--- a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/AdminMarketGovernanceServiceImpl.java
+++ b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/AdminMarketGovernanceServiceImpl.java
@@ -91,6 +91,7 @@ public class AdminMarketGovernanceServiceImpl implements AdminMarketGovernanceSe
private final MuseMarketGovernanceImpactMapper governanceImpactMapper;
private final MuseMarketSourceStatusEventMapper sourceStatusEventMapper;
private final MarketCommandService commandService;
+ private final MarketEventPublishOutboxService eventPublishOutboxService;
@Override
public PageResult listMarketAssets(Long adminUserId, String apiVersion, Integer pageNo,
@@ -349,6 +350,8 @@ public class AdminMarketGovernanceServiceImpl implements AdminMarketGovernanceSe
action.setReason(reason);
action.setTenantId(tenantId);
governanceActionMapper.insert(action);
+ // 治理事实和 Events 发布意图必须同事务落地;任一失败都回滚,避免用户可见通知与事实审计断链。
+ eventPublishOutboxService.createForGovernanceAction(action);
writeActionImpact(tenantId, asset, actionId, commandId, requestHash, actionType, STATUS_APPLIED,
linkedMap("scope", scope, "actionPolicy", actionPolicy, "source", "market_owned_projection"));
return new GovernanceActionResult(String.valueOf(asset.getId()), listingStatus,
diff --git a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPayloads.java b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPayloads.java
new file mode 100644
index 00000000..9e8a86b4
--- /dev/null
+++ b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPayloads.java
@@ -0,0 +1,37 @@
+package cn.iocoder.muse.module.market.application.muse;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Market Events payload 安全边界校验。
+ */
+final class MarketEventPayloads {
+
+ private static final Set PAYLOAD_KEYS = Set.of("type", "message", "resourceRef", "timestamp");
+ private static final Set RESOURCE_REF_KEYS = Set.of("resourceType", "resourceId");
+ private static final Set SAFE_MESSAGES = Set.of("资产已下架", "资产已召回");
+ private static final String NOTIFICATION_GOVERNANCE_ACTION = "governance_action";
+ private static final String RESOURCE_TYPE_MARKET_ASSET = "market_asset";
+
+ private MarketEventPayloads() {
+ }
+
+ static boolean isValidGovernancePayload(Map payload) {
+ if (payload == null || !payload.keySet().equals(PAYLOAD_KEYS)
+ || !NOTIFICATION_GOVERNANCE_ACTION.equals(payload.get("type"))
+ || !(payload.get("message") instanceof String message)
+ || !SAFE_MESSAGES.contains(message)
+ || !(payload.get("timestamp") instanceof String)
+ || !(payload.get("resourceRef") instanceof Map, ?> resourceRef)) {
+ return false;
+ }
+ if (!resourceRef.keySet().equals(RESOURCE_REF_KEYS)
+ || !RESOURCE_TYPE_MARKET_ASSET.equals(resourceRef.get("resourceType"))) {
+ return false;
+ }
+ Object resourceId = resourceRef.get("resourceId");
+ return resourceId instanceof Number;
+ }
+
+}
diff --git a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxService.java b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxService.java
new file mode 100644
index 00000000..31f4b735
--- /dev/null
+++ b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxService.java
@@ -0,0 +1,19 @@
+package cn.iocoder.muse.module.market.application.muse;
+
+import cn.iocoder.muse.module.market.dal.dataobject.muse.MuseMarketEventPublishOutboxDO;
+import cn.iocoder.muse.module.market.dal.dataobject.muse.MuseMarketGovernanceActionDO;
+
+/**
+ * Market 治理事实到统一 Events 的本域 outbox 服务。
+ */
+public interface MarketEventPublishOutboxService {
+
+ /**
+ * 为治理动作创建待发布 outbox。
+ *
+ * @param action 已落库的 Market governance action 事实
+ * @return 新建或幂等回查到的 outbox;非法 owner 会跳过并返回 null
+ */
+ MuseMarketEventPublishOutboxDO createForGovernanceAction(MuseMarketGovernanceActionDO action);
+
+}
diff --git a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxServiceImpl.java b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxServiceImpl.java
new file mode 100644
index 00000000..7b5d3532
--- /dev/null
+++ b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishOutboxServiceImpl.java
@@ -0,0 +1,175 @@
+package cn.iocoder.muse.module.market.application.muse;
+
+import cn.iocoder.muse.framework.common.exception.ServiceException;
+import cn.iocoder.muse.framework.common.util.json.JsonUtils;
+import cn.iocoder.muse.module.market.dal.dataobject.muse.MuseMarketEventPublishOutboxDO;
+import cn.iocoder.muse.module.market.dal.dataobject.muse.MuseMarketGovernanceActionDO;
+import cn.iocoder.muse.module.market.dal.mysql.muse.MuseMarketEventPublishOutboxMapper;
+import cn.iocoder.muse.module.market.framework.config.MuseMarketEventsProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.time.LocalDateTime;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Market 治理动作发布 outbox 服务实现。
+ */
+@Service
+@Slf4j
+public class MarketEventPublishOutboxServiceImpl implements MarketEventPublishOutboxService {
+
+ static final String STATUS_QUEUED = "queued";
+
+ private static final String SOURCE_REVISION_NONE = "__none__";
+ private static final String EVENT_TYPE_NOTIFICATION = "notification";
+ private static final String NOTIFICATION_GOVERNANCE_ACTION = "governance_action";
+ private static final String RESOURCE_TYPE_MARKET_ASSET = "market_asset";
+ static final String ERROR_PAYLOAD_INVALID_CODE = "MARKET_EVENTS_PAYLOAD_INVALID";
+ static final int ERROR_PAYLOAD_INVALID_NUMERIC_CODE = 1_044_000_030;
+ private static final Set PUBLISHABLE_ACTION_TYPES = Set.of("delist", "recall");
+
+ private final MuseMarketEventPublishOutboxMapper outboxMapper;
+ private final MuseMarketEventsProperties properties;
+
+ public MarketEventPublishOutboxServiceImpl(MuseMarketEventPublishOutboxMapper outboxMapper,
+ MuseMarketEventsProperties properties) {
+ this.outboxMapper = outboxMapper;
+ this.properties = properties;
+ }
+
+ @Override
+ public MuseMarketEventPublishOutboxDO createForGovernanceAction(MuseMarketGovernanceActionDO action) {
+ if (action == null || !StringUtils.hasText(action.getActionId())
+ || !PUBLISHABLE_ACTION_TYPES.contains(action.getActionType())) {
+ return null;
+ }
+ if (action.getOwnerUserId() == null || action.getOwnerUserId() <= 0) {
+ log.warn("Market Events outbox 跳过非法 owner 治理动作,tenantId={}, actionId={}, assetId={}, ownerUserId={}",
+ action.getTenantId(), action.getActionId(), action.getAssetId(), action.getOwnerUserId());
+ return null;
+ }
+ MuseMarketEventPublishOutboxDO outbox = buildOutbox(action);
+ validatePayloadOrThrow(outbox);
+ int inserted = outboxMapper.insertIgnore(outbox);
+ if (inserted > 0) {
+ return outboxMapper.selectByTenantIdAndOutboxId(action.getTenantId(), outbox.getOutboxId());
+ }
+ MuseMarketEventPublishOutboxDO existing = outboxMapper.selectByTenantIdAndActionIdAndNotificationType(
+ action.getTenantId(), action.getActionId(), NOTIFICATION_GOVERNANCE_ACTION);
+ return existing == null ? outboxMapper.selectByTenantIdAndCommandId(action.getTenantId(), outbox.getCommandId())
+ : existing;
+ }
+
+ private MuseMarketEventPublishOutboxDO buildOutbox(MuseMarketGovernanceActionDO action) {
+ MuseMarketEventPublishOutboxDO outbox = new MuseMarketEventPublishOutboxDO();
+ outbox.setTenantId(action.getTenantId());
+ outbox.setOutboxId(buildOutboxId(action.getTenantId(), action.getActionId(), action.getOwnerUserId()));
+ outbox.setCommandId(buildPublishCommandId(action.getTenantId(), action.getActionId(),
+ action.getOwnerUserId()));
+ outbox.setSourceCommandId(action.getCommandId());
+ outbox.setActionId(action.getActionId());
+ outbox.setActionType(action.getActionType());
+ outbox.setAssetId(action.getAssetId());
+ outbox.setOwnerUserId(action.getOwnerUserId());
+ outbox.setActorUserId(action.getActorUserId());
+ outbox.setPreviewId(action.getPreviewId());
+ outbox.setRequestHash(action.getRequestHash());
+ outbox.setSourceRevision(normalizeSourceRevision(
+ action.getRevision() == null ? null : String.valueOf(action.getRevision())));
+ outbox.setEventType(EVENT_TYPE_NOTIFICATION);
+ outbox.setNotificationType(NOTIFICATION_GOVERNANCE_ACTION);
+ outbox.setResourceType(RESOURCE_TYPE_MARKET_ASSET);
+ outbox.setResourceId(String.valueOf(action.getAssetId()));
+ outbox.setPayloadSummary(JsonUtils.toJsonString(notificationPayload(action)));
+ outbox.setPublishStatus(STATUS_QUEUED);
+ outbox.setAttemptCount(0);
+ outbox.setMaxAttempt(configuredMaxAttempt());
+ outbox.setNextRetryAt(LocalDateTime.now());
+ return outbox;
+ }
+
+ private Map notificationPayload(MuseMarketGovernanceActionDO action) {
+ Map payload = new LinkedHashMap<>();
+ payload.put("type", NOTIFICATION_GOVERNANCE_ACTION);
+ payload.put("message", messageFor(action.getActionType()));
+ payload.put("resourceRef", resourceRef(action.getAssetId()));
+ payload.put("timestamp", eventTimestamp(action).toString());
+ return payload;
+ }
+
+ private LocalDateTime eventTimestamp(MuseMarketGovernanceActionDO action) {
+ return action.getCreateTime() == null ? LocalDateTime.now() : action.getCreateTime();
+ }
+
+ private Map resourceRef(Long assetId) {
+ Map resourceRef = new LinkedHashMap<>();
+ resourceRef.put("resourceType", RESOURCE_TYPE_MARKET_ASSET);
+ resourceRef.put("resourceId", assetId);
+ return resourceRef;
+ }
+
+ private void validatePayloadOrThrow(MuseMarketEventPublishOutboxDO outbox) {
+ Map payload = JsonUtils.parseObject(outbox.getPayloadSummary(), Map.class);
+ if (!MarketEventPayloads.isValidGovernancePayload(payload)) {
+ log.warn("Market Events outbox payload 安全校验失败,tenantId={}, actionId={}, assetId={}, errorCode={}",
+ outbox.getTenantId(), outbox.getActionId(), outbox.getAssetId(),
+ ERROR_PAYLOAD_INVALID_CODE);
+ throw new ServiceException(ERROR_PAYLOAD_INVALID_NUMERIC_CODE, ERROR_PAYLOAD_INVALID_CODE);
+ }
+ }
+
+ private String messageFor(String actionType) {
+ return switch (actionType) {
+ case "delist" -> "资产已下架";
+ case "recall" -> "资产已召回";
+ default -> "资产治理状态已变化";
+ };
+ }
+
+ private String normalizeSourceRevision(String sourceRevision) {
+ return StringUtils.hasText(sourceRevision) ? sourceRevision : SOURCE_REVISION_NONE;
+ }
+
+ private int configuredMaxAttempt() {
+ if (properties == null || properties.getPublishWorker() == null
+ || properties.getPublishWorker().getMaxAttempt() <= 0) {
+ return 5;
+ }
+ return properties.getPublishWorker().getMaxAttempt();
+ }
+
+ private String buildPublishCommandId(Long tenantId, String actionId, Long ownerUserId) {
+ String raw = idempotencyKey(tenantId, actionId, ownerUserId);
+ return "mk_evt:" + sha256Hex(raw).substring(0, 32);
+ }
+
+ private String buildOutboxId(Long tenantId, String actionId, Long ownerUserId) {
+ String raw = idempotencyKey(tenantId, actionId, ownerUserId);
+ return "mk_out:" + sha256Hex(raw).substring(0, 32);
+ }
+
+ private String idempotencyKey(Long tenantId, String actionId, Long ownerUserId) {
+ return tenantId + "|" + actionId + "|" + ownerUserId + "|" + NOTIFICATION_GOVERNANCE_ACTION;
+ }
+
+ private String sha256Hex(String raw) {
+ try {
+ byte[] digest = MessageDigest.getInstance("SHA-256").digest(raw.getBytes(StandardCharsets.UTF_8));
+ StringBuilder hex = new StringBuilder(digest.length * 2);
+ for (byte value : digest) {
+ hex.append(String.format("%02x", value));
+ }
+ return hex.toString();
+ } catch (NoSuchAlgorithmException exception) {
+ throw new IllegalStateException("SHA-256 algorithm is required", exception);
+ }
+ }
+
+}
diff --git a/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishWorker.java b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishWorker.java
new file mode 100644
index 00000000..616e0956
--- /dev/null
+++ b/muse-cloud/muse-module-market/muse-module-market-server/src/main/java/cn/iocoder/muse/module/market/application/muse/MarketEventPublishWorker.java
@@ -0,0 +1,246 @@
+package cn.iocoder.muse.module.market.application.muse;
+
+import cn.iocoder.muse.framework.common.pojo.CommonResult;
+import cn.iocoder.muse.framework.common.util.json.JsonUtils;
+import cn.iocoder.muse.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.muse.module.events.api.publish.EventsPublishApi;
+import cn.iocoder.muse.module.events.api.publish.dto.EventsPublishReqDTO;
+import cn.iocoder.muse.module.events.api.publish.dto.EventsPublishRespDTO;
+import cn.iocoder.muse.module.market.dal.dataobject.muse.MuseMarketEventPublishOutboxDO;
+import cn.iocoder.muse.module.market.dal.mysql.muse.MuseMarketEventPublishOutboxMapper;
+import cn.iocoder.muse.module.market.framework.config.MuseMarketEventsProperties;
+import com.fasterxml.jackson.core.type.TypeReference;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+/**
+ * Market governance action outbox 发布到统一 Events 的 worker。
+ */
+@Slf4j
+@Component
+public class MarketEventPublishWorker {
+
+ private static final String PUBLISH_STATUS_ACCEPTED = "accepted";
+ private static final String PUBLISH_STATUS_REJECTED = "rejected";
+ private static final String PUBLISH_STATUS_BLOCKED = "blocked";
+
+ private static final String SOURCE_OWNER_MARKET = "market";
+ private static final String SOURCE_TYPE_MARKET_GOVERNANCE_ACTION = "market_governance_action";
+ private static final String EVENT_TYPE_NOTIFICATION = "notification";
+
+ private static final String ERROR_RETRY_EXHAUSTED = "MARKET_EVENTS_PUBLISH_RETRY_EXHAUSTED";
+ private static final String ERROR_API_FAILED = "MARKET_EVENTS_PUBLISH_API_FAILED";
+ private static final String ERROR_TEMPORARY_UNAVAILABLE = "MARKET_EVENTS_PUBLISH_TEMPORARY_UNAVAILABLE";
+ private static final String ERROR_UNKNOWN_STATUS = "MARKET_EVENTS_PUBLISH_UNKNOWN_STATUS";
+ private static final String ERROR_PAYLOAD_INVALID = "MARKET_EVENTS_PAYLOAD_INVALID";
+ private static final String ERROR_OUTBOX_INCOMPLETE = "MARKET_EVENTS_OUTBOX_INCOMPLETE";
+
+ static final long RETRY_BACKOFF_SECONDS = 60L;
+
+ private final MuseMarketEventPublishOutboxMapper outboxMapper;
+ private final EventsPublishApi eventsPublishApi;
+ private final MuseMarketEventsProperties properties;
+
+ public MarketEventPublishWorker(MuseMarketEventPublishOutboxMapper outboxMapper,
+ EventsPublishApi eventsPublishApi,
+ MuseMarketEventsProperties properties) {
+ this.outboxMapper = outboxMapper;
+ this.eventsPublishApi = eventsPublishApi;
+ this.properties = properties;
+ }
+
+ @Scheduled(initialDelayString = "${muse.market.events.publish-worker.initial-delay-ms:1000}",
+ fixedDelayString = "${muse.market.events.publish-worker.fixed-delay-ms:1000}")
+ public void dispatchScheduled() {
+ dispatchOnce();
+ }
+
+ public int dispatchOnce() {
+ if (!isEnabled()) {
+ return 0;
+ }
+ MuseMarketEventPublishOutboxDO outbox = TenantUtils.executeIgnore(
+ () -> outboxMapper.claimNextPublishOutbox(configuredClaimTimeoutSeconds()));
+ if (outbox == null) {
+ return 0;
+ }
+ if (outbox.getTenantId() == null || outbox.getId() == null) {
+ markDeadLetter(outbox, ERROR_OUTBOX_INCOMPLETE, "Market Events publish outbox incomplete");
+ return 0;
+ }
+ return TenantUtils.execute(outbox.getTenantId(), () -> publishClaimedOutbox(outbox));
+ }
+
+ private int publishClaimedOutbox(MuseMarketEventPublishOutboxDO outbox) {
+ if (isRetryExhausted(outbox)) {
+ markDeadLetter(outbox, ERROR_RETRY_EXHAUSTED, "Market Events publish retry exhausted");
+ return 0;
+ }
+ BuildPublishRequestResult buildResult = buildReqDTO(outbox);
+ if (!buildResult.success()) {
+ markDeadLetter(outbox, buildResult.errorCode(), buildResult.errorMessage());
+ return 0;
+ }
+
+ CommonResult result;
+ try {
+ result = eventsPublishApi.publish(buildResult.reqDTO());
+ } catch (RuntimeException exception) {
+ log.warn("Market Events publish 临时失败,tenantId={}, ownerUserId={}, outboxId={}, actionId={}, attempt={}, errorType={}",
+ outbox.getTenantId(), outbox.getOwnerUserId(), outbox.getId(), outbox.getActionId(),
+ outbox.getAttemptCount(), exception.getClass().getSimpleName());
+ if (isLastAttempt(outbox)) {
+ markDeadLetter(outbox, ERROR_RETRY_EXHAUSTED, "Market Events publish retry exhausted");
+ return 0;
+ }
+ markRetryable(outbox, ERROR_TEMPORARY_UNAVAILABLE, "Market Events publish temporary unavailable");
+ return 0;
+ }
+ if (result == null || result.isError()) {
+ if (isLastAttempt(outbox)) {
+ markDeadLetter(outbox, ERROR_RETRY_EXHAUSTED, "Market Events publish retry exhausted");
+ return 0;
+ }
+ markRetryable(outbox, ERROR_API_FAILED, "Market Events publish failed");
+ return 0;
+ }
+ return handlePublishResponse(outbox, result.getData());
+ }
+
+ private int handlePublishResponse(MuseMarketEventPublishOutboxDO outbox, EventsPublishRespDTO respDTO) {
+ if (respDTO == null || !StringUtils.hasText(respDTO.getPublishStatus())) {
+ markDeadLetter(outbox, ERROR_UNKNOWN_STATUS, "Market Events publish unknown status");
+ return 0;
+ }
+ String publishStatus = respDTO.getPublishStatus();
+ if (PUBLISH_STATUS_ACCEPTED.equals(publishStatus)) {
+ markPublished(outbox, respDTO);
+ return 1;
+ }
+ if (PUBLISH_STATUS_REJECTED.equals(publishStatus) || PUBLISH_STATUS_BLOCKED.equals(publishStatus)) {
+ markDeadLetter(outbox, safeErrorCode(respDTO.getPublishErrorCode()), "Market Events publish rejected");
+ return 1;
+ }
+ markDeadLetter(outbox, ERROR_UNKNOWN_STATUS, "Market Events publish unknown status");
+ return 0;
+ }
+
+ private BuildPublishRequestResult buildReqDTO(MuseMarketEventPublishOutboxDO outbox) {
+ Map payload = parsePayload(outbox);
+ if (!MarketEventPayloads.isValidGovernancePayload(payload) || outbox.getCreateTime() == null
+ || outbox.getOwnerUserId() == null || outbox.getOwnerUserId() <= 0
+ || !StringUtils.hasText(outbox.getActionId())
+ || !StringUtils.hasText(outbox.getCommandId())) {
+ return BuildPublishRequestResult.failed(ERROR_PAYLOAD_INVALID, "Market Events publish payload invalid");
+ }
+ EventsPublishReqDTO reqDTO = new EventsPublishReqDTO();
+ reqDTO.setCommandId(outbox.getCommandId());
+ reqDTO.setTenantId(outbox.getTenantId());
+ reqDTO.setOwnerUserId(outbox.getOwnerUserId());
+ reqDTO.setSourceOwner(SOURCE_OWNER_MARKET);
+ reqDTO.setSourceType(SOURCE_TYPE_MARKET_GOVERNANCE_ACTION);
+ reqDTO.setSourceId(outbox.getActionId());
+ reqDTO.setSourceRevision(outbox.getSourceRevision());
+ reqDTO.setEventType(EVENT_TYPE_NOTIFICATION);
+ reqDTO.setResourceType(outbox.getResourceType());
+ reqDTO.setResourceId(outbox.getResourceId());
+ reqDTO.setPayloadSummary(payload);
+ reqDTO.setEmittedAt(outbox.getCreateTime());
+ return BuildPublishRequestResult.success(reqDTO);
+ }
+
+ private Map parsePayload(MuseMarketEventPublishOutboxDO outbox) {
+ try {
+ Map parsed = JsonUtils.getObjectMapper()
+ .readValue(outbox.getPayloadSummary(), new TypeReference