5.0 KiB
| status |
|---|
| accepted |
可转商机候选线索目录 inbound seam:ConvertibleLeadCatalogPort(crm-lead 声明并实现,crm-opportunity 调用)
Context
架构审查(/improve-codebase-architecture,2026-08-25,候选 #2):商机侧直接新建入口(票 12,oppSource=线索转入)需要一份「关联线索」下拉数据源——该用户名下 status IN (已领取 3 / 跟进中 4) 的候选线索。此前 OpportunityCreateServiceImpl 为这唯一一处查询注入了 crm-lead 的宽服务接口 ILeadService(20+ 方法),并 import com.crm.lead.domain.dto.ConvertibleLeadView。
这放大了 ADR-0029 记录的 crm-opportunity → crm-lead 依赖:商机侧不仅背着 pom 依赖,还把一整个宽域服务接口 + 域内 DTO 包拖进了自己的编译面,契约面远宽于实际所需(仅一个方法)。宽接口一旦演进(新增/改签名),商机侧被动重编译;domain/dto 是线索域内部包,本不该对外域可见。
方向约束:crm-lead → crm-rule 为既定单向;商机侧对线索的依赖是 ADR-0029 已接受的技术债,本 ADR 不改 pom 方向,只收窄跨域契约面。
Considered Options
- A(选中):crm-lead 声明窄 inbound port
ConvertibleLeadCatalogPort(单方法)并自实现,crm-opportunity 只依赖该 port + 随包 view。 宽服务接口ILeadService.listConvertibleLeads及其实现删除,逻辑原样迁入ConvertibleLeadCatalogPortImpl(直查LeadMapper,票 12 口径不变)。ConvertibleLeadView从domain/dto移到port/inbound随端口同包,成为线索域对外发布的契约面(对称port/outbound的CreateOpportunityCmd/OpportunityCreationExceptioncmd/异常随端口同包先例)。 - B:保留
ILeadService注入,仅移ConvertibleLeadView到契约包。 契约面仍是 20+ 方法宽接口,泄漏未收窄,否。 - C:商机侧直查 lead 表。 无 Java 依赖但 DB 层耦合、跨域判定线索准入口径,违背 seam 精神(同 ADR-0025 选项 B 的否决理由),否。
与 ADR-0025 的关系:两者都是把跨域协作收进一个窄 port,但方向相反。ADR-0025 是 crm-rule 声明 outbound port、crm-lead 实现(下游声明、上游依赖倒置实现);本 ADR 是 crm-lead 声明 inbound port 并自实现、crm-opportunity 调用(上游发布契约面、下游消费)。对称 port/outbound 的 OpportunityCreationPort:出站契约 lead 声明他域实现,入站契约本域声明本域实现供他域调用。
Decision
crm-lead 新增 com.crm.lead.port.inbound 包:
ConvertibleLeadCatalogPort:接口,单方法List<ConvertibleLeadView> listConvertibleLeads(Long ownerUserId);ConvertibleLeadView:record(id/名称/电话轻量投影),从domain/dto迁入随端口同包——本包类型是线索域对商机侧发布的契约面,外域不得 import 线索域service/domain内部包;impl/ConvertibleLeadCatalogPortImpl:@Service,逻辑自LeadServiceImpl.listConvertibleLeads原样迁入(直查LeadMapper:归属 +status IN (STATUS_CLAIMED 3 / STATUS_FOLLOWING 4)),不复用宽服务接口。
删除 ILeadService.listConvertibleLeads 声明 + LeadServiceImpl 实现 + domain/dto/ConvertibleLeadView。
crm-opportunity 侧 4 处改注入 port:OpportunityCreateServiceImpl(ILeadService → ConvertibleLeadCatalogPort)、IOpportunityCreateService、OpportunityCreateController、及测试;「未被商机占用」过滤(查 opportunity.source_lead_id)仍留商机侧——线索域不知 opportunity 表,职责边界与 ADR-0025 一致。
Consequences
- crm-opportunity 对 crm-lead 的编译契约面从「宽服务接口
ILeadService(20+ 方法)+ 域内domain/dto」收窄到「单方法ConvertibleLeadCatalogPort+ 随包 view」。grep确认商机侧不再 import 任何com.crm.lead.service.*/com.crm.lead.domain.*,只剩com.crm.lead.port.*(契约面)。ADR-0029 泄漏的ILeadService半边自此消除。 - pom 依赖方向不变(仍
crm-opportunity → crm-lead,ADR-0029 技术债照旧)——本 ADR 只收窄契约面,方向随 ADR-0020 独立部署时再重设。 - 准入口径不变(status IN 3/4,线索域判定);占用过滤留商机侧。逻辑原样迁移,无行为变化。
- 测试随迁不 layer:
LeadConvertibleQueryTest(测宽服务方法)重命名为ConvertibleLeadCatalogPortImplTest(测端口实现),断言口径不变;OpportunityCreateServiceImplTest的候选线索用例改 mockConvertibleLeadCatalogPort。验证:crm-lead + crm-opportunity 相关单测全绿。 - 决策来源:
/improve-codebase-architecture审查(2026-08-25,候选 #2)+ 代码审查(/code-review,2026-08-25)——审查发现实现已落但引用的本 ADR 尚未写下,本文补齐该悬空引用。