Simplifying ERD with potential null and repeated values - mysql

I am currently creating an Entity Relationship Diagram for a project but it seems to look strange.
I feel like there must be a better way to store the data to avoid repeated values or multiple NULL values but can't quite seem to figure how.
The project is a website that allows users to request their own forum which is then approved and added to the site.
Other times, administrators can create forums between themselves by skipping the request stage.
I have 3 tables:
Users
Requests
Forums
Users table stores the administrators and subscribers (using a role field).
Requests table stores the requested forum title and user, as well as whether this was approved and who by if so.
Forums table stores the active forums with their URL, the ID of the administrator, which admin user created the actual page, and if created from a request then request_id.
Here is how the model looks at the minute:
Entity Relationship Diagram
The issues I see are related to forums that are created without requests, the request_id field in Forums would be NULL if there was no request.
Also, if the forum IS associated with a request, then the user_id field will be duplicated in both the Forums and Requests table.
Can anyone see any problems with keeping it this way or whether there are better ways to model this?

Related

How to design tables for a complicated messaging system between two different entities?

I'm developing a web application that contains a messaging system. The web application has a basic entity (users), users can own another entity in the application (companies), each company may have more than one user (think of it as employees of a team). A user might not necessarily have a relation with a company. A company must have a relation with at least one user.
I'm trying to create a messaging (more of an intra-application email system rather than a chat) system within the application. However, the messaging system has certain restrictions on who is allowed to send messages to whom:
Users can send messages to companies
Companies can send messages to users
Companies can send messages to companies
We will have two different inboxes/outboxes for users and companies. Meaning inside the dashboard, if a user owns a company, he will have a page to his own user inbox, and a page for his company inbox.
My problem is with determining the entity of the sender and receiver and I can't seem to find a good maintainable table design for the messages table.
Below is the structure for the users table, companies table and company_users table:
The design I had in mind (which after implementation I don't believe is the best possible design) is to have a sender_user_id field and a sender_company_id field for each row. If the sender_user_id is null, while sender_company_id is set. This would mean that the sender of this message is a company and vice versa. The same thing for the receiver. Below is the design for the messages table
Does anyone have a better design in mind? Something more maintainable maybe? This is currently relationship hell in the backend. Thank you.
Taking into account Microsoft ExchangeServer and its single instance storage as an example, I think the thing you're missing is pointers.
If your use cases were wound back to a single sender can send a single message to a single receipient then I think your schema would be almost bang on.
If you want a person (e.g. Company Admin) to be able to send a message to all members of a company then what you're actually saying is:
"I'd like the Company Admin to send pointers to the message to all current members of the company".
What I mean is that when they send the message, they're actually creating message_pointers to the original message. That way, when a recipient deletes "the message", all they're actually doing is deleting their individual reference to that message.
Does that help?

Designing a SaaS on a single database, multi-tenant (SQL)

I'm working on a SaaS product and trying to figure out the best way to design the database for my scenario, which I think is pretty standard.
I should not that I don't have an experience designing such a database.
I tired researched online, but there isn't really any info I could find about implementation. There are quite a few comparing the different multi-tenant architectures.
For the multi-tenant approach, I decided go with a single database - seemed to be the most fitting.
Here's the basic list of what should be supported:
Multiple clients, all separated, no sharing of data between them.
Each client has it's own user base (staff/employees).
The client's staff members have different access levels to the system (exposure to different areas, ability to perform certain actions)
Each client have it's own customers.
I can wrap my head around the basic concept of having the tenant_id on any table belongs to that tenant. I guess my issue is more with how to combine it with different access levels per client's staff member.
How would you go about it?
Any reference some implementation of such a DB?
Thanks
Update
After #dmfy answer, I gave it some thought and came up with this solution:
account
-id
-name
user
-id
-account_id
-username
-password
role
-id
-account_id
-name
user_role
-user_id
-role_id
access
-id
-role_id
-name
role_access
-role_id
-access_id
session
-account_id
-user_id
-token
I'll explain-
The role table is essentially a "group" of users associated with a list of permissions/access levels.
The access table represents a single permission. An area of the platform, an action that can (or cannot) be performed.
A row in the session table is created after a successful login. Each time there's a call to the server, if the user has been verified against the token, I will lookup the roles for that user (using the session.user_id on the user_roles and collect it's access list using role.id on role_access.role_id).
Once I have the access list I can check against the request and see if the user is permitted to perform the action.
Notes
role can be customized for each tenant/account (e.g one can have "Management" and "Employees" and another can have "Management", "Support", and "Sales" ), hence the association with account.
access on the other hand, is platform-wide. The platform have the same set of areas and actions across all tenants. So there is not need to associate it with a specific account.
An improvement to the access lookup could be to store the access list on the session on login, to eliminate the double join (get all the user's roles, get all the roles' access lists).
Questions
Firstly, what is your overall opinion on the design. Do you see any flaws?
Is saving the account_id on the session really needed/a good idea?
Is having the server check whether the user has access to a certain resource is the standard way of doing this? Is there a way to do this as part of the itself query (e.g get an error from the DB itself)?
You might get a better answer by describing the requirements before you outline the solution.
Your design seems to describe an authorisation scheme. It looks fairly credible - I'd summarize it in natural language as:
A tenant is an account.
An account has many users.
A user can have
many roles.
Roles grant access to many permissions.
The system
maintains a list of sessions, mapping requests to users; this in turn
allows the system to check whether the user has permissions for a
given action.
Without knowing your requirements, that seems fairly reasonable. You may want to include a link from "account" to something your application recognizes as "tenant".
The big question is how you will use this data in your application. Checking permissions - especially fine-grained permissions - for each request could be expensive.
The specific solution here depends heavily on your application framework - many have built-in authentication/authorization models, and it's usually a good idea to use those built-in features.
For ideas on how to implement this, you could look at CanCanCan, an authorization framework for Ruby on Rails, or Authority for Laravel.
It's also not clear how the actual data in your system will be linked to an account - if your system tracks widgets, does the "widgets" table have an "account_id" column? If so, how does your application track who is and is not allowed to access that row?
It sounds like you're conflating database users with application users. In a SaaS product with a shared-schema model, individual users won't have direct acess to the database; instead, your application connects as a single user with appropriate rights on all objects it needs. What you're worried about is what areas of the application users can access and what actions they can take. This means you need to build your authorization model into your schema.
The simplest possible model has two levels of access: regular users and administrators. This can be represented with a users table having a tenant_id to associate individual logins with the correct client, and an is_admin flag. Your application then ensures that only users with the flag set can access administrative functionality. If your authorization model is more complex, design your schema appropriately (users may have a many:many relationship with roles, for example).
Note also that a tenant_id column is only strictly required for tables directly related to tenants; if you have a profiles table with a user_id, you can trace the relationship back to the tenant through users. In some cases it may make sense to add the tenant_id to avoid long join chains.

