diff --git a/.gitignore b/.gitignore
index a9183b55b68a71ca47809af2e9361e03903aae0c..0a8e0559ee40f980c98cf9af85ceef89e5cdc385 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-################################################################################
+################################################################################
 # This .gitignore file was automatically created by Microsoft(R) Visual Studio.
 ################################################################################
 
diff --git a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
index 19b56f853a2c8cb1db658771f40e43ca5a466815..cb90fae29fb465e9298dddbe750edfbf5e5677c3 100644
--- a/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
+++ b/Tsi1.Api/Tsi1.Api/Controllers/CourseController.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Security.Claims;
 using System.Threading.Tasks;
@@ -19,9 +20,12 @@ namespace Tsi1.Api.Controllers
     {
         private readonly ICourseService _courseService;
 
-        public CourseController(ICourseService courseService)
+        private readonly IFileService _fileService;
+
+        public CourseController(ICourseService courseService, IFileService fileService)
         {
             _courseService = courseService;
+            _fileService = fileService;
         }
 
         [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor)]
@@ -54,6 +58,10 @@ namespace Tsi1.Api.Controllers
                 return BadRequest(result.Message);
             }
 
+            var path = Path.Combine(tenantId.ToString(), result.Data.Id.ToString());
+
+            _fileService.CreateFolder(path);
+
             return Ok();
         }
 
@@ -65,11 +73,38 @@ namespace Tsi1.Api.Controllers
             var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
 
             var result = await _courseService.Matriculate(userId, courseId);
+            
             if (result.HasError)
             {
                 return BadRequest(result.Message);
             }
 
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.Student)]
+        [HttpPost("DropOutFromCourse/{courseId}")]
+        public async Task<IActionResult> DropOutFromCourse(int courseId)
+        {
+            var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+
+            var result = await _courseService.DropOutFromCourse(userId, courseId);
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
             return Ok();
         }
 
@@ -78,12 +113,112 @@ namespace Tsi1.Api.Controllers
         public async Task<IActionResult> AddProfessorToCourse(ProfessorCourseDto professorCourseDto)
         {
             var result = await _courseService.AddProfessorToCourse(professorCourseDto);
+            
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.FacultyAdmin)]
+        [HttpPost("RemoveProfessorToCourse")]
+        public async Task<IActionResult> RemoveProfessorFromCourse(ProfessorCourseDto professorCourseDto)
+        {
+            var result = await _courseService.RemoveProfessorToCourse(professorCourseDto);
+            
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor + ", " + UserTypes.FacultyAdmin)]
+        [HttpGet("GetAll")]
+        public async Task<IActionResult> GetAll()
+        {
+            var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+            var result = await _courseService.GetAll(tenantId);
             if (result.HasError)
             {
                 return BadRequest(result.Message);
             }
 
+            return Ok(result.Data);
+        }
+
+        [Authorize(Roles = UserTypes.UdelarAdmin)]
+        [HttpGet("GetAll/{tenantId}")]
+        public async Task<IActionResult> GetAll(int tenantId)
+        {
+            var result = await _courseService.GetAll(tenantId);
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            return Ok(result.Data);
+        }
+
+
+        [Authorize(Roles = UserTypes.Professor + ", " + UserTypes.FacultyAdmin)]
+        [HttpPut("Modify/{courseId}")]
+        public async Task<IActionResult> Modify(int courseId, CourseCreateDto courseDto)
+        {
+            var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+            courseDto.TenantId = tenantId;
+
+            var result = await _courseService.Modify(courseId, courseDto);
+            
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.FacultyAdmin)]
+        [HttpDelete("Delete/{courseId}")]
+        public async Task<IActionResult> Delete(int courseId)
+        {
+            var result = await _courseService.Delete(courseId);
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == null)
+            {
+                return NotFound(result.Message);
+            }
+
+            var path = Path.Combine(result.Data.TenantId.ToString(), result.Data.Id.ToString());
+
+            _fileService.DeleteFolder(path);
+
             return Ok();
         }
+
     }
 }
diff --git a/Tsi1.Api/Tsi1.Api/Controllers/FileController.cs b/Tsi1.Api/Tsi1.Api/Controllers/FileController.cs
new file mode 100644
index 0000000000000000000000000000000000000000..144a8298f82892a2caafe88b4957da0c01b96b24
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/Controllers/FileController.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Tsi1.BusinessLayer.Helpers;
+using Tsi1.BusinessLayer.Interfaces;
+
+namespace Tsi1.Api.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class FileController : ControllerBase
+    {
+        private readonly IFileService _fileService;
+
+        public FileController(IFileService fileService)
+        {
+            _fileService = fileService;
+        }
+
+        [Authorize(Roles = UserTypes.Professor)]
+        [HttpPost("Create/{courseId}")]
+        public async Task<IActionResult> Create(IFormFile file, int courseId)
+        {
+            var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+            var result = await _fileService.Create(file, tenantId, courseId);
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            return Ok(result.Data);
+        }
+
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs b/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs
index f89bb6beb7a7a425bda20d76669b2315ba465083..92a0665ffad2a0892a1365f1b16fbbf9730a92e6 100644
--- a/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs
+++ b/Tsi1.Api/Tsi1.Api/Controllers/TenantController.cs
@@ -17,9 +17,12 @@ namespace Tsi1.Api.Controllers
     {
         private readonly ITenantService _tenantService;
 
-        public TenantController(ITenantService tenantService)
+        private readonly IFileService _fileService;
+
+        public TenantController(ITenantService tenantService, IFileService fileService)
         {
             _tenantService = tenantService;
+            _fileService = fileService;
         }
 
         [Authorize(Roles = UserTypes.UdelarAdmin)]
@@ -47,6 +50,76 @@ namespace Tsi1.Api.Controllers
                 return BadRequest(result.Message);
             }
 
+            _fileService.CreateFolder(result.Data.Id.ToString());
+
+            return Ok(result.Data);
+        }
+
+        [Authorize(Roles = UserTypes.UdelarAdmin)]
+        [HttpPut("Modify/{tenantId}")]
+        public async Task<IActionResult> Modify(int tenantId, TenantCreateDto tenantDto)
+        {
+            var result = await _tenantService.Modify(tenantId, tenantDto);
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.UdelarAdmin)]
+        [HttpDelete("Delete/{tenantId}")]
+        public async Task<IActionResult> Delete(int tenantId)
+        {
+            var result = await _tenantService.Delete(tenantId);
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            if (result.Data == false)
+            {
+                return NotFound(result.Message);
+            }
+
+            _fileService.DeleteFolder(tenantId.ToString());
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.UdelarAdmin)]
+        [HttpGet("FacultyList")]
+        public async Task<IActionResult> FacultyList()
+        {
+            var result = await _tenantService.FacultyList();
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            return Ok(result.Data);
+        }
+
+        [Authorize(Roles = UserTypes.UdelarAdmin)]
+        [HttpGet("CourseList")]
+        public async Task<IActionResult> CourseList()
+        {
+            var result = await _tenantService.CourseList();
+
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
             return Ok(result.Data);
         }
     }
diff --git a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs
index 1fbbe5ca1f7cdb42755c0717dbfc42a9035983aa..ac1b1b8b0df52c850b35dd1c4c1c15e5a6153b4f 100644
--- a/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs
+++ b/Tsi1.Api/Tsi1.Api/Controllers/UserController.cs
@@ -23,21 +23,27 @@ namespace Tsi1.Api.Controllers
         private readonly IUserService _userService;
         private readonly IUserTypeService _userTypeService;
         private readonly ITenantService _tenantService;
-
-        public UserController(IJwtAuthManager jwtAuthManager, IUserService userService,
-            IUserTypeService userTypeService, ITenantService tenantService)
+        private readonly IEmailService _emailService;
+
+        public UserController(
+            IJwtAuthManager jwtAuthManager,
+            IUserService userService,
+            IUserTypeService userTypeService,
+            ITenantService tenantService,
+            IEmailService emailService)
         {
             _jwtAuthManager = jwtAuthManager;
             _userService = userService;
             _userTypeService = userTypeService;
             _tenantService = tenantService;
+            _emailService = emailService;
         }
 
         [AllowAnonymous]
         [HttpPost("Login")]
         public async Task<IActionResult> Login(LoginRequest request)
         {
-            var resultSplit = request.UserName.Split("@");
+            var resultSplit = request.Username.Split("@");
 
             if (resultSplit.Count() != 2)
             {
@@ -45,9 +51,7 @@ namespace Tsi1.Api.Controllers
             }
 
             var userName = resultSplit[0];
-
             var tenantName = resultSplit[1];
-
             var tenantId = await _tenantService.GetByName(tenantName);
 
             if (tenantId.HasError)
@@ -56,7 +60,6 @@ namespace Tsi1.Api.Controllers
             }
 
             var result = await _userService.Authenticate(userName, request.Password, tenantId.Data);
-
             if (result.HasError)
             {
                 return BadRequest(result.Message);
@@ -110,68 +113,178 @@ namespace Tsi1.Api.Controllers
             }
         }
 
-        [Authorize(Roles = UserTypes.FacultyAdmin)]
+        [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)]
         [HttpPost("Register")]
-        public async Task<IActionResult> Register(UserRegisterDto dto)
+        public async Task<IActionResult> Register(UserRegisterDto dto, [FromQuery] int? tenantId = null)
         {
-            var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+            var myUserType = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role).Value;
+
+            if (myUserType == UserTypes.UdelarAdmin && tenantId == null)
+            {
+                return BadRequest(string.Format(ErrorMessages.TenantDoesNotExist, tenantId));
+            }
+
+            if (myUserType == UserTypes.FacultyAdmin)
+            {
+                tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+            }
 
             var userTypeResult = await _userTypeService.GetById(dto.UserTypeId);
 
+            if (userTypeResult.HasError)
+            {
+               return BadRequest(userTypeResult.Message);
+            }
+
+            var userType = userTypeResult.Data;
+
+            if (myUserType == UserTypes.UdelarAdmin &&
+                (userType.Name == UserTypes.Student ||
+                userType.Name == UserTypes.Professor))
+            {
+                return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
+            }
+
+            if (myUserType == UserTypes.FacultyAdmin &&
+                (userType.Name == UserTypes.UdelarAdmin ||
+                userType.Name == UserTypes.FacultyAdmin))
+            {
+                return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
+            }
+
+            var userServiceResult = await _userService.Create(dto, userType.Name, (int) tenantId);
+
+            if (userServiceResult.HasError)
+            {
+                BadRequest(userServiceResult.Message);
+            }
+
+            return Ok();
+        }
+
+        [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)]
+        [HttpPut("Modify/{userId}")]
+        public async Task<IActionResult> Modify(UserModifyDto dto, int userId)
+        {
+            var myUserType = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role).Value;
+
+            var userTypeResult = await _userService.GetUserType(userId);
+
             if (userTypeResult.HasError)
             {
                 return BadRequest(userTypeResult.Message);
             }
 
