13 October 2026 · 3 min read
Who Changed That Number? User Roles and Audit Trails in an ERP
One shared login is the most expensive shortcut in a business system. How proper user roles, server-side permissions and an audit trail protect your numbers.
It is the least exciting feature in any business system, and the one that matters most: who is allowed to see what, and who changed what.
In the old setup at the mill, one shared login opened everything. Everyone could see everything and change everything. Nobody could say who did what.
That is not only a security problem. It is an accountability problem. On a factory floor, a quantity is metres of fabric, and metres are money. When a figure reads 500 on Tuesday and 5,000 on Thursday, somebody has to be able to answer why.
Rule 1: every person gets their own account
No shared logins. Each person signs in as themselves and sees only their own area. In the mill's ERP, access is given screen by screen, across more than twenty roles in seven departments. A printing operator sees printing entry. A dispatch clerk sees gate passes. Neither sees the other's screens.
Rule 2: passwords are never stored
Only a one-way hash of the password goes into the database. If someone read the whole users table, they still could not sign in as anyone. I cannot tell a user their forgotten password. I can only reset it. That is not a limit of the system. It is the point.
Rule 3: a hidden button is not security
Hiding a button in the screen is a courtesy, not a control. Anyone on the network can send a request directly to the server. So every request is checked on the server: are you signed in, and are you allowed to do this?
In the mill's system the menu a person sees is built from the same list of grants that the server checks. What you see and what you are allowed to do cannot drift apart.
Rule 4: sessions must not be guessable
The first version I inherited identified a signed-in user by a simple running number. Anyone on the network could have guessed a number and become another user, including an administrator. I replaced it with long random tokens, and only a hash of each token is stored. A copy of the database, or a backup, no longer hands over live sessions.
The audit trail: an answer for every disputed number
Every change in the system writes one record:
- which values actually changed
- the old value and the new one
- who made the change
- when it was made
Two design choices matter here.
It is recorded by the application, not by a database trigger. A trigger only knows the database login, which is the same for everybody. The audit exists to answer one question, "which person?", so it has to be written where the person is known.
It never blocks the real work. If writing the audit record fails, the operator's entry is still saved. Someone standing at a machine waiting to save production must not be stopped by a history log.
Permissions are a foundation, not a feature
I used to think of permissions as something to add later. They are not. Adding them to a finished system means checking every single request you ever wrote. Building them in from the first day costs almost nothing.
A short checklist for your own system
- Does every person have their own login?
- Are passwords stored only as hashes?
- Is every request checked on the server, not only hidden in the screen?
- Can you see who changed a value, what it was before, and when?
- Can an administrator remove one person's access in one minute?
If any answer is no, the fix is usually smaller than owners expect. See how this works in practice in the reporting, backup and audit project, or tell me about your system and I will tell you where the gaps are.