Skip to content

fix(approvals): resolve department approvers against env-wide business units (#3807) - #3811

Merged
os-zhuang merged 1 commit into
mainfrom
claude/approver-value-lookup-fix-t9hr0r
Jul 28, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/approver-value-lookup-fix-t9hr0r

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3807.

问题

expandBusinessUnitUsers(approval-service.ts)读 sys_business_unit 时用的是严格等值 organization_id = <请求的 org>,于是 organization_id = null 的单元完全不可见:种子检查查不到行 → 整个展开返回 [] → 审批人落到死值 department:<id>,路由到没有人。

这不是边角情况,而是常态。应用的组织架构一般是 seed 出来的,而 seed 阶段拿不到运行时才创建的组织 id,所以每一行都是 organization_id = null;审批请求却总是带着 org。结果:设计器 Department 选择器里能选到的每一个单元,都解析到没有人,而且是静默的 —— 请求照常打开、名单为空,配上 lockRecord 记录就此锁死没人能动(#3424 就是同一条死路的下游形态)。

配合 #3508 刚落地的记录 lookup,这条路更容易被走到:以前要手敲 BU id,现在从选择器里点一下就得到一个死槽位。

改动

种子检查与子树下钻都改为「本组织 ∪ 无组织」:

$or: [{ organization_id: <org> }, { organization_id: null }]

与 sys_metadata 待发布草稿列表为同一个原因(严格等值静默丢掉 env-wide 行)所采用的谓词一致。

两个组织之间的墙没有变:别的组织的单元仍然匹配不上;null org 的父单元也不会把别的组织的子单元拖进子树。只有「不属于任何组织」的行变得可见 —— 而这类行只可能由部署方(seed / 文件层 / bootstrap)写入,租户管理员写不出来(写路径会盖 org 戳)。

验证

真机,同一个库、同一条 flow、只换构建:

记录 BU 的 org 构建 department 槽位
pm8MCA… null(seed 原样) 修前 department:bu_hq_finance ❌ 死值
0h-cVa… 手工补上 org 戳 修前 usr_showcase_phone_demo ✅(印证因果)
p-G0OQ… 改回 null 本 PR usr_showcase_phone_demo ✅

单测:新增 4 例 —— env-wide 单元能解析;别的组织的单元仍然不可见;null org 的父单元不会拉进别组织的子单元;停用的 env-wide 单元仍然不出人。其中两个正向用例在不改源码时确实失败(已回退验证)。

plugin-approvals 全量 252/252 通过;仓库 pnpm lint 干净。

未一并改动的地方

plugin-sharing 的 BusinessUnitGraphService.orgScope 有同形的严格等值。目前不可达 —— 实测所有物化出来的 sys_sharing_rule 行 organization_id 都是 null,过滤器整个被跳过,BU 子树共享规则照常生效。它是一条授权路径(决定谁能看到记录),在没有可复现失败的前提下不宜跟着放宽,故本 PR 不动它,只在此备案。

🤖 Generated with Claude Code

https://claude.ai/code/session_01BVRVgSvmyCwmDfTmKmCZoH


Generated by Claude Code

…ess units (#3807)

`expandBusinessUnitUsers` scoped its `sys_business_unit` reads with a strict
`organization_id = <request org>` equality, so a unit whose `organization_id`
is `null` was invisible: the seed check found no row, the expansion returned
`[]`, and the approver fell back to the dead `department:<id>` literal that
routes to nobody.

That is the normal case, not an edge case. An app's org tree is seeded, and a
seed cannot know the organization id the runtime mints at boot, so every seeded
unit carries `organization_id = null` — while an approval request always
carries one. Every business unit a flow author could pick therefore resolved to
nobody, silently, and with `lockRecord` the record stays locked with no one able
to act (#3424 is the downstream shape of the same dead end).

Both the seed check and the subtree descent now scope to this org ∪ env-wide —
`$or: [{ organization_id: <org> }, { organization_id: null }]` — the same
predicate `sys_metadata`'s pending-draft listing settled on for the identical
reason. The wall between two organizations is unchanged: another org's unit
still fails the match, and a null-org parent does not drag another org's child
unit into the subtree.

Verified on a live showcase stack, same DB and same flow across builds:
seeded (null-org) unit + old build → `pending_approvers: department:bu_hq_finance`;
same unit + this build → the unit's member.

Tests: 4 new cases (env-wide unit resolves; another org's unit stays invisible;
a null-org parent does not pull in another org's child; an inactive env-wide
unit still contributes nobody). The two positive cases fail without the source
change. plugin-approvals 252/252 pass; repo lint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVRVgSvmyCwmDfTmKmCZoH
@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 28, 2026 6:54am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-approvals.

4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/approvals.mdx (via @objectstack/plugin-approvals)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-approvals)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-approvals)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-approvals)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

approvals: a department approver never resolves when the business unit has organization_id = null (every seeded BU)

2 participants