Edit: The view should not call the model. Having the view call the model couples the view to the model which means if you want two different views (mobile phone native app, web desktop) they have to do all the same model calls again in both views instead of both views just taking in the same blob of data and doing something different with it. Also, FETCH HIGH RENDER LOW is a better pattern where you have all your data fetch calls in one place so being able to reason about performance is easier. If a low level component fetches data, then we lose context of how often that component is called and won't have an idea of how expensive it is. This is applicable to controllers being the only ones allowed to call models because if views did it a view sub component could also do it and the door to hell begins to open. Model calls from the controller end up being used for fancy validation stuff so you might as well keep things consistent and put all model calls in one place. The controllers concern is orchestration, that means how errors are communicated to the user, or what for ensuring that the client worries about http marshaling
model and view were originally decoupled from one another because the program state could be updated much quicker than the view state could so it made sense to decouple for the benefit of faster updates of the program state.
Personal takes
Main is for assembling objects
Router is for consumer interaction entry point.
A good way to scope controllers is to a single page of interaction. So CRUD pages map to http.methods and a single controller handles all methods for that endpoint. This way if you are working on one page you get 4 locations to navigate to: Controller, View, Model, Client. It also makes it very easy to reason about where all the code is because you have a physical page to trace everything from. If it isn't a page you can still treat it as CRUD work scope based on resource theme the interactions.
The controller, view, and model, need to share data at times. The controller will parse data then share it. The view will used the shared data to produce the html. The model will use the shared data to perform operations on it and maybe use clients to add more data to that data. I don't why there would be an issue passing the data between the model and the view through the controller. I don't see how you could get around this for something like validation which should belong in the model because it is unknown during a post if you are either going to accept the request and create a new resource or return feedback to the user via view about failed validation. It's also nice to see the high level flow in one place, which should be the controller since the model doesn't know about sudden major flow changes like redirect user to different page.
Where to put the shared data struct? I guess at the tip of the lowest dependency which could be the client worst case or controller best case. It's either you use one struct for moving data around the controller or you keep transforming structs into other structs or do what warden did, which was pass everything around in the form (talk about hiding your data). I don't really see the value in the latter because you are still working with the same data regardless. I think using one struct really simplifies everything, even if the view might care about some fields that the client has not interest in. I can call it just the name of the controller minus the controller part since it doesn't belong to any one mvc component, but rather is shared among them all.
What about lists? Maybe i can just extend them name with "item" to mean part of a collection. This keeps the subject of the CRUD pattern centered around that resource. This makes generic rules pretty rigged and hard to follow. Also if there is marshalling the extra fields could end getting defaults even if they are not used. Which greatly impacts performance as seen on the services page.
I think I just use the generic DTO term to describe structs that need to pass between component boundaries like view, controller, send over the network exec. I can also use the Request and Response terms to describe structs that are just for payloads. But DTO is better suited if its both for requests and responses like a struct that I put form values into and then also use that struct to render some html. It doesn't really matter in that case if its two seperate structs because most of the data is just going to be passed from one to the other anyway.
When models share state or code, its ok to create a sub-module in the modules package. I will start off with just variables to hold any state, and maybe use a singleton model, but not sure if thats needed yet.
Seems having 3 different controller types makes sense for dealing with different interaction patterns:
Can initialize all of these in main or router.
If something in one controller needs to trigger an update flow in another controller, I don't see an issue currently with letting that happen through a shared channel living in the controllers.go file. This is i similar pattern to services triggering async updates with nats, but at the controller level.
Using mvc makes life cycle of objects more manageable because its clear where everything belongs. Easier to reason about memory management.
putting validators in the controller makes sense because you can unmarshal and build the DTO at the same time. The function doing two things is ok because its still a very simple task and these two things can safely be coupled together because validation and unmarslhaling will always be done in the same flow.