+            if (myUserType == UserTypes.FacultyAdmin)
+            {
+                var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+                var userTenant = await _userService.GetTenant(userId);
+
+                if (userTenant.HasError)
+                {
+                    return BadRequest(userTenant.Message);
+                }
+
+                if (userTenant.Data != tenantId)
+                {
+                    return BadRequest("No se puede modificar un usuario de otra facultad");
+                }
+            } 
+
             var userType = userTypeResult.Data;
 
-            if (userType.Name == UserTypes.UdelarAdmin ||
-                userType.Name == UserTypes.FacultyAdmin)
+            if (myUserType == UserTypes.UdelarAdmin &&
+                (userType.Name == UserTypes.Student ||
+                userType.Name == UserTypes.Professor))
+            {
+                return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
+            }
+
+            if (myUserType == UserTypes.FacultyAdmin &&
+                (userType.Name == UserTypes.UdelarAdmin ||
+                userType.Name == UserTypes.FacultyAdmin))
             {
                 return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
             }
 
-            var userServiceResult = await _userService.Create(dto, userType.Name, tenantId);
+            var userServiceResult = await _userService.Modify(dto, userType.Name, userId);
 
             if (userServiceResult.HasError)
             {
                 return BadRequest(userServiceResult.Message);
             }
 
+            if (userServiceResult.Data == false)
+            {
+                return NotFound(userServiceResult.Message);
+            }
+
             return Ok();
         }
 
-        [Authorize(Roles = UserTypes.UdelarAdmin)]
-        [HttpPost("RegisterAdmin/{tenantId}")]
-        public async Task<IActionResult> RegisterAdmin(UserRegisterDto dto, int tenantId)
+        [Authorize(Roles = UserTypes.FacultyAdmin + ", " + UserTypes.UdelarAdmin)]
+        [HttpDelete("Delete/{userId}")]
+        public async Task<IActionResult> Delete(int userId)
         {
-            var userTypeResult = await _userTypeService.GetById(dto.UserTypeId);
+            var myUserType = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Role).Value;
+
+            if (myUserType == UserTypes.FacultyAdmin)
+            {
+                var tenantId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+                var userTenant = await _userService.GetTenant(userId);
+
+                if (userTenant.HasError)
+                {
+                    return BadRequest(userTenant.Message);
+                }
+
+                if (userTenant.Data != tenantId)
+                {
+                    return BadRequest("No se puede borrar un usuario de otra facultad");
+                }
+            }
+
+            var userTypeResult = await _userService.GetUserType(userId);
 
             if (userTypeResult.HasError)
             {
-                BadRequest(userTypeResult.Message);
+                return BadRequest(userTypeResult.Message);
             }
 
             var userType = userTypeResult.Data;
 
-            if (userType.Name == UserTypes.Student ||
-                userType.Name == UserTypes.Professor)
+            if (myUserType == UserTypes.UdelarAdmin &&
+                (userType.Name == UserTypes.Student ||
+                userType.Name == UserTypes.Professor))
             {
                 return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
             }
 
-            var userServiceResult = await _userService.Create(dto, userType.Name, tenantId);
+            if (myUserType == UserTypes.FacultyAdmin &&
+                (userType.Name == UserTypes.UdelarAdmin ||
+                userType.Name == UserTypes.FacultyAdmin))
+            {
+                return BadRequest(string.Format(ErrorMessages.InvalidUserType, userType.Name));
+            }
+
+            var userServiceResult = await _userService.Delete(userId);
 
             if (userServiceResult.HasError)
             {
-                BadRequest(userServiceResult.Message);
+                return BadRequest(userServiceResult.Message);
+            }
+
+            if (userServiceResult.Data == false)
+            {
+                return NotFound(userServiceResult.Message);
             }
 
             return Ok();
         }
 
-
-        [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor)]
+        [Authorize(Roles = UserTypes.Student + ", " + UserTypes.Professor + ", " + UserTypes.FacultyAdmin)]
         [HttpGet("GetAll")]
         public async Task<IActionResult> GetAll()
         {
@@ -217,5 +330,108 @@ namespace Tsi1.Api.Controllers
             return Ok(result.Data);
         }
 
+        [AllowAnonymous]
+        [HttpGet("ForgotPassword/{username}")]
+        public async Task<IActionResult> ForgotPassword(string username)
+        {
+            var resultSplit = username.Split("@");
+
+            if (resultSplit.Count() != 2)
+            {
+                return BadRequest(ErrorMessages.InvalidUsername);
+            }
+
+            username = resultSplit[0];
+            var tenantName = resultSplit[1];
+            var tenantId = await _tenantService.GetByName(tenantName);
+
+            if (tenantId.HasError)
+            {
+                return BadRequest(tenantId.Message);
+            }
+
+            var userResult = await _userService.GetByUsername(username, tenantId.Data);
+
+            if (userResult.HasError)
+            {
+                return BadRequest(userResult.Message);
+            }
+
+            var code = _jwtAuthManager.GenerateVerificationCode(username, DateTime.Now);
+
+            var result = await _emailService.SendVerificationCode(userResult.Data.Email, code);
+            if (result.HasError)
+            {
+                return BadRequest("Ha ocurrido un error");
+            }
+
+            return Ok();
+        }
+
+        [AllowAnonymous]
+        [HttpGet("VerificationCode/{username}/{code}")]
+        public async Task<IActionResult> VerificationCode(string username, int code)
+        {
+            var resultSplit = username.Split("@");
+
+            if (resultSplit.Count() != 2)
+            {
+                return BadRequest(ErrorMessages.InvalidUsername);
+            }
+
+            username = resultSplit[0];
+            var tenantName = resultSplit[1];
+            var tenantId = await _tenantService.GetByName(tenantName);
+
+            if (tenantId.HasError)
+            {
+                return BadRequest(tenantId.Message);
+            }
+
+            if (!_jwtAuthManager.ValidateVerificationCode(username, code))
+            {
+                return BadRequest("Código de verificación incorrecto");
+            }
+
+            var userResult = await _userService.GetByUsername(username, tenantId.Data);
+            if (userResult.HasError)
+            {
+                return BadRequest(userResult.Message);
+            }
+
+            var user = userResult.Data;
+            var claims = new[]
+            {
+                new Claim("Id", user.Id.ToString()),
+                new Claim("Username", user.Username),
+                new Claim("TenantId", user.TenantId.ToString()),
+                new Claim(ClaimTypes.Role, user.UserType.Name)
+            };
+
+            var jwtResult = _jwtAuthManager.GenerateTokens(user.Username, claims, DateTime.Now);
+
+            return Ok(new LoginResult
+            {
+                Id = user.Id,
+                UserName = user.Username,
+                Role = user.UserType.Name,
+                AccessToken = jwtResult.AccessToken,
+                RefreshToken = jwtResult.RefreshToken.TokenString
+            });
+        }
+
+        [HttpPost("RestorePassword")]
+        public async Task<IActionResult> RestorePassword(RestorePasswordDto dto)
+        {
+            var userId = int.Parse(HttpContext.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+
+            var result = await _userService.UpdatePassword(userId, dto.Password);
+            if (result.HasError)
+            {
+                return BadRequest(result.Message);
+            }
+
+            return Ok();
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.Api/Infrastructure/IJwtAuthManager.cs b/Tsi1.Api/Tsi1.Api/Infrastructure/IJwtAuthManager.cs
index e9342c6dbb7d95fbf866b95abdd4a4fe6142e254..ab8bf680e9aa66084d608abaa9cc6b9a57c182ee 100644
--- a/Tsi1.Api/Tsi1.Api/Infrastructure/IJwtAuthManager.cs
+++ b/Tsi1.Api/Tsi1.Api/Infrastructure/IJwtAuthManager.cs
@@ -14,5 +14,8 @@ namespace Tsi1.Api.Infrastructure
         void RemoveExpiredRefreshTokens(DateTime now);
         void RemoveRefreshTokenByUserName(string userName);
         (ClaimsPrincipal, JwtSecurityToken) DecodeJwtToken(string token);
+        int GenerateVerificationCode(string username, DateTime now);
+        bool ValidateVerificationCode(string username, int code);
+        public void RemoveExpiredVerificationCodes(DateTime now);
     }
 }
diff --git a/Tsi1.Api/Tsi1.Api/Infrastructure/JwtAuthManager.cs b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtAuthManager.cs
index 672247e7bf45a0cd68789cd77290da0f2f2bf606..f1bf057d038a817c83884e80eb99bece1e185bf2 100644
--- a/Tsi1.Api/Tsi1.Api/Infrastructure/JwtAuthManager.cs
+++ b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtAuthManager.cs
@@ -15,6 +15,7 @@ namespace Tsi1.Api.Infrastructure
     {
         public IImmutableDictionary<string, RefreshToken> UsersRefreshTokensReadOnlyDictionary => _usersRefreshTokens.ToImmutableDictionary();
         private readonly ConcurrentDictionary<string, RefreshToken> _usersRefreshTokens;  // can store in a database or a distributed cache
+        private readonly ConcurrentDictionary<string, VerificationCode> _usersVerificationCodes;
         private readonly JwtTokenConfig _jwtTokenConfig;
         private readonly byte[] _secret;
 
@@ -22,6 +23,7 @@ namespace Tsi1.Api.Infrastructure
         {
             _jwtTokenConfig = jwtTokenConfig;
             _usersRefreshTokens = new ConcurrentDictionary<string, RefreshToken>();
+            _usersVerificationCodes = new ConcurrentDictionary<string, VerificationCode>();
             _secret = Encoding.ASCII.GetBytes(jwtTokenConfig.Secret);
         }
 
@@ -118,6 +120,36 @@ namespace Tsi1.Api.Infrastructure
             return (principal, validatedToken as JwtSecurityToken);
         }
 
