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.

33 lines
3.9 KiB

5 hours ago
---
status: accepted
---
# 公海规则「绑定商机(数量)」计数出站 seam:PoolRuleOpportunityCountPort(crm-rule 声明,crm-opportunity 实现)
## Context
一期记账缺口([gap-report](../../.scratch/a7-parity/gap-report.md) §六,P2):公海规则 detail 出参缺原型 A7-3-2-5-1「绑定商机:N 条」(字段说明:当前规则版本**已实际绑定或适用**的商机数量)。商机侧无 pool_rule 引用列(无持久绑定可数),运行时 `OpportunityPoolRuleMatcher.loadPublished().match(ownerDeptId)` 动态匹配(快照式、实时、不锁版本)。a7-heavy 票 03 毕业此缺口,建图时拍板方案 B(动态计数)+ 计数口径钉 match 语义。
方向约束同 ADR-0025:`crm-rule → (crm-auth / crm-dict / crm-base)` 单向,不得反向依赖 crm-opportunity(pom 明文),而 opportunity 表归 crm-opportunity。
## Considered Options
- **A:opportunity 加 pool_rule_id 快照列(掉入/分配时落)**——需 DDL + 存量回填,语义 = 历史绑定;与运行时 match(实时快照式)双口径并存必漂移。否(同一期票 09 查重规则「引用计数=实时统计不落列」先例)。
- **B(选中):出站端口动态计数——crm-rule 声明 `PoolRuleOpportunityCountPort`,crm-opportunity 实现 adapter,按部门谓词 count**。零 DDL 零迁移;口径(哪条规则/发布态/默认排除集)由 crm-rule 自持,实现方只做无语义计数。
- **C:crm-rule 直查 opportunity 表**——跨域 DB 耦合,违背 seam 精神(同 ADR-0025 选项 B 否决理由)。否。
## Decision
1. **端口落位 crm-rule**:`com.crm.rule.port.outbound.PoolRuleOpportunityCountPort`。票面原写「crm-base 定义」,执行改钉 **ADR-0025 同构**——同消费方(crm-rule)、同方向(下游 provider 实现)的既有出站端口先例;crm-opportunity 本就依赖 crm-rule(消费匹配引擎),DIP 不破坏方向;crm-base 不必承载规则域词汇。
2. **端口形状按「部门谓词」两方法**:`countByOwnerDepts(deptIds)`(部门专用口径)/ `countOutsideOwnerDepts(excludedDeptIds)`(默认规则兜底口径,owner_dept_id 为空或不在排除集)。实现方 `PoolRuleOpportunityCountAdapter`(crm-opportunity `adapter` 包,对称 crm-lead `PoolLeadOccupationAdapter`)只钉三条数据口径:软删过滤(`@TableLogic`)、排除已转项目(`opp_status=5` 绝对终态不再受公海规则治理,与 `UserTransferPort` 商机域计数同口径)、公海态照常计入(release-pool 保留 `owner_dept_id` 作公海可见锚点,claim 守卫即按它匹配——按存量 `owner_dept_id` 计数即与运行时一致)。
3. **消费口径 crm-rule 自持**:仅发布中规则计数——部门专用 = `port.countByOwnerDepts(本版本 deptIds)`;发布中默认 = `port.countOutsideOwnerDepts(发布中专用规则部门并集)`(match 兜底语义:不命中任何发布中专用规则的商机数,非全部商机);非默认通用/草稿/停用运行时永不命中 → 0。
4. **仅 detail 出参回填 `boundOppCount`**:原型 v29 列表页列头 10 项无「绑定商机」(票面「原型列头在列表页」前提经原型文本库核实不成立),page 不补列不计数。
5. **消费注入 `ObjectProvider` 可选**,port 缺失(纯 rule 装配)fail-open 展示 0——展示型计数,非 ADR-0025 守卫型 fail-safe。
## Consequences
- detail 增量:部门专用 = 1 次 count;默认规则 = 规则查询 + 子表查询 + 1 次 count;page 零增量。
- bruno 文档 detail 出参表 +1 字段(bruno-sync 重生成);e2e(a7-heavy 票 05)断言口径即本 ADR 口径。
- 无 DDL、无迁移、无 README 错误码变更;零 pom 改动(复用既有依赖方向)。
- 决策来源:a7-heavy 票 03(map 建图拍板方案 B + match 口径)+ 执行拍板(端口落位 crm-rule / 公海态计入 / 排除已转项目 / page 不补列 / fail-open)。