瀏覽代碼

wip(ac20): 分账 3 层业务上限常量(只加常量+注释,不改行为)

- 新增 MaxDivideBizDepth = 3:业务规则上限(超管 → 校区主任 → 老师),
  拍板 2026-11-10,来源前端 mock divide-into.ts:26 MAX_DIVIDE_DEPTH = 3。
- MaxDivideDepth = 100 保留不动,但注释改成「结构上限」,并写明两个常量
  不是同一个概念、不要合并、校验顺序先 3 后 100。
- 本提交不引入任何行为变化(尚无调用点),只固定常量的语义与出处。
Q 8 小時之前
父節點
當前提交
ab122347a8
共有 1 個文件被更改,包括 25 次插入 和 1 次删除
  1. 25 1
      internal/academic/service/divide_service.go

+ 25 - 1
internal/academic/service/divide_service.go

@@ -33,12 +33,36 @@ import (
 	infraerrors "yuansiwei/unified-backend/internal/infra/errors"
 )
 
-// MaxDivideDepth 分账树深度上限(根 layer=1;超限 → apperr.ErrDivideQuotaExceeded 3111)。
+// MaxDivideDepth 是分账树的**结构上限**(根 layer=1;超限 → apperr.ErrDivideQuotaExceeded 3111)。
+//
+// 它的含义**不是**业务规则,而是"算法必须终止"的安全阀:AddSubordinate 要插链,
+// 撤销/入账分支还要沿 parent 链做**上行 BFS**,一旦数据成环或链路极长,
+// 递归会爆栈、BFS 会不终止。所以这个数字与"业务上最多几层"无关,
+// **不要**用它表达业务规则(业务规则是下面的 MaxDivideBizDepth)。
 //
 // 依据:模型注释 layer「深度上限 100(超限 → 3111,防递归栈溢出)」+ dump 的层数保护。
 // BFS 迭代在本上限内必然终止(即使数据成环也不会死循环)。
+//
+// ⚠ 与 MaxDivideBizDepth 是**两个不同概念,不要合并、也不要用其中一个替掉另一个**:
+//   - MaxDivideDepth(本常量,100)= 结构上限,防不终止/爆栈,正常业务永远碰不到;
+//   - MaxDivideBizDepth(100 之外的那个,3)= 业务上限,超管 → 校区主任 → 老师,第 4 层直接拒。
+//
+// 两者唯一的收敛点都是 AddSubordinate,但判定顺序固定为**先 3 后 100**
+// (3 是更常见的失败,先判能给出更准确的错误语义)。
 const MaxDivideDepth int32 = 100
 
+// MaxDivideBizDepth 是分账层级的**业务规则**上限:最多 3 层(超管 → 校区主任 → 老师)。
+//
+// 拍板日期 2026-11-10(业务确认为**硬规则**,不是建议),来源 = 前端 mock
+// `divide-into.ts:26 MAX_DIVIDE_DEPTH = 3`。超限一律 apperr.ErrDivideQuotaExceeded(3111)。
+//
+// 为什么必须落在后端而不是只靠前端常量:mock 里的常量只保证"界面上不让你点"。
+// 真后端一旦没有这道校验,绕过前端(或第三方直接调 API)就能建出第 4 层,
+// 而前端的树渲染与分成计算都按 3 层假设实现 ⇒ 联调时一切正常,上线后才发现数据坏。
+//
+// ⚠ 与 MaxDivideDepth(100,结构上限)**不是同一个概念,不要合并**,理由见上方注释。
+const MaxDivideBizDepth int32 = 3
+
 // remarkRebind 撤销改绑分支写入的备注文案(dump 原样:"推广分成")。
 const remarkRebind = "推广分成"