How to architect an API first multi app platform?

I am trying to build an API first web app that has two parts:
Part A: The Project Management App. This would be built using php/mysql. One of the table in the mysql DB will be the users table where all users information will be stored viz username, password, email etc.
Part B: The online chat App. The users of the project management system will be able to chat among themselves. This will be built using nodejs/mongo. The mongodb DB would store the chat transcripts of each users and so would have a users collection containing the user details. The users collection would contain the same user information that the mysql users table has viz username, password, email etc.
Now, i have a couple of questions in terms of the architecture of this app.
Question 1: Is it at all a wise idea to maintain two different sources to store the user's information? The reason why I wanted to have a replica of the users table in the MongoDB as well is because since there will be too many reads and writes happening in the chat app so its best we use a nosql DB. (Lets assume here that my app will be used heavily going forward)
Question 2: If the answer to Question 1 is "Yes", how do we make sure of data consistency? I have thought of two approaches to achieve this:
Option A: Since we are using the API first approach, so during the registration of a user when the CREATE user api call is made, it will add the user in both mysql and mongodb databases.
Option B: I setup a cron that will sync the data between the mysql users table and the mongodb users collection periodically.
Can someone please throw some light on this and tell me if my approaches are right and that if I am going towards the right direction.
Many thanks

access - showing multiple queries in one form

I am new to access, and I am trying to make a simplae project of managing users.
I have a table of USERS, and to more tables of SERVICES and GAMES.
I have connections of ID in USERS, and ID -> USER_ID in SERVICES, as well in GAMES.
Now I want to display in one form, USER profile, and to print the games related to the user and the services related to the user.
I added a query, that joins with USERS and SERVICES and GAMES, and it shows everything right, except that if the user for example has two services and only one game connected to the USER_ID, then it prints the game twice.
is there a way to display it correctly?
in normal SQL and PHP, it would be easy, though in access I have no idea how to do it.
thaks

Storing and retrieving users shopping cart from database - Cart class - CodeIgniter

I haven't started the coding yet and really just want to get feedback on my ideas.
I would like to know how to store a users shopping cart contents in order to be able to retrieve them once they have returned to the website.
I'm confused with the idea of allowing users to create accounts, as I've read on this website that forcing people to create an account with you in order to put items in their shopping basket is bad practice. However, if I do give the ability to have an account, then I can create a table holding the accounts information, along with having a column for storing that users shopping cart content via the CI Cart class' function $this->cart->contents; (which I would then have to serialize before putting it in the table, right?).
I also wanted to know if it is possible to store the contents of a users shopping basket into a column as stated above, and then retrieve it back to display as the users shopping basket contents once they log back in.
Having an account would benefit in terms of having your shopping cart items available in different browsers, as they would be associated with the account and not your session.
But if I don't want to implement customers having accounts, do I just have to implement the Cart class, with no interaction with the database (and just setting the session variables in the config file to not expire, or expire in a year etc)? I don't understand why I would need the ci_sessions table in this case (any arguments for using it?)
Really confused because I've pondered over this for a long time, getting more confused as time goes by :(. Could someone please shed some light for me. Thanks
I think its always a good idea to get customers to create accounts because
Its a good way to stop span. Only allowing registered and logged in users to access the checkout stages is a lot better than just letting anyone get to it
Its also a good way to gather information about your customers that can be used for marketing
In regards to the cart you can save sessions to a database by making sure sess_use_database is set to true in the config files
$config['sess_use_database'] = TRUE;
That way you can add the customer previous items into the cart when they log back in.
But I agree with #dispake you've asked quite a lot of questions so its hard to give you a definitive answer