☒ That's a tricky one. From what I've seen, adding the node modules to the assets path will allow searching the yarn packages in the asset pipeline. How did you set up stimulus in this application? Also, in your config/application.rb, did you set the load defaults to 6.1?
☒ Yea, it really depends on how you want to handle this kind of situation. Since you are in the middle of the session, would you want to block non commands from being entered and stay within the session. The proper logic will greatly vary depending on the business need.
I think that caching, regardless of multi-tenant or not, doesn't really matter if you follow certain practices.
For example, I avoid using static strings as my cache keys. I.e., "users_list" would be a poor choice for a cache key as it would be a "global" return. Always scope in the account for something like this; for example, [account.id, "users_list"]. You could use [account, "users_list"], but you have to ask yourself if this list should be immutable if data on the account changes. It has to be handled on a case by case basis. In the account.id example, if you have new users added to the list, the cache will not update. In the later example of account being in the cache key, if you update the name of the account, it will also invalidate the cache which wouldn't be desirable or accurate since you'd then be querying the database more often.
Likely, I would take the most simplistic approach with caching the individual records. If I outgrow this solution, I would then implement something like Russian Doll Caching. I would start simple because the more caching you add into your application, the greater chance of something "strange" going on. It's best to ease into caching and really put it in place where it is needed.
I don't think I have an episode for Russian Doll Caching, so I think that this suggestion would be a good fit for that. But, I would likely follow this methodology regardless of it being for a multi-tenant solution or not. On a side note with multi-tenant solutions, I never search off of the base class. For example, I don't do a User.find(X). I would always do something like current_account.users.find(X). This will inherently prevent the cross talk between accounts that you mentioned.
☒ I would start by having an attribute on the response that is tied to the user/student (user:belongs_to) and put a validation uniqueness scope on the response which scopes the user and questionnaire. This would limit the user for one response per questionnaire/exam. What other kind of functionality are you looking for?
A couple of thoughts,
when displaying out the answers when gathering the response, you could shuffle the array of answers so they do not appear in the same order for everyone.
the creator of the exam could mark an answer as correct on each question. when a response is submitted, a background job can be queued up to grade the questionnaire response.
A grading table which has user:belongs_to, questionnaire:belongs_to, and response:belongs_to along with grade could be created as a result. This would increase the performance of the application as it doesn't have to do the grading calculations every time.