When writing backends with Go, I follow a simple pattern.
At the core there is the, well, core object, the service.
It has its own configuration struct. In this struct are all the configurations for the related services.
It is the central gateway for everything.
Connected to it on the back side are all the related services like oidc middleware, keycloak api service, the various entity repositories, validation, markup processor and so on.
Connected on the front are the various outlets, RESTful API handlers, gRPC service, SSR handlers, websocket handlers. Everything has its place and concern.
Cobra is used as the flag parser and command structure. There you have commands that reflect the outlets, restful, grpc etc.
Each of those has its own way to configure the core service. If you for instance use gin to serve RESTful data here’s where all the gin related stuff is configured and also where the database client is initialized and passed to the core service.
In the past I followed a trend that defined all the backend repositories as interfaces. This did not turn out to be the correct approach, as mental overhead is there and you can’t have proper, simple repository definitions. If you need those parts done differently, you can do that later. The main concern is getting to your goal, which is a finished, working backend. Bother with abstractions later if you have to.
Do that’s all there is to it. It’s not rocket science. This way you can have separately maintained services that you can just plug into your core service for each new backend you start writing and hopefully also finishing.