权限与访问

Carbon 如何决定谁能看到和更改什么——从模块-动作模型到员工类型、用户组、邀请和车间 PIN 账户。

Carbon 通过按公司划分的显式授权来为每个用户授权。每项授权组合一个模块(例如销售或库存)和一个动作:查看、创建、更新或删除。例如,sales_view 允许读取销售记录,inventory_update 允许编辑库存。授权不隐含其他授权;没有任何授权的用户可以登录,但无法访问任何模块。

员工类型提供授权模板,并可为每个员工设置例外。员工记录参见人员,同一模型下的程序化访问参见 API 密钥,登录安全参见双因素认证。

模块-动作模型

单个权限写作 <module>_<action>——sales_view、inventory_update、purchasing_create。模块是数据库中定义的固定集合(module 枚举,packages/database/supabase/migrations/20240909194622_jobs.sql:10,Quality 在 20250325103806_quality-module.sql:1 中加入):

会计、文档、开票、库存、部件、人员、生产、采购、质量、资源、销售、设置和用户。数据中还有一些内部模块(Items、Messaging、Timecards),但它们在权限界面中隐藏(apps/erp/app/hooks/usePermissionMatrix.ts:64),因此你编辑的是上面的列表。

动作始终是相同的四种(apps/erp/app/hooks/usePermissionMatrix.ts:56):

字段类型
读取模块中的记录。没有该权限,模块页面对该用户不可见。
新增记录。
编辑现有记录。
删除记录。

Carbon 中的每个权限界面都是同一个控件:一个每行一个模块、每个动作一个复选框的矩阵(apps/erp/app/components/PermissionMatrix.tsx)。可以切换某个单元格授予单项权限,切换整行翻转整个模块,或使用表头全选。员工类型模板、单个员工的覆盖、批量编辑器,甚至 API 密钥的作用域都渲染同一个矩阵,因此心智模型处处一致。

NOTE

授权按公司划分

内部每项授权都存储其适用的公司列表,因此一个人可以在所属的每家公司拥有不同权限。界面中你始终编辑当前公司的权限。特殊值 "0" 表示「所有公司」,是真正的跨公司管理员的表示方式。用户如何跨多家公司,参见多公司设置。

Carbon 同时在两处执行这些授权。应用检查它们以显示或隐藏界面和按钮,数据库通过行级安全执行同样的授权,因此绕过界面的请求仍然无法访问授权不允许的数据。第二层正是同一模型能安全用于 API 密钥的原因,API 密钥的作用域正是这种 module_action 形式。

员工类型

员工类型是具名的权限模板。无需为每个新员工手工勾选几十个单元格,你只需定义一次类型(例如「采购员」,拥有完整采购权限和只读库存),然后分配。每种类型都在设置 → 用户 → 员工类型下用同一矩阵编辑,其授权成为分配给该类型的任何人的起点。

HEADS UP

编辑类型只改变模板,不影响现有人员

修改类型的权限只会为更改之后分配的人设置默认值。已经属于该类型的员工保留其现有权限。要把更改推送给现有员工,请使用下方的批量权限编辑器。

有两种类型是预置的且不能删除,通过稳定的 systemType 值标记,因此管理员可以重命名显示标签而不破坏 Carbon 的内部查找(packages/database/supabase/migrations/20260401000000_protect-console-operator-type.sql:6):

字段类型
完全访问类型。分配给负责公司 Carbon 配置的人。
车间 PIN 账户使用的类型。添加操作员时自动管理(见下文),无需手动分配。

其他所有类型都由你创建、重命名和删除。每家公司每种系统类型最多一个,由唯一索引执行(20260401000000_protect-console-operator-type.sql:20)。

个人覆盖与批量编辑

员工在设置 → 用户 → 账户中的权限矩阵从员工类型授予开始。勾选或清除单元格会创建按员工的例外,而不改变类型。切换类型时,Carbon 会询问是用新模板替换当前授权还是保留它们。

当更改需要同时影响很多人时,使用批量权限编辑器。选择用户、选择模式,然后设置矩阵:

字段类型
把所选授权叠加到每个用户现有权限之上,不会移除任何内容。
用下方矩阵整体替换每个所选用户的权限集。

这是把员工类型更改传播到现有员工、或一次性为整个部门授予新模块的工具。两种模式的区别是「也给大家这些」和「让大家正好只有这些」——只有确实想覆盖时才用 Update。

NOTE

权限更改可能需要片刻生效

Carbon 会缓存每个用户的有效权限以提高速度。更改某人的授权时,Carbon 会清除其缓存,使新权限在下次请求时生效。如果更改似乎没有生效,几乎总是会话陈旧——退出再登录会强制重新读取。

邀请人员

你不为用户创建密码。你通过邮件邀请他们,他们在接受时自行设置登录方式。在设置 → 用户 → 账户中添加员工,填写姓名、邮箱、员工类型和地点。Carbon 创建账户、记录邀请,并发送完成加入的链接。

由于邀请是一条真实记录,员工有一个由邀请和账户推导出的明确状态(employees 视图,packages/database/supabase/migrations/20260529160000_employees-view-status.sql:16):

偏轨状态
在职
邀请已接受,账户已激活。这是正常工作状态。

邀请是按邮箱建键、按公司划分的记录,携带此人起始的权限集,因此他们接受的那一刻授权就已就绪。在邀请待处理期间,你可以从账户列表重发邀请邮件或撤销邀请。停用在职员工会将其从公司移除、剥离授权并标记为停用;它不会删除此人,此人可能仍属于其他公司。个人记录的完整说明参见人员。

车间 PIN 账户

终端操作员在共享工位上用 4 位 PIN 登录 MES,而不是基于邮箱的登录。它们是单独的账户类型。

在设置 → 用户 → 操作员中(仅在为公司启用终端模式时可见)添加操作员,填写姓名和地点。Carbon 创建一个无邮箱登录的轻量账户,自动分配终端操作员员工类型,并生成一个仅显示一次的 4 位 PIN——Carbon 只保存其哈希,因此请在此时复制。车间里操作员点击自己的名字并输入 PIN,Carbon 在开始其会话前校验。PIN 丢失时,在同一界面重置并生成新 PIN,旧 PIN 立即失效。重置操作员的 PIN 需要 users_update;为其他任何员工设置终端 PIN(在账户列表中)还需要 settings_update。

NOTE

操作员可以升级为完整用户

当 PIN 账户需要真正的 ERP 访问时,可以转换:为其提供邮箱和完整员工类型,Carbon 会把同一个人提升为普通受邀用户而不丢失历史(apps/erp/app/modules/users/users.server.ts:905)。其原来的车间活动仍挂接到同一身份。

PIN 账户在设计上限定于车间。它们只拥有终端操作员类型允许的授权,因此丢失或共享的平板无法用来访问 Carbon 的办公室侧。操作员体验本身——打卡、报告数量、发料——参见 MES 参考和车间运行指南。

各部分所在位置