+        public int GenerateVerificationCode(string username, DateTime now)
+        {
+            var code = new Random().Next(1000000);
+
+            var verficationCode = new VerificationCode()
+            {
+                Username = username,
+                Code = code,
+                ExpireAt = now.AddMinutes(_jwtTokenConfig.VerificationCodeExpiration)
+            };
+
+            _usersVerificationCodes.AddOrUpdate(username, verficationCode, (s, t) => verficationCode);
+
+            return code;
+        }
+
+        public bool ValidateVerificationCode(string username, int code)
+        {
+            return _usersVerificationCodes.TryGetValue(username, out _);
+        }
+
+        public void RemoveExpiredVerificationCodes(DateTime now)
+        {
+            var expiredCodes = _usersVerificationCodes.Where(x => x.Value.ExpireAt < now).ToList();
+            foreach (var expiredCode in expiredCodes)
+            {
+                _usersVerificationCodes.TryRemove(expiredCode.Key, out _);
+            }
+        }
+
         private static string GenerateRefreshTokenString()
         {
             var randomNumber = new byte[32];
diff --git a/Tsi1.Api/Tsi1.Api/Infrastructure/JwtTokenConfig.cs b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtTokenConfig.cs
index 854d596cf716e1388a8c507ba3c9426b77031016..5eacf5d9d79ecab406e690f602e7a8789c21c357 100644
--- a/Tsi1.Api/Tsi1.Api/Infrastructure/JwtTokenConfig.cs
+++ b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtTokenConfig.cs
@@ -4,19 +4,11 @@ namespace Tsi1.Api.Infrastructure
 {
     public class JwtTokenConfig
     {
-        [JsonPropertyName("secret")]
         public string Secret { get; set; }
-
-        [JsonPropertyName("issuer")]
         public string Issuer { get; set; }
-
-        [JsonPropertyName("audience")]
         public string Audience { get; set; }
-
-        [JsonPropertyName("accessTokenExpiration")]
         public int AccessTokenExpiration { get; set; }
-
-        [JsonPropertyName("refreshTokenExpiration")]
         public int RefreshTokenExpiration { get; set; }
+        public int VerificationCodeExpiration { get; set; }
     }
 }
diff --git a/Tsi1.Api/Tsi1.Api/Infrastructure/JwtVerificationCodeCache.cs b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtVerificationCodeCache.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7805cedf35a8d75c22f860acd5f849ecf7d0a4fb
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/Infrastructure/JwtVerificationCodeCache.cs
@@ -0,0 +1,41 @@
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Tsi1.Api.Infrastructure
+{
+    public class JwtVerificationCodeCache : IHostedService, IDisposable
+    {
+        private Timer _timer;
+        private readonly IJwtAuthManager _jwtAuthManager;
+
+        public JwtVerificationCodeCache(IJwtAuthManager jwtAuthManager)
+        {
+            _jwtAuthManager = jwtAuthManager;
+        }
+
+        public Task StartAsync(CancellationToken stoppingToken)
+        {
+            // remove expired refresh tokens from cache every minute
+            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
+            return Task.CompletedTask;
+        }
+
+        private void DoWork(object state)
+        {
+            _jwtAuthManager.RemoveExpiredVerificationCodes(DateTime.Now);
+        }
+
+        public Task StopAsync(CancellationToken stoppingToken)
+        {
+            _timer?.Change(Timeout.Infinite, 0);
+            return Task.CompletedTask;
+        }
+
+        public void Dispose()
+        {
+            _timer?.Dispose();
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs
index 96e87b18d03e7185430f760fb0a5c9caefe6611f..5408e8b422bb74b8ad6257bacefdc6aedef08259 100644
--- a/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs
+++ b/Tsi1.Api/Tsi1.Api/Models/LoginRequest.cs
@@ -11,7 +11,7 @@ namespace Tsi1.Api.Models
     {
         [Required]
         [JsonPropertyName("username")]
-        public string UserName { get; set; }
+        public string Username { get; set; }
 
         [Required]
         [JsonPropertyName("password")]
diff --git a/Tsi1.Api/Tsi1.Api/Models/VerificationCode.cs b/Tsi1.Api/Tsi1.Api/Models/VerificationCode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..253d88390adeeadd50843b579cc03d3e5372d153
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/Models/VerificationCode.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Tsi1.Api.Models
+{
+    public class VerificationCode
+    {
+        public string Username { get; set; }
+        public int Code { get; set; }
+        public DateTime ExpireAt { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/SignalR/ChatHub.cs b/Tsi1.Api/Tsi1.Api/SignalR/ChatHub.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0c54af61a8bd5ac751eec8dd173a9f1140b4f5c8
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/SignalR/ChatHub.cs
@@ -0,0 +1,146 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.SignalR;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Dtos;
+using Tsi1.BusinessLayer.Interfaces;
+using Tsi1.DataLayer;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.Api.SignalR
+{
+    [Authorize]
+    public class ChatHub : Hub
+    {
+        private readonly IMapper _mapper;
+        private readonly IHubContext<PresenceHub> _presenceHub;
+        private readonly PresenceTracker _tracker;
+        private readonly IMessageService _messageService;
+        private readonly IChatService _chatService;
+
+        public ChatHub(IMapper mapper, IHubContext<PresenceHub> presenceHub,
+            PresenceTracker tracker, IMessageService messageService, IChatService chatService)
+        {
+            _tracker = tracker;
+            _presenceHub = presenceHub;
+            _mapper = mapper;
+            _messageService = messageService;
+            _chatService = chatService;
+        }
+
+        public override async Task OnConnectedAsync()
+        {
+            var httpContext = Context.GetHttpContext();
+
+            var otherUserId = int.Parse(httpContext.Request.Query["id"].ToString());
+
+            var userId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+            var tenantId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+            var groupName = GetGroupName(userId, otherUserId);
+            await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
+
+            await AddToGroup(groupName);
+
+            var messages = await _messageService.GetMessages(userId, otherUserId, tenantId);
+
+            await Clients.Caller.SendAsync("ReceiveMessages", messages);
+        }
+
+        public override async Task OnDisconnectedAsync(Exception exception)
+        {
+
+            await RemoveFromGroup();
+
+            await base.OnDisconnectedAsync(exception);
+        }
+
+        public async Task SendMessage(MessageCreateDto newMessage)
+        {
+            var userId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+            var tenantId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "TenantId").Value);
+
+            if (userId == newMessage.ReceiverId)
+                throw new HubException("You cannot send messages to yourself");
+
+            var groupName = GetGroupName(userId, newMessage.ReceiverId);
+
+            var group = await _chatService.GetGroupByName(groupName);
+
+            if (group == null)
+            {
+                throw new HubException($"No existe el grupo {groupName}");
+            }
+
+            if (!group.Connections.Any(x => x.UserId == newMessage.ReceiverId))
+            {
+                var connections = await _tracker.GetConnectionsForUser(newMessage.ReceiverId);
+                if (connections != null)
+                {
+                    await _presenceHub.Clients.Clients(connections).SendAsync("NewMessageReceived", userId);
+                }
+            }
+
+            newMessage.SenderId = userId;
+            var messageDto = await _messageService.Send(newMessage);
+
+            await Clients.Group(groupName).SendAsync("NewMessage", messageDto);
+        }
+
+        private async Task<Group> AddToGroup(string groupName)
+        {
+            var group = await _chatService.GetGroupByName(groupName);
+
+            if (group == null)
+            {
+                throw new HubException($"No existe el grupo {groupName}");
+            }
+
+            var userId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+
+            var connection = new Connection
+            {
+                ConnectionId = Context.ConnectionId,
+                UserId = userId,
+            };
+
+            if (group == null)
+            {
+                group = new Group
+                {
+                    Name = groupName,
+                };
+            }
+
+            group.Connections.Add(connection);
+
+            var result = await _chatService.CreateGroup(group);
+
+            if (result.HasError)
+            {
+                throw new HubException($"Error al crear el grupo {group}");
+            }
+
+            return group;
+        }
+
+        private async Task<bool> RemoveFromGroup()
+        {
+            await _chatService.RemoveConnectionFromGroup(Context.ConnectionId);
+
+            return true;
+        }
+
+        private string GetGroupName(int callerId, int otherId)
+        {
+            var compare = callerId < otherId;
+            return compare ? $"{callerId}-{otherId}" : $"{otherId}-{callerId}";
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/SignalR/PresenceHub.cs b/Tsi1.Api/Tsi1.Api/SignalR/PresenceHub.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e606bc97df59fe20017906c434941e3b40ca28a8
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/SignalR/PresenceHub.cs
@@ -0,0 +1,41 @@
+using Microsoft.AspNetCore.SignalR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Tsi1.Api.SignalR
+{
+    public class PresenceHub : Hub
+    {
+        private readonly PresenceTracker _tracker;
+        public PresenceHub(PresenceTracker tracker)
+        {
+            _tracker = tracker;
+        }
+
+        public override async Task OnConnectedAsync()
+        {
+            var userId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+
+            var isOnline = await _tracker.UserConnected(userId, Context.ConnectionId);
+            if (isOnline)
+                await Clients.Others.SendAsync("UserIsOnline", userId);
+
+            var currentUsers = await _tracker.GetOnlineUsers();
+            await Clients.Caller.SendAsync("GetOnlineUsers", currentUsers);
+        }
+
+        public override async Task OnDisconnectedAsync(Exception exception)
+        {
+            var userId = int.Parse(Context.User.Claims.FirstOrDefault(x => x.Type == "Id").Value);
+
+            var isOffline = await _tracker.UserDisconnected(userId, Context.ConnectionId);
+
+            if (isOffline)
+                await Clients.Others.SendAsync("UserIsOffline", userId);
+
+            await base.OnDisconnectedAsync(exception);
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/SignalR/PresenceTracker.cs b/Tsi1.Api/Tsi1.Api/SignalR/PresenceTracker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f11f18db7d18e01b3a2f8b82d65f8a07dcb3db47
--- /dev/null
+++ b/Tsi1.Api/Tsi1.Api/SignalR/PresenceTracker.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Tsi1.Api.SignalR
+{
+    public class PresenceTracker
+    {
+        private static readonly Dictionary<int, List<string>> OnlineUsers =
+            new Dictionary<int, List<string>>();
+
+        public Task<bool> UserConnected(int userId, string connectionId)
+        {
+            bool isOnline = false;
+            lock (OnlineUsers)
+            {
+                if (OnlineUsers.ContainsKey(userId))
+                {
+                    OnlineUsers[userId].Add(connectionId);
+                }
+                else
+                {
+                    OnlineUsers.Add(userId, new List<string> { connectionId });
+                    isOnline = true;
+                }
+            }
+
+            return Task.FromResult(isOnline);
+        }
+
+        public Task<bool> UserDisconnected(int userId, string connectionId)
+        {
+            bool isOffline = false;
+            lock (OnlineUsers)
+            {
+                if (!OnlineUsers.ContainsKey(userId)) return Task.FromResult(isOffline);
+
+                OnlineUsers[userId].Remove(connectionId);
+                if (OnlineUsers[userId].Count == 0)
+                {
+                    OnlineUsers.Remove(userId);
+                    isOffline = true;
+                }
+            }
+
+            return Task.FromResult(isOffline);
+        }
+
+        public Task<int[]> GetOnlineUsers()
+        {
+            int[] onlineUsers;
+            lock (OnlineUsers)
+            {
+                onlineUsers = OnlineUsers.OrderBy(k => k.Key).Select(k => k.Key).ToArray();
+            }
+
+            return Task.FromResult(onlineUsers);
+        }
+
+        public Task<List<string>> GetConnectionsForUser(int userId)
+        {
+            List<string> connectionIds;
+            lock (OnlineUsers)
+            {
+                connectionIds = OnlineUsers.GetValueOrDefault(userId);
+            }
+
+            return Task.FromResult(connectionIds);
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.Api/Startup.cs b/Tsi1.Api/Tsi1.Api/Startup.cs
index 9e0df6280b29f68a2954b9cb32413a6b44cedd46..135212e330271889277770863aa98754ea3dcd31 100644
--- a/Tsi1.Api/Tsi1.Api/Startup.cs
+++ b/Tsi1.Api/Tsi1.Api/Startup.cs
@@ -1,17 +1,21 @@
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using AutoMapper;
 using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.HttpsPolicy;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.StaticFiles;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.FileProviders;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Options;
@@ -48,6 +52,8 @@ namespace Tsi1.Api
             var postgreSqlSection = isElasticCloud ? "PostgreSqlCloud" : "PostgreSql";
             var mongoDbSection = isElasticCloud ? "Tsi1DatabaseSettingsCloud" : "Tsi1DatabaseSettings";
 
+            var jwtTokenConfig = Configuration.GetSection("jwtTokenConfig").Get<JwtTokenConfig>();
+
             services.AddDbContext<Tsi1Context>(x => x.UseNpgsql(Configuration.GetConnectionString(postgreSqlSection)));
 
             services.Configure<Tsi1DatabaseSettings>(
@@ -56,6 +62,13 @@ namespace Tsi1.Api
             services.AddSingleton<ITsi1DatabaseSettings>(sp =>
                 sp.GetRequiredService<IOptions<Tsi1DatabaseSettings>>().Value);
 
+            services.AddSingleton(jwtTokenConfig);
+
+            services.AddSingleton<IJwtAuthManager, JwtAuthManager>();
+            services.AddHostedService<JwtRefreshTokenCache>();
+            services.AddHostedService<JwtVerificationCodeCache>();
+
+
             services.AddSingleton<IMessageService, MessageService>();
 
             services.AddScoped<IUserService, UserService>();
@@ -65,14 +78,19 @@ namespace Tsi1.Api
             services.AddScoped<IPostService, PostService>();
             services.AddScoped<IPostMessageService, PostMessageService>();
             services.AddScoped<ITenantService, TenantService>();
+            services.AddScoped<IFileService, FileService>();
 
             services.Configure<MailSettings>(Configuration.GetSection("MailSettings"));
             services.AddScoped<IEmailService, EmailService>();
 
             services.AddCors();
 
-            var jwtTokenConfig = Configuration.GetSection("jwtTokenConfig").Get<JwtTokenConfig>();
-            services.AddSingleton(jwtTokenConfig);
+            services.AddAuthorization(options =>
+            {
+                options.FallbackPolicy = new AuthorizationPolicyBuilder()
+                    .RequireAuthenticatedUser()
+                    .Build();
+            });
 
             services.AddAuthentication(x =>
             {
@@ -112,9 +130,6 @@ namespace Tsi1.Api
                 };
             });
 
-            services.AddSingleton<IJwtAuthManager, JwtAuthManager>();
-            services.AddHostedService<JwtRefreshTokenCache>();
-
             services.AddSwaggerGen(c =>
             {
                 c.SwaggerDoc("v1", new OpenApiInfo { Title = "Tsi1 api", Version = "v1" });
@@ -145,7 +160,7 @@ namespace Tsi1.Api
                 mc.AddProfile(new MappingProfile());
             });
 
-            IMapper mapper = mappingConfig.CreateMapper();
+            var mapper = mappingConfig.CreateMapper();
             services.AddSingleton(mapper);
         }
 
@@ -172,10 +187,22 @@ namespace Tsi1.Api
             app.UseAuthentication();
             app.UseAuthorization();
 
+            var provider = new FileExtensionContentTypeProvider();
+            app.UseStaticFiles(new StaticFileOptions()
+            {
+                ContentTypeProvider = provider,
+                FileProvider = new PhysicalFileProvider(
+                     Path.Combine(env.ContentRootPath, "StaticFiles")),
+                RequestPath = "/static"
+            }
+            );
+
             app.UseEndpoints(endpoints =>
             {
                 endpoints.MapControllers();
                 endpoints.MapHub<VideoHub>("hubs/video");
+                endpoints.MapHub<PresenceHub>("hubs/presence");
+                endpoints.MapHub<ChatHub>("hubs/chat");
             });
         }
     }
diff --git a/Tsi1.Api/Tsi1.Api/Tsi1.Api.csproj b/Tsi1.Api/Tsi1.Api/Tsi1.Api.csproj
index 1ed4b443527a84acaf750eab3427ac11002a946a..7fa4dab4f5b7683e724fdac0596793f7c778db45 100644
--- a/Tsi1.Api/Tsi1.Api/Tsi1.Api.csproj
+++ b/Tsi1.Api/Tsi1.Api/Tsi1.Api.csproj
@@ -14,5 +14,9 @@
     <ProjectReference Include="..\Tsi1.BusinessLayer\Tsi1.BusinessLayer.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="StaticFiles\" />
+  </ItemGroup>
+
 
 </Project>
diff --git a/Tsi1.Api/Tsi1.Api/appsettings.json b/Tsi1.Api/Tsi1.Api/appsettings.json
index 45af97fda74df094689e136d9938c4e8affeab61..810e99c8b712f19dba9b1aa60a3397e8533f5881 100644
--- a/Tsi1.Api/Tsi1.Api/appsettings.json
+++ b/Tsi1.Api/Tsi1.Api/appsettings.json
@@ -14,12 +14,13 @@
     "ConnectionString": "mongodb://mongo:27017",
     "DatabaseName": "Tsi1Db"
   },
-  "jwtTokenConfig": {
-    "secret": "1234567890123456789",
-    "issuer": "https://localhost:5000",
-    "audience": "https://localhost:5000",
-    "accessTokenExpiration": 20,
-    "refreshTokenExpiration": 60
+  "JwtTokenConfig": {
+    "Secret": "1234567890123456789",
+    "Issuer": "https://localhost:5000",
+    "Audience": "https://localhost:5000",
+    "AccessTokenExpiration": 20,
+    "RefreshTokenExpiration": 60,
+    "VerificationCodeExpiration": 5
   },
   "MailSettings": {
     "Mail": "tsi1.grupo2.2020@gmail.com",
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CoursePreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CoursePreviewDto.cs
index de761a5eb908f333c2ceb7c394341f9febb165c8..c4a7e56fa3c89bcfbddfeb21ddf9156e329bcd93 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CoursePreviewDto.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/CoursePreviewDto.cs
@@ -8,5 +8,6 @@ namespace Tsi1.BusinessLayer.Dtos
     {
         public int Id { get; set; }
         public string Name { get; set; }
+        public int StudentQuantity { get; set; }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/FileDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/FileDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..977a0596daafe431f74776ab1dca5530a569655b
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/FileDto.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class FileDto
+    {
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+
+        public string Path { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/RestorePasswordDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/RestorePasswordDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b1e4c4d35789e8edc7413f1e4fe3e8eb245e4dfe
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/RestorePasswordDto.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class RestorePasswordDto
+    {
+        public string Password { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCourseDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCourseDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..549efe2b0f218f6bf7b989d7fc9c7318bf72e619
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantCourseDto.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class TenantCourseDto
+    {
+        public TenantCourseDto()
+        {
+            Courses = new List<CoursePreviewDto>();
+        }
+
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+
+        public List<CoursePreviewDto> Courses { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs
index 74b8300acafec93c16aac87e34da1af457055766..273d9f5b5deedc458ab30fdb2333a594a889f731 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/TenantPreviewDto.cs
@@ -9,5 +9,7 @@ namespace Tsi1.BusinessLayer.Dtos
         public int Id { get; set; }
 
         public string Name { get; set; }
+
+        public int StudentQuantity { get; set; }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserModifyDto.cs b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserModifyDto.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c3e9894b71f0a081a566e718800561479a75b076
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Dtos/UserModifyDto.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Dtos
+{
+    public class UserModifyDto
+    {
+        [Required]
+        public string Username { get; set; }
+
+        [Required]
+        public string Password { get; set; }
+
+        [Required]
+        public string FirstName { get; set; }
+
+        [Required]
+        public string LastName { get; set; }
+
+        [Required]
+        public string Email { get; set; }
+
+        [Required]
+        public string IdentityCard { get; set; }
+
+        public int Age { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
index 99c521a4d670fd66eb3eee6753c7b97c4afc902b..8dc7c9fb645af7ec4886187388f9ec2c5e662b8e 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/ErrorMessages.cs
@@ -10,10 +10,13 @@ namespace Tsi1.BusinessLayer.Helpers
         public const string IncorrectPassword = "Contraseña incorrecta";
         public const string UserTypeDoesNotExist = "El tipo de usuario con id '{0}' no existe";
         public const string StudentDoesNotExist = "El estudiante con Id de usuario: '{0}' no existe";
+        public const string StudentCourseDoesNotExists = "El estudiante '{0}' no se encuentra matriculado en el curso '{1}'";
         public const string StudentCourseAlreadyExists = "El estudiante '{0}' ya se encuentra matriculado en el curso '{1}'";
         public const string ProffesorDoesNotExist = "El profesor con Id de usuario: '{0}' no existe";
         public const string ProfessorCourseAlreadyExists = "El profesor '{0}' ya es docente del curso '{1}'";
+        public const string ProfessorCourseDoesNotExists = "El profesor '{0}' no es docente del curso '{1}'";
         public const string InvalidUsername = "El nombre de usuario debe ser de la forma: 'usuario@facultad'";
+        public const string DuplicateUsername = "Ya existe un usuario con username '{0}'";
 
 
         public const string ForumDoesNotExist = "El foro con id '{0}' no existe";
@@ -36,5 +39,8 @@ namespace Tsi1.BusinessLayer.Helpers
 
         public const string InvalidUserType = "Tipo de usuario invalido '{0}'";
 
+        public const string ErrorSavingFile = "No se pudo guardar el archivo '{0}'";
+        public const string ErrorDeletingFile = "No se pudo borrar el archivo '{0}'";
+        public const string DuplicateFile = "Ya existe el archivo '{0}'";
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs
index 5d666d16c6f9578c22a8c22b867329345ee444ae..00a67f4141fbdb357d1dc3552ed02951b200b20c 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/MappingProfile.cs
@@ -22,13 +22,16 @@ namespace Tsi1.BusinessLayer.Helpers
             CreateMap<Message, MessageCreateDto>();
             CreateMap<User, UserPreviewDto>();
             CreateMap<User, UserRegisterDto>();
+            CreateMap<User, UserModifyDto>();
             CreateMap<Student, StudentPreviewDto>();
             CreateMap<Professor, ProfessorPreviewDto>();
             CreateMap<Course, CourseCreateDto>();
             CreateMap<Course, CoursePreviewDto>();
             CreateMap<Tenant, TenantPreviewDto>();
             CreateMap<Tenant, TenantCreateDto>();
+            CreateMap<Tenant, TenantCourseDto>().ForMember(x => x.Courses, opt => opt.Ignore());
             CreateMap<UserType, UserTypeDto>();
+            CreateMap<File, FileDto>();
 
             CreateMap<ForumCreateDto, Forum>();
             CreateMap<ForumPreviewDto, Forum>();
@@ -40,13 +43,16 @@ namespace Tsi1.BusinessLayer.Helpers
             CreateMap<MessageCreateDto, Message>();
             CreateMap<UserPreviewDto, User>();
             CreateMap<UserRegisterDto, User>();
+            CreateMap<UserModifyDto, User>();
             CreateMap<StudentPreviewDto, Student>();
             CreateMap<ProfessorPreviewDto, Professor>();
             CreateMap<CourseCreateDto, Course>();
             CreateMap<CoursePreviewDto, Course>();
             CreateMap<TenantPreviewDto, Tenant>();
             CreateMap<TenantCreateDto, Tenant>();
+            CreateMap<TenantCourseDto, Tenant>();
             CreateMap<UserTypeDto, UserType>();
+            CreateMap<FileDto, File>();
         }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Helpers/TenantAdmin.cs b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/TenantAdmin.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4672c8518bed0f807b1b449625ee79209bc5dddb
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Helpers/TenantAdmin.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.BusinessLayer.Helpers
+{
+    public static class TenantAdmin
+    {
+        public const string Name = "admin";
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IChatService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IChatService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cf332b0a11d11b5b77f9058d9d1a95488293b9ea
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IChatService.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Helpers;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.BusinessLayer.Interfaces
+{
+    public interface IChatService
+    {
+        Task<Group> GetGroupByName(string groupName);
+
+        Task<ServiceResult<Group>> CreateGroup(Group group);
+
+        Task<bool> RemoveConnectionFromGroup(string connectionId);
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
index 082798fedb9a2cc7a9802f2266558a00e8111c8d..f13641f98f895d1f846b25bda95135e3a6b5be64 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ICourseService.cs
@@ -17,5 +17,15 @@ namespace Tsi1.BusinessLayer.Interfaces
         Task<ServiceResult<bool>> Matriculate(int userId, int courseId);
 
         Task<ServiceResult<bool>> AddProfessorToCourse(ProfessorCourseDto professorCourseDto);
+
+        Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId);
+
+        Task<ServiceResult<bool>> Modify(int courseId, CourseCreateDto courseDto);
+
+        Task<ServiceResult<Course>> Delete(int courseId);
+
+        Task<ServiceResult<bool>> DropOutFromCourse(int userId, int courseId);
+
+        Task<ServiceResult<bool>> RemoveProfessorToCourse(ProfessorCourseDto professorCourseDto);
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs
index a97ea5c312cf5448689c731402cf293ea49ebca4..3cafba23552d1fb40adb046cebae313398b60098 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IEmailService.cs
@@ -14,5 +14,7 @@ namespace Tsi1.BusinessLayer.Interfaces
         Task<ServiceResult<bool>> SendEmailAsync(MimeMessage message);
 
         Task<ServiceResult<bool>> NotifyNewPostOrMessage(PostCreateDto postCreateDto, List<string> mails);
+
+        public Task<ServiceResult<bool>> SendVerificationCode(string mail, int code);
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IFileService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IFileService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a42bbf693f410735a37715369574479ae29b6551
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IFileService.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Dtos;
+using Tsi1.BusinessLayer.Helpers;
+
+namespace Tsi1.BusinessLayer.Interfaces
+{
+    public interface IFileService
+    {
+        Task<ServiceResult<FileDto>> Create(IFormFile file, int tenantId, int courseId);
+
+        void CreateFolder(string folderPath);
+
+        void DeleteFolder(string folderPath);
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs
index 90bf95b9d814421c99c54eff4ff0a2e20885af0f..a1b88ed057e0435a0c6ff68901bdccd86d235ca4 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/ITenantService.cs
@@ -11,8 +11,18 @@ namespace Tsi1.BusinessLayer.Interfaces
     {
         Task<ServiceResult<int>> GetByName(string tenantName);
 
+        Task<ServiceResult<int>> GetById(int tenantId);
+
         Task<ServiceResult<List<TenantPreviewDto>>> GetAll();
 
         Task<ServiceResult<TenantPreviewDto>> Create(TenantCreateDto newTenant);
+
+        Task<ServiceResult<bool>> Modify(int tenantId, TenantCreateDto tenantDto);
+
+        Task<ServiceResult<bool>> Delete(int tenantId);
+
+        Task<ServiceResult<List<TenantPreviewDto>>> FacultyList();
+
+        Task<ServiceResult<List<TenantCourseDto>>> CourseList();
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
index 12444e66d7fe3e492bbcbdb8b0d7353730c89beb..54550814463757e24870ae34bb6b51a68217ce11 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Interfaces/IUserService.cs
@@ -17,5 +17,17 @@ namespace Tsi1.BusinessLayer.Interfaces
         Task<ServiceResult<List<UserPreviewDto>>> GetAll(int tenantId);
 
         Task<ServiceResult<UserPreviewDto>> GetById(int userId);
+
+        Task<ServiceResult<User>> GetByUsername(string username, int tenantId);
+
+        Task<ServiceResult<bool>> UpdatePassword(int userId, string password);
+
+        Task<ServiceResult<bool>> Modify(UserModifyDto dto, string type, int userId);
+
+        Task<ServiceResult<int>> GetTenant(int userId);
+
+        Task<ServiceResult<bool>> Delete(int userId);
+
+        Task<ServiceResult<UserTypeDto>> GetUserType(int userId);
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/ChatService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/ChatService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4e4ac8e76aaca0017a0d35dca73cd1e57503da3e
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/ChatService.cs
@@ -0,0 +1,60 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Helpers;
+using Tsi1.BusinessLayer.Interfaces;
+using Tsi1.DataLayer;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.BusinessLayer.Services
+{
+    public class ChatService : IChatService
+    {
+        private readonly Tsi1Context _tsi1Context;
+
+        public ChatService(Tsi1Context tsi1Context)
+        {
+            _tsi1Context = tsi1Context;
+        }
+        public async Task<ServiceResult<Group>> CreateGroup(Group group)
+        {
+            var result = new ServiceResult<Group>();
+
+            _tsi1Context.Groups.Add(group);
+            try
+            {
+                await _tsi1Context.SaveChangesAsync();
+            }
+            catch (Exception)
+            {
+                result.HasError = true;
+            }
+
+            return result;
+        }
+
+        public async Task<Group> GetGroupByName(string groupName)
+        {
+            var result = new ServiceResult<Group>();
+
+            var group = await _tsi1Context.Groups.FirstOrDefaultAsync(x => x.Name == groupName);
+
+            return group;
+        }
+
+        public async Task<bool> RemoveConnectionFromGroup(string connectionId)
+        {
+            var connection = await _tsi1Context.Connections.FirstOrDefaultAsync(x => x.ConnectionId == connectionId);
+
+            if (connection != null)
+            {
+                connection.Group = null;
+                await _tsi1Context.SaveChangesAsync();
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
index 4c1f4ceec956384a2df10f16c45ab66fb0f6cc8f..6930b541c7218a1262f4c772951d1d29ef787be3 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/CourseService.cs
@@ -41,7 +41,7 @@ namespace Tsi1.BusinessLayer.Services
             }
 
             var course = _mapper.Map<Course>(newCourse);
-                
+
             _context.Courses.Add(course);
 
             await _context.SaveChangesAsync();
@@ -97,7 +97,6 @@ namespace Tsi1.BusinessLayer.Services
 
             if (user == null || user.Student == null)
             {
-                result.HasError = true;
                 result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
                 return result;
             }
@@ -106,7 +105,6 @@ namespace Tsi1.BusinessLayer.Services
 
             if (course == null)
             {
-                result.HasError = true;
                 result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId);
                 return result;
             }
@@ -130,7 +128,9 @@ namespace Tsi1.BusinessLayer.Services
             _context.StudentCourses.Add(studentCourse);
           
             await _context.SaveChangesAsync();
-  
+
+            result.Data = true;
+
             return result;
         }
 
@@ -144,7 +144,6 @@ namespace Tsi1.BusinessLayer.Services
 
             if (user == null || user.Professor == null)
             {
-                result.HasError = true;
                 result.Message = string.Format(ErrorMessages.UserDoesNotExist, user.Username);
                 return result;
             }
@@ -154,7 +153,6 @@ namespace Tsi1.BusinessLayer.Services
 
             if (course == null)
             {
-                result.HasError = true;
                 result.Message = string.Format(ErrorMessages.CourseDoesNotExist, professorCourseDto.CourseId);
                 return result;
             }
@@ -179,6 +177,150 @@ namespace Tsi1.BusinessLayer.Services
 
             await _context.SaveChangesAsync();
 
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<List<CoursePreviewDto>>> GetAll(int tenantId)
+        {
+            var result = new ServiceResult<List<CoursePreviewDto>>();
+
+            var courses = await _context.Courses
+                .Where(x => x.TenantId == tenantId)
+                .ToListAsync();
+
+            var coursesDto = _mapper.Map<List<CoursePreviewDto>>(courses);
+
+            result.Data = coursesDto;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> Modify(int courseId, CourseCreateDto courseDto)
+        {
+            var result = new ServiceResult<bool>();
+
+            var course = await _context.Courses
+                .FirstOrDefaultAsync(x => x.Id == courseId);
+
+            if (course == null)
+            {
+                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId);
+                return result;
+            }
+
+            _mapper.Map(courseDto, course);
+          
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<Course>> Delete(int courseId)
+        {
+            var result = new ServiceResult<Course>();
+
+            var course = await _context.Courses
+                .FirstOrDefaultAsync(x => x.Id == courseId);
+
+            if (course == null)
+            {
+                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId);
+                return result;
+            }
+
+            _context.Courses.Remove(course);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = course;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> DropOutFromCourse(int userId, int courseId)
+        {
+            var result = new ServiceResult<bool>();
+
+            var user = await _context.Users
+                .Include(x => x.Student)
+                .FirstOrDefaultAsync(x => x.Id == userId);
+
+            if (user == null || user.Student == null)
+            {
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+                return result;
+            }
+
+            var course = await _context.Courses.FirstOrDefaultAsync(x => x.Id == courseId);
+
+            if (course == null)
+            {
+                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, courseId);
+                return result;
+            }
+
+            var studentCourse = await _context.StudentCourses
+                .FirstOrDefaultAsync(x => x.StudentId == user.StudentId && x.CourseId == course.Id);
+
+            if (studentCourse == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.StudentCourseDoesNotExists, user.Username, course.Name);
+                return result;
+            }
+
+            _context.StudentCourses.Remove(studentCourse);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> RemoveProfessorToCourse(ProfessorCourseDto professorCourseDto)
+        {
+            var result = new ServiceResult<bool>();
+
+            var user = await _context.Users
+                .Include(x => x.Professor)
+                .FirstOrDefaultAsync(x => x.Id == professorCourseDto.UserId);
+
+            if (user == null || user.Professor == null)
+            {
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, user.Username);
+                return result;
+            }
+
+            var course = await _context.Courses
+                .FirstOrDefaultAsync(x => x.Id == professorCourseDto.CourseId);
+
+            if (course == null)
+            {
+                result.Message = string.Format(ErrorMessages.CourseDoesNotExist, professorCourseDto.CourseId);
+                return result;
+            }
+
+            var professorCourse = await _context.ProfessorCourses
+                .FirstOrDefaultAsync(x => x.ProfessorId == user.ProfessorId && x.CourseId == course.Id);
+
+            if (professorCourse == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.ProfessorCourseDoesNotExists, user.Username, course.Name);
+                return result;
+            }
+
+            _context.ProfessorCourses.Remove(professorCourse);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
             return result;
         }
     }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs
index d00e398d81ef6e05d34547d90d87d5a6e11f7ffd..9519fc5b0cf3037535e101a866a297392b786825 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/EmailService.cs
@@ -86,9 +86,22 @@ namespace Tsi1.BusinessLayer.Services
             };
 
             var result = await SendEmailAsync(message);
-
             return result;
         }
 
+        public async Task<ServiceResult<bool>> SendVerificationCode(string mail, int code)
+        {
+            var message = new MimeMessage();
+
+            message.To.Add(MailboxAddress.Parse(mail));
+            message.Subject = "Código de verificación";
+            message.Body = new TextPart("html")
+            {
+                Text = $"<p>Su código de verificación es {code}</p>"
+            };
+
+            var result = await SendEmailAsync(message);
+            return result;
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/FileService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/FileService.cs
new file mode 100644
index 0000000000000000000000000000000000000000..315250148761311cbd020f1da7863798800a7793
--- /dev/null
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/FileService.cs
@@ -0,0 +1,139 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Tsi1.BusinessLayer.Dtos;
+using Tsi1.BusinessLayer.Helpers;
+using Tsi1.BusinessLayer.Interfaces;
+using Tsi1.DataLayer;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.BusinessLayer.Services
+{
+    public class FileService : IFileService
+    {
+        private readonly Tsi1Context _context;
+
+        private readonly IMapper _mapper;
+
+        private readonly string _path;
+
+        public FileService(Tsi1Context context, IMapper mapper, IHostingEnvironment hostingEnvironment)
+        {
+            _context = context;
+            _mapper = mapper;
+            _path = hostingEnvironment.ContentRootPath + "/StaticFiles";
+        }
+
+        public async Task<ServiceResult<string>> SaveFile(IFormFile file, string filePath)
+        {
+            var result = new ServiceResult<string>();
+
+            var fileStream = new FileStream(filePath, FileMode.Create);
+
+            try
+            {
+                await file.CopyToAsync(fileStream);
+            }
+            catch (Exception)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.ErrorSavingFile, filePath);
+                return result;
+            }
+            finally
+            {
+                fileStream.Close();
+            }
+
+            return result;
+        }
+
+       
+
+        public async Task<ServiceResult<FileDto>> Create(IFormFile file, int tenantId, int courseId)
+        {
+            var result = new ServiceResult<FileDto>();
+
+            var tenant = await _context.Tenants
+                .FirstOrDefaultAsync(x => x.Id == tenantId);
+
+            var course = await _context.Courses
+                .FirstOrDefaultAsync(x => x.Id == courseId);
+
+            var filePath = Path.Combine(_path, tenant.Name, course.Name, file.FileName);
+
+            var existingFile = await _context.Files.FirstOrDefaultAsync(x => x.Path == filePath);
+            if (existingFile != null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.DuplicateFile, filePath);
+                return result;
+            }
+
+            var newFile = new DataLayer.Entities.File
+            {
+                Name = file.FileName,
+                Path = filePath.Replace(_path, ""),
+            };
+
+            _context.Add(newFile);
+            await _context.SaveChangesAsync();
+
+            var resultSaveFile = await this.SaveFile(file, filePath);
+            if (resultSaveFile.HasError)
+            {
+                result.HasError = true;
+                result.Message = resultSaveFile.Message;
+
+                _context.Remove(newFile);
+                await _context.SaveChangesAsync();
+
+                return result;
+            }
+
+            var fileDto = _mapper.Map<FileDto>(newFile);
+            result.Data = fileDto;
+
+            return result;
+        }
+
+
+        public async Task<ServiceResult<bool>> DeleteFile(string filePath)
+        {
+            var result = new ServiceResult<bool>();
+            
+            try
+            {
+                using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) {}
+            }
+            catch (Exception)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.ErrorDeletingFile, filePath);
+                return result;
+            }
+
+            return result;
+        }
+
+        public void CreateFolder(string folderPath)
+        {
+            var path = Path.Combine(_path, folderPath);
+
+            Directory.CreateDirectory(path);
+        }
+
+        public void DeleteFolder(string folderPath)
+        {
+            var path = Path.Combine(_path, folderPath);
+
+            Directory.Delete(path);
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs
index c2659069a5eacd7516d4c4c6d49cf6dcb06d749a..17d6668ac6a2234260d9a64fb1007dcdeefa7437 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/TenantService.cs
@@ -1,7 +1,8 @@
-using AutoMapper;
+using AutoMapper;
 using Microsoft.EntityFrameworkCore;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using Tsi1.BusinessLayer.Dtos;
@@ -79,5 +80,119 @@ namespace Tsi1.BusinessLayer.Services
             return result;
         }
 
+        public async Task<ServiceResult<bool>> Modify(int tenantId, TenantCreateDto tenantDto)
+        {
+            var result = new ServiceResult<bool>();
+
+            var tenant = await _context.Tenants
+                .FirstOrDefaultAsync(x => x.Id == tenantId);
+
+            if (tenant == null)
+            {
+                result.Message = string.Format(ErrorMessages.TenantDoesNotExist, tenantId);
+                return result;
+            }
+
+            _mapper.Map(tenantDto, tenant);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> Delete(int tenantId)
+        {
+            var result = new ServiceResult<bool>();
+
+            var tenant = await _context.Tenants
+                .FirstOrDefaultAsync(x => x.Id == tenantId);
+
+            if (tenant == null)
+            {
+                result.Message = string.Format(ErrorMessages.TenantDoesNotExist, tenantId);
+                return result;
+            }
+
+            _context.Tenants.Remove(tenant);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<List<TenantPreviewDto>>> FacultyList()
+        {
+            var result = new ServiceResult<List<TenantPreviewDto>>();
+
+            var tenants = await _context.Tenants
+                .Include(x => x.Students)
+                .Where(x => x.Name != TenantAdmin.Name)
+                .ToListAsync();
+
+            var tenantDtos = new List<TenantPreviewDto>();
+            foreach (var tenant in tenants)
+            {
+                var tenantDto = _mapper.Map<TenantPreviewDto>(tenant);
+                tenantDto.StudentQuantity = tenant.Students.Count();
+
+                tenantDtos.Add(tenantDto);
+            }
+
+            result.Data = tenantDtos;
+            return result;
+        }
+
+        public async Task<ServiceResult<List<TenantCourseDto>>> CourseList()
+        {
+            var result = new ServiceResult<List<TenantCourseDto>>();
+
+            var tenants = await _context.Tenants
+                .Include(x => x.Courses)
+                    .ThenInclude(x => x.StudentCourses)
+                .Where(x => x.Name != TenantAdmin.Name)
+                .ToListAsync();
+
+            var tenantDtos = new List<TenantCourseDto>();
+            foreach (var tenant in tenants)
+            {
+                var tenantDto = _mapper.Map<TenantCourseDto>(tenant);
+
+                foreach (var course in tenant.Courses)
+                {
+                    var courseDto = _mapper.Map<CoursePreviewDto>(course);
+                    courseDto.StudentQuantity = course.StudentCourses.Count();
+
+                    tenantDto.Courses.Add(courseDto);
+                }
+
+                tenantDtos.Add(tenantDto);
+            }
+
+            result.Data = tenantDtos;
+            return result;
+        }
+
+        public async Task<ServiceResult<int>> GetById(int tenantId)
+        {
+            var result = new ServiceResult<int>();
+
+            var tenant = await _context.Tenants
+                .FirstOrDefaultAsync(x => x.Id == tenantId);
+
+            if (tenant == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.TenantDoesNotExist, tenantId);
+                return result;
+            }
+
+            result.Data = tenant.Id;
+
+            return result;
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
index 35b14f29c797130271be0d4adacb9190d0ffbc70..3a54107291fd41bd09bd26976997cfe64e3788e7 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserService.cs
@@ -57,6 +57,7 @@ namespace Tsi1.BusinessLayer.Services
             var result = new ServiceResult<User>();
 
             var user = _mapper.Map<User>(dto);
+
             user.TenantId = tenantId;
     
             if (type == UserTypes.Student)
@@ -85,6 +86,55 @@ namespace Tsi1.BusinessLayer.Services
             return result;
         }
 
+        public async Task<ServiceResult<bool>> Modify(UserModifyDto dto, string type, int userId)
+        {
+            var result = new ServiceResult<bool>();
+
+            var user = await _context.Users
+                .Include(x => x.Student)
+                .Include(x => x.Professor)
+                .FirstOrDefaultAsync(x => x.Id == userId);
+
+            if (user == null)
+            {
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+                return result;
+            }
+
+            if (dto.Username != user.Username)
+            {
+                var existingUser = await _context.Users
+                    .FirstOrDefaultAsync(x => x.Username == dto.Username 
+                        && x.TenantId == user.TenantId);
+
+                if (existingUser != null)
+                {
+                    result.HasError = true;
+                    result.Message = string.Format(ErrorMessages.DuplicateUsername, dto.Username);
+                    return result;
+                }
+            }
+
+            _mapper.Map(dto, user);
+
+            if (type == UserTypes.Student)
+            {
+                user.Student.IdentityCard = dto.IdentityCard;
+                user.Student.Age = dto.Age;
+            }
+
+            if (type == UserTypes.Professor)
+            {
+                user.Professor.IdentityCard = dto.IdentityCard;
+            }
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
         public async Task<ServiceResult<List<UserPreviewDto>>> GetAll(int tenantId)
         {
             var result = new ServiceResult<List<UserPreviewDto>>();
@@ -138,5 +188,119 @@ namespace Tsi1.BusinessLayer.Services
 
             return result;
         }
+
+        public async Task<ServiceResult<User>> GetByUsername(string username, int tenantId)
+        {
+            var result = new ServiceResult<User>();
+
+            var user = await _context.Users
+                .Include(x => x.UserType)
+                .Include(x => x.Student)
+                .Include(x => x.Professor)
+                .Where(x => x.TenantId == tenantId
+                    && x.Username == username)
+                .FirstOrDefaultAsync();
+
+            if (user == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, username);
+                return result;
+            }
+
+            var userType = user.UserType.Name;
+
+            if (userType == UserTypes.Student && user.Student == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.StudentDoesNotExist, username);
+                return result;
+            }
+            else if (userType == UserTypes.Professor && user.Professor == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.ProffesorDoesNotExist, username);
+                return result;
+            }
+
+            result.Data = user;
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> UpdatePassword(int userId, string password)
+        {
+            var result = new ServiceResult<bool>();
+            var user = await _context.Users.FirstOrDefaultAsync();
+
+            if (user == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+                return result;
+            }
+
+            user.Password = password;
+            await _context.SaveChangesAsync();
+
+            return result;
+        }
+
+        public async Task<ServiceResult<int>> GetTenant(int userId)
+        {
+            var result = new ServiceResult<int>();
+
+            var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId);
+
+            if (user == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+                return result;
+            }
+
+            result.Data = user.TenantId;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<bool>> Delete(int userId)
+        {
+            var result = new ServiceResult<bool>();
+
+            var user = await _context.Users.FirstOrDefaultAsync(x => x.Id == userId);
+
+            if (user == null)
+            {
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+                return result;
+            }
+
+            _context.Users.Remove(user);
+
+            await _context.SaveChangesAsync();
+
+            result.Data = true;
+
+            return result;
+        }
+
+        public async Task<ServiceResult<UserTypeDto>> GetUserType(int userId)
+        {
+            var result = new ServiceResult<UserTypeDto>();
+
+            var user = await _context.Users
+                .Include(x => x.UserType)
+                .FirstOrDefaultAsync(x => x.Id == userId);
+
+            if (user == null)
+            {
+                result.HasError = true;
+                result.Message = string.Format(ErrorMessages.UserDoesNotExist, userId);
+            }
+
+            result.Data = _mapper.Map<UserTypeDto>(user.UserType);
+
+            return result;
+        }
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserTypeService.cs b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserTypeService.cs
index e11f550b6dd13589a7379b8579efa715632b989b..be8f6786758d37071c7db5025954e0e9fa1c6673 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Services/UserTypeService.cs
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Services/UserTypeService.cs
@@ -67,6 +67,5 @@ namespace Tsi1.BusinessLayer.Services
 
             return result;
         }
-
     }
 }
diff --git a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
index a21bff7c2af2796490606eab2c96c0b6c51598ae..a18735ed0c8c52887e85611f1b353106330f869f 100644
--- a/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
+++ b/Tsi1.Api/Tsi1.BusinessLayer/Tsi1.BusinessLayer.csproj
@@ -8,6 +8,8 @@
     <PackageReference Include="AutoMapper" Version="10.1.1" />
     <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
     <PackageReference Include="MailKit" Version="2.9.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Http.Features" Version="3.1.9" />
     <PackageReference Include="MimeKit" Version="2.9.2" />
   </ItemGroup>
 
diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Connection.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Connection.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2e2e9366bdd5dd35d36650f805c1672806f08f69
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Connection.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.DataLayer.Entities
+{
+    public class Connection
+    {
+        public string ConnectionId { get; set; }
+        public int UserId { get; set; }
+        public Group Group { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/File.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/File.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4643d9c27c0f79917b66a41b0bff4435b6cfdc21
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Entities/File.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.DataLayer.Entities
+{
+    public class File
+    {
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+
+        public string Path { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Entities/Group.cs b/Tsi1.Api/Tsi1.DataLayer/Entities/Group.cs
new file mode 100644
index 0000000000000000000000000000000000000000..38291ebfd52def7d9d2e21d177a72fc191b7129c
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Entities/Group.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tsi1.DataLayer.Entities
+{
+    public class Group
+    {
+        public Group()
+        {
+            Connections = new List<Connection>();
+        }
+
+        public string Name { get; set; }
+        public ICollection<Connection> Connections { get; set; }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ConnectionConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ConnectionConfiguration.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7c085f952b6ad8859207d0eb4371c69d0edb2301
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/ConnectionConfiguration.cs
@@ -0,0 +1,24 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.DataLayer.EntityConfiguration
+{
+    public class ConnectionConfiguration : IEntityTypeConfiguration<Connection>
+    {
+        public void Configure(EntityTypeBuilder<Connection> builder)
+        {
+            builder.HasKey(x => x.ConnectionId);
+
+            builder.Property(x => x.UserId)
+                .IsRequired();
+
+            builder.HasOne(x => x.Group)
+                .WithMany(x => x.Connections);
+
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/FileConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/FileConfiguration.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ee21323fe9a845cfc5d780b24877022c0b09b2c2
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/FileConfiguration.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.DataLayer.EntityConfiguration
+{
+    public class FileConfiguration : IEntityTypeConfiguration<File>
+    {
+        public void Configure(EntityTypeBuilder<File> builder)
+        {
+            builder.HasKey(x => x.Id);
+
+            builder.Property(x => x.Name)
+                .IsRequired()
+                .HasColumnType("character varying(50)");
+
+            builder.Property(x => x.Path)
+                .IsRequired()
+                .HasColumnType("character varying(1000)");
+
+            builder.HasIndex(x => x.Path)
+                .IsUnique();
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/GroupConfiguration.cs b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/GroupConfiguration.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e64b95e6eb1fca0fff085e53679025dfa95728a
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/EntityConfiguration/GroupConfiguration.cs
@@ -0,0 +1,17 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Tsi1.DataLayer.Entities;
+
+namespace Tsi1.DataLayer.EntityConfiguration
+{
+    public class GroupConfiguration : IEntityTypeConfiguration<Group>
+    {
+        public void Configure(EntityTypeBuilder<Group> builder)
+        {
+            builder.HasKey(x => x.Name);
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5dba9e6375b1de286038bffe7e78d016f6cdd791
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.Designer.cs
@@ -0,0 +1,491 @@
+// <auto-generated />
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Tsi1.DataLayer;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    [DbContext(typeof(Tsi1Context))]
+    [Migration("20201029004502_added-entities-Group-and-Connection")]
+    partial class addedentitiesGroupandConnection
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
+                .HasAnnotation("ProductVersion", "3.1.4")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b =>
+                {
+                    b.Property<string>("ConnectionId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("GroupName")
+                        .HasColumnType("text");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ConnectionId");
+
+                    b.HasIndex("GroupName");
+
+                    b.ToTable("Connections");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("Name", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Courses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CourseId", "Name")
+                        .IsUnique();
+
+                    b.ToTable("Forums");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ForumId", "UserId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("ForumUsers");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Group", b =>
+                {
+                    b.Property<string>("Name")
+                        .HasColumnType("text");
+
+                    b.HasKey("Name");
+
+                    b.ToTable("Groups");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("character varying(100)");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.HasIndex("ForumId", "Title")
+                        .IsUnique();
+
+                    b.ToTable("Posts");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Content")
+                        .IsRequired()
+                        .HasColumnType("character varying(10485760)");
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("PostId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("PostId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("PostMessages");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Professors");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.Property<int>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ProfessorId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("ProfessorCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("Age")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Students");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.Property<int>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("StudentId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("StudentCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Tenant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("Tenants");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Email")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("FirstName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("LastName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<int?>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserTypeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Username")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ProfessorId")
+                        .IsUnique();
+
+                    b.HasIndex("StudentId")
+                        .IsUnique();
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("UserTypeId");
+
+                    b.HasIndex("Username", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.UserType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("UserTypes");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Group", "Group")
+                        .WithMany("Connections")
+                        .HasForeignKey("GroupName");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Courses")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("Forums")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("Posts")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("Posts")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Post", "Post")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("PostId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Professors")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("ProfessorId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Students")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("StudentId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "ProfessorId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "StudentId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Users")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.UserType", "UserType")
+                        .WithMany()
+                        .HasForeignKey("UserTypeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dfece7bb6d2fa79e3edd1afe268602d00477a253
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201029004502_added-entities-Group-and-Connection.cs
@@ -0,0 +1,54 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    public partial class addedentitiesGroupandConnection : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "Groups",
+                columns: table => new
+                {
+                    Name = table.Column<string>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Groups", x => x.Name);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "Connections",
+                columns: table => new
+                {
+                    ConnectionId = table.Column<string>(nullable: false),
+                    UserId = table.Column<int>(nullable: false),
+                    GroupName = table.Column<string>(nullable: true)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Connections", x => x.ConnectionId);
+                    table.ForeignKey(
+                        name: "FK_Connections_Groups_GroupName",
+                        column: x => x.GroupName,
+                        principalTable: "Groups",
+                        principalColumn: "Name",
+                        onDelete: ReferentialAction.Restrict);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_Connections_GroupName",
+                table: "Connections",
+                column: "GroupName");
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "Connections");
+
+            migrationBuilder.DropTable(
+                name: "Groups");
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..13074745a6636f6ee5f1fb3231bbc45b2c8aada6
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.Designer.cs
@@ -0,0 +1,479 @@
+// <auto-generated />
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Tsi1.DataLayer;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    [DbContext(typeof(Tsi1Context))]
+    [Migration("20201101163611_add-File-entity")]
+    partial class addFileentity
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
+                .HasAnnotation("ProductVersion", "3.1.4")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("Name", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Courses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.File", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Path")
+                        .IsRequired()
+                        .HasColumnType("character varying(100)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Path")
+                        .IsUnique();
+
+                    b.ToTable("Files");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CourseId", "Name")
+                        .IsUnique();
+
+                    b.ToTable("Forums");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ForumId", "UserId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("ForumUsers");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("character varying(100)");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.HasIndex("ForumId", "Title")
+                        .IsUnique();
+
+                    b.ToTable("Posts");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Content")
+                        .IsRequired()
+                        .HasColumnType("character varying(10485760)");
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("PostId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("PostId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("PostMessages");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Professors");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.Property<int>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ProfessorId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("ProfessorCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("Age")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Students");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.Property<int>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("StudentId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("StudentCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Tenant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("Tenants");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Email")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("FirstName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("LastName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<int?>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserTypeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Username")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ProfessorId")
+                        .IsUnique();
+
+                    b.HasIndex("StudentId")
+                        .IsUnique();
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("UserTypeId");
+
+                    b.HasIndex("Username", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.UserType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("UserTypes");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Courses")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("Forums")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("Posts")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("Posts")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Post", "Post")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("PostId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Professors")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("ProfessorId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Students")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("StudentId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "ProfessorId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "StudentId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Users")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.UserType", "UserType")
+                        .WithMany()
+                        .HasForeignKey("UserTypeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ace7d115279d1651eb0cfa5bc55035751cda87a2
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101163611_add-File-entity.cs
@@ -0,0 +1,37 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    public partial class addFileentity : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "Files",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
+                    Name = table.Column<string>(type: "character varying(50)", nullable: false),
+                    Path = table.Column<string>(type: "character varying(100)", nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Files", x => x.Id);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_Files_Path",
+                table: "Files",
+                column: "Path",
+                unique: true);
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "Files");
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.Designer.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..44695b906c006a5365bb3a1ea89a00e5d0b5425c
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.Designer.cs
@@ -0,0 +1,479 @@
+// <auto-generated />
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Tsi1.DataLayer;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    [DbContext(typeof(Tsi1Context))]
+    [Migration("20201101164258_change-File-Path-Property")]
+    partial class changeFilePathProperty
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
+                .HasAnnotation("ProductVersion", "3.1.4")
+                .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("Name", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Courses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.File", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Path")
+                        .IsRequired()
+                        .HasColumnType("character varying(1000)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Path")
+                        .IsUnique();
+
+                    b.ToTable("Files");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CourseId", "Name")
+                        .IsUnique();
+
+                    b.ToTable("Forums");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ForumId", "UserId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("ForumUsers");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("ForumId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Title")
+                        .IsRequired()
+                        .HasColumnType("character varying(100)");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.HasIndex("ForumId", "Title")
+                        .IsUnique();
+
+                    b.ToTable("Posts");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Content")
+                        .IsRequired()
+                        .HasColumnType("character varying(10485760)");
+
+                    b.Property<DateTime>("Date")
+                        .HasColumnType("timestamp without time zone");
+
+                    b.Property<int>("PostId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("PostId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("PostMessages");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Professors");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.Property<int>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ProfessorId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("ProfessorCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<int>("Age")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("IdentityCard")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("IdentityCard", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Students");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.Property<int>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("CourseId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("StudentId", "CourseId");
+
+                    b.HasIndex("CourseId");
+
+                    b.ToTable("StudentCourses");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Tenant", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("Tenants");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Email")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("FirstName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("LastName")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<string>("Password")
+                        .IsRequired()
+                        .HasColumnType("character varying(255)");
+
+                    b.Property<int?>("ProfessorId")
+                        .HasColumnType("integer");
+
+                    b.Property<int?>("StudentId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("TenantId")
+                        .HasColumnType("integer");
+
+                    b.Property<int>("UserTypeId")
+                        .HasColumnType("integer");
+
+                    b.Property<string>("Username")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ProfessorId")
+                        .IsUnique();
+
+                    b.HasIndex("StudentId")
+                        .IsUnique();
+
+                    b.HasIndex("TenantId");
+
+                    b.HasIndex("UserTypeId");
+
+                    b.HasIndex("Username", "TenantId")
+                        .IsUnique();
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.UserType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("UserTypes");
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Courses")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("Forums")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ForumUser", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("ForumUsers")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Forum", "Forum")
+                        .WithMany("Posts")
+                        .HasForeignKey("ForumId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("Posts")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.PostMessage", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Post", "Post")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("PostId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.User", "User")
+                        .WithMany("PostMessages")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Professors")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithMany("ProfessorCourses")
+                        .HasForeignKey("ProfessorId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Students")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("CourseId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithMany("StudentCourses")
+                        .HasForeignKey("StudentId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "ProfessorId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
+                        .WithOne("User")
+                        .HasForeignKey("Tsi1.DataLayer.Entities.User", "StudentId");
+
+                    b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
+                        .WithMany("Users")
+                        .HasForeignKey("TenantId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+
+                    b.HasOne("Tsi1.DataLayer.Entities.UserType", "UserType")
+                        .WithMany()
+                        .HasForeignKey("UserTypeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a348b6798398c41cc70117d6a0f4594c06784eee
--- /dev/null
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/20201101164258_change-File-Path-Property.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Tsi1.DataLayer.Migrations
+{
+    public partial class changeFilePathProperty : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AlterColumn<string>(
+                name: "Path",
+                table: "Files",
+                type: "character varying(1000)",
+                nullable: false,
+                oldClrType: typeof(string),
+                oldType: "character varying(100)");
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AlterColumn<string>(
+                name: "Path",
+                table: "Files",
+                type: "character varying(100)",
+                nullable: false,
+                oldClrType: typeof(string),
+                oldType: "character varying(1000)");
+        }
+    }
+}
diff --git a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
index ad82bacaa2af11e43014e891983a77d56bc0255b..9f2b80da778b9cfc5bb392f6faa481cab6f4eea7 100644
--- a/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
+++ b/Tsi1.Api/Tsi1.DataLayer/Migrations/Tsi1ContextModelSnapshot.cs
@@ -19,6 +19,24 @@ namespace Tsi1.DataLayer.Migrations
                 .HasAnnotation("ProductVersion", "3.1.4")
                 .HasAnnotation("Relational:MaxIdentifierLength", 63);
 
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b =>
+                {
+                    b.Property<string>("ConnectionId")
+                        .HasColumnType("text");
+
+                    b.Property<string>("GroupName")
+                        .HasColumnType("text");
+
+                    b.Property<int>("UserId")
+                        .HasColumnType("integer");
+
+                    b.HasKey("ConnectionId");
+
+                    b.HasIndex("GroupName");
+
+                    b.ToTable("Connections");
+                });
+
             modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
                 {
                     b.Property<int>("Id")
@@ -43,6 +61,29 @@ namespace Tsi1.DataLayer.Migrations
                     b.ToTable("Courses");
                 });
 
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.File", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("integer")
+                        .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("character varying(50)");
+
+                    b.Property<string>("Path")
+                        .IsRequired()
+                        .HasColumnType("character varying(1000)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Path")
+                        .IsUnique();
+
+                    b.ToTable("Files");
+                });
+
             modelBuilder.Entity("Tsi1.DataLayer.Entities.Forum", b =>
                 {
                     b.Property<int>("Id")
@@ -80,6 +121,16 @@ namespace Tsi1.DataLayer.Migrations
                     b.ToTable("ForumUsers");
                 });
 
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Group", b =>
+                {
+                    b.Property<string>("Name")
+                        .HasColumnType("text");
+
+                    b.HasKey("Name");
+
+                    b.ToTable("Groups");
+                });
+
             modelBuilder.Entity("Tsi1.DataLayer.Entities.Post", b =>
                 {
                     b.Property<int>("Id")
@@ -315,6 +366,13 @@ namespace Tsi1.DataLayer.Migrations
                     b.ToTable("UserTypes");
                 });
 
+            modelBuilder.Entity("Tsi1.DataLayer.Entities.Connection", b =>
+                {
+                    b.HasOne("Tsi1.DataLayer.Entities.Group", "Group")
+                        .WithMany("Connections")
+                        .HasForeignKey("GroupName");
+                });
+
             modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
                 {
                     b.HasOne("Tsi1.DataLayer.Entities.Tenant", "Tenant")
diff --git a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs
index c9fb14f74a1844a4fdc09fb7a9dea866975c2430..d442517b50b82f0ebd6f86812ac69f463cd16239 100644
--- a/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs
+++ b/Tsi1.Api/Tsi1.DataLayer/Tsi1Context.cs
@@ -21,6 +21,9 @@ namespace Tsi1.DataLayer
         public DbSet<PostMessage> PostMessages { get; set; }
         public DbSet<Tenant> Tenants { get; set; }
         public DbSet<ForumUser> ForumUsers { get; set; }
+        public DbSet<Group> Groups { get; set; }
+        public DbSet<Connection> Connections { get; set; }
+        public DbSet<File> Files { get; set; }
 
 
         public Tsi1Context(DbContextOptions options) : base(options) { }
@@ -39,6 +42,9 @@ namespace Tsi1.DataLayer
             modelBuilder.ApplyConfiguration(new PostMessageConfiguration());
             modelBuilder.ApplyConfiguration(new TenantConfiguration());
             modelBuilder.ApplyConfiguration(new ForumUserConfiguration());
+            modelBuilder.ApplyConfiguration(new GroupConfiguration());
+            modelBuilder.ApplyConfiguration(new ConnectionConfiguration());
+            modelBuilder.ApplyConfiguration(new FileConfiguration());
         }
     }
 }