It is entirely up to you where you put your business logic. The discussion about whether to have fat controllers or fat models is a long one and you will see that both sides are both right and wrong at the same time.
I have always kept my controllers thin and used more of a fat model approach. You can do the same but it is your choice to do so.
What I usually do is ensure for starters that all my models are properly defined with getters and setters. Although using a getter/setter is "slower" than using a public variable, much of my validations and logic does happen in my getters/setters so I prefer that over a direct access (to the public variable) approach.
beforeSave/afterSave are also good places to put logic in. If possible you can pass some of the processing to your database using triggers which can help tremendously in terms of performance. For instance if you want to update fields such as created_date and updated_date in your table, you can use triggers instead of code. (see here: https://www.niden.net/2013/09/let-rdbms-do-more-than-just-store-data.html)
You don't necessarily need to have a model Table and Row. You can do everything with a base model and the ones that extend it. It is just a different way of coding that's all.