Browse Source
Candidate #2 代码审查(/code-review)收尾:实现(8329911)已落且双轴通过, 但通篇引用的 ADR-0031 从未写下(悬空引用,5+ 文件)。本次补齐: - docs/adr/0031:记录 crm-lead 声明并自实现的窄 inbound port(收窄 ADR-0029 的 ILeadService 泄漏),与 ADR-0025 PoolLeadOccupationPort 方向相反的同型 seam - crm-lead/CONTEXT.md:新增「可转商机候选线索目录端口」术语master
2 changed files with 45 additions and 0 deletions
@ -0,0 +1,41 @@ |
|||
--- |
|||
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](0029-opportunity-depends-on-lead-tech-debt.md) 记录的 `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`/`OpportunityCreationException` cmd/异常随端口同包先例)。 |
|||
- **B:保留 `ILeadService` 注入,仅移 `ConvertibleLeadView` 到契约包。** 契约面仍是 20+ 方法宽接口,泄漏未收窄,否。 |
|||
- **C:商机侧直查 lead 表。** 无 Java 依赖但 DB 层耦合、跨域判定线索准入口径,违背 seam 精神(同 ADR-0025 选项 B 的否决理由),否。 |
|||
|
|||
与 [ADR-0025](0025-pool-lead-occupation-port-seam.md) 的关系:两者都是把跨域协作收进一个窄 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` 的候选线索用例改 mock `ConvertibleLeadCatalogPort`。验证:crm-lead + crm-opportunity 相关单测全绿。 |
|||
- 决策来源:`/improve-codebase-architecture` 审查(2026-08-25,候选 #2)+ 代码审查(`/code-review`,2026-08-25)——审查发现实现已落但引用的本 ADR 尚未写下,本文补齐该悬空引用。 |
|||
Loading…
Reference in new issue