Focusing on Security First
In the newest application I am creating for work, I've taken a security first approach. In a past project, I built most of the application with security measures through out, then tagged on the remaining security at the end. This made it harder to test while building. And because the security had been spread out through the application, it is more difficult to maintain and update.
In this new application I've decided to use a Role Based Access Control (RBAC) model. At first, I thought this would be difficult, but it turns out that I can manage the majority of the security in a middleware with an associated service and repository. I am using the the URL to determine the the action and object, and the user authorization to determine if that user can perform that action on that type of object. Therefore my middleware is as simple as calling isAuthorized, err := authorization(user, action, object)
. That calls a series of services that determine the authorization based on a set of rules.
A little about the organization of the project
I am structuring my code so that there are handlers to manage the incoming request, a service that handles all the business logic, and a repository (or two) that manage database queries and object storage queries. Several years ago I read about domain based design and I created an application with that paradigm in mind. That application is well organized and easy to maintain. So I am building the newest application this way as well.
My first Go application feels a little disorganized. The entire application is all in one directory/package, which is how I saw several Go applications built at the time. I was new to creating big-ish (big for one person) projects and was learning Go at the same time. (The applications that I adopted when I started this job were in PHP, and I didn't want to use PHP for this project. Therefore, I learned the newest cool language that I had read about - Go. Clearly this was a few years ago when Go was newish.)
With domain driven design, there are layers, which make it easier to organize the application into separate packages. The layers have a dependency of the layer above it, but upper layers never depend on lower layers. The layers that I use consists of a handler to handle incoming requests, a service to manage any business logic, and a repository to handle data to and from the database(s). The models are used in used throughout and have no dependencies on any other layer.
Each of these object types are separated into packages. For instance, I have a handlers package, and service packages, etc. The files that contain the specific services are named and organized based on the business function. Another way to organize it would be that a package contains everything needed for business function, each having a handler, service, and repository.
So far I have built the security middleware, but have not started building the individual business functions yet. As I build out the application the security can be tested along the way. The security will be centralized and fine grained making it easy to maintain and update. The overall organization of the project has made the security easy to separate into it's own entity.
Next, I am going to tackle the work-flow that obtains approvals from each user. Because the application is very specific, I can hard code some of the workflow for simplicity. Ultimately, the work-flow is just a state machine with a set of services that use the current state and the user action that lead to that state to determine who to contact (which emails to send), who can currently make changes, which statuses to set, and logs every action.