Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5c28d9f
list of questions for identifying the relationships between entities
Mar 16, 2023
b526c34
added schema for the entities, relationships and queries at each step…
Mar 16, 2023
e9e88a1
complete schema for ditio backend, along with queries for each step d…
Mar 16, 2023
fa7d73d
added more questions
Mar 16, 2023
4c18684
actual db schema to showing primary key and foreign keys
Mar 16, 2023
474cfc7
chore: Answered your questions @raauhl
dineshram Mar 16, 2023
94464bd
add schema creation code
Mar 16, 2023
38cd189
added the queries for each step
Mar 16, 2023
d86ebd7
remove the entity after feedback on assumptions
Mar 16, 2023
76b9cb5
remove the entity after feedback on assumptions
Mar 16, 2023
e8969df
adding serivce layer interfaces that can implement specific queries
Mar 16, 2023
c3e2749
added api layer for the backend
Mar 16, 2023
cd643d8
nit updating the task to completed on checkout
Mar 16, 2023
70b5f44
added userResourceService and userProjectService and appropriate cont…
Mar 16, 2023
2625f61
nit: removed redundant controller, added comment on using Task as cla…
Mar 16, 2023
db26a38
update the resource service
Mar 16, 2023
e48d7a1
adding ER diagram for relationships and cardinality ratio
Mar 17, 2023
50db440
update er diagram
Mar 17, 2023
315796d
updated the model classes with references to other entities according…
Mar 17, 2023
b84bb10
added models and updated service layer
Mar 17, 2023
a0873e3
nit: spellings
Mar 17, 2023
c2bfeb4
added the sequence of service calls for the transaction
Mar 17, 2023
ed95b81
final changes to controller classes
Mar 17, 2023
f889a37
nit: naming function
Mar 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Questions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Q1: When a user changes the company. What happens to the project, resources and tasks?
I assume each company has its own set of project, resources and tasks and doesn't overlap
with other companies (p, r, t) ?

i.e a project, resource and task belong to a single company. Is this understanding correct?

Clarification: Projects have a many to one relationship with a Company and Tasks have a many to one relationship with a Project.
i.e. Assume that a project is not shared between companies and a task is not shared between projects.

Q2: I estimate we don't need the scale of google and facebook reaching 1B users for our database
design, based on some estimate and fair idea about which business ditio is in lets estimate the
range for the number of users be in range of 100k-10M as of now. So as to scope our discussion.
What do you think of this estimate?

Clarification: Yes at the moment, that scale is even smaller. But to design a solution for the range that you specified is more than enough.

Q3: There can be many projects inside the company, so the user is shown only a subset of it -
project he is been assigned/scheduled? So a company might have project p1, p2, p3, p4 etc.
But user A is scheduled for project p1, p3.

Is this understanding correct?

Clarification: Yes that is correct. A user will usually work on a subset of projects in a company.

Q4. Similarly, a project can have many tasks, so the user is shown only a subset of these tasks
or all the tasks?

Clarification: Assume that the user has the ability to pick any of his scheduled projects and any task in the project when he checks in.

Q5. I think resources are company wide entity and can be used across different projects and tasks
albeit only when free and not used in some other task. Is this understanding correct?
So the same resource R1 can be shown to user in Project P1 -> task T1 and Project P2 -> task T2?
If a user select a resource, then should it become unavailble to other users who might have
that resource scheduled for them?

Clarification: Exactly right.
104 changes: 104 additions & 0 deletions SchemaAndQueries.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# LIST OF ENTITIES AND RELATIONSHIPS

1. users(user_id, user_name, email, password)

2. projects(project_id, project_name, description, location)

3. tasks(task_id, task_name, description, project_id)

4. resources(resource_id, resource_name)

5. companies(company_id, comapany_name)

6. admins(admin_id, admin_name)

7. user_works_for_company(user_id, company_id)

8. user_scheduled_for_project(user_id, project_id)

9. user_scheduled_for_resources(user_id, resource_id)

10. user_tasks(user_task_id, user_id, task_id, resource_id, check_in_time, check_out_time)


# DB QUERIES FOR A TYPICAL TRANSACTION AT DITIO:

Let's say we have a user in table users with following data,
(1234, "RAHUL", "RAHUL@GMAIL.COM", "HASH_PASSWORD")

# User logins into the app.
1. SELECT *
FROM users
WHERE users.email == "RAHUL@GMAIL.COM" and password == "HASH_PASSWORD"

