Skip to main content
Alforse authorizes each user through explicit grants scoped to a company. Each grant combines a module, such as Sales or Inventory, with an action: view, create, update, or delete. For example, sales_view permits reading sales records, and inventory_update permits editing inventory. Grants do not imply other grants; a user with none can sign in but cannot access any module. An employee type provides a grant template, with per-employee exceptions. See People for employee records, API keys for programmatic access under the same model, and two-factor authentication for sign-in security.

The module-action model

A single permission is written <module>_<action> — sales_view, inventory_update, purchasing_create. The modules are a fixed set that the database accepts (the permission tables reject any other key): Accounting, Documents, Invoicing, Inventory, Messaging, Parts, People, Printing, Production, Purchasing, Quality, Resources, Sales, Settings, Users, and Workflows. Two internal modules, Items and Timecards, are hidden from every permission screen (HIDDEN_MODULES in apps/erp/app/hooks/usePermissionMatrix.ts), so what you edit is the list above. The actions are the same four (ALL_ACTIONS in apps/erp/app/hooks/usePermissionMatrix.ts); a module’s row only shows the actions that module supports: Every permission screen in Alforse is the same widget: a matrix with a row per module and a checkbox per action (apps/erp/app/components/PermissionMatrix.tsx). Toggle a cell for one grant, a row to flip a whole module, or the header to select everything. The employee-type template, a single employee’s overrides, the bulk editor, and even an API key’s scopes all render this identical matrix, so the mental model is the same everywhere. Alforse enforces these grants in two places at once. The app checks them to show or hide screens and buttons, and the database enforces the same grants through row-level security, so a request that skips the UI still can’t reach data the grant doesn’t allow. That second layer is what makes the same model safe for API keys, which carry scopes in exactly this module_action shape.

Employee types

An employee type is a named permission template. Instead of hand-checking dozens of cells for every hire, you define a type once (say “Buyer” with full Purchasing and view-only Inventory) and assign it. Each type is edited with the same matrix under Users → Employee Types (available on plans that include custom permissions), and its grants become the starting point for anyone you assign to it. Two types are seeded and can’t be deleted, marked by a stable systemType value so an admin can rename their display label without breaking Alforse’s internal lookups: Every other type is yours to create, rename, and delete. A company can hold at most one type of each system kind.

Per-person overrides and bulk edits

An employee’s permission matrix under Users → Accounts starts with the grants from their employee type. Checking or clearing a cell creates a per-employee exception without changing the type. When you switch types, Alforse asks whether to replace the current grants with the new template or preserve them. When a change needs to reach many people at once, use the bulk permission editor. Select the users, pick a mode, then set the matrix: This is the tool for propagating an employee-type change to existing staff, or for granting a new module to a whole department in one action. The two modes are the difference between “give everyone these too” and “make everyone exactly this” — reach for Update only when you mean to overwrite.

Inviting people

You don’t create passwords for people. You invite them by email, and they set up their own sign-in when they accept. Add an employee under Users → Accounts with their name, email, employee type, and location. Alforse creates their account, records an invite, and emails them a link to finish joining. Because an invite is a real record, an employee has a clear status derived from it and their account:
An invite is a company-scoped record keyed by email, and it carries the permission set the person will start with, so their grants are ready the moment they accept. While it’s outstanding you can resend the invite email or revoke it entirely, both from the accounts list. Deactivating an active employee removes them from the company, strips their grants, and marks them inactive; it doesn’t delete the person, who may still belong to other companies. For the full picture of a person’s record, see people.

Shop-floor PIN accounts

Console operators sign in to MES on a shared station with a 4-digit PIN instead of an email-based login. They are a separate account type. Add one under Users → Operators (visible only when console mode is enabled for the company) with a name and a location. Alforse creates a lightweight account with no email login, assigns it the Console Operator employee type automatically, and generates a 4-digit PIN that is shown once, when the operator is created — Alforse stores only a hash of it, so copy it then. On the shop floor the operator taps their name and enters the PIN, which Alforse checks before starting their session. If a PIN is lost, reset it from the same screen to generate a new one; the old PIN stops working immediately. Resetting an operator’s PIN takes users_update; setting a console PIN for any other employee (from the Accounts list) also takes settings_update. PIN accounts are scoped to the floor by design. They carry only the grants their Console Operator type allows, which is why a lost or shared tablet can’t be used to reach the office side of Alforse. For the operator experience itself — clocking on, reporting quantities, issuing material — see the MES reference.

Where each piece lives