Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.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),含两条通用规则:no_business_bc_may_depend_on_another_bc_dal(禁跨域.dal)+no_business_bc_may_depend_on_another_bc_application(禁跨域.application,2026-06-17 新增,见 §四)。 - CI:随仓库根
.github/workflows/maven.yml(P0 已打开测试门、JDK21)在 PR/push 阻断。 - 任何新增跨域 DAL / application 依赖 → 测试红 → 阻断合入。
三、违例登记与整改
规则现为通用条件(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/.application跨域依赖,无需为新方向加@Test。 - 新增业务 BC:加入
BcBoundaryArchTest.BUSINESS_BCS即纳入约束。 - 收紧已知违例:整改后从
KNOWN_VIOLATION_EXEMPTIONS删除该类,门禁随即收紧。 - ✅ 跨域
.application边界门已实现(2026-06-17):no_business_bc_may_depend_on_another_bc_application(平行.dal规则、共用豁免清单),禁任一业务 BC 依赖他域.application(service / facade 实现)。facade 端口已统一上移-api(见 §三 MarketAccountProjectionFacade 收口),故.application无合规跨域通道——直接禁止、无需为 facade 留例外。验收:0 违例全绿(全仓扫描跨 BC.applicationimport=0,ArchUnit 字节码级 2/0F);反假绿反向证:同款检测逻辑临时指向.api(已知有跨 BC 引用)→ 找到 238 例违例,证明检测机制非空转、绿是因真无跨域耦合。 - 进一步收紧(留后续):当前全仓跨 BC 仅经
-api,连.controller/.convert/.enums等内部包亦 0 跨域耦合,可泛化为"跨 BC 仅许-api"单一通用门;暂保持分层显式(.dal/.application)以利清晰报错。