I’m need a little help here for some best practices setting up a multi-tenant style app with data needing to be segregated by Company, each Company having multiple Users and datas.
Background
My app is currently set up using the Sub Apps structure
My company is using the application, another company has just begun, and a third is (hopefully!) starting soon
I’m finding out that cost is a major downside to the sub apps model, so I want to move this to a multi-tenant model with all Companies sharing a single set of databases.
Assumptions
Every tenant is tied to a unique Company record
Every piece of data has a single Company ID
Every User has a Company and every Privacy Role is set up to limit data access to Current User is logged in and DATATYPE’s Company is Current User’s Company
Questions
Is my third assumption above sufficient to limit access?
does the privacy model need to be “duplicated” in every Search and workflow in the application?
For instance: if a tenant wants to view all of their Records, does the Search need a Company is Current User’s Company constraint OR does the privacy role already established handle this need?
Is this the correct way to set up privacy roles for a SAAS application at all? Or is there a best-practice I’m missing?
You are on the right track, but I would also use an “account” qualifier linked to the user and the company. So create a new table call it Account and for each new account generate an account number or create one manually, add in this account table the company (you can link to your exist company table if you have one) and any other details you need about the account add in the account table. I also would add list of administrators if you have any.
When anyone logs in they must belong to the account and then instead of using company use account in the query.
Use privacy settings but you need to get used to adding “account” to all your data queries.
We have a very large app and lots private data and works very well.
You can keep company as a data qualifier too but you may find this becomes restrictive.
You would also need to link the account table with you user table so create a new field in the user table and add the Account. So when you create the user also add the account number for the company. You may find you need to add account number to other tables by linking to the account table as I described the user table above.
I’m finishing up a multi tenant app that has grown enormously complicated. Company A being able to see some of Company B’s data but none of Company B’s data that belongs to Company C. All while Company B maintains the ability to restrict what Company A can see and whether Company C can see anything at all.
Anyway, I’ve structured everything around the Company data type also being the Account data type so I’m obviously super interested in this statement:
Can you expound on that a bit more? Why is having a separate Account data type in addition to a Company data type less restrictive?
Thanks @StevenM. I think I’ve seen you described a similar format elsewhere on the forum.
This feels like it accomplishes the same goal, but using a separate accounts table vs just the Company ID. What would be the reason for this? Is it in case you want a user to see multiple companies?
Well if you had an account table attached to a company it will make it easier to pull them away from each other in the future and would think that at a top level you would need to manage users by account as I think as you grow using a company id which seems to be a query parameter rather than account management will become problematic and very messy.
With account table you could just add a company field as list and put in the field against the account the company id data the account is able to view.
So when querying data, does the Privacy rule need to be duplicated in the search?
For instance… (not using the Accounts table @StevenM talks about above)
User is associated with Company A
Datasource Contacts contains many Contacts, some of which may be associated with Company A
Privacy role limits User to only seeing Contacts where Company is Company A
User wants to search for Contacts where Company is Company A
I see two options possible:
Do a Search For Contacts where Company is Current Users Company
Contacts returned would be limited by the Privacy role AND the search constraint
OR
Do a Search For Contacts
Contacts returned would be limited by ONLY the privacy role
While potentially less secure, is Option 2 possible? What effect does either the additional search constraint or the constraint searching with privacy role have on speed?
The privacy role will work as a constraint but I still manually put the constraints on the search anyway, just as a safe guard. I don’t know that it’s necessary but it gives me peace of mind.
Performance wise, it should not make any difference. Bubble is already performing the search with the constraints of the privacy role, the constraints are just being restated in the search parameters
@zachwhitt - interesting to see how you are moving way from multi app.
I am building a multi-tenant SaaS and in addition to privacy, trying to focus on speed as well. My Business data type has many lists – list of products, list of contacts, list of employees, list of orders, etc. and I have nearly eliminated the need to “Do a Search for…”. Looks like this approach may solve both problems - privacy (since the User can only see Businesss…ListOfContacts based on the Business that they belong to, as well as speed (hopefully!, fingers crossed).
So when the User logs in and I pick up the Business they belong to (or own), then that info travels with them on all pages, feeding off on the associated data. Not sure how many items bubble supports in lists though… does anyone know?
@eli thanks, that’s exactly what I was hoping for. No performance difference makes sense, but I didn’t know if this was applied differently (server vs client side, search constraint vs filter, etc.)
I’ve essentially moved everything in my app to Searches vs Lists based on a few concerns over lists speed. This is one area where I think we seriously need better documentation from Bubble. How does each query method actually work? When should one be used vs another? How is speed impacted?
@zachwhitt - agreed… we need more documentation… So have you found lists speed to be less performant than “Do a search”? Would be interested to learn from your experience - how big were your lists?
No, this is hearsay from others who have experimented with the two methods… which is entirely why we need more documentation on it!
I moved for a few reasons:
wanted my searches and language to be consistent across the app
didn’t want to add child records to parent records lists when creating things, instead, I now just add the parent record to the child record as one would join records in a traditional relational db
a few forum posts had indicated slowness with lists vs quick searches, even with millions of records, so I felt confident going that direction
@zachwhitt - good to know, although I am pretty sure our outcomes will vary since lots of factors are involved - db schema, data size, etc. etc. Will experiment and see how my approach does. Please post any further findings down the road. Cheers.
I am still a little unclear as to how this is put in practice and would love to set up my app built with security and data silos for individual companies/users.
Anyone know of any good video walkthroughs, diagrams or even courses on the subject?
I found this for reference and I ‘believe’ I understand the basics
There is also a Bubble template that suggest this is part of it that I am yet to purchase and may to help me understand how its set up.
I understand this is an old thread but some reference this one and I can’t find a solid walk through tutorial that explains it in enough detail.