I know the topic of permissions has been discussed before, but I couldn't find anything related to this specific issue. There seems to be a piece missing when it comes to using permissions in your code that are also stored in the database. I'll try to explain what I mean as best I can.
I've built several apps over the years that use roles and permissions. I've done this from scratch before, as well as used packages such as Spatie's: https://github.com/spatie/laravel-permission.
In all cases, I've run across this issue of keeping the permissions in the database synced up with the permissions I'm referencing in my code. Let me explain with a short example. Using Spatie's package, I can create a permission like this:
Permission::create(['name' => 'edit articles']);
That gets stored in the database. I can even create a seeder to seed the database with all the permissions I need. Now I can assign that permission to a user like this:
$user->givePermissionTo('edit articles');
The relationship there is stored in the database as well. I can build a UI to help me assign these permissions. So far so good. Now, somewhere in the code I need to check to see if the current user has permission to visit a certain page, or perform an action, or whatever. There are tons of ways to do this in Laravel, via gates, policies, middlewares, etc. None of that is relevant to my question, except for the part where you get to actually check the permission. Something like this:
$user->hasPermissionTo('edit articles');
That works, and is similar to how I've seen permissions done everywhere else. Most articles, packages, forum posts, etc, all use some form of this. But there is a big glaring problem. The permissions name, in this case "edit articles", is hard coded into your code. That's fine, except that it's referencing the name stored in the database. If that permission doesn't exist in the database already, then it won't work. Since I already seeded the database, it does exist, and life goes on. But what happens 6 months down the road, and I build a new widget feature.
So now I have code checking for the permission "edit widgets". Since this app has been in production for 6 months, that permission doesn't exist in the database yet. I can't just add it to my seeder class and run that again. Laravel doesn't have the concept of seed migrations, and it feels wrong to me to seed data into a production database after the fact. The way I've handled this before was to simply create a UI for adding permissions, and now I have to go into that UI after my code is deployed, and create the permission that matches what I'm checking for in the code. To me, this creates a very brittle situation. The code is tied to the data in the database. If I'm the developer and also the administrator of the site, I can fix this up manually. But what if I'm not? What if I am shipping this code off to a customer to deploy on their servers, and for whatever reason, I am not an admin on the site. I do not have permissions to log in and create the permission. I have to give them instructions on how to do it themselves. While that works, it just seems wrong to me. To me, the permissions in the database should reflect the permissions being checked in the code at all times, without any human involvement.
So my question comes down to, logically how would you handle this? Build some class or command or something that will enumerate all the permissions in the code, and update the database to match? Or have some separate config file listing all the permissions, and again enumerate that on a schedule or as part of code deployment, and sync with the database? I don't really need code samples as I can build anything just fine, but I'm struggling to figure out the concept of how this would work, and what would be the best way to resolve this. Am I crazy to think this is an issue?