oh-my-muse/.agents/rules/bc-boundaries.md
lili 4e9923ce68 refactor(market): pom 坐标收口 market→member-api(facade 移入 member-api)+ tenant 依赖诚实化
承 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>
2026-06-17 14:08:19 -07:00

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-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 从未在本特性分支运行而潜伏)。


四、扩展方式

  • 规则已是通用条件,自动覆盖所有业务 BC 间的 .dal 跨域依赖,无需为新方向加 @Test
  • 新增业务 BC:加入 BcBoundaryArchTest.BUSINESS_BCS 即纳入约束。
  • 收紧已知违例:整改后从 KNOWN_VIOLATION_EXEMPTIONS 删除该类,门禁随即收紧。
  • 更强边界(如禁跨域 .application 非 facade-api 包耦合):在条件里追加判断,但须为合规 facade 端口留通道(见评审 P1-3,属后续)。