Back to Feed
article 3m read

New role editor appears to undo its own saves on the next page load

Job titles were swapped for permission-based roles in the scheduling app, and the diff shows that the seeding step run on every staff listing rewrites any edit to a built-in role, alongside non-atomic writes, no last-admin guard, and a few access changes I can't swear I meant.

Article DepthPractice

Flow

How my editor loses a built-in role edit

Based on reading the diff. I have not reproduced it.

  1. 1Edit and save

    The server accepts changes to built-in roles.

  2. 2Reload

    The screen fetches the staff list and the role list again.

  3. 3Reseed

    Both lists rewrite built-in roles from the code first.

  4. 4Edit lost

    The role matches the code again and no error appears.

  5. 5Ways out

    Read-only built-in roles, or seeding that only creates roles that are missing.

Flow

Access that moved in the swap

From reading the role lists. The diff does not say which were intended.

  1. 1Managers

    Lost the settings read the API used to allow.

  2. 2Staff

    Can now open the locations page.

  3. 3Top admin role

    Holds PIN login, which the old code blocked for that title.

  4. 4Brand-new workspaces

    Two shortcuts that granted extra power are gone.

  5. 5Older accounts

    No backfill visible, and an account with no roles is refused.

The reload right after it, judging from the code, undoes the save button on the role editor I shipped.

Four titles, compared as strings

My scheduling app used to give every account one of four job titles, and every access check compared that title. The checks were all over the place: the API, the page routing, sign-in, the invite form. I swapped that for a list of named permissions. A role is a bundle of permissions, a person can have more than one role, and they get everything their roles add up to. The four old titles became built-in roles so nobody's access would change on day one.

It all shipped in one commit labeled as planner work. I wasn't reading my own diff closely.

The editor and the seeder fight

Built-in roles get created by a seeding step that wipes each one and rewrites it from a list in code. I call that step every time the staff list or the role list loads. The editor also lets you edit built-in roles, and the server never says no.

So you edit the manager role and save. The screen reloads its lists, the seeding runs, and the manager role goes back to what the code says. I'm reading that off the diff rather than watching it, but I can't find a way around it. Either fix would do: lock the built-in roles, or have seeding fill in only what's missing. This commit has neither.

Gaps and lockouts

Changing a role, or someone's roles, deletes the old set and then writes the new one, with nothing tying the two steps together. A request in between can see a role with no permissions, or a person with no roles. Nothing stops an admin from clearing their own roles, or the last admin's, and an account with no roles is refused on every request. Roles only get handed out automatically when an account is created, and I don't see anything giving roles to accounts that already existed.

Where a request gets decided

Every request looks up the person's current roles. The login token only says who you are. That means taking a role away works on the next click, which I like. The cost is a database lookup on every call that I haven't measured.

Who gained and lost access

From reading the role lists, not from watching:

  • Managers can no longer read settings through the API.
  • Staff can now open the locations page.
  • The top admin role can now use PIN login, which the old code blocked.
  • Two shortcuts that gave extra power in a brand-new workspace are gone.

If you're doing the same swap, write a table of old answers next to new answers for each title before you ship. I didn't, so I can't tell you which of those I meant.

The tests that changed mostly pretend the access lookup works. Nothing tests the lookup itself, or editing a built-in role and reloading.

The first test I'd add is the dumbest one: edit a built-in role, reload, and check the edit is still there.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward