I didn't make that much backend changes this time, but mostly because my web routes are different than my API routes. It's not an issue since they weren't named the same, but next time I would like to restructure my backend by using routes for my API. Other than that, there weren't significant backend changes. I used only server-side validation because it's easier for me to pinpoint where data went wrong - I only need to look at the server side. The cons of using only server side validation is that it puts load on the server compared to if the client stops the request for going out in the first place.
useState made managing component state straightforward for me, and it helped me by breaking down logic into smaller, reusable hooks when possible. One struggle I had was handling arrays for useEffect to avoid unnecessary rerenders or missing updates. I was trying to ensure that data fetching triggered correctly when a user input like searchYear changed. Types helped me catch bugs, especially revolving around the API calls. I didn't use "any" types as the types I defined were pretty straightforward.
It's been a while since I took CS375 and I don't remember much of my SPA front-end experience, but I definitely feel like MPA front-end was more enjoyable. Mostly because I am more experienced with web development and I know what I'm doing now, at least compared to last year. MPA front-end I think is more complex, but having SPA front-end knowledge definitely helped. Learning SPA front-end from scratch was harder.