# User chooses a company.
2. SELECT company_id, company_name
FROM companies
WHERE company_id IN (SELECT company_id
FROM user_works_for_company
WHERE user_id == 1234)




# If the assumption is correct and there is not an overlap between the project, task and resources
# from one company to another. We have a natural partition happening in the tables.

# So for example, instead of having a single table project having project details of all the companies
# we can partition the table horizontally pulling out the data for each company into its separate tables
# for each company.

# User chooses a company from the list of companies they work for, let say company_id = "company_123".
# Now we have sharded the database on company_id i.e we have a separate database running for every
# company having its own tables with from table numbers [2, 3, 4, 5, 6, 8, 9, 10]

# we pick the database url to which the subsequent queries should hit, lets say we maintain a cache
# server with redis having (key, value) = (company_id, database_server_url)
# let say it looks like following,
# company_database_map = {
"ditioas" : "https://ditioas.mysql.database.azure.com",
"company_123" : "https://company_123.mysql.database.azure.com",
"vassabank" : "https://vassabank.mysql.database.azure.com",
}
# so the following queries will go to "https://company_123.mysql.database.azure.com".

# User gets a list of project which are scheduled for them and selects one project.
3. SELECT project_name, description, location
FROM projects
WHERE project_id IN (SELECT project_id
FROM user_scheduled_for_project
WHERE user_id = 1234)

# User gets a list of resources which are scheduled for them and selects one resource.
4. SELECT resource_id, resource_name
FROM resources
WHERE resource_id IN (SELECT resource_id
FROM user_scheduled_for_resources
WHERE user_id = 1234)

# Let say user chooses a project with project_id = "project_123" and resource with resource_id = "resource_123"
# User get a list of tasks belonging to the chosen project and chooses one task.
5. SELECT tasks.task_id, tasks.task_name, tasks.description
FROM tasks
WHERE tasks.project_id = "project_123"
AND tasks.task_id IN (
SELECT user_scheduled_for_task.task_id
FROM user_scheduled_for_task
WHERE user_scheduled_for_task.user_id = 1234
);


# Let say user chooses a task with task_id = "task_123"
# User clicks on check-in and records the check-in time.
6. UPDATE user_scheduled_for_task
SET resource_id = "resource_123", checkin_time = '2023-01-25 09:00:00'
WHERE user_id = 1234 AND task_id = "task_123"

# User clicks on check-out and records the check-out time.
7. UPDATE user_scheduled_for_task
SET checkout_time = '2023-01-25 11:00:00'
WHERE user_id = 1234 AND task_id = "task_123"




76 changes: 76 additions & 0 deletions backend/ApiLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
public class UserController : ControllerBase
{
private readonly IUserService _userService;

[HttpGet("{userId}/companies")]
public IActionResult GetAllCompaniesForUser(int userId)
{
var companies = _userService.GetAllCompaniesForUser(userId);
return Ok(companies);
}

[HttpGet("{userId}/projects")]
public IActionResult GetAllProjectsForUser(int userId)
{
var projects = _userService.GetAllProjectsForUser(userId);
return Ok(projects);
}

[HttpGet("{userId}/resources")]
public IActionResult GetAllAvailableResourcesForUser(int userId)
{
var resources = _userService.GetAllAvailableResourcesForUser(userId);
return Ok(resources);
}
}

public class CompanyController : ControllerBase
{
private readonly ICompanyService _companyService;

[HttpGet("{companyId}/databaseUrl")]
public ActionResult<string> GetDatabaseUrl(int companyId)
{
var url = _companyService.GetDatabaseUrl(companyId);
return Ok(url);
}
}

public class ProjectController : ControllerBase
{
private readonly IProjectService _projectService;

[HttpGet("{projectId}/tasks")]
public ActionResult<List<Task>> GetAllTasksForProject(int projectId)
{
var tasks = _projectService.GetAllTasksForProject(projectId);
return Ok(tasks);
}
}

