Roles are a template, permissions are the truth, and the screen should teach the admin
An admin changed a role and nothing happened, which was exactly correct and exactly the bug, because a role is a stamp you press once, not a wire that stays connected.
An admin edited the “dispatcher” role to add a permission, saved it, and watched it do nothing to the three dispatchers already on the team. That was not a bug in the code. That was the code working exactly as I designed it, and it still landed on my desk as a complaint, because the model in my head and the model in the admin’s head disagreed about what a role even is.
In my head, a role is a stamp. You press it on a new user once, it seeds their permissions, and then it lets go. The saved per-user permissions are the truth from that second onward. In the admin’s head, a role was a live wire: edit it here, everyone wearing it lights up over there. Both models are defensible. Only one was implemented, and I had never said which out loud.
Pick a precedence and say it where they can see it
There are two honest designs and you have to commit to one. Either roles stay connected and editing a role rewrites every attached user, or roles are a one-time template and per-user permissions win forever after. I chose the template, because admins want to grant one person a little extra without disturbing everyone else, and a live wire makes that impossible without inventing per-user overrides anyway.
The mistake was not the choice. It was leaving the precedence implicit, where the only way to learn it was to be surprised by it.
Ambiguity about which layer wins is not a UX wrinkle. In an access-control screen it is a security hole, because the admin thinks they revoked something they didn’t.
So now the screen states it in plain words, right where the decision happens. The role dropdown carries a note: changing this seeds defaults for new users and does nothing to existing ones until you hit reset-to-role. Reset-to-role is a real button, not a hidden behavior, so re-applying the template is a deliberate act, not an accident an admin trips over. The rule stops living in my head and starts living on the page.
The toggles are written for the wrong reader
That fixed the model. The uglier problem was comprehension, and it had nothing to do with precedence. My permissions screen was a wall of switches labeled like fleet.live, orders.void, billing.export. Perfectly clear to me. I named them. They are flags written by the one person who never needs to read them.
The person granting access is not me. It is an operations lead deciding whether the new hire should see live vehicle positions. They are looking at fleet.live with no idea whether that is a map, a report, or a button that does something irreversible, one wrong guess away from either blocking someone’s job or handing out the keys.
The fix was boring and it worked.
- A plain-language line next to every toggle. Not the flag name, a sentence: “See real-time vehicle locations on the live map.” The label is for the database. The description is for the human with their finger on the switch.
- A reference tab listing every role and what it grants. So before assigning “dispatcher” to someone, the admin reads the whole template in one place instead of reverse-engineering it from twenty switches.
- The two halves kept honest. When a permission changes meaning, the description changes with it, or you are back to a label that lies.
A permissions screen is documentation
An internal tool is not finished when it is correct. It is finished when the person using it can predict what it will do before they click. Correctness and comprehension are different features, and I had shipped the first while assuming the second came free with it.
So the verdict is two sentences. A role is a template that seeds, per-user permissions are the truth that wins, and the screen says so out loud. And every switch that controls who can touch what is written for an ops lead at 9am, not for the engineer who named the flag at midnight. Get the precedence wrong and you have a quiet security hole. Get the labels wrong and you have a confident admin granting the wrong thing on purpose, certain they did the right one.