Skip to content

docs(adr): ADR-0092 — sys_user 档案字段经引擎 hook 委托,放开 edit affordance(RFC #2784) - #2787

Merged
os-zhuang merged 1 commit into
mainfrom
claude/sys-user-field-delegation-4p8l20
Jul 10, 2026
Merged

docs(adr): ADR-0092 — sys_user 档案字段经引擎 hook 委托,放开 edit affordance(RFC #2784)#2787
os-zhuang merged 1 commit into
mainfrom
claude/sys-user-field-delegation-4p8l20

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

概要

针对 RFC #2784 的评估产出:新增 ADR-0092(Proposed),决策是否/如何放开 sys_user 纯档案字段的标准表单编辑。仅文档,不含实现代码;ADR 通过后再立实现 issue。

结论(TL;DR)

放开一条窄口径、服务端强制的档案写路径:

  • D1 字段分层:可编辑档案字段仅 nameimagerole / phone_number / manager_id / ai_access / ban 列归专用管理面;email、凭据、全部 system-managed stamp 列永不直写。phone_number 是登录标识(唯一索引)、manager_id 驱动 own_and_reports RLS 范围,都排除在表单层之外。
  • D2 机制:plugin-auth 注册 beforeUpdate 白名单守卫 hook(fail-closed,仅拦截用户上下文写入;better-auth adapter 与 system 写入不受影响)。不采用仅 UI readonly 的方案 —— 调研发现字段级 readonly 在服务端只是校验跳过而非写入拦截,违反 ADR-0049。附带收益:堵上现存漏洞 —— admin_full_access 今天就能经 data API 裸写 sys_user 任意列(含 email)。
  • D3 单一白名单:新模块导出两级集合,import upsert 的 UPDATE_ALLOWED_FIELDS(PR feat(auth): 管理员直建用户 + 手机号登录 + sys_user 批量导入(#2766 V1/V1.5/V2) #2771)改为 superset-by-construction 复用,杜绝两处漂移。
  • D4 affordance:守卫落地后才在 sys_user 上加 userActions: { edit: true }(create/import/delete 保持关闭);顺序是硬约束(ADR-0049)。
  • D5 权限拓扑不变:member/org-admin 仍 allowEdit: false,标准编辑路径实际只对平台管理员开放;自助改档案继续走 better-auth /update-user(既有 update_my_profile action)。
  • D6 会话一致性afterUpdate hook 令该用户的 secondary-storage 会话快照失效,不把写入委托给 internalAdapter.updateUser(避免 adapter→engine 重入与 API 耦合)。
  • 审计(评估项 4):无需新建 —— plugin-audit 的引擎级 hook 天然捕获该路径,字段级 before/after 快照优于专用端点的显式审计。

主要调研依据

  • packages/spec/src/data/object.zod.tsresolveCrudAffordances / userActions 仅为 UI 提示;sys_user 的 data API 全量开启。
  • packages/objectql/src/engine.ts + validation/record-validator.ts — 静态 readonly 不在服务端拦截写入(仅 readonlyWhen 被 strip)。
  • packages/plugins/plugin-auth/src/objectql-adapter.ts — better-auth 写入本身走 engine.update,守卫必须按调用上下文而非对象区分。
  • packages/plugins/plugin-security/src/objects/default-permission-sets.ts — 现有 deny 拓扑与 sys_user RLS carve-out。
  • packages/plugins/plugin-auth/src/admin-import-users.tsUPDATE_ALLOWED_FIELDS = {name, phone_number, role}(与表单层白名单刻意不同,故取"同源派生"而非"同一份集合")。

后续

ADR 接受后按 Rollout 章节立实现 issue(守卫 hook + 白名单模块 + import 重构 + 测试 → D6 → affordance 翻转 + objectui 验证)。

Closes#2784 需等实现落地,此 PR 仅关联不关闭。

🤖 Generated with Claude Code

https://claude.ai/code/session_01YGAN5VvvBi4YRGwpNT6e21


Generated by Claude Code

…ne hook (#2784)
Evaluation outcome for RFC #2784: open a narrow, server-enforced profile
write path on sys_user instead of keeping name/image edits endpoint-only
or relying on UI readonly flags.
- D1 field tiers: profile-editable (name, image) / admin-surface-only
(role, phone_number, manager_id, ai_access, ban columns) / never-direct
(email, credentials, system-managed stamps)
- D2 fail-closed beforeUpdate whitelist guard in plugin-auth, user-context
writes only (better-auth adapter + system writes bypass); also closes
the existing admin_full_access raw-write hole on sys_user
- D3 single whitelist module; import upsert's UPDATE_ALLOWED_FIELDS
becomes a superset-by-construction re-export (anti-drift, PR #2771)
- D4 userActions.edit flip ships only after the guard exists (ADR-0049)
- D5 permission topology unchanged: platform-admin only; self-service
stays on better-auth /update-user
- D6 afterUpdate hook invalidates cached session snapshots
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGAN5VvvBi4YRGwpNT6e21
@vercel

vercelBot commented Jul 10, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 10, 2026 12:02pm

Request Review

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

Labels

documentationImprovements or additions to documentationsize/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rfc(identity): 评估 sys_user 档案字段经引擎 hook 委托,放开 edit affordance

2 participants

@os-zhuang@claude