public class UserTaskController : ControllerBase
{
private readonly IUserTaskService _userTaskService;
private readonly IResourceService _resourceService;

[HttpPost("checkin")]
public IActionResult Checkin(int userId, int taskId, int resourceId, DateTime checkInTime)
{
// on check in user creates a task, with default value for istaskcompleted as false
_userTaskService.CreateUserTask(userId, taskId, resourceId, checkInTime);
_resourceService.UpdateResourceAvailability(resourceId, resourceAvailable=false);
return Ok();
}

[HttpPost("checkout")]
public IActionResult Checkout(int userId, int taskId, int resourceId, DateTime checkOutTime)
{
// Get the usertaskid for user,task,resource combination where taskisnotcompleted
int userTaskId = userTaskService.GetUserTaskId(userId, taskId, resourceId, taskCompleted=false);

// Update the task as completed, record the checkout time and set the resource available
userTaskService.UpdateUserTaskCompletion(userTaskId, checkOutTime, taskCompleted=true);
resourceService.UpdateResourceAvailability(resourceId, resourceAvailable=true);
return Ok();
}
}
120 changes: 120 additions & 0 deletions backend/Models.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
public class User
{
public int UserId { get; set; }

public string UserName { get; set; }

public string UserEmail { get; set; }

public string Password { get; set; }

public List<UserWorksForCompany> UserWorksForCompany {get; set;}

public List<ProjectScheduledForUser> ProjectScheduledForUser {get; set;}

public List<ResourceScheduledForUser> ResourceScheduledForUser {get; set;}
}

public class Company
{
public int CompanyId { get; set; }

public string CompanyName { get; set; }

public string CompanyDatabaseUrl { get; set; }

public List<UserWorksForCompany> UserWorksForCompany {get; set;}

public List<Project> Project {get; set;}

public List<Resource> Resource {get; set;}
}

public class UserWorksForCompany
{
public int UserId { get; set; }

public string CompanyId { get; set; }

public User User { get; set; }

public Company Company { get; set; }
}

public class Project
{
public int ProjectId { get; set; }

public string ProjectName { get; set; }

public string ProjectDescription { get; set; }

public List<ProjectScheduledForUser> ProjectScheduledForUser {get; set; }

public Company Company {get; set;}

public List<Task> Task;
}

public class ProjectScheduledForUser
{
public int ProjectId { get; set; }

public int UserId {get; set;}

public Project Project {get; set;}

public User User {get; set;}
}

public class Resource
{
public int ResourceId { get; set; }

public string ResourceName { get; set; }

public bool ResourceAvailable { get; set; }

public Company Company {get; set;}

public List<ResourceScheduledForUser> ResourceScheduledForUser;
}

public class ResourceScheduledForUser
{
public int ResourceId { get; set; }

public int UserId {get; set;}

public Resource Resource {get; set;}

public User User {get; set;}
}

public class Task
{
public int TaskId { get; set; }

public string TaskName { get; set; }

public string TaskDescription { get; set; }

public Project Project {get; set;}
}

public class UserTask
{
public int UserTaskId { get; set; }

public int UserId { get; set; }

public int TaskId { get; set; }

public int ResourceId { get; set; }

public bool TaskCompleted {get; set;}

public DateTime CheckInTime { get; set; }

public DateTime CheckOutTime { get; set; }
}
51 changes: 51 additions & 0 deletions backend/ServiceLayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
public interface IUserService
{
List<Company> GetAllCompaniesForUser(int userId);

List<Project> GetAllProjectsForUser(int userId);

List<Resource> GetAllAvailableResourcesForUser(int userId);
}

public interface ICompanyService
{
string GetDatabaseUrl(int companyId);
}

public interface IProjectService
{
List<Task> GetAllTasksForProject(int projectId);
}

public interface IResourceService
{
void UpdateResourceAvailability(int resourceId, bool isAvailable);
}

public interface IUserTaskService
{
void CreateUserTask(int userId, int taskId, int resourceId, DateTime checkInTime);

int GetUserTaskId(int userId, int taskId, int resourceId, bool taskCompleted);

void UpdateUserTaskCompletion(int userTaskId, DateTime checkOutTime, bool taskCompleted);
}

// Client activity sequence for the api calls,
// 1. userService.GetAllCompaniesForUser()
// 2. companyService.GetDatabaseUrl()

// subsequent queries will go the the database server with the URL in step2.
// 3. userService.GetAllProjectsForUser()
// 4. userService.GetAllAvailableResourcesForUser()
// 5. projectService.GetAllTasksForProject()

// Check-in
// 6. userTaskService.CreateUserTask()
// 7. resourceService.UpdateResourceAvailability(false)

// Check-out
// 8. userTaskService.GetUserTaskId()
// 9. userTaskService.UpdateUserTaskCompletion()
// 10. resourceService.UpdateResourceAvailability(true)

Binary file added backend/er_diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading