I am creating a granular permissions system and am having trouble deciding the best way to go about it. The database I am using is Postgres.
Basically, I will have 3 tables:
permissions
-----------
p_id, name, description
permissions_groups
------------------
pg_id, name, description
permissions_users
-----------------
pu_id, user_id
Anything ending in '_id' will be an integer, the rest will be varchar or text.
The permissions system will be a part of a greater system where I rely on the user ID from another table.
Heres where I am stuck. I have two ideas:
Idea 1
permissions_group will have a column called permissions which will be an integer array. This will contain all p_ids for that permissions group.
permissions_users will have a column called pg_ids which will be an integer array containing all permission groups a user has, and a column called permissions (int array) which have all p_ids of assigned permissions which do not belong in a group.
Sample data:
permissions
-----------
1, add_user, Can create a user
2, delete_user, Can delete a user
3, view_users, Can view all users
4, random_perm, Some example permission
permissions_groups
-----------------
1, user_management, User management, [1,2,3]
// This group contains permissions 1,2, and 3
permissions_users
-----------------
1, 1, [1], [4]
// This user links to user with id of 1, has permissions group 1 and permission 4
Idea 2
The second idea is more classic SQL. The 3 tables will stay the same. There will be 2 new tables:
permissions_groups_link
-----------------------
pgl_id, pg_id, p_id
permissions_users_link
----------------------
pul_id, pu_id, p_id, pg_id
Now it will work like this:
permissions_users[pu_id]
|
V
permissions_users_link[pu_id]
|
V
p_id OR pg_id
| |
V V
permissions[p_id] <- permissions_groups[pg_id]
Sample data:
permissions
-----------
1, add_user, Can create a user
2, delete_user, Can delete a user
3, view_users, Can view all users
4, random_perm, Some example permission
permissions_groups
-----------------
1, user_management, User management
permissions_groups_link
-----------------------
1, 1, 1
2, 1, 2
3, 1, 3
// Assign permissions 1,2, and 3 to group 1
permissions_users
-----------------
1, 1
permissions_users_link
----------------------
1, 1, 4, NULL
2, 1, NULL, 1
// Assign permission 4 to user 1
// Assign group 1 to user 1
Summary
In the end, all this data will be aggregated into a list containing all permissions a user has, regardless of group. So with the above examples, the server-side code will aggregate all of that into:
Permissions for user 1:
1 => add_user
2 => delete_user
3 => view_users
4 => random_perm
The groups will serve only for visual distinction and easy application of permissions per user.
My questions
Which one of those ideas would scale best and be the fastest? Assume that in a live environment, there are 10000 users and 1000 permissions and each user has on average 500 permissions.
Or are both ideas really bad and have I overlooked some fundamental RDBMS concepts that would make it easier?