承 bc-boundaries §三遗留(更深一层 BC 收口)。market-server pom 此前依赖 muse-module-member-server(可见 member 全部 internal),根因是 market 唯一引用的 member-server 类型 MarketAccountProjectionFacade(单方法读校验端口、无 DTO)。 - 接口 MarketAccountProjectionFacade 从 member-server application.account.facade 移到 member-api api.account(对称写端口 MuseAccountRecordProjectionApi:member 定义端口、 market 提供适配器 MarketAccountProjectionProvider、member-alone 回落 Unavailable*, 符合 bc-boundaries §一"本域定义端口、他域提供适配器") - market-server pom: muse-module-member-server → muse-module-member-api - market-server 直接声明 muse-spring-boot-starter-biz-tenant(此前经 member-server 传递, 收口暴露的隐性传递耦合 → 依赖诚实化) - 顺带修预存潜伏 test 编译破损:AppMuseMarketPublishControllerTest 的 9 参 PublishRecordItem 构造(record 自 commit a00c758 加 marketAssetId/appealStatus 变 10 参、 test 未同步;因 CI 从未在本特性分支运行而潜伏)→补 marketAssetId=null 验收: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 Architecture Violation)。同步 bc-boundaries §三 + 台账 §一 TODO。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.5 KiB
规则:BC 边界 —— 禁跨域 DAL 直连(ArchUnit 机械门禁)
类型:硬约束(rules) · 状态:生效 2026-06-14 · 门禁:ArchUnit(机械阻断,非自觉) 上位:
verification-and-anti-false-green.md§二.6 由来:对抗复盘 A4——软约束下 AI 模块ContentMuseWorkOwnerFacade直连 content 的WorkMapper/ChapterMapper/BlockMapper+WorkDO/ChapterDO/BlockDO,实质破了"模块化单体 + 清晰 BC 边界"(ADR)的根基,且会随时间蔓延、拆服务时代价爆炸。
一、规则
- 一个业务域(BC)模块不得 import / 依赖他域的 DAL(
.dal..,含 dataobject 与 mysql Mapper)。 - 跨 BC 读写只能走对外 API 或 facade-api 契约(本域定义端口,他域提供适配器;或经对外 API)。
- 本域读自己的 DAL 不受限。
正面范例:P1 增量 2 的
AiSuggestionMergeProjectionFacade—— AI 实现 content 的ContentAiSuggestionFacade端口、只读 AI 自有 suggestion 库,不碰 content DAL,即合规的跨 BC 接缝。
二、机械门禁(不是自觉)
- 测试:
muse-server/src/test/java/cn/iocoder/muse/server/framework/arch/BcBoundaryArchTest.java(ArchUnit 1.3.0)。 - CI:随
muse-cloud/.github/workflows/maven.yml(P0 已打开测试门、JDK21)在 PR/push 阻断。 - 任何新增跨域 DAL 依赖 → 测试红 → 阻断合入。
三、违例登记与整改
规则现为通用条件(BcBoundaryArchTest.no_business_bc_may_depend_on_another_bc_dal):覆盖全部业务 BC 间方向(ai/content/knowledge/market/meta/member/events),任一域依赖他域 .dal 即红;已知违例在测试的 KNOWN_VIOLATION_EXEMPTIONS 单点显式登记(2026-06-14 评审整改:此前只守 AI 单向,放过了 knowledge/market 同构活违例)。
已整改(历史)
| 违例类 | 曾经内容 | 整改 | 验收 |
|---|---|---|---|
module.ai.application.muse.facade.ContentMuseWorkOwnerFacade |
直连 content Work/Chapter/Block Mapper+DO(字节码 31 处) |
content 暴露只读端口 MuseContentWorkOwnerApi(content-api 定义、content-server 实现读自有 DAL);AI 适配器改消费该端口 |
反向删豁免+旧码→红报 31 例;正向整改→绿,适配器 13/0F、端口实现 7/0F |
module.knowledge.application.muse.facade.ContentKnowledgeWorkOwnerFacade |
直连 content WorkMapper/WorkDO(与 AI 同构) |
复用同一 MuseContentWorkOwnerApi.getActiveOwnedWorkRevision 端口,移除 content.dal 依赖 |
通用门禁绿(0 Architecture Violation)、新增适配器单测 3/0F |
module.market.application.muse.{MarketAccountProjectionProvider, AdminMarketReviewServiceImpl, MarketInstallServiceImpl, MarketLicenseServiceImpl, MarketPublishServiceImpl}(5 类) |
写路径:构建 member.dal.AccountRecordProjectionDO、经 AccountRecordProjectionMapper upsert 进 member 表 |
member 暴露写端口 MuseAccountRecordProjectionApi.upsertRecordProjection(DTO)(member-api 定义、member-server 实现读写自有 DAL,整体平移原 upsert 语义且事务上下文沿用调用方);market 5 类改消费端口 + MuseAccountRecordProjectionSaveReqDTO 替代 DO,移除 member.dal 依赖 |
反向:删豁免 5 类即门禁收紧;正向整改→通用门禁绿(0 Architecture Violation),新增 member 端口实现单测 4/0F、market provider 测试迁移为 mock 写端口 |
活跃登记(待整改,单点豁免)
| 违例类 | 内容 | 处置 | 整改方向 |
|---|---|---|---|
| (空) | —— | —— | 当前无活跃跨域 DAL 违例;BcBoundaryArchTest.KNOWN_VIOLATION_EXEMPTIONS 已清空 |
豁免一律临时、显式、可见(测试源码点名)。违例消除后必须从
KNOWN_VIOLATION_EXEMPTIONS删除该类——收紧即整改验收。新违例不在豁免内,一律红。
✅ pom 坐标收口已完成(2026-06-17):market-server pom 由
muse-module-member-server(可见 member 全部 internal)收窄为muse-module-member-api。前置整改:market 唯一引用的 member-server 类型MarketAccountProjectionFacade(单方法读校验端口、无 DTO)移到 member-apiapi.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 reactortest-compileBUILD SUCCESS;AccountMarketRecordServiceTest 8/0、MarketAccountProjectionFacadeConfigurationTest 3/0、MarketAccountProjectionProviderTest 5/0、AppMuseMarketPublishControllerTest 10/0;BcBoundaryArchTest1/0(0 违例)。顺带修预存潜伏 test 编译破损:AppMuseMarketPublishControllerTest的 9 参PublishRecordItem构造(record 自 commita00c758加 marketAssetId/appealStatus 变 10 参、该 test 未同步,因 CI 从未在本特性分支运行而潜伏)。
四、扩展方式
- 规则已是通用条件,自动覆盖所有业务 BC 间的
.dal跨域依赖,无需为新方向加@Test。 - 新增业务 BC:加入
BcBoundaryArchTest.BUSINESS_BCS即纳入约束。 - 收紧已知违例:整改后从
KNOWN_VIOLATION_EXEMPTIONS删除该类,门禁随即收紧。 - 更强边界(如禁跨域
.application非 facade-api 包耦合):在条件里追加判断,但须为合规 facade 端口留通道(见评审 P1-3,属后续)。