You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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 口径不变)。ConvertibleLeadViewdomain/dto 移到 port/inbound 随端口同包,成为线索域对外发布的契约面(对称 port/outboundCreateOpportunityCmd/OpportunityCreationException cmd/异常随端口同包先例)。
  • 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/outboundOpportunityCreationPort:出站契约 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:OpportunityCreateServiceImplILeadServiceConvertibleLeadCatalogPort)、IOpportunityCreateServiceOpportunityCreateController、及测试;「未被商机占用」过滤(查 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 的候选线索用例改 mock ConvertibleLeadCatalogPort。验证:crm-lead + crm-opportunity 相关单测全绿。
  • 决策来源:/improve-codebase-architecture 审查(2026-08-25,候选 #2)+ 代码审查(/code-review,2026-08-25)——审查发现实现已落但引用的本 ADR 尚未写下,本文补齐该悬空引用。