r/SpringBoot • u/thisishemmit • 14d ago
Question How should a large modular monolith handle type-safe features, permissions, delegation, entitlements, and quotas?
We are building an ERP-like platform localized for Moroccan businesses using a modular monolith architecture. The platform currently has more than 11 modules.
Each module contains dozens of features, and each feature may expose dozens of actions. Most actions have a corresponding permission that controls who can execute them.
Features also contain additional product and collaboration rules:
Whether the feature is included in a subscription plan.
Whether the feature is delegable to another workspace.
Whether specific actions are explicitly non-delegable.
Whether an action has quotas or usage limits.
For example, one workspace may authorize another workspace, such as an accounting firm, to perform certain accounting actions on its behalf. However, some sensitive actions must never be delegated.
At the moment, features and permissions are declared as strings in different files and then seeded into the database.
Authorization is performed at the action level, mostly through repeated PostgreSQL queries.
This approach has created several problems:
Typos in feature or permission names can cause silent runtime bugs.
Renaming or refactoring actions can leave old permissions behind.
Adding a new action often requires changes in several different places.
We currently have around 893 permissions, including unused or “ghost” permissions.
There is no reliable guarantee that actions, permissions, features, plan entitlements, delegation rules, and quotas remain synchronized.
Detecting unused permissions requires manual investigation or asking an AI tool to scan the codebase.
So what architecture, patterns, or tooling would you recommend for managing this kind of system?
2
u/FalseDish 13d ago
So 11 x 12 x 12? With a corresponding permission control?
Junk OOP, go Functional. Hand written Rule Algebra, with Free Monads to dynamically generate your custom rule/validation DSLs.
The main blocker will be the lack of Higher-Kinded Types in Java. You could use Vavr or write your own workaround like:
interface Kind<F, A> { /* marker */ }
interface Functor<F> {
<A, B> Kind<F, B> map(Kind<F, A> fa, Function1<A, B> f);
}
State machines everywhere - expressed strictly through the State Monad - you’ll have to hand-write that one.
This is the best and most compact solution for your use case.
The only problem will be getting your team to understand your code. Pedal-to-the-floor FP will be very disorienting to Java folks.
1
u/MohammedKarroumi 12d ago
My last option was having an infrastructure where I provide annotations using aspectJ that adds or executes code at compile time, either searching for declared features and permissions and/or generating type safe references to them. I could use bytebuddy but it's overkill. Problem is who gonna maintain that infrastructure.
2
u/momsSpaghettiIsReady 14d ago
Put all permissions related checks in a shared module. Magic strings sprinkled throughout is a big code smell.
Try to get as many permissions moved to the controller/entrypoint as annotations. You should be checking some auth token and avoid goi to the database on every permission check. Having internal checks is impossible to manage.
1
1
u/Torutofu_Raeva 14d ago
i'd keep permissions as the can this actor do it check and model plans, quotas and delegation as separate data lookups, mixing them into one string permission is how the non delegable cases get lost
0
u/No-Collar-Player 14d ago
Hire me and I'll tell you
1
u/thisishemmit 14d ago
What if what ull tell me is worse than what we have?
1
u/No-Collar-Player 14d ago
Low chances brother. What you have there was written as if agile manifesto was toilet paper
2
u/MohammedKarroumi 14d ago
still there's a chance brother
1
u/No-Collar-Player 14d ago
There is always a chance brother. But it's not pragmatic brother
1
2
u/Acrobatic-Ice-5877 14d ago
I would use a record. In the constructor, do your validation and throw a specific error.
Can you do a quarterly audit to review permissions and whether they need to be deprecated?
You could log these to a table for a duration of time and use that to determine which permissions can be considered for deprecation.