ToolJet 用户归档与取消归档完整指南:实例级与工作区级的权限控制、状态流转与底层实现
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
归档(Archive)是 ToolJet 中回收用户访问权限而非删除用户的重要手段。管理员可以将工作区中的某个用户归档,使其立即失去对该工作区的访问能力,同时完整保留该用户此前创建的所有应用、查询与配置数据;当业务需要时,又可以随时通过取消归档(Unarchive)让用户重新回到工作区。本指南将基于 ToolJet 3.0.0-LTS 文档与当前仓库源码,系统讲解实例级与工作区级归档/取消归档的操作步骤、状态语义、底层数据模型与关键实现,帮助你正确管理用户生命周期。
归档的核心语义:移除访问权,保留数据
归档的本质是"软禁用"。根据官方文档,管理员归档工作区中的用户后,会发生两件事:
- 用户立即失去对该工作区的访问权限,无法再登录、查看或编辑其中的应用;
- 用户此前创建的应用以及所有更改都会被完整保留,不会被删除;
- 后续如果业务需要,管理员可以取消归档该用户,将其重新邀请回工作区。
这与"删除用户"有本质区别:删除通常意味着数据清理与不可恢复,而归档是一条可逆的回收路径,适合离职、休假、权限冻结等临时或长期的访问管控场景。
两条强制约束
归档操作并非毫无限制,官方文档明确了两条规则:
- 已归档用户不计入计费/许可(billing/licensing):这意味着归档既能释放席位,又无需删除数据。在源码中也有印证,计费统计服务 在统计活跃用户数时,会显式排除
USER_STATUS.ARCHIVED状态(如users.status != :archived、status: Not(USER_STATUS.ARCHIVED)等查询条件)。 - 工作区必须保留至少一名活跃管理员:不能归档工作区中全部管理员。这条规则在服务端有硬性校验,详见下文源码解析。
实例级(Instance Level)与工作区级(Workspace Level)的区别
ToolJet 的用户管理分为两个层级,归档/取消归档在两层的行为差异非常关键:
| 维度 | 实例级(Instance Level) | 工作区级(Workspace Level) |
|---|---|---|
| 操作入口 | Settings > All Users | Workspace settings > Users |
| 示例 URL | https://app.corp.com/instance-settings/all-users | https://app.corp.com/nexus/workspace-settings/users |
| 所需角色 | Super Admin(超级管理员) | Admin(工作区管理员) |
| 影响范围 | 用户从所有工作区被归档,且无法被邀请到任何新工作区 | 仅移除用户在当前工作区的访问权限,不影响其他工作区 |
| 对应后端能力 | archive-all / unarchive-all(跨工作区批量生效) | archive / unarchive(限定单个工作区) |
从仓库前端代码可以直观看到这两类操作是分开的 API:organization_user.service.js 中同时暴露了archiveAll/unarchiveAll(对应POST /organization-users/:userId/archive-all与/unarchive-all)和archive/unarchive(对应POST /organization-users/:id/archive与/unarchive)两套接口。
归档用户(Archive User)操作步骤
实例级归档(Super Admin)
当用户在实例级被归档后,会被自动从所有工作区移除,且无法再被邀请到任何新工作区。操作步骤:
- 点击仪表盘左下角的设置图标(⚙️);
- 进入Settings > All Users(示例 URL:
https://app.corp.com/instance-settings/all-users); - 找到需要归档的用户,点击其所在行末尾的 kebab 菜单(竖排三点图标);
- 选择Archive user;
- 该用户的状态列会更新为 archived。
工作区级归档(Admin)
工作区级归档只移除用户对当前工作区的访问权,用户在其他被邀请的工作区仍然可用。操作步骤:
- 点击仪表盘左下角的设置图标(⚙️);
- 进入Workspace settings > Users(示例 URL:
https://app.corp.com/nexus/workspace-settings/users); - 找到目标用户,点击其行末的 kebab 菜单;
- 选择Archive user;
- 状态列更新为 archived。
取消归档用户(Unarchive User)操作步骤
实例级取消归档(Super Admin)
注意:用户仅在实例级被取消归档后,并不会自动恢复任何工作区。管理员还需要在每个工作区中单独取消归档(或重新邀请)该用户。操作步骤:
- 点击左下角设置图标(⚙️);
- 进入Settings > All Users;
- 找到目标用户,点击 kebab 菜单;
- 选择Unarchive user;
- 用户状态更新为invited。
工作区级取消归档(Admin)
工作区级取消归档有一个值得注意的联动效果:如果用户在工作区级被取消归档,其实例级状态也会被自动取消归档。操作步骤:
- 点击左下角设置图标(⚙️);
- 进入Workspace settings > Users;
- 找到目标用户,点击 kebab 菜单;
- 选择Unarchive user;
- 用户状态更新为invited,并且系统会向该用户发送一封新的邀请邮件(invitation mail),用户需通过邮件中的邀请链接重新加入工作区。
状态模型:归档背后的数据语义
要深入理解归档行为,需要先了解 ToolJet 中用户状态的两套枚举。它们分别定义在 server/src/modules/users/constants/lifecycle.ts:
实例级用户状态(USER_STATUS):invited(已邀请)、verified(已验证)、active(活跃)、archived(已归档)。
工作区用户状态(WORKSPACE_USER_STATUS):invited(已邀请)、active(活跃)、archived(已归档)。
可以看到,归档状态的落点同时存在于用户实体(User)与工作区用户关联实体(OrganizationUser)两个层面,这正是"实例级归档影响所有工作区、工作区级归档只影响单个工作区"的数据基础。工作区用户来源(WORKSPACE_USER_SOURCE)也分为invite(邀请)与signup(注册)两类,取消归档后工作区用户会被重新标记为invite来源并生成新的邀请令牌。
此外,lifecycle.ts 中还定义了一个用户友好的错误提示:当已归档用户尝试访问时,系统会返回"You have been archived from this instance. Contact super admin to know more.",明确指引其联系超级管理员处理。
源码级原理:归档与取消归档的完整调用链
前端交互入口
前端用户列表中的 kebab 菜单由 UsersActionMenu.jsx 组件渲染。其中 Archive 按钮会根据当前用户状态动态切换文案与动作:
user.status === 'archived'时显示Unarchive user并调用unarchiveOrgUser(user);- 否则显示Archive user并调用
archiveOrgUser(user); - 当归档/取消归档请求进行中(
archivingUser === user.id或unarchivingUser === user.id),按钮会被禁用,避免重复提交。
后端 API 端点
归档相关的能力集中在 server/src/modules/organization-users/controller.ts:
| 方法 | 端点 | 说明 |
|---|---|---|
| POST | /organization-users/:id/archive | 单工作区归档,organizationId取自请求体,缺省时使用当前用户所在工作区 |
| POST | /organization-users/:userId/archive-all | 实例级归档(所有工作区),且禁止自我归档(Self archive not allowed) |
| POST | /organization-users/:id/unarchive | 单工作区取消归档 |
| POST | /organization-users/:userId/unarchive-all | 实例级取消归档(所有工作区) |
这些端点都带有@InitFeature(FEATURE_KEY.USER_ARCHIVE / USER_UNARCHIVE / ...)特性开关标记,且依赖角色权限体系(CASL)的授权校验。
归档的服务端实现
核心逻辑在 server/src/modules/organization-users/service.ts 中:
archive(id, organizationId)(单工作区):在数据库事务内先校验"目标用户不是最后一个活跃管理员"(throwErrorIfUserIsLastActiveAdmin),随后将 OrganizationUser 的状态置为WORKSPACE_USER_STATUS.ARCHIVED,并清空邀请令牌invitationToken(防止被归档者继续使用旧邀请链接进入),最后写入审计日志(记录归档用户与被归档者邮箱、姓名,以及对应工作区名称与 ID)。archiveFromAll(userId)(实例级):查找该用户的所有 OrganizationUser 记录并批量更新为 archived、清空邀请令牌,同时将 User 实体的实例级状态更新为USER_STATUS.ARCHIVED,并记录跨工作区的审计日志。- 最后一个活跃管理员的校验逻辑:
throwErrorIfUserIsLastActiveAdmin会查询该工作区所有 Admin 角色用户,筛选出状态为active的活跃管理员;如果目标用户是唯一活跃管理员,则抛出BadRequestException('Atleast one active admin is required'),从机制上保证了"至少保留一名活跃管理员"的约束。
取消归档的服务端实现
unarchiveUser(userId)(实例级):特殊处理"用户在 invited 状态下被归档"的场景——如果用户实例级状态为 archived 且仍持有邀请令牌,则恢复为invited,否则恢复为active;随后进行 license 校验并写入审计日志。unarchive(user, id, organizationId)(单工作区):首先校验目标 OrganizationUser 必须处于ARCHIVED状态(否则抛出User status must be archived to unarchive);随后生成全新的 UUID 邀请令牌与过期时间(过期分钟数由环境变量LINK_EXPIRY_MINUTES控制,未配置或非正数时不设过期),将工作区用户状态置为invited、来源置为invite;最后根据用户是否已在实例级激活,选择发送setup/welcome 邮件或工作区欢迎邀请邮件(见EMAIL_EVENTS.SEND_WELCOME_EMAIL与SEND_ORGANIZATION_USER_WELCOME_EMAIL)——这正是文档所述"取消归档后用户会收到新的邀请邮件"的底层来源。
边界情况与注意事项
结合文档与源码,使用归档功能时还应注意以下几点:
- 归档不可逆的唯一门槛是数据保留:归档后所有应用与改动都保留,取消归档后数据立即恢复可见,因此归档适合作为临时、可逆的访问管控手段。
- 实例级取消归档 ≠ 恢复工作区访问:实例级 unarchive 只解除"全局禁用",各工作区的访问需要管理员逐工作区重新取消归档或邀请(工作区级 unarchive 会自动联动恢复实例级状态,但反向不成立)。
- 邀请令牌会失效并被刷新:归档会清空邀请令牌,取消归档会生成新令牌并重新发送邮件,旧链接无法再使用。
- 计费立即生效:归档用户不计入席位,取消归档后重新计入,因此该功能也常用于许可证席位紧张时的临时收缩。
- 管理员保护机制:工作区最后一名活跃管理员无法被归档,避免工作区陷入无人管理的状态。
- 批量导入的连带影响:在 service.ts 的 CSV 批量上传逻辑中,已归档用户的邮箱会被单独收集并直接抛出错误提示(
User with email ... is archived. No users were uploaded),即归档用户不能通过批量上传重新邀请,必须先取消归档。
小结
ToolJet 的归档/取消归档功能通过"实例级 + 工作区级"的双层设计,配合User与OrganizationUser两套状态模型,实现了可逆的访问回收、自动化的邀请邮件恢复以及与计费席位联动的能力。对运维与管理员而言,只需记住三条原则:归档即软移除、数据永远保留、最后一名活跃管理员不可归档,即可安全地管理团队成员的访问生命周期。若需进一步了解用户管理相关的其他能力,可继续阅读 用户管理文档目录 下的其他主题,或查阅本文引用的前端组件与后端服务源码深入实现细节。
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考