diff --git a/.agents/rules/bc-boundaries.md b/.agents/rules/bc-boundaries.md
index df0cb8e9..a4b3c796 100644
--- a/.agents/rules/bc-boundaries.md
+++ b/.agents/rules/bc-boundaries.md
@@ -42,7 +42,7 @@
> 豁免一律**临时、显式、可见**(测试源码点名)。违例消除后必须从 `KNOWN_VIOLATION_EXEMPTIONS` 删除该类——**收紧即整改验收**。新违例不在豁免内,一律红。
-> 遗留(更深一层 BC 收口,不在本次范围):market-server 的 pom 仍依赖 `muse-module-member-server`(可见 member 全部 internal);本次只消除 member.dal 的**代码 import**(ArchUnit 校验 import、不校验 pom 坐标),pom 坐标收口可登记后续。
+> ✅ **pom 坐标收口已完成(2026-06-17)**:market-server pom 由 `muse-module-member-server`(可见 member 全部 internal)收窄为 `muse-module-member-api`。前置整改:market 唯一引用的 member-server 类型 `MarketAccountProjectionFacade`(单方法读校验端口、无 DTO)移到 member-api `api.account`——对称于写端口 `MuseAccountRecordProjectionApi`(member 定义端口、market 提供适配器 `MarketAccountProjectionProvider`、member-alone 回落 `UnavailableMarketAccountProjectionFacade`,符合 §一"本域定义端口、他域提供适配器");并把 market-server 此前**经 member-server 传递**获得的 `muse-spring-boot-starter-biz-tenant` 显式直接声明(依赖诚实化,收口暴露的隐性传递耦合)。验收:member-api/member-server/market-server scoped reactor `test-compile` BUILD SUCCESS;AccountMarketRecordServiceTest 8/0、MarketAccountProjectionFacadeConfigurationTest 3/0、MarketAccountProjectionProviderTest 5/0、AppMuseMarketPublishControllerTest 10/0;`BcBoundaryArchTest` 1/0(0 违例)。**顺带修**预存潜伏 test 编译破损:`AppMuseMarketPublishControllerTest` 的 9 参 `PublishRecordItem` 构造(record 自 commit a00c758 加 marketAssetId/appealStatus 变 10 参、该 test 未同步,因 CI 从未在本特性分支运行而潜伏)。
---
diff --git a/docs/mvp/进度总账.md b/docs/mvp/进度总账.md
index a071473f..3779dd8c 100644
--- a/docs/mvp/进度总账.md
+++ b/docs/mvp/进度总账.md
@@ -22,7 +22,7 @@
**market 写路径整改(2026-06-14,ultracode)**:member 暴露写端口 `MuseAccountRecordProjectionApi` + DTO(member-server 实现读写自有 DAL、tenantId 由实现侧从上下文注入防伪造、事务沿用调用方),market 5 类改消费端口、移除 member.dal 依赖 → `KNOWN_VIOLATION_EXEMPTIONS` 清空、BC 门全绿。**附带修复**:round-2 重构 `ContentKnowledgeWorkOwnerFacade` 时遗留的旧测试 `KnowledgeWorkOwnerFacadeTest`(仍断言旧 WorkMapper 行为)已删除,其装配守卫/兜底两用例并入 `ContentKnowledgeWorkOwnerFacadeTest`(5/0F)——此为 round-2 一处假绿(当时构建在平台时区用例处中止、未真正跑到 knowledge),现已补正。
-**后续基建 TODO**:openapi-diff CI 首跑验证(🔧 检测逻辑+循环聚合已本地实证 2026-06-17:oasdiff v1.19.1 对 7 域真实契约 5/5 拦真破坏/放行安全演化,镜像钉版本+复现脚本已落地;**仅余 GHA 触发管道待真实 PR 首跑**)、`completed=测试证据`兜底(台账加 testFiles 字段 + 门禁)、`dev-baseline` 收敛进 rules、跨域 `.application` 边界门、market-server→member-server pom 坐标收口(本次只消除 member.dal 代码 import,见 bc-boundaries §三遗留)、**ai/平台预存红测试整改**(CI 接电后将暴露;均非本轮改动引入):`MuseAiTaskServiceTest` 缺 `eventPublishOutboxService`/`candidateReviewService` 桩致 11 例 NPE **✅ 已整改 40/40(2026-06-15,补桩 + review lenient,零产代码改动)**;`QiniuSmsClientTest` 时区硬编码 **✅ 已整改 5/5(2026-06-15,断言改用与生产同款 `LocalDateTimeUtil.of` 由系统时区换算→机器无关)**;`MuseAiEventPublishOutboxMapperTest` **✅ 真实 PG 实跑 5/5(2026-06-15,mini-infra PG 100.64.0.8:5433;跑法=`source infra.env` + `-DargLine='-DsocksProxyHost= -DsocksProxyPort='`;隔离 schema 自建自清、零代码改动——原"红"仅缺真 PG 环境)**。**至此 ai/平台预存红三项全清。**
+**后续基建 TODO**:openapi-diff CI 首跑验证(🔧 检测逻辑+循环聚合已本地实证 2026-06-17:oasdiff v1.19.1 对 7 域真实契约 5/5 拦真破坏/放行安全演化,镜像钉版本+复现脚本已落地;**仅余 GHA 触发管道待真实 PR 首跑**)、`completed=测试证据`兜底(台账加 testFiles 字段 + 门禁)、`dev-baseline` 收敛进 rules、跨域 `.application` 边界门、market-server→member-server pom 坐标收口(✅ **已完成 2026-06-17**:接口 `MarketAccountProjectionFacade` 移入 member-api→market-server pom 收窄至 member-api + 直接声明 tenant starter[依赖诚实化];编译/4 测试 26 用例/BcBoundaryArchTest 0 违例全绿;顺带修预存潜伏 test 编译破损 AppMuseMarketPublishControllerTest;详见 bc-boundaries §三)、**ai/平台预存红测试整改**(CI 接电后将暴露;均非本轮改动引入):`MuseAiTaskServiceTest` 缺 `eventPublishOutboxService`/`candidateReviewService` 桩致 11 例 NPE **✅ 已整改 40/40(2026-06-15,补桩 + review lenient,零产代码改动)**;`QiniuSmsClientTest` 时区硬编码 **✅ 已整改 5/5(2026-06-15,断言改用与生产同款 `LocalDateTimeUtil.of` 由系统时区换算→机器无关)**;`MuseAiEventPublishOutboxMapperTest` **✅ 真实 PG 实跑 5/5(2026-06-15,mini-infra PG 100.64.0.8:5433;跑法=`source infra.env` + `-DargLine='-DsocksProxyHost= -DsocksProxyPort='`;隔离 schema 自建自清、零代码改动——原"红"仅缺真 PG 环境)**。**至此 ai/平台预存红三项全清。**
---
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 3c67b0c8..e9977de9 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
@@ -29,9 +29,15 @@
该 Bean 实现 member 模块既有 {@link MarketAccountProjectionFacade}(该端口在 member-server, 非 .dal, 合规),
+ * 该 Bean 实现 member 模块既有 {@link MarketAccountProjectionFacade}(该端口在 member-api, 非 .dal, 合规),
* 用于替换默认 fail-closed unavailable facade,让读侧"投影已接入"判定不变。Account 查询仍只读 member 的
* muse_account_record_projection。 Purchase / License / Publish records 在 Account 域只能读取
+ * {@code muse_account_record_projection}。该 Facade 用来表达外部 Market 投影同步是否已经接入,
+ * 防止 Account 在上游投影不可用时返回伪造的空数据。 端口归属 member(读侧 fail-closed 判定, 由 member-server 的 {@code AccountMarketRecordServiceImpl} 消费);
+ * 适配器由 Market owner 提供(market-server 的 {@code MarketAccountProjectionProvider} 实现),
+ * member-alone(无 Market 接入)时回落 member-server 的 {@code UnavailableMarketAccountProjectionFacade}。
+ * 置于 member-api 以便 market 在【不依赖 member-server internal】前提下提供适配器(对称于写端口
+ * {@code MuseAccountRecordProjectionApi} 的布局, 使 market-server 的 pom 仅需依赖 member-api)。
+ * 与【写】端口职责不同、刻意保持分离。
注:故意不把 member 既有【读校验】端口 {@code MarketAccountProjectionFacade.requireProjectionAvailable} - * 合并进来 —— 那是 member 读侧 fail-closed 判定(member-server 内部用, 见 AccountMarketRecordServiceImpl), - * 与本【写】端口职责不同, 保持分离。
+ * 合并进来 —— 那是 member 读侧 fail-closed 判定(同置本 member-api 包, 由 AccountMarketRecordServiceImpl 消费、 + * Market 适配器实现), 与本【写】端口职责不同, 保持分离。 */ public interface MuseAccountRecordProjectionApi { diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/autoconfigure/member/account/MarketAccountProjectionFacadeAutoConfiguration.java b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/autoconfigure/member/account/MarketAccountProjectionFacadeAutoConfiguration.java index 9a5edda2..7d83e49d 100644 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/autoconfigure/member/account/MarketAccountProjectionFacadeAutoConfiguration.java +++ b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/autoconfigure/member/account/MarketAccountProjectionFacadeAutoConfiguration.java @@ -1,6 +1,6 @@ package cn.iocoder.muse.autoconfigure.member.account; -import cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade; +import cn.iocoder.muse.module.member.api.account.MarketAccountProjectionFacade; import cn.iocoder.muse.module.member.application.account.facade.UnavailableMarketAccountProjectionFacade; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceImpl.java b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceImpl.java index 525622d2..09bf0ef6 100644 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceImpl.java +++ b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceImpl.java @@ -3,7 +3,7 @@ package cn.iocoder.muse.module.member.application.account; import cn.iocoder.muse.framework.common.exception.ServiceException; import cn.iocoder.muse.framework.common.pojo.PageParam; import cn.iocoder.muse.framework.common.pojo.PageResult; -import cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade; +import cn.iocoder.muse.module.member.api.account.MarketAccountProjectionFacade; import cn.iocoder.muse.module.member.controller.account.vo.AccountPageResult; import cn.iocoder.muse.module.member.controller.admin.account.vo.AdminPurchaseRecordRespVO; import cn.iocoder.muse.module.member.controller.app.account.vo.AppLicenseRecordRespVO; diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacade.java b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacade.java deleted file mode 100644 index 25a2caa6..00000000 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacade.java +++ /dev/null @@ -1,18 +0,0 @@ -package cn.iocoder.muse.module.member.application.account.facade; - -/** - * Account 市场记录投影可用性边界。 - * - *Purchase / License / Publish records 在 Account 域只能读取 - * {@code muse_account_record_projection}。该 Facade 用来表达外部 Market 投影同步是否已经接入, - * 防止 Account 在上游投影不可用时返回伪造的空数据。
- */ -public interface MarketAccountProjectionFacade { - - /** - * 确认指定记录类型的 Market 投影已经可用。 - * - * @param recordType Account 投影记录类型,只允许 service 内部传入固定值 - */ - void requireProjectionAvailable(String recordType); -} diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableMarketAccountProjectionFacade.java b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableMarketAccountProjectionFacade.java index 870e274a..392a6159 100644 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableMarketAccountProjectionFacade.java +++ b/muse-cloud/muse-module-member/muse-module-member-server/src/main/java/cn/iocoder/muse/module/member/application/account/facade/UnavailableMarketAccountProjectionFacade.java @@ -1,6 +1,7 @@ package cn.iocoder.muse.module.member.application.account.facade; import cn.iocoder.muse.framework.common.exception.ServiceException; +import cn.iocoder.muse.module.member.api.account.MarketAccountProjectionFacade; import static cn.iocoder.muse.module.member.enums.ErrorCodeConstants.ACCOUNT_MARKET_PROJECTION_UNAVAILABLE; diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java b/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java index 9be83604..9b05efbf 100644 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java +++ b/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/AccountMarketRecordServiceTest.java @@ -4,7 +4,7 @@ import cn.iocoder.muse.framework.common.exception.ServiceException; import cn.iocoder.muse.framework.common.pojo.PageParam; import cn.iocoder.muse.framework.common.pojo.PageResult; import cn.iocoder.muse.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.muse.module.member.application.account.facade.MarketAccountProjectionFacade; +import cn.iocoder.muse.module.member.api.account.MarketAccountProjectionFacade; import cn.iocoder.muse.module.member.application.account.facade.UnavailableMarketAccountProjectionFacade; import cn.iocoder.muse.module.member.controller.account.vo.AccountPageResult; import cn.iocoder.muse.module.member.controller.admin.account.vo.AdminPurchaseRecordRespVO; diff --git a/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacadeConfigurationTest.java b/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacadeConfigurationTest.java index 9afc351a..41c9733b 100644 --- a/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacadeConfigurationTest.java +++ b/muse-cloud/muse-module-member/muse-module-member-server/src/test/java/cn/iocoder/muse/module/member/application/account/facade/MarketAccountProjectionFacadeConfigurationTest.java @@ -2,6 +2,7 @@ package cn.iocoder.muse.module.member.application.account.facade; import cn.iocoder.muse.autoconfigure.member.account.MarketAccountProjectionFacadeAutoConfiguration; import cn.iocoder.muse.framework.common.exception.ServiceException; +import cn.iocoder.muse.module.member.api.account.MarketAccountProjectionFacade; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfiguration;