RBAC Done Wrong: Why Hardcoded Permissions Bite You Later
I've inherited enough systems with hardcoded permissions to know: build it dynamic from day one or pay for it later.
Every developer thinks they'll never need dynamic permissions. Then a client asks for custom roles at 3am, and you're rewriting database migrations.
I learned this the hard way building ERPNext modules. Early projects? Permissions scattered in code. Controllers checking user roles with magic strings. Views hiding UI elements with nested if statements. It works until it doesn't.
The problem isn't complexity—it's maintenance. When you hardcode if user.role == 'admin', that rule lives in your codebase. Want to create a new role? Code change. Want to grant one permission to three roles? Database query plus code review. Scaling breaks quickly.
Here's what I do now: three tables. Roles, Permissions, Role_Permissions. Dead simple. Your app stores what users can do in the database, not your controllers.
But there's a practical catch: you still need sensible defaults. I keep a seed file with standard roles (viewer, editor, admin, accountant, whatever your domain needs). Don't start empty. Don't hardcode either. Balance.
Implementation pattern I use:
- Middleware layer checks permissions once per request
- Guard against permission checks in controllers (not views)
- Cache aggressively—permission checks hit the database constantly
- Audit logs for permission changes (required by clients anyway)
For Seven CMS, we baked this in from the start. Free core includes basic RBAC. Custom permissions are a paid module. Makes sense—most users want generic roles. Power users pay for complexity.
One more thing: don't overcomplicate it early. Start with roles + permissions. If you need granular resource-level access control later, add it. But don't build ACL infrastructure for a feature you haven't shipped yet.
The cost of refactoring from hardcoded to dynamic is absurd. The cost of building dynamic from the start is maybe 4 hours of your time. Do the math.
Build it now. Thank yourself when the inevitable "can you create a custom role" request lands.