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.

74 lines
7.6 KiB

2 weeks ago
<!-- wayfinder:grilling -->
# 作废态保留 owner 的状态机小改:残留触点核实与文档定稿
Type: grilling
Status: resolved
Blocked by:
## Question
决策 01 已定:作废态**保留 `owner_user_id`**(反馈无效自动作废时不再清空),使销售能在「我的线索」看到自己作废的线索;名额 `hold_limit` / 可转商机目录按 status IN(3,4) 排除作废、不依赖 owner=null,已核实不受影响。
本 ticket 把这个「小改」的边界钉死——核实残留触点,产出改动清单(仍是 spec 层,不写实现):
1. **`LeadTransitionImpl#applyFeedback`(line 211)**:改为 targetStatus=VOID 时**不** `set(ownerUserId, null)`。但 `ownerNameSnapshot` / `claimTime` / `recycleDeadline` 是否也保留?(recycleDeadline 关系回收计时,见下。)
2. **回收计时 N**:作废保留 owner 后,回收 job / `LeadDeadlines` 是否会把「作废且 owner 非空」误当私海去续期或回收?作废态 N 应停(PRD §3.4:作废态 N 不跑,M 继续)。需确认保留 owner **不会**让作废线索重新被回收扫描命中。
3. **激活恢复(过期失效→失效前态)**:作废→失效→激活 恢复到作废态,现在 owner 已保留,`statusBeforeExpire` 恢复逻辑读 owner 是否仍自洽。
4. **`@DataScope`**:作废线索 owner=me 后,会不会改变它在「线索管理」等视图的部门天花板/owner 过滤判定,导致别处列表意外多/少数据。
5. **边 #15「作废自环换 owner」**(管理员把作废线索重新分配给新销售):原逻辑是「作废态 owner 可能为空→写入新 owner」。保留 owner 后,重新分配=**覆盖**原 owner,语义是否仍正确(原持有人被顶替)。
6. **文档**:PRD §3.4 / 状态机边 #14 / `crm-lead/CONTEXT.md` 中「进入作废时清空 owner_user_id」全部要改。列出待改条目(PRD §3.4、边#14、§6.10 G1/G2、CONTEXT「线索作废」段)。
7. **回归面**:列出受影响的现有测试(`LeadTransitionImplTest` 的作废/反馈无效用例、`ClaimLimitCheckerTest`、可转商机目录测试)需要新增/改写的断言清单。
产出:一份「作废保留 owner」改动清单 + 文档待改条目 + 回归断言清单,作为 spec 的领域改动章节。这是 02(口径表)的前置——「我的线索」到底含哪些作废线索,取决于本 ticket 把归属语义钉死。
## 已定(逐步澄清)
**① 作废 VOID 分支的字段取舍**(`applyFeedback` line 211 四个 `set(...,null)`)——用户认可推荐:
- `owner_user_id`**保留**(本 ticket 核心)
- `owner_name_snapshot`**保留**(否则列表“归我却无名”)
- `claim_time`**保留**(列表显示领取时间;每日领取上限本就按 claim_time 计次,不受影响)
- `recycle_deadline`**继续置 null**(PRD §3.4:作废态 N 不跑;且回收扫描 `recycle_deadline<cutoff AND status IN(3,4)` 双保险,永不误扫)
扫描层安全性已核实(均 status-keyed,不看 owner):`executeRecycle`=`status IN(3,4)`;`executeExpire`=`status NOT IN(5,6)`(作废本就会失效,M 继续,符 PRD);`applyActivate` 按 `statusBeforeExpire` 恢复、不碰 owner。→ 保留 owner 在扫描层安全。
**② 边#15「作废自环换 owner」语义**(`applyAssignToUser` VOID 分支,line 149-172)——用户选 **甲:顶替**
- 管理员把作废线索改派给新销售 = `set(owner=新销售)` 覆盖原持有人,线索离开原销售的「我的线索」、进新销售的。符合「当前归属只一人」。
- **现有分配逻辑一行不动**(本就是 set 新 owner),无需额外守卫/提示。
**③ 名额连带效应(已核实确认)**:反馈无效作废、owner 仍=小张的线索,**不占** 小张 `hold_limit`(只数 status IN(3,4),作废是7)——即用户最初要的「作废不算持有上限、但归属还在」。
**④ `@DataScope` 连带可见性**(`DataScopeInterceptor`)——用户选 **甲:可以**
- 数据范围=本人档的用户被注入 `owner_user_id=我`;改前作废 owner=null 天然被排除,改后 owner=我 会通过过滤,可能出现在该用户能访问的其它视图(如线索管理)。
- 定为**合理**:“我的作废线索”在我数据范围内任何视图可见,**不在视图口径层为作废设限**。(部门档/全部可见用户不受影响:部门档按 dept_id、作废 dept_id 不变;全部可见不注入。)
- 对 02 口径表的含义:各视图作废计数 = 各自自然过滤 + status=7,不额外设限。
## 待改文档与回归面(清单,无需拍板,实现 session 执行)
**文档待改(把“进入作废时清空 owner”改为“保留 owner,N 停、清 recycle_deadline”)**:
- `.scratch/clue-module/线索业务-PRD.md`:**line 100**(状态表行 #14 “清空 owner_user_id”→“保留 owner;N 停、清 recycle_deadline”)、**line 101**(行 #15 写新 owner→“覆盖原 owner(顶替)”)、**line 126** 图“线索作废(清空 owner)”、**line 136** §3.4「归属:进入作废时清空 owner_user_id”、**G1**(“我的线索里作废 owner 必=我”——结论不变,但理由从“重新分派才归我”变为“作废保留原 owner”)。
- `crm-lead/CONTEXT.md`:**line 12**「领取人」段(删“、进入作废时清空”)、**line 56**「线索作废」段(删“进入时清空 owner_user_id”,改为“保留 owner;N 停、清 recycle_deadline”)。
- 注:释放(PRD line 354)/ 回收 清 owner 不动——那是退回公海,非作废。
**回归断言(新增/改写)**:
- `LeadTransitionImplTest`:反馈=无效作废后断言 `owner_user_id / owner_name_snapshot / claim_time` **保留**、`recycle_deadline` = null(原用例若断言 owner=null 需反转);作废自环分配断言 owner 被新销售覆盖。
- `ClaimLimitCheckerTest`:新增“owner=我且 status=7 的线索不计入 hold_limit”用例(防回归)。
- `LeadViewQueryImplTest`:“我的线索”含 owner=我的作废线索;countStats 作废计数(待 03 定字段后写)。
- 可转商机目录测试:确认 owner=我的作废线索**不入**可转商机目录(status IN(3,4) 卡住)。
## Answer
**结论(在路线上 resolved):作废态保留 owner 的状态机小改馆括已完成,结论比预想更小——**无回收/激活/名额副作用**,只需一处代码改动 + 两份文档更新 + 一批回归断言。**
**七个点的决策(与用户逐条澄清)**:
1. **字段取舍**(`applyFeedback` VOID 分支):`owner_user_id` / `owner_name_snapshot` / `claim_time` 保留;`recycle_deadline` 继续置 null。
2. **回收扫描**:安全(status-keyed,不看 owner)。
3. **激活恢复**:自洽(按 `statusBeforeExpire` 恢复、不碰 owner)。
4. **`@DataScope` 连带可见性**:选甲——“我的作废线索”在我数据范围内任何视图可见,不在视图口径层为作废设限。
5. **边 #15 作废自环换 owner**:选甲——分配 = 覆盖原 owner(顶替);现有分配逻辑一行不动。
6. **文档待改(已钉行号)**:PRD line 100/101/126/136 + G1;CONTEXT line 12/56。
7. **回归断言**:`LeadTransitionImplTest` / `ClaimLimitCheckerTest` / `LeadViewQueryImplTest` / 可转商机目录测试;具体断言见上文。
**对下游 ticket 的预填**:
- 02(口径表):各视图作废计数 = 各自自然过滤 + status=7,不额外设限(第 4 点预填)。「我的线索」含 owner=我的作废(第 1 点预填)。
- 03(DTO):字段形态仍等 02 口径表定稿。