Back to build log

Designing role based access systems

·7 min read

Designing role based access systems

Every multi-user application eventually needs access control. Here's how I built one that scales.

The Permission Model

I settled on a hierarchical model:

**Admin** - Full access

**Organizer** - Can manage events they own

**Staff** - Can check in attendees

**Attendee** - Can view and register

Database Schema

The key insight was separating roles from permissions:

CREATE TABLE roles (
  id UUID PRIMARY KEY,
  name TEXT NOT NULL,
  level INT NOT NULL
);

CREATE TABLE permissions (
  id UUID PRIMARY KEY,
  role_id UUID REFERENCES roles(id),
  resource TEXT NOT NULL,
  action TEXT NOT NULL
);

Middleware Pattern

Every protected route runs through a single middleware:

export function requirePermission(resource: string, action: string) {
  return async (req, res, next) => {
    const hasAccess = await checkPermission(req.user, resource, action);
    if (!hasAccess) return res.status(403).json({ error: 'Forbidden' });
    next();
  };
}

Lessons Learned

Start simple, add complexity only when needed

Always log permission checks for debugging

Test edge cases: What happens when a user has multiple roles?