Resources

Designing Roles Before You Build

Permission models rarely get designed. They accumulate, one reasonable exception at a time, until nobody can say who is able to issue a refund. Here is what to decide before the build, and the three questions that turn a job into a role.

Every operational system I have been handed has a version of the same story in it. Somebody needs to cover the billing queue for two weeks. Building a proper role for that would take a sprint nobody has, so they get handed access that already works, which is usually the controller's. The coverage ends. The access does not. Months later a credit goes out that nobody can account for, and the honest answer to "who could have done this" is a number in the dozens.

Nothing careless happened there. Every step was the reasonable move in front of a person with a queue to clear. That is what makes this worth designing on purpose, before the build, rather than discovering it during an audit or after a bad week.

Two levels is not a permission model

Most internal tools, including many custom ones, start with two settings: admin and everyone else. It works for a while because the first users are the people who commissioned the system.

Then the finance lead needs to correct a posted invoice, which only admins can do, so she becomes an admin. Then the new operations coordinator needs the same queue, so he becomes an admin. Then support needs to resend a receipt. Within a year, admin is not a role. It is a list of people who once needed something.

The tell is easy to check. Ask how many accounts can issue a refund, waive a fee, change a bank account on file, or export the full contact list. If the person who runs the system has to go look, and then looks surprised, the model already drifted.

The three questions that make a role

When I work through permissions with a client, I do not start from job titles or from the software's built-in roles. I start from the actions that carry consequence, and I ask three questions about each one.

Can they see it?
Visibility is its own decision. A support agent may need the donation history to answer a question, and may have no business seeing the donor's employer, giving capacity note, or full card record.
Can they do it?
The write side. Issuing the refund, approving the grant disbursement, changing the payout account, closing the fund.
Can they do it alone?
The one most systems skip. Some actions should be possible for a role to start and impossible for that role to finish without a second person.
A single action, issuing a refund, drawn as a row passing through three checks in sequence. The first check is can they see it, the second is can they do it, and the third is can they do it alone. The first two are drawn as solid navy outlined boxes and the third is drawn with a dashed navy outline, marked as the check most systems skip.
The third check is the one that gets skipped, and the only one that is expensive to add after the workflow is built.

That third question is where the real protection lives, and it is the cheapest of the three to build if you decide on it early. Retrofitting a second approver into a workflow that assumed one actor is a rewrite of that workflow. Deciding up front that disbursements above a threshold need a second pair of eyes is a field, a queue, and a rule.

It also protects the people doing the work. A coordinator who cannot single-handedly move money is a coordinator nobody can pressure into moving money, and who cannot be blamed when something goes wrong at three in the afternoon on a Friday.

Roles belong to jobs, exceptions belong to records

The rule that keeps a model from rotting is short: a role describes a job, not a person. If you cannot name a role without naming an individual, it is not a role yet. "Refund approver" is a role. "Whatever Dana needs" is a standing exception wearing a role's clothes.

Real work still produces exceptions. Somebody has to handle the escalation while the approver is on leave. The way to keep that from becoming permanent is to attach the exception to the record and the moment, not to the account. A one time override, with a reason typed in, an expiration, and a line in the history saying who granted it. Access that expires on its own is the single highest value feature in a permission model, because nobody has ever reliably remembered to take access away.

Two rows compared on a shared time axis. The first row, a standing exception granted to an account, is a bar that starts when coverage begins and never ends. The second row, a scoped override attached to the record, is a bar that starts at the same point and stops at a marked expiry date, after which the access is gone without anyone having to remember to remove it.
Both start the same way, on a Tuesday when somebody needs cover; only one of them ends without a person deciding to end it.

Reading is an action too

Teams tend to argue hard about who can approve things and wave through who can look at things. In regulated and donor facing operations, the reading side is usually the larger exposure.

Export is the one to watch closely. Once a spreadsheet of constituents leaves the system, every control you built stops applying to it. It lives in an inbox, then in a downloads folder, then in a personal drive after somebody leaves. If exporting is its own permission, logged with who and when and what filter was applied, you can still answer questions about it later. If export is a button everyone has, you cannot.

A model you could actually write down

Here is the shape of the thing I am asking for. Four or five rows, plain language, agreed by the people who run the work, before anyone opens an editor.

RoleCan seeCan doNeeds a second person
SupportAccount, transaction history, statusResend receipt, update contact detailsAny refund
Billing coordinatorEverything support sees, plus payment method on fileRefund up to the stated limit, correct a coding errorRefund above the limit, fee waiver
ControllerAll financial records, all exportsApprove refunds and waivers, close a periodChange a payout bank account
ExecutiveAll records, reporting viewsRead only in the operational systemNot applicable

Two things about that table are deliberate. The executive row is read only, because leadership almost never needs to transact and the account is the most valuable one to compromise. And the controller, the most trusted person in the list, still cannot change a bank account by herself. Controls that only constrain junior staff are not controls. They are an org chart.

What you get for the trouble

This work never feels urgent, which is why it gets deferred. What it buys is specific.

  • Offboarding becomes one change. Somebody leaves, you remove them from a role, and you are done. Without roles, offboarding is an archaeology project across a dozen screens, and the parts you miss are invisible.
  • The audit question becomes answerable. "Who could have done this, and who did" is a question about roles and history. If the answer requires a database query and a guess, you are going to spend a week on it and still hedge.
  • A mistake stays small. Most incidents I have seen were not malice. Someone with more access than their job required clicked the wrong row. Scope limits damage from ordinary human error more often than it stops anyone dishonest.
  • You can staff flexibly. Temporary coverage stops being a security decision. You add someone to a role for a month and it expires.

What to decide before anyone writes code

You do not need a security consultant for this. You need an afternoon with the people who do the work, and answers to five things.

  1. Which actions in this system move money, change who gets paid, or expose personal data. List them by name.
  2. For each one, the three questions: see, do, do alone.
  3. The thresholds. Not "large refunds need approval," but the number, and who owns changing that number later.
  4. Who reviews the access list, and how often. Quarterly is fine. Never is what usually happens.
  5. What happens to an account the day someone leaves, and who is responsible for making it happen.

Write the answers in plain sentences. That document is a specification, and a good build team will turn it into the system's permission model without much translation. Skipping it does not save the work. It moves the work to the point where it has to be done live, in a system people already depend on, usually right after something has gone wrong.

If you are scoping an internal system and you are not sure who should be able to do what inside it, that is exactly the kind of thing we map in discovery. It is a short, structured engagement that works out how the operation really runs, and what the system has to enforce, before anyone writes code. You can start that conversation by clicking on the button below. Start with Discovery

Turn Systems Thinking Into a Clear Next Decision

SongSwift resources are written for leaders evaluating complex software, AI workflows, integrations, payments, data, reporting, and operational risk.

If an article clarified the problem but the next step still feels uncertain, Systems Discovery helps turn the workflow reality, constraints, risks, and implementation options into a responsible path forward.

Best fit when the question is not just what the technology can do, but how the workflow, data, roles, integrations, AI controls, and operational accountability should fit together.