diff --git a/src/ClientServer/Config/AppConfiguration.cs b/src/ClientServer/Config/AppConfiguration.cs
index 7917e82d42139a6f971fe671cd55c1bf2bbaf3d1..11f14d4c7ffbd8afdfc4da5d4b99aba45c6cc94d 100644
--- a/src/ClientServer/Config/AppConfiguration.cs
+++ b/src/ClientServer/Config/AppConfiguration.cs
@@ -152,6 +152,18 @@ namespace ClientServer.Helpers
 
         //5 mb?
         public static long MaxUploadFileSizeInByte = 1024 * 1024 * 5;
+
+        /// <summary>
+        /// the <see cref="TestServerTraceLogWorker"/> executes every X minutes where X is this value
+        /// </summary>
+        public static int TestServerTraceLogWorkerIntervalInMinutes = 60 * 24; //1 day
+
+        /// <summary>
+        /// delete trace logs on the test server that are older than this in minues
+        /// </summary>
+        public static int TestServerTraceLogDeleteTraceLogOlderThanMinutes = 60 * 24 * 15; // 14 days
+        
+        public static int TestServerTraceLogDeleteTraceLogTimeoutInMs = 1000 * 60; //60s
         
         
         //--- methods ---
@@ -383,6 +395,44 @@ namespace ClientServer.Helpers
                     overwriteCount++;
                 }
             }
+            
+            if (string.IsNullOrWhiteSpace(ConfigurationRoot[Constants.TestServerTraceLogWorkerIntervalInMinutesKey]) == false)
+            {
+                var temp = ConfigurationRoot[Constants.TestServerTraceLogWorkerIntervalInMinutesKey];
+                int tempValue;
+                if (int.TryParse(temp, out tempValue))
+                {
+                    //keep the setting
+                    AppConfiguration.TestServerTraceLogWorkerIntervalInMinutes = tempValue;
+                    overwriteCount++;
+                }
+            }
+            
+            if (string.IsNullOrWhiteSpace(ConfigurationRoot[Constants.TestServerTraceLogDeleteTraceLogOlderThanMinutesKey]) == false)
+            {
+                var temp = ConfigurationRoot[Constants.TestServerTraceLogDeleteTraceLogOlderThanMinutesKey];
+                int tempValue;
+                if (int.TryParse(temp, out tempValue))
+                {
+                    //keep the setting
+                    AppConfiguration.TestServerTraceLogDeleteTraceLogOlderThanMinutes = tempValue;
+                    overwriteCount++;
+                }
+            }
+            
+            if (string.IsNullOrWhiteSpace(ConfigurationRoot[Constants.TestServerTraceLogDeleteTraceLogTimeoutInSecondsKey]) == false)
+            {
+                var temp = ConfigurationRoot[Constants.TestServerTraceLogDeleteTraceLogTimeoutInSecondsKey];
+                int tempValue;
+                if (int.TryParse(temp, out tempValue))
+                {
+                    //keep the setting
+                    AppConfiguration.TestServerTraceLogDeleteTraceLogTimeoutInMs = tempValue;
+                    overwriteCount++;
+                }
+            }
+            
+            
 
             Console.WriteLine($"[INFO] {overwriteCount} app settings overwritten by appsettings.json");
         }
diff --git a/src/ClientServer/Config/Constants.cs b/src/ClientServer/Config/Constants.cs
index f331451ea8556a50b26718d9fe7e0c04fa65a9f2..d1aae06d1f757df43e22d11149b8abecf1fe5d51 100644
--- a/src/ClientServer/Config/Constants.cs
+++ b/src/ClientServer/Config/Constants.cs
@@ -13,7 +13,7 @@ namespace ClientServer.Helpers
     /// </summary>
     public static class Constants
     {
-        public static string VersionString = "2.5.12";
+        public static string VersionString = "2.6.0";
 
         /// <summary>
         /// this is only set once at program.cs!!
@@ -204,9 +204,10 @@ namespace ClientServer.Helpers
         
         public static string MaxUploadFileSizeInByteKey = "MaxUploadFileSizeInByte";
         
-        
-        
-        
+
+        public  static string TestServerTraceLogWorkerIntervalInMinutesKey = "TestServerTraceLogWorkerIntervalInMinutes";
+        public  static string TestServerTraceLogDeleteTraceLogOlderThanMinutesKey = "TestServerTraceLogDeleteTraceLogOlderThanMinutes";
+        public static string TestServerTraceLogDeleteTraceLogTimeoutInSecondsKey = "TestServerTraceLogDeleteTraceLogTimeoutInSecondsKey";
         
         
         //--- some core constants ---
diff --git a/src/ClientServer/Config/InitialSystemSettings.cs b/src/ClientServer/Config/InitialSystemSettings.cs
index 32a34b609a3fb84ebba70354a260edd70ee43b26..99878fd0eec3f5fddfcca43acd30ca74a172d47d 100644
--- a/src/ClientServer/Config/InitialSystemSettings.cs
+++ b/src/ClientServer/Config/InitialSystemSettings.cs
@@ -40,6 +40,11 @@ namespace ClientServer.Helpers
         /// the test server stats url
         /// </summary>
         public static string TestServerStatsUrl = "http://localhost:8003/stats/";
+        
+        /// <summary>
+        /// the submit test server stats url
+        /// </summary>
+        public static string SubmitTestServerStatsUrl = "http://localhost:8003/stats/";
 
         /// <summary>
         /// the submit test server url, used to run submit tests
@@ -50,6 +55,11 @@ namespace ClientServer.Helpers
         /// the url to the ui to configure the test server
         /// </summary>
         public static string TestServerConfigUiUrl = "http://localhost:8000";
+        
+        /// <summary>
+        /// the url to the ui to configure the submit test server
+        /// </summary>
+        public static string SubmitTestServerConfigUiUrl = "http://localhost:8000";
 
         /// <summary>
         ///  the timeout in ms to wait for a response from the test server before returning a testserver connection error
@@ -117,6 +127,11 @@ namespace ClientServer.Helpers
         /// </summary>
         public static int CustomProjectTestMaxDiskSpaceInKb = 1000;
 
+        /// <summary>
+        /// the initial test server trace log api url
+        /// </summary>
+        public static string TestServerTraceLogApiUrl = "http://localhost:8003/worker/traceLog.php";
+
 
         //--- these cannot be used because the default role could have changed and deleted so this is would be invalid...
         
diff --git a/src/ClientServer/Controllers/Core/SystemSettingsController.cs b/src/ClientServer/Controllers/Core/SystemSettingsController.cs
index 2956a9b2d6510ca0be59b761e2304ecfdd6bfe59..1156f4c3a7dad59c35aca1624a9961578dca62a1 100644
--- a/src/ClientServer/Controllers/Core/SystemSettingsController.cs
+++ b/src/ClientServer/Controllers/Core/SystemSettingsController.cs
@@ -72,11 +72,13 @@ namespace ClientServer.Controllers.Core
                 CurrentServerMessage = systemSettings.CurrentServerMessage,
                 SubmitTestServerTimeoutInMs = systemSettings.SubmitTestServerTimeoutInMs,
                 TestServerStatsUrl = systemSettings.TestServerStatsUrl,
+                SubmitTestServerStatsUrl = systemSettings.SubmitTestServerStatsUrl,
                 TestServerTimeoutInMs = systemSettings.TestServerTimeoutInMs,
                 MaxCustomTestsPerParticipation = systemSettings.MaxCustomTestsPerParticipation,
                 TestServerUrl = systemSettings.TestServerUrl,
                 SubmitTestServerUrl = systemSettings.SubmitTestServerUrl,
                 TestServerConfigUiUrl = systemSettings.TestServerConfigUiUrl,
+                SubmitTestServerConfigUiUrl = systemSettings.SubmitTestServerConfigUiUrl,
                 MaxCustomProjectsPerUser = systemSettings.MaxCustomProjectsPerUser,
                 MaxNumberOfTestsWithOneRequest = systemSettings.MaxNumberOfTestsWithOneRequest,
                 MaxNumberOfTestsWithOneRequestSubmitTestServer =
@@ -91,7 +93,8 @@ namespace ClientServer.Controllers.Core
                 CustomProjectTestMaxDiskSpaceInKb = systemSettings.CustomProjectTestMaxDiskSpaceInKb,
                 DefaultGroupRoleId = systemSettings.DefaultGroupRoleId,
                 DefaultUserGroupId = systemSettings.DefaultUserGroupId,
-                DefaultGroupCreatorGroupRoleId = systemSettings.DefaultGroupCreatorGroupRoleId
+                DefaultGroupCreatorGroupRoleId = systemSettings.DefaultGroupCreatorGroupRoleId,
+                TestServerTraceLogApiUrl = systemSettings.TestServerTraceLogApiUrl,
             };
         }
 
@@ -182,11 +185,13 @@ namespace ClientServer.Controllers.Core
                 CurrentServerMessage = InitialSystemSettings.CurrentServerMessage,
                 SubmitTestServerTimeoutInMs = InitialSystemSettings.SubmitTestServerTimeoutInMs,
                 TestServerStatsUrl = InitialSystemSettings.TestServerStatsUrl,
+                SubmitTestServerStatsUrl = InitialSystemSettings.SubmitTestServerStatsUrl,
                 TestServerTimeoutInMs = InitialSystemSettings.TestServerTimeoutInMs,
                 MaxCustomTestsPerParticipation = InitialSystemSettings.MaxCustomTestsPerParticipation,
                 TestServerUrl = InitialSystemSettings.TestServerUrl,
                 SubmitTestServerUrl = InitialSystemSettings.SubmitTestServerUrl,
                 TestServerConfigUiUrl = InitialSystemSettings.TestServerConfigUiUrl,
+                SubmitTestServerConfigUiUrl = InitialSystemSettings.SubmitTestServerConfigUiUrl,
                 MaxCustomProjectsPerUser = InitialSystemSettings.MaxCustomProjectsPerUser,
                 MaxNumberOfTestsWithOneRequest = InitialSystemSettings.MaxNumberOfTestsWithOneRequest,
                 MaxNumberOfTestsWithOneRequestSubmitTestServer =
@@ -202,7 +207,8 @@ namespace ClientServer.Controllers.Core
                 //the default group could be changed and deleted so this could be invalid
                 DefaultGroupRoleId = -1,
                 DefaultUserGroupId = -1,
-                DefaultGroupCreatorGroupRoleId = -1
+                DefaultGroupCreatorGroupRoleId = -1,
+                TestServerTraceLogApiUrl = InitialSystemSettings.TestServerTraceLogApiUrl
             };
 
             await
@@ -272,10 +278,12 @@ namespace ClientServer.Controllers.Core
             oldSystemSettings.CurrentServerMessage = systemSettings.CurrentServerMessage;
             oldSystemSettings.SubmitTestServerTimeoutInMs = systemSettings.SubmitTestServerTimeoutInMs;
             oldSystemSettings.TestServerStatsUrl = systemSettings.TestServerStatsUrl;
+            oldSystemSettings.SubmitTestServerStatsUrl = systemSettings.SubmitTestServerStatsUrl;
             oldSystemSettings.TestServerTimeoutInMs = systemSettings.TestServerTimeoutInMs;
             oldSystemSettings.MaxCustomTestsPerParticipation = systemSettings.MaxCustomTestsPerParticipation;
             oldSystemSettings.TestServerUrl = systemSettings.TestServerUrl;
             oldSystemSettings.TestServerConfigUiUrl = systemSettings.TestServerConfigUiUrl;
+            oldSystemSettings.SubmitTestServerConfigUiUrl = systemSettings.SubmitTestServerConfigUiUrl;
             oldSystemSettings.SubmitTestServerUrl = systemSettings.SubmitTestServerUrl;
             oldSystemSettings.MaxCustomProjectsPerUser = systemSettings.MaxCustomProjectsPerUser;
             oldSystemSettings.MaxNumberOfTestsWithOneRequest = systemSettings.MaxNumberOfTestsWithOneRequest;
@@ -295,6 +303,7 @@ namespace ClientServer.Controllers.Core
             oldSystemSettings.DefaultGroupRoleId = systemSettings.DefaultGroupRoleId;
             oldSystemSettings.DefaultUserGroupId = systemSettings.DefaultUserGroupId;
             oldSystemSettings.DefaultGroupCreatorGroupRoleId = systemSettings.DefaultGroupCreatorGroupRoleId;
+            oldSystemSettings.TestServerTraceLogApiUrl = systemSettings.TestServerTraceLogApiUrl;
 
             try
             {
@@ -311,11 +320,13 @@ namespace ClientServer.Controllers.Core
                 CurrentServerMessage = oldSystemSettings.CurrentServerMessage,
                 SubmitTestServerTimeoutInMs = oldSystemSettings.SubmitTestServerTimeoutInMs,
                 TestServerStatsUrl = oldSystemSettings.TestServerStatsUrl,
+                SubmitTestServerStatsUrl = oldSystemSettings.SubmitTestServerStatsUrl,
                 TestServerTimeoutInMs = oldSystemSettings.TestServerTimeoutInMs,
                 MaxCustomTestsPerParticipation = oldSystemSettings.MaxCustomTestsPerParticipation,
                 TestServerUrl = oldSystemSettings.TestServerUrl,
                 SubmitTestServerUrl = oldSystemSettings.SubmitTestServerUrl,
                 TestServerConfigUiUrl = systemSettings.TestServerConfigUiUrl,
+                SubmitTestServerConfigUiUrl = systemSettings.SubmitTestServerConfigUiUrl,
                 MaxCustomProjectsPerUser = oldSystemSettings.MaxCustomProjectsPerUser,
                 MaxNumberOfTestsWithOneRequest = oldSystemSettings.MaxNumberOfTestsWithOneRequest,
                 MaxNumberOfTestsWithOneRequestSubmitTestServer =
@@ -330,7 +341,8 @@ namespace ClientServer.Controllers.Core
                 CustomProjectTestMaxDiskSpaceInKb = oldSystemSettings.CustomProjectTestMaxDiskSpaceInKb,
                 DefaultGroupRoleId = oldSystemSettings.DefaultGroupRoleId,
                 DefaultUserGroupId = oldSystemSettings.DefaultUserGroupId,
-                DefaultGroupCreatorGroupRoleId = oldSystemSettings.DefaultGroupCreatorGroupRoleId
+                DefaultGroupCreatorGroupRoleId = oldSystemSettings.DefaultGroupCreatorGroupRoleId,
+                TestServerTraceLogApiUrl = oldSystemSettings.TestServerTraceLogApiUrl,
             };
 
             await
@@ -340,13 +352,18 @@ namespace ClientServer.Controllers.Core
         }
 
 
-        [HttpGet("testserver/settings/public")]
-        public async Task GetTestServerSettings()
+        [HttpGet("testserver/settings/public/{isSubmitTestServerSettings}")]
+        public async Task GetTestServerSettings(bool isSubmitTestServerSettings)
         {
             if (!await base.IsLoggedIn()) return;
 
+            await _GetSubmitOrNormalTestServerSettings(isSubmitTestServerSettings);
+        }
 
+        private async Task _GetSubmitOrNormalTestServerSettings(bool isSubmitTestServerSettings)
+        {
             var systemSettings = await _context.SystemSettings.FirstOrDefaultAsync();
+            string errorReportingName = isSubmitTestServerSettings ? "submit" : "normal";
 
             if (systemSettings == null)
             {
@@ -364,8 +381,16 @@ namespace ClientServer.Controllers.Core
             {
                 var tokenSource = new CancellationTokenSource();
 
-                client.Timeout = new TimeSpan(0, 0, 0, 0, systemSettings.TestServerTimeoutInMs);
-                tokenSource.CancelAfter(new TimeSpan(0, 0, 0, 0, systemSettings.TestServerTimeoutInMs));
+                //abuse test running timeouts here...
+                
+                client.Timeout = new TimeSpan(0, 0, 0, 0, isSubmitTestServerSettings 
+                    ? systemSettings.SubmitTestServerTimeoutInMs 
+                    : systemSettings.TestServerTimeoutInMs);
+                
+                tokenSource.CancelAfter(new TimeSpan(0, 0, 0, 0, isSubmitTestServerSettings 
+                    ? systemSettings.SubmitTestServerTimeoutInMs 
+                    : systemSettings.TestServerTimeoutInMs)
+                );
 
                 var requestPayload = new StringContent("", SubmissionController.UTF8WithoutBom,
                     "application/json");
@@ -373,18 +398,20 @@ namespace ClientServer.Controllers.Core
                 try
                 {
                     jsonResponse = await client.PostAsync(
-                        UrlHelper.GetTestServerStatsUrl(systemSettings.TestServerStatsUrl,
+                        UrlHelper.GetTestServerStatsUrl(isSubmitTestServerSettings 
+                                ? systemSettings.SubmitTestServerStatsUrl 
+                                : systemSettings.TestServerStatsUrl,
                             Constants.TestServerPublicStatsUrlPart), requestPayload, tokenSource.Token);
                 }
                 catch (Exception ex)
                 {
-                    Console.WriteLine("ERROR getting test server settings: " + ex);
+                    Console.WriteLine($"ERROR getting {errorReportingName} test server settings: " + ex);
                     //throw;
 
                     await
                         Response.WriteAsync(
                             Jc.Serialize(new BasicResponseWithData<TestServerPublicSettings>(ResponseCode.PartialOk,
-                                "error getting test server settings", InvalidTestServerPublicSettings)));
+                                $"error getting {errorReportingName} test server settings", InvalidTestServerPublicSettings)));
                     return;
                 }
             }
@@ -402,7 +429,7 @@ namespace ClientServer.Controllers.Core
                     if (answerFromTestServer.ResponseCode != (int) TestServerResponseCode.Ok &&
                         AppConfiguration.IsDebugMode)
                     {
-                        Console.WriteLine("not ok response code from test server, content: " + contentResult);
+                        Console.WriteLine($"not ok response code from {errorReportingName} test server, content: " + contentResult);
                     }
                 }
             }
@@ -414,7 +441,7 @@ namespace ClientServer.Controllers.Core
                 await
                     Response.WriteAsync(
                         Jc.Serialize(new BasicResponseWithData<TestServerPublicSettings>(ResponseCode.PartialOk,
-                            "could not deserialize test server settings", InvalidTestServerPublicSettings)));
+                            $"could not deserialize test {errorReportingName} server settings", InvalidTestServerPublicSettings)));
                 return;
             }
 
@@ -422,7 +449,7 @@ namespace ClientServer.Controllers.Core
             {
                 await Response.WriteAsync(
                     Jc.Serialize(new BasicResponseWithData<TestServerPublicSettings>(ResponseCode.PartialOk,
-                        "received test server config null or could not deserialize", InvalidTestServerPublicSettings)));
+                        $"received {errorReportingName} test server config null or could not deserialize", InvalidTestServerPublicSettings)));
                 return;
             }
 
@@ -446,12 +473,16 @@ namespace ClientServer.Controllers.Core
         public string CurrentServerMessage { get; set; }
 
         public string TestServerStatsUrl { get; set; }
+        
+        public string SubmitTestServerStatsUrl { get; set; }
 
         public string TestServerUrl { get; set; }
 
         public string SubmitTestServerUrl { get; set; }
 
         public string TestServerConfigUiUrl { get; set; }
+        
+        public string SubmitTestServerConfigUiUrl { get; set; }
 
         public int TestServerTimeoutInMs { get; set; }
 
@@ -486,6 +517,11 @@ namespace ClientServer.Controllers.Core
         /// the default group when a user creates a new group
         /// </summary>
         public int DefaultGroupCreatorGroupRoleId { get; set; }
+
+        /// <summary>
+        /// the test server trace log api url
+        /// </summary>
+        public string TestServerTraceLogApiUrl { get; set; }
     }
 
     /// <summary>
diff --git a/src/ClientServer/Controllers/Core/Testing/TestingController.cs b/src/ClientServer/Controllers/Core/Testing/TestingController.cs
index bd901ba0d9a03dd117660120ac439f1f778b3629..83483bc2368ceb7c537797f93174eb4a4e9d10e9 100644
--- a/src/ClientServer/Controllers/Core/Testing/TestingController.cs
+++ b/src/ClientServer/Controllers/Core/Testing/TestingController.cs
@@ -60,7 +60,7 @@ namespace ClientServer.Controllers.Core.Testing
         /// <summary>
         /// a unique id for the testing request (use unchecked mode in case we reach max)
         /// also use the userId as prefix in case we spread across several backend nodes
-        /// BUT there is still a small chance that one user runs > 1 tests with the same userId_requestSequentialNumber
+        /// BUT there is still a small chance that one user runs > 1 tests with the same userId_requestSequentialNumber (when using multiple server instances/nodes)
         ///
         /// this also needs to be thread safe!!
         /// </summary>
@@ -79,7 +79,7 @@ namespace ClientServer.Controllers.Core.Testing
 
         /// <summary>
         /// compiles the given single file on the test server
-        /// user can check file that is not yet saved
+        /// user can check a file that is not yet saved
         /// THIS only checks if the user is logged in, no time is up check for some exercise or release
         ///
         /// files are used from frontend --> readonly replace is not need (replace solution readonly file with exercise template readonly file)
@@ -206,7 +206,9 @@ namespace ClientServer.Controllers.Core.Testing
             {
                 //use the running userid as request distinct number
                 answerFromTestServer = await this._RunTestOnTestServer(solution, new List<AllTest>() {test},
-                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings);
+                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings,
+                    $"compileSingleFile_executingUser:{userId}_releaseCode:{runCompileSingleFileCommand.GeneratedCode}"
+                    );
             }
             catch (Exception ex)
             {
@@ -353,7 +355,9 @@ namespace ClientServer.Controllers.Core.Testing
             {
                 //use the running userid as request distinct number
                 answerFromTestServer = await this._RunTestOnTestServer(solution, new List<AllTest>() {test},
-                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings);
+                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings,
+                    $"compileSingleFileCustomProject_executingUser:{userId}_customProjectId:{runCompileSingleFileCommand.CustomProjectId}_plangId:{runCompileSingleFileCommand.PlangId}_mainFileId:{solution.MainFileId}"
+                    );
             }
             catch (Exception ex)
             {
@@ -525,7 +529,9 @@ namespace ClientServer.Controllers.Core.Testing
             {
                 //use the running userid as request distinct number
                 answerFromTestServer = await this._RunTestOnTestServer(solution, new List<AllTest>() {test},
-                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings);
+                    pLangToUse, systemSettings.TestServerUrl, false, userId, systemSettings,
+                    $"compileSingleFileTutorView_executingUser:{userId}_releaseCode:{runCompileSingleFileCommand.GeneratedCode}"
+                    );
             }
             catch (Exception ex)
             {
@@ -741,13 +747,14 @@ namespace ClientServer.Controllers.Core.Testing
             //or a normal solution edit (solution can still be edited)
 
             Solution userSolution;
+            AfterSolution afterSolution = null;
             
             //check if available working time is up
             if (ReleaseHelper.IsTimeUp(participation, participation.ExerciseRelease))
             {
                 //then the user is editing the after solution...
                 
-                var afterSolution = await _context.AfterSolutions
+                afterSolution = await _context.AfterSolutions
                     .Include(p => p.SolutionFiles)
                     .ThenInclude(p => p.TemplateFile)
                     .Include(p => p.TestResults) //only include tests here because its a normal test (not a custom test)
@@ -840,8 +847,14 @@ namespace ClientServer.Controllers.Core.Testing
 
             //--- run test
 
+            string traceStringPartSolution = afterSolution != null
+                ? TraceStringHelper.GetTraceStringPartAfterSolution(afterSolution)
+                : TraceStringHelper.GetTraceStringPartSolution(userSolution)
+                ;
            
-            results = await this._RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings, false);
+            results = await this._RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings, 
+                $"justRunProgram_executingUser:{userId}_{traceStringPartSolution}",
+                false);
 
             //this is handled in the method
             if (results == null) return;
@@ -864,7 +877,7 @@ namespace ClientServer.Controllers.Core.Testing
         /// </summary>
         /// <param name="command"></param>
         [HttpPost("justrunprogram/custom/project")]
-        public async Task RequestJustRunProgram([FromBody] JustRunProgramTestCustomProjectCommandForBackend command)
+        public async Task RequestJustRunProgramCustomProject([FromBody] JustRunProgramTestCustomProjectCommandForBackend command)
         {
             if (!await base.IsLoggedIn()) return;
 
@@ -917,13 +930,13 @@ namespace ClientServer.Controllers.Core.Testing
             //just find the correct version then start another query to get the solution version + files
 
 
-            var solution = await _context.CustomProjectSolutions
+            var customProjectSolution = await _context.CustomProjectSolutions
                     .Include(p => p.SolutionFiles)
                     .Include(p => p.TestResults)
                     .FirstOrDefaultAsync(p => p.CustomProjectId == customProject.Id && p.PLangId == pLangToUse.Id)
                 ;
 
-            if (solution == null)
+            if (customProjectSolution == null)
             {
                 await
                     Response.WriteAsync(Jc.Serialize(new BasicResponse(ResponseCode.NotFound, "solution not found")));
@@ -931,7 +944,7 @@ namespace ClientServer.Controllers.Core.Testing
             }
 
 
-            var solutionFiles = solution.SolutionFiles.Select(p => new SolutionFile()
+            var solutionFiles = customProjectSolution.SolutionFiles.Select(p => new SolutionFile()
             {
                 Id = p.Id,
                 Content = p.Content,
@@ -942,7 +955,7 @@ namespace ClientServer.Controllers.Core.Testing
                 TemplateFileId = -1
             }).ToList();
 
-            var mainFile = solutionFiles.FirstOrDefault(p => p.Id == solution.MainFileId);
+            var mainFile = solutionFiles.FirstOrDefault(p => p.Id == customProjectSolution.MainFileId);
 
             if (mainFile == null)
             {
@@ -952,14 +965,14 @@ namespace ClientServer.Controllers.Core.Testing
                 return;
             }
 
-            var solutionVersion = new Solution()
+            var tmpSolution = new Solution()
             {
-                CreatedAt = solution.CreatedAt,
+                CreatedAt = customProjectSolution.CreatedAt,
                 SolutionFiles = solutionFiles,
                 CustomTestResults = null,
                 Note = "",
                 TestResults = null,
-                MainFileId = solution.MainFileId,
+                MainFileId = customProjectSolution.MainFileId,
                 MainFile = mainFile
             };
 
@@ -969,8 +982,12 @@ namespace ClientServer.Controllers.Core.Testing
             var allTests = new List<AllTest>();
             allTests.Add(justRunTest);
 
+            string traceStringPartSolution = TraceStringHelper.GetTraceStringPartCustomProjectSolution(customProjectSolution);
+
             List<TestAnswerFromBackend> results =
-                await this._RunTempTests(userId, solutionVersion, pLangToUse, allTests, systemSettings, false);
+                await this._RunTempTests(userId, tmpSolution, pLangToUse, allTests, systemSettings,
+                    $"requestJustRunProgramCustomProject_executingUser:{userId}_customProjectId:{command.CustomProjectId}_{traceStringPartSolution}",
+                    false);
 
             //this is handled in the method
             if (results == null) return;
@@ -1131,7 +1148,9 @@ namespace ClientServer.Controllers.Core.Testing
             allTests.Add(justRunTest);
 
             List<TestAnswerFromBackend> results =
-                await this._RunTempTests(userId, solution, pLangToUse, allTests, systemSettings, false);
+                await this._RunTempTests(userId, solution, pLangToUse, allTests, systemSettings, 
+                    $"justRunProgramTutor_executingUser:{userId}_releaseId:{exerciseRelease.Id}",
+                    false);
 
             //this is handled in the method
             if (results == null) return;
@@ -1326,7 +1345,7 @@ namespace ClientServer.Controllers.Core.Testing
         /// this does not checks the available working time or if the release is still released!
         /// </summary>
         /// <param name="runNormalTestCommand">the test to run (with all dependecies) from frontend</param>
-        /// <param name="userId">the user id</param>
+        /// <param name="userId">the executing user id</param>
         /// <param name="plang">the plang to use</param>
         /// <param name="exerciseRelease">the exercise release to find the user solution, make sure exercise and coded template is loadedd!</param>
         /// <param name="isSubmitTest">true: is a submit test, false: not</param>
@@ -1473,7 +1492,12 @@ namespace ClientServer.Controllers.Core.Testing
             
             //---run the test
 
-            var testResultAnswerFromBackend = await _RunTempTests(userId, userSolution, plang, allTests, systemSettings, false);
+            string solutionTraceString = TraceStringHelper.GetTraceStringPartSolution(userSolution);
+            string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
+
+            var testResultAnswerFromBackend = await _RunTempTests(userId, userSolution, plang, allTests, systemSettings,
+                $"runNormalOrSubmitTest_executingUser:{userId}_{solutionTraceString}_{testTraceString}",
+                false);
 
             if (testResultAnswerFromBackend == null)
             {
@@ -1811,8 +1835,13 @@ namespace ClientServer.Controllers.Core.Testing
                 //ignore isSubmit tests and use normal test conditions... this is to protect the submit test server from
                 //user spamming BUT this might introduce inconsistent test results because submit test server can have different settings e.g. timeouts
 
+                string solutionTraceString = TraceStringHelper.GetTraceStringPartAfterSolution(afterSolution);
+                string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
+                
                 var testResultAnswerFromBackend =
-                    await _RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings, false);
+                    await _RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings,
+                        $"runAfterTest_normalOrSubmit_executingUser:{userId}_{solutionTraceString}_{testTraceString}",
+                        false);
 
 
                 if (testResultAnswerFromBackend == null)
@@ -1990,8 +2019,13 @@ namespace ClientServer.Controllers.Core.Testing
                 //ignore isSubmit tests and use normal test conditions... this is to protect the submit test server from
                 //user spamming BUT this might introduce inconsistent test results because submit test server can have different settings e.g. timeouts
 
+                string solutionTraceString = TraceStringHelper.GetTraceStringPartAfterSolution(afterSolution);
+                string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
+                
                 var testResultAnswerFromBackend =
-                    await _RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings, false);
+                    await _RunTempTests(userId, userSolution, pLangToUse, allTests, systemSettings,
+                        $"runAfterTest_customTest_executingUser:{userId}_{solutionTraceString}_{testTraceString}",
+                        false);
 
 
                 if (testResultAnswerFromBackend == null)
@@ -2224,8 +2258,12 @@ namespace ClientServer.Controllers.Core.Testing
                 return;
             }
 
+            string solutionTraceString = TraceStringHelper.GetTraceStringPartSolution(userSolution);
+            string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
 
-            var testResultAnswerFromBackend = await _RunTempTests(userId, userSolution, plang, allTests, systemSettings, false);
+            var testResultAnswerFromBackend = await _RunTempTests(userId, userSolution, plang, allTests, systemSettings,
+                $"runCustomTest_executingUser:{userId}_{solutionTraceString}_{testTraceString}",
+                false);
 
             if (testResultAnswerFromBackend == null)
             {
@@ -2361,13 +2399,13 @@ namespace ClientServer.Controllers.Core.Testing
                 return;
             }
 
-            var solution = await _context.CustomProjectSolutions
+            var customProjectSolution = await _context.CustomProjectSolutions
                     .Include(p => p.SolutionFiles)
                     .Include(p => p.TestResults)
                     .FirstOrDefaultAsync(p => p.CustomProjectId == customProject.Id && p.PLangId == plang.Id)
                 ;
 
-            if (solution == null)
+            if (customProjectSolution == null)
             {
                 await
                     Response.WriteAsync(Jc.Serialize(new BasicResponse(ResponseCode.NotFound, "solution not found")));
@@ -2418,7 +2456,7 @@ namespace ClientServer.Controllers.Core.Testing
             }
             
 
-            var solutionFiles = solution.SolutionFiles.Select(p => new SolutionFile()
+            var solutionFiles = customProjectSolution.SolutionFiles.Select(p => new SolutionFile()
             {
                 Id = p.Id,
                 Content = p.Content,
@@ -2429,7 +2467,7 @@ namespace ClientServer.Controllers.Core.Testing
                 TemplateFileId = -1
             }).ToList();
 
-            var mainFile = solutionFiles.FirstOrDefault(p => p.Id == solution.MainFileId);
+            var mainFile = solutionFiles.FirstOrDefault(p => p.Id == customProjectSolution.MainFileId);
 
             if (mainFile == null)
             {
@@ -2441,17 +2479,21 @@ namespace ClientServer.Controllers.Core.Testing
 
             var tempSolution = new Solution()
             {
-                CreatedAt = solution.CreatedAt,
+                CreatedAt = customProjectSolution.CreatedAt,
                 SolutionFiles = solutionFiles,
                 CustomTestResults = null,
                 Note = "",
                 TestResults = null,
-                MainFileId = solution.MainFileId,
+                MainFileId = customProjectSolution.MainFileId,
                 MainFile = mainFile
             };
 
+            string solutionTraceString = TraceStringHelper.GetTraceStringPartCustomProjectSolution(customProjectSolution);
+            string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
 
-            var testResultAnswerFromBackend = await _RunTempTests(userId, tempSolution, plang, allTests, systemSettings, false)
+            var testResultAnswerFromBackend = await _RunTempTests(userId, tempSolution, plang, allTests, systemSettings, 
+                    $"runCustomProjectCustomTest_executingUser:{userId}_{solutionTraceString}_{testTraceString}",
+                    false)
                 ;
 
             if (testResultAnswerFromBackend == null)
@@ -2466,10 +2508,10 @@ namespace ClientServer.Controllers.Core.Testing
 
 
                 //get the old custom test result
-                var oldResult = solution.TestResults
+                var oldResult = customProjectSolution.TestResults
                     .FirstOrDefault(
                         p => p.CustomProjectTestId == test.Id
-                             && p.CustomProjectSolutionId == solution.Id);
+                             && p.CustomProjectSolutionId == customProjectSolution.Id);
 
                 //and store test result
 
@@ -2478,7 +2520,7 @@ namespace ClientServer.Controllers.Core.Testing
                     //no old result, create new one
                     oldResult = new CustomProjectTestWithSolutionAsTestResult()
                     {
-                        CustomProjectSolution = solution,
+                        CustomProjectSolution = customProjectSolution,
                         CustomProjectTest = test,
                         Passed = testResult.Passed,
                         Protocol = string.Join(Constants.TestProtocolSplitString, testResult.Protocol),
@@ -2803,8 +2845,15 @@ namespace ClientServer.Controllers.Core.Testing
 
             #region running tests
 
+            
+            string testTraceString = TraceStringHelper.GetTraceStringPartFromTests(allTests);
+            string testTypes = tutorCommand.IsNormalTest ? "normalTests" : "submitTests";
+                
             var testResultAnswerFromBackend =
-                    await _RunTempTests(userId, tempSolution, pLangToUse, allTests, systemSettings, tutorCommand.IsSubmitTest)
+                    await _RunTempTests(userId, tempSolution, pLangToUse, allTests, systemSettings, 
+                        $"runAnyTestAsTutor_executingUser:{userId}_releaseCode:{tutorCommand.ReleaseCode}_{testTypes}_{testTraceString}",
+                        tutorCommand.IsSubmitTest
+                        )
                 ;
 
             if (testResultAnswerFromBackend == null)
@@ -2876,9 +2925,10 @@ namespace ClientServer.Controllers.Core.Testing
         /// <param name="solution"></param>
         /// <param name="pLangToUse"></param>
         /// <param name="tests"></param>
+        /// <param name="traceString">some string to identify who wants to run the code and what code and test should be run (to trace back errors) <see cref="RunTestCommandForTestServer.TraceString"/> and <see cref="TraceStringHelper"/> for more information</param>
         /// <param name="isSubmitTest">true: use submit test (timeout), false: normal test</param>
         private async Task<List<TestAnswerFromBackend>> _RunTempTests(int userId, Solution solution, PLang pLangToUse,
-            List<AllTest> tests, SystemSetting systemSettings,  bool isSubmitTest = false)
+            List<AllTest> tests, SystemSetting systemSettings, string traceString,  bool isSubmitTest = false)
         {
             bool tooManyTestsRequested = false;
 
@@ -2923,7 +2973,9 @@ namespace ClientServer.Controllers.Core.Testing
                 var testServerUrl = isSubmitTest ? systemSettings.SubmitTestServerUrl : systemSettings.TestServerUrl;
                 //use the running userid as request distinct number, it's unlikely that the user runs two tests at the same time...
                 answerFromTestServer = await _RunTestOnTestServer(solution, allTests, pLangToUse,
-                    testServerUrl, isSubmitTest, userId, systemSettings);
+                    testServerUrl, isSubmitTest, userId, systemSettings,
+                    traceString
+                    );
             }
             catch (Exception ex)
             {
@@ -3089,10 +3141,12 @@ namespace ClientServer.Controllers.Core.Testing
         /// <param name="runOnSubmitTestServer">true: use the submit test server timeout, false: use the normal test server timeout</param>
         /// <param name="userId">a number to help the test server to separate two requests that arrive at the same time
         /// </param>
+        /// <param name="traceString">some string to identify who wants to run the code and what code and test should be run (to trace back errors) <see cref="RunTestCommandForTestServer.TraceString"/> and <see cref="TraceStringHelper"/> for more information</param>
         /// <returns>the answer from the test server </returns>
         internal async Task<Tuple<ResponseFromTestServer, string>> _RunTestOnTestServer(
             Solution solution, List<AllTest> tests,
-            PLang plang, string testServerUrl, bool runOnSubmitTestServer, int userId, SystemSetting systemSettings)
+            PLang plang, string testServerUrl, bool runOnSubmitTestServer, int userId, SystemSetting systemSettings,
+            string traceString)
         {
             var mainFile = solution.SolutionFiles.FirstOrDefault(p => p.Id == solution.MainFileId);
 
@@ -3137,7 +3191,8 @@ namespace ClientServer.Controllers.Core.Testing
                     }).ToList(),
                 }).ToList(),
                 RequestDistinctionString = userId + "_" + nextSequentialNumber,
-                CharacterLimitProtocol = YapexDbContext.TestProtocolMaxStringLength
+                CharacterLimitProtocol = YapexDbContext.TestProtocolMaxStringLength,
+                TraceString = traceString,
             };
 
 
@@ -3246,6 +3301,7 @@ namespace ClientServer.Controllers.Core.Testing
 
             return new Tuple<ResponseFromTestServer, string>(answerFromTestServer, contentResult);
         }
+        
     }
 
     /// <summary>
@@ -3487,6 +3543,22 @@ namespace ClientServer.Controllers.Core.Testing
         /// </summary>
         public string RequestDistinctionString { get; set; }
 
+        /// <summary>
+        /// a string describing what we execute... the has no real shape
+        /// the idea is that we know where we get the source code for the request in case some code makes trouble
+        ///   we can log this in the test server (or here) and we can lookup the source code and fix the bug
+        /// 
+        /// so a good thing to start with is the userId who owns the code (even if a tutor runs the code we want the owner)
+        ///
+        ///
+        /// pattern: [user id how owns the code]_[solution primary key: userId, releaseId, plangId]_[first test id]_[number of total tests]
+        ///
+        /// the test server then saves the tuple: trace string + executed cmd
+        /// when a process won't terminate we can lookup the process with hop = the executed command
+        /// and get the connected trace string and find the source code + test that led to this  
+        /// </summary>
+        public string TraceString { get; set; }
+
         /// <summary>
         /// the plang the solution files are written in
         /// </summary>
diff --git a/src/ClientServer/Controllers/dashboard/DashboardController.cs b/src/ClientServer/Controllers/dashboard/DashboardController.cs
index 37d00a51925ce470d246c0dbce009e0103d442b3..56f64082846b8988adc483bec4fddf10999bef3c 100644
--- a/src/ClientServer/Controllers/dashboard/DashboardController.cs
+++ b/src/ClientServer/Controllers/dashboard/DashboardController.cs
@@ -287,15 +287,15 @@ namespace ClientServer.Controllers
 //            int totalSubmissions2 =
 //                await _context.ExerciseReleases
 //                    .SumAsync(p => p.ExerciseReleaseWithUserAsParticipations.Count);
-            
+
             //or maybe only count where we have >2 / >5 submissions? else it's likely to be a test release
             //also excludes releases where we have no submissions 
             int totalReleases = await _context.ExerciseReleases
                 .CountAsync(p => p.ExerciseReleaseWithUserAsParticipations.Count >= 5);
-            
+
 //            int totalReleases2 = await _context.ExerciseReleases
 //                .CountAsync();
-            
+
             int totalTags = await _context.Tags.CountAsync();
 
             var statistic = new LogicalUsageStatistic()
@@ -319,8 +319,8 @@ namespace ClientServer.Controllers
         }
 
 
-        [HttpGet("testserver/settings/private")]
-        public async Task GetTestServerSettings()
+        [HttpGet("testserver/settings/private/{isSubmitTestServerSettings}")]
+        public async Task GetTestServerSettings(bool isSubmitTestServerSettings)
         {
             if (!await base.IsLoggedIn()) return;
 
@@ -333,6 +333,14 @@ namespace ClientServer.Controllers
                 return;
             }
 
+            await _GetSubmitOrNormalTestServerSettings(isSubmitTestServerSettings);
+        }
+
+        private async Task _GetSubmitOrNormalTestServerSettings(bool isSubmitTestServerSettings)
+        {
+            
+            string errorReportingName = isSubmitTestServerSettings ? "submit" : "normal";
+            
             var systemSettings = await _context.SystemSettings.FirstOrDefaultAsync();
 
             if (systemSettings == null)
@@ -348,8 +356,16 @@ namespace ClientServer.Controllers
             {
                 var tokenSource = new CancellationTokenSource();
 
-                client.Timeout = new TimeSpan(0, 0, 0, 0, systemSettings.TestServerTimeoutInMs);
-                tokenSource.CancelAfter(new TimeSpan(0, 0, 0, 0, systemSettings.TestServerTimeoutInMs));
+                //abuse test running timeouts here...
+
+                client.Timeout = new TimeSpan(0, 0, 0, 0, isSubmitTestServerSettings
+                    ? systemSettings.SubmitTestServerTimeoutInMs
+                    : systemSettings.TestServerTimeoutInMs);
+
+                tokenSource.CancelAfter(new TimeSpan(0, 0, 0, 0, isSubmitTestServerSettings
+                    ? systemSettings.SubmitTestServerTimeoutInMs
+                    : systemSettings.TestServerTimeoutInMs)
+                );
 
                 var requestPayload = new StringContent("", SubmissionController.UTF8WithoutBom,
                     "application/json");
@@ -357,19 +373,21 @@ namespace ClientServer.Controllers
                 try
                 {
                     jsonResponse = await client.PostAsync(
-                        UrlHelper.GetTestServerStatsUrl(systemSettings.TestServerStatsUrl,
+                        UrlHelper.GetTestServerStatsUrl(isSubmitTestServerSettings
+                                ? systemSettings.TestServerStatsUrl
+                                : systemSettings.SubmitTestServerStatsUrl,
                             Constants.TestServerPrivateStatsUrlPart), requestPayload, tokenSource.Token);
                 }
                 catch (Exception ex)
                 {
-                    Console.WriteLine("ERROR getting test server settings: " + ex);
+                    Console.WriteLine($"ERROR getting {errorReportingName} test server settings: " + ex);
                     //throw;
 
                     //only users with permission see this so we can output the full exception
                     await
                         Response.WriteAsync(
                             Jc.Serialize(new BasicResponse(ResponseCode.ServerError,
-                                "error getting test server settings, error: " + ex)));
+                                $"error getting {errorReportingName} test server settings, error: " + ex)));
                     return;
                 }
             }
@@ -387,7 +405,7 @@ namespace ClientServer.Controllers
                     if (answerFromTestServer.ResponseCode != (int) TestServerResponseCode.Ok &&
                         AppConfiguration.IsDebugMode)
                     {
-                        Console.WriteLine("not ok response code from test server, content: " + contentResult);
+                        Console.WriteLine($"not ok response code from {errorReportingName} test server, content: " + contentResult);
                     }
                 }
             }
@@ -399,7 +417,7 @@ namespace ClientServer.Controllers
                 await
                     Response.WriteAsync(
                         Jc.Serialize(new BasicResponse(ResponseCode.ServerError,
-                            "could not deserialize test server settings")));
+                            $"could not deserialize {errorReportingName} test server settings")));
                 return;
             }
 
@@ -407,7 +425,7 @@ namespace ClientServer.Controllers
             {
                 await Response.WriteAsync(
                     Jc.Serialize(new BasicResponse(ResponseCode.ServerError,
-                        "received test server config null")));
+                        $"received {errorReportingName} test server config null")));
                 return;
             }
 
diff --git a/src/ClientServer/Helpers/TraceStringHelper.cs b/src/ClientServer/Helpers/TraceStringHelper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c926002409b06759f303afc446afb07cc7b7ff48
--- /dev/null
+++ b/src/ClientServer/Helpers/TraceStringHelper.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.Linq;
+using ClientServer.Models.CustomProjects;
+using ClientServer.Models.Exercises.AfterSolutions;
+using ClientServer.Models.Exercises.Solution;
+using ClientServer.Models.Interfaces;
+
+namespace ClientServer.Helpers
+{
+    public static class TraceStringHelper
+    {
+        
+        /// <summary>
+        /// returns the trace string part for a solution
+        /// NOTE that the pk properties must be set!
+        /// </summary>
+        /// <param name="solution"></param>
+        /// <returns></returns>
+        public static string GetTraceStringPartSolution(Solution solution)
+        {
+            return $"solution::userId:{solution.UserId}_releaseId:{solution.ExerciseReleaseId}_plangId:{solution.PLangId}_mainFileId:{solution.MainFileId}";
+        }
+        
+        /// <summary>
+        /// returns the trace string part for a solution
+        /// NOTE that the pk properties must be set!
+        /// </summary>
+        /// <param name="solution"></param>
+        /// <returns></returns>
+        public static string GetTraceStringPartAfterSolution(AfterSolution solution)
+        {
+            return $"afterSolution::userId:{solution.SolutionUserId}_releaseId:{solution.SolutionExerciseReleaseId}_plangId:{solution.SolutionPLangId}_mainFileId:{solution.MainFileId}";
+        }
+        
+        /// <summary>
+        /// returns the trace string part for a solution
+        /// NOTE that the pk properties must be set!
+        /// </summary>
+        /// <param name="solution"></param>
+        /// <returns></returns>
+        public static string GetTraceStringPartCustomProjectSolution(CustomProjectSolution solution)
+        {
+            return $"solution::id:{solution.Id}_plangId:{solution.PLangId}_mainFileId:{solution.MainFileId}";
+        }
+        
+        public static string GetTraceStringPartFromTests(List<AllTest> tests)
+        {
+            return $"tests_{tests.FirstOrDefault()}_{tests.Count}";
+        }
+    }
+}
diff --git a/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.Designer.cs b/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.Designer.cs
new file mode 100755
index 0000000000000000000000000000000000000000..c4a601c065de4a4289107df77eaef2acd46390e3
--- /dev/null
+++ b/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.Designer.cs
@@ -0,0 +1,2167 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using ClientServer.Db;
+using ClientServer.Models.Exercises.Release;
+
+namespace ClientServer.Migrations
+{
+    [DbContext(typeof(YapexDbContext))]
+    [Migration("20191117200002_TestServerTraceLogs")]
+    partial class TestServerTraceLogs
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "1.0.3");
+
+            modelBuilder.Entity("ClientServer.Models.AwaitDummy", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.HasKey("Id");
+
+                    b.ToTable("AwaitDummies");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProject", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("LastEditorPLangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("CustomProjects");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescription", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(50000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId")
+                        .IsUnique();
+
+                    b.ToTable("CustomProjectDescriptions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomProjectDescriptionId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomProjectDescriptionId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomProjectDescriptionId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomProjectDescriptionWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolution", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("PLangId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("CustomProjectSolutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int?>("CustomProjectSolutionId")
+                        .IsRequired();
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectSolutionId");
+
+                    b.ToTable("CustomProjectSolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTest", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("Weight");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.ToTable("CustomProjectTests");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<byte[]>("Content");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.ToTable("CustomProjectTestAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectTestId")
+                        .IsUnique();
+
+                    b.ToTable("CustomProjectTestSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomProjectTestId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomProjectTestId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomProjectTestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomProjectSolutionId");
+
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomProjectSolutionId", "CustomProjectTestId");
+
+                    b.HasIndex("CustomProjectSolutionId");
+
+                    b.HasIndex("CustomProjectTestId");
+
+                    b.ToTable("CustomProjectTestWithSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .IsUnique();
+
+                    b.ToTable("AfterSolutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("TemplateFileId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("TemplateFileId");
+
+                    b.ToTable("AfterSolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.CustomTestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomTestId", "AfterSolutionId");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.ToTable("CustomTestWithAfterSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.TestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("TestId", "AfterSolutionId");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("TestId");
+
+                    b.ToTable("TestWithAfterSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CodeTemplate", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("PLangId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("Templates");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CustomTestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomTestId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomTestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Exercise", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanUserCreateCustomTests");
+
+                    b.Property<bool>("CanUserCreateFiles");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsOnlyVisibleToOwner");
+
+                    b.Property<bool>("IsPermanentlyLocked");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.Property<string>("ShortDescription")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("UserGroupId");
+
+                    b.Property<int?>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserGroupId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Exercises");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescription", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(50000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("ExerciseDescriptions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("ExerciseDescriptionId");
+
+                    b.Property<int>("FileReferenceMarkdownAssetId");
+
+                    b.HasKey("ExerciseDescriptionId", "FileReferenceMarkdownAssetId");
+
+                    b.HasIndex("ExerciseDescriptionId");
+
+                    b.HasIndex("FileReferenceMarkdownAssetId");
+
+                    b.ToTable("ExerciseDescriptionWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.MetaData", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("MetaDatas");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Release.ExerciseRelease", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime?>("AutomaticEndAt");
+
+                    b.Property<DateTime?>("AutomaticStartAt");
+
+                    b.Property<int>("AvailableWorkingTimeInMinutes");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<string>("GeneratedCode")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("HadAutomaticAssessmentErrors");
+
+                    b.Property<bool>("HasAutomaticAssessmentFinished");
+
+                    b.Property<bool>("HasAutomaticAssessmentStarted");
+
+                    b.Property<bool>("HasLimitedWorkingTime");
+
+                    b.Property<bool>("HideExerciseLeaveActions");
+
+                    b.Property<bool>("HideInOverviews");
+
+                    b.Property<bool>("HidePrintOptions");
+
+                    b.Property<bool>("HideSiteHeaderBar");
+
+                    b.Property<bool>("IsReleased");
+
+                    b.Property<bool>("IsVisibleToAllAfterRelease");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MaxManualPoint");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<int>("ReleaseDurationType");
+
+                    b.Property<int>("ReleaseStartType");
+
+                    b.Property<DateTime?>("ReleasedAt");
+
+                    b.Property<bool>("RunAlsoNormalTests");
+
+                    b.Property<bool>("ShouldAutomaticAssessSubmissions");
+
+                    b.Property<bool>("ShouldClearClipboard");
+
+                    b.Property<bool>("ShowAdditionalLogButton");
+
+                    b.HasKey("Id");
+
+                    b.HasAlternateKey("GeneratedCode")
+                        .HasName("Unique_GeneratedCode");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("ExerciseReleases");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.CustomTestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomTestId", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("CustomTestWithSingleSolutionAsTestResult");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("LastEditedPLangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("LockSolutionsFlag");
+
+                    b.Property<bool>("ShouldNotCount");
+
+                    b.HasKey("UserId", "ExerciseReleaseId");
+
+                    b.HasIndex("ExerciseReleaseId");
+
+                    b.HasIndex("LastEditedPLangId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("ExerciseReleaseWithUserAsParticipations");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.Solution", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("LastEditingIpAddress")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.HasKey("UserId", "ExerciseReleaseId", "PLangId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId");
+
+                    b.ToTable("Solutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionAssessment", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<string>("FeedbackForStudent")
+                        .HasMaxLength(10000);
+
+                    b.Property<string>("LastAssessmentErrorMessage")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("ManualPoints");
+
+                    b.Property<int>("MaxNormalTestPoints");
+
+                    b.Property<int>("MaxSubmitTestPoints");
+
+                    b.Property<int?>("NormalTestPoints");
+
+                    b.Property<string>("NoteForOtherTutors")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<int?>("SubmitTestPoints");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId", "PLangId")
+                        .IsUnique();
+
+                    b.ToTable("SolutionAssessment");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int?>("TemplateFileId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TemplateFileId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("SolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.TestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("TestId", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.HasIndex("TestId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("TestWithSingleSolutionAsTestResult");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tag", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Description")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlBackgroundColor")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlColor")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlIcon")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("DisplayName")
+                        .HasName("Unique_Tag");
+
+                    b.ToTable("Tags");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TagWithMetaData", b =>
+                {
+                    b.Property<int>("TagId");
+
+                    b.Property<int>("MetaDataId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("TagId", "MetaDataId");
+
+                    b.HasIndex("MetaDataId");
+
+                    b.HasIndex("TagId");
+
+                    b.ToTable("TagWithMetaDatas");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TemplateFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int?>("CodeTemplateId")
+                        .IsRequired();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsContentVisibleForUser");
+
+                    b.Property<bool>("IsEditableByUser");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CodeTemplateId");
+
+                    b.ToTable("TemplateFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.CustomTest", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId");
+
+                    b.ToTable("CustomTest");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("DefaultCustomTestSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.Test", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<bool>("IsSubmitTest");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("Weight");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.ToTable("Tests");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TestId")
+                        .IsUnique();
+
+                    b.ToTable("TestCaseSettingses");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("InternalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("TestTypes");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("FileReferenceTestAssetId");
+
+                    b.HasKey("TestId", "FileReferenceTestAssetId");
+
+                    b.HasIndex("FileReferenceTestAssetId");
+
+                    b.HasIndex("TestId");
+
+                    b.ToTable("TestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceMarkdownAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceMarkdownAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceTestAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceTestAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceUserFileAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceUserFileAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Lang", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("LangShortcut")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Language")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Langs");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.PLang", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("EditorHighlightModeName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FileExtensionsWithDot")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("InternalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("PLangs");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.AuthToken", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("CsrfToken")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("ExpirationDateTime");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("RandomSecret")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("UserAuthToken")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("UserId");
+
+                    b.HasIndex("UserAuthToken")
+                        .IsUnique();
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("AuthTokens");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.ExternalUser", b =>
+                {
+                    b.Property<int>("ExternalId")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FirstName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("LastName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("NeedToRefreshData");
+
+                    b.Property<string>("Token")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("ExternalId");
+
+                    b.HasAlternateKey("Token")
+                        .HasName("Unique_ExternalToken");
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("ExternalUsers");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRole", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("GroupRoles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRolePermission", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanAddUserToGroup");
+
+                    b.Property<bool>("CanAssessExercises");
+
+                    b.Property<bool>("CanChangeExercises");
+
+                    b.Property<bool>("CanChangeGroupData");
+
+                    b.Property<bool>("CanChangeOtherMembersRole");
+
+                    b.Property<bool>("CanCreateExercises");
+
+                    b.Property<bool>("CanDeleteExercises");
+
+                    b.Property<bool>("CanLockExercisesPermanently");
+
+                    b.Property<bool>("CanManageExerciseReleases");
+
+                    b.Property<bool>("CanRemoveMemberFromGroup");
+
+                    b.Property<bool>("CanSeeExercisesFromOthersInGroup");
+
+                    b.Property<bool>("CanSeeOtherMembers");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("GroupRoleId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("GroupRoleId")
+                        .IsUnique();
+
+                    b.ToTable("GroupRolePermissions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.CodeEditorSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("FontSize");
+
+                    b.Property<bool>("HighlightCurrentLine");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("ShowInvisibles");
+
+                    b.Property<bool>("ShowLineIndentions");
+
+                    b.Property<bool>("ShowLineNumbers");
+
+                    b.Property<int>("TabSize");
+
+                    b.Property<string>("Theme")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("UseWrapping");
+
+                    b.Property<int>("UserSettingId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserSettingId")
+                        .IsUnique();
+
+                    b.ToTable("CodeEditorSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.UserSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int?>("LangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Theme")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("LangId");
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("UserSettingses");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRole", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("SystemRoles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRolePermission", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanChangeOtherUsersSystemRole");
+
+                    b.Property<bool>("CanChangeRoles");
+
+                    b.Property<bool>("CanChangeSystemSettings");
+
+                    b.Property<bool>("CanChangeUserData");
+
+                    b.Property<bool>("CanCreateGroups");
+
+                    b.Property<bool>("CanCreateRoles");
+
+                    b.Property<bool>("CanDeleteActivatedUsers");
+
+                    b.Property<bool>("CanDeleteGroups");
+
+                    b.Property<bool>("CanDeleteRoles");
+
+                    b.Property<bool>("CanDownloadPersonalDataFromOthers");
+
+                    b.Property<bool>("CanManageNewUsers");
+
+                    b.Property<bool>("CanManageTags");
+
+                    b.Property<bool>("CanViewDashboard");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("SystemRoleId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("SystemRoleId")
+                        .IsUnique();
+
+                    b.ToTable("SystemRolePermissions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("CurrentServerMessage")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("CustomProjectTestCompileTimeoutInMs");
+
+                    b.Property<int>("CustomProjectTestMaxDiskSpaceInKb");
+
+                    b.Property<int>("CustomProjectTestMemoryLimitInKb");
+
+                    b.Property<int>("CustomProjectTestTimeoutInMs");
+
+                    b.Property<int>("DefaultGroupCreatorGroupRoleId");
+
+                    b.Property<int>("DefaultGroupRoleId");
+
+                    b.Property<int>("DefaultUserGroupId");
+
+                    b.Property<int>("JustRunProgramCompileTimeoutInMs");
+
+                    b.Property<int>("JustRunProgramMaxDiskSpaceInKb");
+
+                    b.Property<int>("JustRunProgramMemoryLimitInKb");
+
+                    b.Property<int>("JustRunProgramTimeoutInMs");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxCustomProjectsPerUser");
+
+                    b.Property<int>("MaxCustomTestsPerParticipation");
+
+                    b.Property<int>("MaxNumberOfTestsWithOneRequest");
+
+                    b.Property<int>("MaxNumberOfTestsWithOneRequestSubmitTestServer");
+
+                    b.Property<int>("SubmitTestServerTimeoutInMs");
+
+                    b.Property<string>("SubmitTestServerUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerConfigUiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerStatsUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("TestServerTimeoutInMs");
+
+                    b.Property<string>("TestServerTraceLogApiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerUrl")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("DefaultGroupCreatorGroupRoleId")
+                        .IsUnique();
+
+                    b.HasIndex("DefaultGroupRoleId")
+                        .IsUnique();
+
+                    b.HasIndex("DefaultUserGroupId")
+                        .IsUnique();
+
+                    b.ToTable("SystemSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FirstName")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsActivated");
+
+                    b.Property<DateTime>("LastLoginAt");
+
+                    b.Property<string>("LastName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Password")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("SystemRoleId");
+
+                    b.Property<string>("Token")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasAlternateKey("Token")
+                        .HasName("Unique_Token");
+
+                    b.HasIndex("SystemRoleId");
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserGroup", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("UserGroups");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserWithUserGroup", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("UserGroupId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("GroupRoleId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("UserId", "UserGroupId");
+
+                    b.HasIndex("GroupRoleId");
+
+                    b.HasIndex("UserGroupId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("UserWithUserGroups");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProject", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("CustomProjects")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescription", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithOne("Description")
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectDescription", "CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectDescription", "CustomProjectDescription")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomProjectDescriptionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomProjectDescriptionWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolution", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithMany("Solutions")
+                        .HasForeignKey("CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectSolution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("CustomProjectSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTest", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithMany("Tests")
+                        .HasForeignKey("CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithOne("CustomProjectTestSettings")
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectTestSettings", "CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomProjectTestWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolution", "CustomProjectSolution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("CustomProjectSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithMany("TestResults")
+                        .HasForeignKey("CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithOne("AfterSolution")
+                        .HasForeignKey("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "TemplateFile")
+                        .WithMany()
+                        .HasForeignKey("TemplateFileId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.CustomTestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("CustomTestResults")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("AfterTestResults")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.TestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("AfterTestResults")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CodeTemplate", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("CodeTemplates")
+                        .HasForeignKey("ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.CodeTemplate", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CustomTestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomTestWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Exercise", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "UserGroup")
+                        .WithMany("Exercises")
+                        .HasForeignKey("UserGroupId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("Exercises")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.SetNull);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescription", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("Description")
+                        .HasForeignKey("ClientServer.Models.Exercises.ExerciseDescription", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.ExerciseDescription", "ExerciseDescription")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("ExerciseDescriptionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceMarkdownAsset", "FileReferenceMarkdownAsset")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("FileReferenceMarkdownAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.MetaData", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("MetaData")
+                        .HasForeignKey("ClientServer.Models.Exercises.MetaData", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Release.ExerciseRelease", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("Releases")
+                        .HasForeignKey("ExerciseId");
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.CustomTestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("TestResultsNew")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("CustomTestResults")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Release.ExerciseRelease", "ExerciseRelease")
+                        .WithMany("ExerciseReleaseWithUserAsParticipations")
+                        .HasForeignKey("ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.PLang", "LastEditedPLang")
+                        .WithMany()
+                        .HasForeignKey("LastEditedPLangId");
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("ExerciseReleaseWithUserAsParticipations")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.Solution", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Solution.SolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.Solution.Solution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", "ExerciseReleaseWithUserAsParticipation")
+                        .WithMany("Solutions")
+                        .HasForeignKey("UserId", "ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionAssessment", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithOne("Assessment")
+                        .HasForeignKey("ClientServer.Models.Exercises.Solution.SolutionAssessment", "UserId", "ExerciseReleaseId", "PLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "TemplateFile")
+                        .WithMany("SolutionParts")
+                        .HasForeignKey("TemplateFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.TestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("TestResultsNew")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TagWithMetaData", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.MetaData", "MetaData")
+                        .WithMany("TagWithMetaDatas")
+                        .HasForeignKey("MetaDataId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tag", "Tag")
+                        .WithMany()
+                        .HasForeignKey("TagId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TemplateFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.CodeTemplate")
+                        .WithMany("TemplateFiles")
+                        .HasForeignKey("CodeTemplateId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.CustomTest", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation")
+                        .WithMany("CustomTests")
+                        .HasForeignKey("UserId", "ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("DefaultCustomTestSettings")
+                        .HasForeignKey("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.Test", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("Tests")
+                        .HasForeignKey("ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithOne("TestSettings")
+                        .HasForeignKey("ClientServer.Models.Exercises.Tests.TestSettings", "TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Files.FileReferenceTestAsset", "FileReferenceTestAsset")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("FileReferenceTestAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.AuthToken", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.AuthToken", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.ExternalUser", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne("ExternalUser")
+                        .HasForeignKey("ClientServer.Models.Users.ExternalUser", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRolePermission", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "GroupRole")
+                        .WithOne("GroupRolePermission")
+                        .HasForeignKey("ClientServer.Models.Users.GroupRolePermission", "GroupRoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.CodeEditorSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.Settings.UserSetting", "UserSetting")
+                        .WithOne("CodeEditorSetting")
+                        .HasForeignKey("ClientServer.Models.Users.Settings.CodeEditorSetting", "UserSettingId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.UserSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Lang", "Lang")
+                        .WithMany()
+                        .HasForeignKey("LangId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne("UserSettings")
+                        .HasForeignKey("ClientServer.Models.Users.Settings.UserSetting", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRolePermission", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.SystemRole", "SystemRole")
+                        .WithOne("SystemRolePermission")
+                        .HasForeignKey("ClientServer.Models.Users.SystemRolePermission", "SystemRoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "DefaultGroupCreatorGroupRole")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultGroupCreatorGroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "DefaultGroupRole")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultGroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "DefaultUserGroup")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultUserGroupId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.User", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.SystemRole", "SystemRole")
+                        .WithMany()
+                        .HasForeignKey("SystemRoleId")
+                        .OnDelete(DeleteBehavior.SetNull);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserWithUserGroup", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "GroupRole")
+                        .WithMany("UserUserGroups")
+                        .HasForeignKey("GroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "UserGroup")
+                        .WithMany("UserWithUserGroups")
+                        .HasForeignKey("UserGroupId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("UserWithUserGroups")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+        }
+    }
+}
diff --git a/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.cs b/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.cs
new file mode 100755
index 0000000000000000000000000000000000000000..3870ce22e0aac56fcb81ddb5f000d76365ed665a
--- /dev/null
+++ b/src/ClientServer/Migrations/20191117200002_TestServerTraceLogs.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ClientServer.Migrations
+{
+    public partial class TestServerTraceLogs : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<string>(
+                name: "TestServerTraceLogApiUrl",
+                table: "SystemSettings",
+                maxLength: 2000,
+                nullable: true);
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "TestServerTraceLogApiUrl",
+                table: "SystemSettings");
+        }
+    }
+}
diff --git a/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.Designer.cs b/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.Designer.cs
new file mode 100755
index 0000000000000000000000000000000000000000..23d3ac7a7d13d4252e7afdc229c4b2de49b88afd
--- /dev/null
+++ b/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.Designer.cs
@@ -0,0 +1,2173 @@
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using ClientServer.Db;
+using ClientServer.Models.Exercises.Release;
+
+namespace ClientServer.Migrations
+{
+    [DbContext(typeof(YapexDbContext))]
+    [Migration("20191117212447_SubmitTestServerStats")]
+    partial class SubmitTestServerStats
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+            modelBuilder
+                .HasAnnotation("ProductVersion", "1.0.3");
+
+            modelBuilder.Entity("ClientServer.Models.AwaitDummy", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.HasKey("Id");
+
+                    b.ToTable("AwaitDummies");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProject", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("LastEditorPLangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("CustomProjects");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescription", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(50000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId")
+                        .IsUnique();
+
+                    b.ToTable("CustomProjectDescriptions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomProjectDescriptionId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomProjectDescriptionId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomProjectDescriptionId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomProjectDescriptionWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolution", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("PLangId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("CustomProjectSolutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int?>("CustomProjectSolutionId")
+                        .IsRequired();
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectSolutionId");
+
+                    b.ToTable("CustomProjectSolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTest", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectId");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("Weight");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectId");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.ToTable("CustomProjectTests");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<byte[]>("Content");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.ToTable("CustomProjectTestAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CustomProjectTestId")
+                        .IsUnique();
+
+                    b.ToTable("CustomProjectTestSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomProjectTestId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomProjectTestId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomProjectTestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomProjectSolutionId");
+
+                    b.Property<int>("CustomProjectTestId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomProjectSolutionId", "CustomProjectTestId");
+
+                    b.HasIndex("CustomProjectSolutionId");
+
+                    b.HasIndex("CustomProjectTestId");
+
+                    b.ToTable("CustomProjectTestWithSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .IsUnique();
+
+                    b.ToTable("AfterSolutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("TemplateFileId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("TemplateFileId");
+
+                    b.ToTable("AfterSolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.CustomTestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomTestId", "AfterSolutionId");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.ToTable("CustomTestWithAfterSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.TestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("AfterSolutionId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("TestId", "AfterSolutionId");
+
+                    b.HasIndex("AfterSolutionId");
+
+                    b.HasIndex("TestId");
+
+                    b.ToTable("TestWithAfterSolutionAsTestResults");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CodeTemplate", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<int>("PLangId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("Templates");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CustomTestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("FileReferenceUserFileAssetId");
+
+                    b.HasKey("CustomTestId", "FileReferenceUserFileAssetId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.HasIndex("FileReferenceUserFileAssetId");
+
+                    b.ToTable("CustomTestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Exercise", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanUserCreateCustomTests");
+
+                    b.Property<bool>("CanUserCreateFiles");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsOnlyVisibleToOwner");
+
+                    b.Property<bool>("IsPermanentlyLocked");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.Property<string>("ShortDescription")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("UserGroupId");
+
+                    b.Property<int?>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserGroupId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("Exercises");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescription", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(50000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("ExerciseDescriptions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("ExerciseDescriptionId");
+
+                    b.Property<int>("FileReferenceMarkdownAssetId");
+
+                    b.HasKey("ExerciseDescriptionId", "FileReferenceMarkdownAssetId");
+
+                    b.HasIndex("ExerciseDescriptionId");
+
+                    b.HasIndex("FileReferenceMarkdownAssetId");
+
+                    b.ToTable("ExerciseDescriptionWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.MetaData", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("MetaDatas");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Release.ExerciseRelease", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime?>("AutomaticEndAt");
+
+                    b.Property<DateTime?>("AutomaticStartAt");
+
+                    b.Property<int>("AvailableWorkingTimeInMinutes");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<string>("GeneratedCode")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("HadAutomaticAssessmentErrors");
+
+                    b.Property<bool>("HasAutomaticAssessmentFinished");
+
+                    b.Property<bool>("HasAutomaticAssessmentStarted");
+
+                    b.Property<bool>("HasLimitedWorkingTime");
+
+                    b.Property<bool>("HideExerciseLeaveActions");
+
+                    b.Property<bool>("HideInOverviews");
+
+                    b.Property<bool>("HidePrintOptions");
+
+                    b.Property<bool>("HideSiteHeaderBar");
+
+                    b.Property<bool>("IsReleased");
+
+                    b.Property<bool>("IsVisibleToAllAfterRelease");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MaxManualPoint");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<int>("ReleaseDurationType");
+
+                    b.Property<int>("ReleaseStartType");
+
+                    b.Property<DateTime?>("ReleasedAt");
+
+                    b.Property<bool>("RunAlsoNormalTests");
+
+                    b.Property<bool>("ShouldAutomaticAssessSubmissions");
+
+                    b.Property<bool>("ShouldClearClipboard");
+
+                    b.Property<bool>("ShowAdditionalLogButton");
+
+                    b.HasKey("Id");
+
+                    b.HasAlternateKey("GeneratedCode")
+                        .HasName("Unique_GeneratedCode");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("PLangId");
+
+                    b.ToTable("ExerciseReleases");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.CustomTestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("CustomTestId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("CustomTestId", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.HasIndex("CustomTestId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("CustomTestWithSingleSolutionAsTestResult");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("LastEditedPLangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("LockSolutionsFlag");
+
+                    b.Property<bool>("ShouldNotCount");
+
+                    b.HasKey("UserId", "ExerciseReleaseId");
+
+                    b.HasIndex("ExerciseReleaseId");
+
+                    b.HasIndex("LastEditedPLangId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("ExerciseReleaseWithUserAsParticipations");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.Solution", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("LastEditingIpAddress")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("MainFileId");
+
+                    b.Property<string>("Note")
+                        .HasMaxLength(10000);
+
+                    b.HasKey("UserId", "ExerciseReleaseId", "PLangId");
+
+                    b.HasIndex("MainFileId")
+                        .IsUnique();
+
+                    b.HasIndex("PLangId");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId");
+
+                    b.ToTable("Solutions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionAssessment", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<string>("FeedbackForStudent")
+                        .HasMaxLength(10000);
+
+                    b.Property<string>("LastAssessmentErrorMessage")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int?>("ManualPoints");
+
+                    b.Property<int>("MaxNormalTestPoints");
+
+                    b.Property<int>("MaxSubmitTestPoints");
+
+                    b.Property<int?>("NormalTestPoints");
+
+                    b.Property<string>("NoteForOtherTutors")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("PLangId");
+
+                    b.Property<int?>("SubmitTestPoints");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId", "PLangId")
+                        .IsUnique();
+
+                    b.ToTable("SolutionAssessment");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsDisplayed");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int?>("TemplateFileId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TemplateFileId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("SolutionFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.TestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("SolutionUserId");
+
+                    b.Property<int>("SolutionExerciseReleaseId");
+
+                    b.Property<int>("SolutionPLangId");
+
+                    b.Property<bool>("CharacterLimitExceeded");
+
+                    b.Property<int?>("CharacterLimitUsed");
+
+                    b.Property<int?>("CompileTimeoutInMsUsed");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<bool?>("HasCompiled");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool?>("Passed");
+
+                    b.Property<int?>("ProgramExitCode");
+
+                    b.Property<string>("Protocol")
+                        .HasMaxLength(160100);
+
+                    b.Property<string>("RunnerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TestResultCode");
+
+                    b.Property<string>("TestServerVersion")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("TimeForCompiling");
+
+                    b.Property<int?>("TimeForUserProgram");
+
+                    b.Property<int?>("TimeoutInMsUsed");
+
+                    b.HasKey("TestId", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.HasIndex("TestId");
+
+                    b.HasIndex("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId");
+
+                    b.ToTable("TestWithSingleSolutionAsTestResult");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tag", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Description")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlBackgroundColor")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlColor")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("HtmlIcon")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("DisplayName")
+                        .HasName("Unique_Tag");
+
+                    b.ToTable("Tags");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TagWithMetaData", b =>
+                {
+                    b.Property<int>("TagId");
+
+                    b.Property<int>("MetaDataId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("TagId", "MetaDataId");
+
+                    b.HasIndex("MetaDataId");
+
+                    b.HasIndex("TagId");
+
+                    b.ToTable("TagWithMetaDatas");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TemplateFile", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int?>("CodeTemplateId")
+                        .IsRequired();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(70000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("FileNameWithExtension")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsContentVisibleForUser");
+
+                    b.Property<bool>("IsEditableByUser");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("CodeTemplateId");
+
+                    b.ToTable("TemplateFiles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.CustomTest", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("ExerciseReleaseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.HasIndex("UserId", "ExerciseReleaseId");
+
+                    b.ToTable("CustomTest");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId")
+                        .IsUnique();
+
+                    b.ToTable("DefaultCustomTestSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.Test", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<string>("Content")
+                        .HasMaxLength(80000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("DisplayIndex");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("ExerciseId");
+
+                    b.Property<bool>("IsSubmitTest");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("TestTypeId");
+
+                    b.Property<int>("Weight");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ExerciseId");
+
+                    b.HasIndex("TestTypeId");
+
+                    b.ToTable("Tests");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestSettings", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<int>("CompileTimeoutInMs");
+
+                    b.Property<string>("CompilerOptions")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxDiskSpaceInKb");
+
+                    b.Property<int>("MemoryLimitInKb");
+
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("TimeoutInMs");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("TestId")
+                        .IsUnique();
+
+                    b.ToTable("TestCaseSettingses");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("InternalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("TestTypes");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TestWithFileAsAssetReference", b =>
+                {
+                    b.Property<int>("TestId");
+
+                    b.Property<int>("FileReferenceTestAssetId");
+
+                    b.HasKey("TestId", "FileReferenceTestAssetId");
+
+                    b.HasIndex("FileReferenceTestAssetId");
+
+                    b.HasIndex("TestId");
+
+                    b.ToTable("TestWithFileAsAssetReferences");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceMarkdownAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceMarkdownAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceTestAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceTestAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Files.FileReferenceUserFileAsset", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Hash")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("MimeType")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("OriginalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<long>("SizeInBytes");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("FileReferenceUserFileAssets");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Lang", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("LangShortcut")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Language")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("Langs");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.PLang", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("EditorHighlightModeName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FileExtensionsWithDot")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("InternalName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("PLangs");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.AuthToken", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("CsrfToken")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("ExpirationDateTime");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("RandomSecret")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("UserAuthToken")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("UserId");
+
+                    b.HasIndex("UserAuthToken")
+                        .IsUnique();
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("AuthTokens");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.ExternalUser", b =>
+                {
+                    b.Property<int>("ExternalId")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FirstName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("LastName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("NeedToRefreshData");
+
+                    b.Property<string>("Token")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("UserId");
+
+                    b.HasKey("ExternalId");
+
+                    b.HasAlternateKey("Token")
+                        .HasName("Unique_ExternalToken");
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("ExternalUsers");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRole", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("GroupRoles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRolePermission", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanAddUserToGroup");
+
+                    b.Property<bool>("CanAssessExercises");
+
+                    b.Property<bool>("CanChangeExercises");
+
+                    b.Property<bool>("CanChangeGroupData");
+
+                    b.Property<bool>("CanChangeOtherMembersRole");
+
+                    b.Property<bool>("CanCreateExercises");
+
+                    b.Property<bool>("CanDeleteExercises");
+
+                    b.Property<bool>("CanLockExercisesPermanently");
+
+                    b.Property<bool>("CanManageExerciseReleases");
+
+                    b.Property<bool>("CanRemoveMemberFromGroup");
+
+                    b.Property<bool>("CanSeeExercisesFromOthersInGroup");
+
+                    b.Property<bool>("CanSeeOtherMembers");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("GroupRoleId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("GroupRoleId")
+                        .IsUnique();
+
+                    b.ToTable("GroupRolePermissions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.CodeEditorSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("FontSize");
+
+                    b.Property<bool>("HighlightCurrentLine");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<bool>("ShowInvisibles");
+
+                    b.Property<bool>("ShowLineIndentions");
+
+                    b.Property<bool>("ShowLineNumbers");
+
+                    b.Property<int>("TabSize");
+
+                    b.Property<string>("Theme")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("UseWrapping");
+
+                    b.Property<int>("UserSettingId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("UserSettingId")
+                        .IsUnique();
+
+                    b.ToTable("CodeEditorSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.UserSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int?>("LangId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Theme")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("UserId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("LangId");
+
+                    b.HasIndex("UserId")
+                        .IsUnique();
+
+                    b.ToTable("UserSettingses");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRole", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("SystemRoles");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRolePermission", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<bool>("CanChangeOtherUsersSystemRole");
+
+                    b.Property<bool>("CanChangeRoles");
+
+                    b.Property<bool>("CanChangeSystemSettings");
+
+                    b.Property<bool>("CanChangeUserData");
+
+                    b.Property<bool>("CanCreateGroups");
+
+                    b.Property<bool>("CanCreateRoles");
+
+                    b.Property<bool>("CanDeleteActivatedUsers");
+
+                    b.Property<bool>("CanDeleteGroups");
+
+                    b.Property<bool>("CanDeleteRoles");
+
+                    b.Property<bool>("CanDownloadPersonalDataFromOthers");
+
+                    b.Property<bool>("CanManageNewUsers");
+
+                    b.Property<bool>("CanManageTags");
+
+                    b.Property<bool>("CanViewDashboard");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("SystemRoleId");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("SystemRoleId")
+                        .IsUnique();
+
+                    b.ToTable("SystemRolePermissions");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemSetting", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("CurrentServerMessage")
+                        .HasMaxLength(10000);
+
+                    b.Property<int>("CustomProjectTestCompileTimeoutInMs");
+
+                    b.Property<int>("CustomProjectTestMaxDiskSpaceInKb");
+
+                    b.Property<int>("CustomProjectTestMemoryLimitInKb");
+
+                    b.Property<int>("CustomProjectTestTimeoutInMs");
+
+                    b.Property<int>("DefaultGroupCreatorGroupRoleId");
+
+                    b.Property<int>("DefaultGroupRoleId");
+
+                    b.Property<int>("DefaultUserGroupId");
+
+                    b.Property<int>("JustRunProgramCompileTimeoutInMs");
+
+                    b.Property<int>("JustRunProgramMaxDiskSpaceInKb");
+
+                    b.Property<int>("JustRunProgramMemoryLimitInKb");
+
+                    b.Property<int>("JustRunProgramTimeoutInMs");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<int>("MaxCustomProjectsPerUser");
+
+                    b.Property<int>("MaxCustomTestsPerParticipation");
+
+                    b.Property<int>("MaxNumberOfTestsWithOneRequest");
+
+                    b.Property<int>("MaxNumberOfTestsWithOneRequestSubmitTestServer");
+
+                    b.Property<string>("SubmitTestServerConfigUiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("SubmitTestServerStatsUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("SubmitTestServerTimeoutInMs");
+
+                    b.Property<string>("SubmitTestServerUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerConfigUiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerStatsUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("TestServerTimeoutInMs");
+
+                    b.Property<string>("TestServerTraceLogApiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("TestServerUrl")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("DefaultGroupCreatorGroupRoleId")
+                        .IsUnique();
+
+                    b.HasIndex("DefaultGroupRoleId")
+                        .IsUnique();
+
+                    b.HasIndex("DefaultUserGroupId")
+                        .IsUnique();
+
+                    b.ToTable("SystemSettings");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.User", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("FirstName")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("IsActivated");
+
+                    b.Property<DateTime>("LastLoginAt");
+
+                    b.Property<string>("LastName")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.Property<string>("Password")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("SystemRoleId");
+
+                    b.Property<string>("Token")
+                        .IsRequired()
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasAlternateKey("Token")
+                        .HasName("Unique_Token");
+
+                    b.HasIndex("SystemRoleId");
+
+                    b.ToTable("Users");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserGroup", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd();
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<string>("DisplayName")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("Email")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("Id");
+
+                    b.ToTable("UserGroups");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserWithUserGroup", b =>
+                {
+                    b.Property<int>("UserId");
+
+                    b.Property<int>("UserGroupId");
+
+                    b.Property<DateTime>("CreatedAt");
+
+                    b.Property<int>("GroupRoleId");
+
+                    b.Property<DateTime>("LastUpdatedAt");
+
+                    b.HasKey("UserId", "UserGroupId");
+
+                    b.HasIndex("GroupRoleId");
+
+                    b.HasIndex("UserGroupId");
+
+                    b.HasIndex("UserId");
+
+                    b.ToTable("UserWithUserGroups");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProject", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("CustomProjects")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescription", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithOne("Description")
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectDescription", "CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectDescription", "CustomProjectDescription")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomProjectDescriptionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomProjectDescriptionWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolution", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithMany("Solutions")
+                        .HasForeignKey("CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectSolution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectSolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("CustomProjectSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTest", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProject", "CustomProject")
+                        .WithMany("Tests")
+                        .HasForeignKey("CustomProjectId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithOne("CustomProjectTestSettings")
+                        .HasForeignKey("ClientServer.Models.CustomProjects.CustomProjectTestSettings", "CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomProjectTestWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.CustomProjects.CustomProjectTestWithSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectSolution", "CustomProjectSolution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("CustomProjectSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.CustomProjects.CustomProjectTest", "CustomProjectTest")
+                        .WithMany("TestResults")
+                        .HasForeignKey("CustomProjectTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithOne("AfterSolution")
+                        .HasForeignKey("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.AfterSolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "TemplateFile")
+                        .WithMany()
+                        .HasForeignKey("TemplateFileId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.CustomTestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("CustomTestResults")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("AfterTestResults")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.AfterSolutions.TestWithAfterSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.AfterSolutions.AfterSolution", "AfterSolution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("AfterSolutionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("AfterTestResults")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CodeTemplate", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("CodeTemplates")
+                        .HasForeignKey("ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.CodeTemplate", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.CustomTestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceUserFileAsset", "FileReferenceUserFileAsset")
+                        .WithMany("CustomTestWithFileAsAssetReferences")
+                        .HasForeignKey("FileReferenceUserFileAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Exercise", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "UserGroup")
+                        .WithMany("Exercises")
+                        .HasForeignKey("UserGroupId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("Exercises")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.SetNull);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescription", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("Description")
+                        .HasForeignKey("ClientServer.Models.Exercises.ExerciseDescription", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.ExerciseDescriptionWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.ExerciseDescription", "ExerciseDescription")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("ExerciseDescriptionId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Files.FileReferenceMarkdownAsset", "FileReferenceMarkdownAsset")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("FileReferenceMarkdownAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.MetaData", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("MetaData")
+                        .HasForeignKey("ClientServer.Models.Exercises.MetaData", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Release.ExerciseRelease", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("Releases")
+                        .HasForeignKey("ExerciseId");
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.CustomTestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.CustomTest", "CustomTest")
+                        .WithMany("TestResultsNew")
+                        .HasForeignKey("CustomTestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("CustomTestResults")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Release.ExerciseRelease", "ExerciseRelease")
+                        .WithMany("ExerciseReleaseWithUserAsParticipations")
+                        .HasForeignKey("ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.PLang", "LastEditedPLang")
+                        .WithMany()
+                        .HasForeignKey("LastEditedPLangId");
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("ExerciseReleaseWithUserAsParticipations")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.Solution", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Solution.SolutionFile", "MainFile")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Exercises.Solution.Solution", "MainFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.PLang", "PLang")
+                        .WithMany()
+                        .HasForeignKey("PLangId");
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation", "ExerciseReleaseWithUserAsParticipation")
+                        .WithMany("Solutions")
+                        .HasForeignKey("UserId", "ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionAssessment", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithOne("Assessment")
+                        .HasForeignKey("ClientServer.Models.Exercises.Solution.SolutionAssessment", "UserId", "ExerciseReleaseId", "PLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.SolutionFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.TemplateFile", "TemplateFile")
+                        .WithMany("SolutionParts")
+                        .HasForeignKey("TemplateFileId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("SolutionFiles")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Solution.TestWithSingleSolutionAsTestResult", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("TestResultsNew")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.Solution", "Solution")
+                        .WithMany("TestResults")
+                        .HasForeignKey("SolutionUserId", "SolutionExerciseReleaseId", "SolutionPLangId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TagWithMetaData", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.MetaData", "MetaData")
+                        .WithMany("TagWithMetaDatas")
+                        .HasForeignKey("MetaDataId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tag", "Tag")
+                        .WithMany()
+                        .HasForeignKey("TagId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TemplateFile", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.CodeTemplate")
+                        .WithMany("TemplateFiles")
+                        .HasForeignKey("CodeTemplateId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.CustomTest", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Solution.ExerciseReleaseWithUserAsParticipation")
+                        .WithMany("CustomTests")
+                        .HasForeignKey("UserId", "ExerciseReleaseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithOne("DefaultCustomTestSettings")
+                        .HasForeignKey("ClientServer.Models.Exercises.Tests.DefaultCustomTestSettings", "ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.Test", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Exercise", "Exercise")
+                        .WithMany("Tests")
+                        .HasForeignKey("ExerciseId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.TestType", "TestType")
+                        .WithMany()
+                        .HasForeignKey("TestTypeId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.Tests.TestSettings", b =>
+                {
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithOne("TestSettings")
+                        .HasForeignKey("ClientServer.Models.Exercises.Tests.TestSettings", "TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Exercises.TestWithFileAsAssetReference", b =>
+                {
+                    b.HasOne("ClientServer.Models.Files.FileReferenceTestAsset", "FileReferenceTestAsset")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("FileReferenceTestAssetId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Exercises.Tests.Test", "Test")
+                        .WithMany("AssetReferences")
+                        .HasForeignKey("TestId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.AuthToken", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.AuthToken", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.ExternalUser", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne("ExternalUser")
+                        .HasForeignKey("ClientServer.Models.Users.ExternalUser", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.GroupRolePermission", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "GroupRole")
+                        .WithOne("GroupRolePermission")
+                        .HasForeignKey("ClientServer.Models.Users.GroupRolePermission", "GroupRoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.CodeEditorSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.Settings.UserSetting", "UserSetting")
+                        .WithOne("CodeEditorSetting")
+                        .HasForeignKey("ClientServer.Models.Users.Settings.CodeEditorSetting", "UserSettingId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.Settings.UserSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Lang", "Lang")
+                        .WithMany()
+                        .HasForeignKey("LangId")
+                        .OnDelete(DeleteBehavior.SetNull);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithOne("UserSettings")
+                        .HasForeignKey("ClientServer.Models.Users.Settings.UserSetting", "UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemRolePermission", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.SystemRole", "SystemRole")
+                        .WithOne("SystemRolePermission")
+                        .HasForeignKey("ClientServer.Models.Users.SystemRolePermission", "SystemRoleId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.SystemSetting", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "DefaultGroupCreatorGroupRole")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultGroupCreatorGroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "DefaultGroupRole")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultGroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "DefaultUserGroup")
+                        .WithOne()
+                        .HasForeignKey("ClientServer.Models.Users.SystemSetting", "DefaultUserGroupId");
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.User", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.SystemRole", "SystemRole")
+                        .WithMany()
+                        .HasForeignKey("SystemRoleId")
+                        .OnDelete(DeleteBehavior.SetNull);
+                });
+
+            modelBuilder.Entity("ClientServer.Models.Users.UserWithUserGroup", b =>
+                {
+                    b.HasOne("ClientServer.Models.Users.GroupRole", "GroupRole")
+                        .WithMany("UserUserGroups")
+                        .HasForeignKey("GroupRoleId");
+
+                    b.HasOne("ClientServer.Models.Users.UserGroup", "UserGroup")
+                        .WithMany("UserWithUserGroups")
+                        .HasForeignKey("UserGroupId")
+                        .OnDelete(DeleteBehavior.Cascade);
+
+                    b.HasOne("ClientServer.Models.Users.User", "User")
+                        .WithMany("UserWithUserGroups")
+                        .HasForeignKey("UserId")
+                        .OnDelete(DeleteBehavior.Cascade);
+                });
+        }
+    }
+}
diff --git a/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.cs b/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.cs
new file mode 100755
index 0000000000000000000000000000000000000000..dc86f423a3397e84ddb02a60fade4b99c5610d08
--- /dev/null
+++ b/src/ClientServer/Migrations/20191117212447_SubmitTestServerStats.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ClientServer.Migrations
+{
+    public partial class SubmitTestServerStats : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.AddColumn<string>(
+                name: "SubmitTestServerConfigUiUrl",
+                table: "SystemSettings",
+                maxLength: 2000,
+                nullable: true);
+
+            migrationBuilder.AddColumn<string>(
+                name: "SubmitTestServerStatsUrl",
+                table: "SystemSettings",
+                maxLength: 2000,
+                nullable: true);
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropColumn(
+                name: "SubmitTestServerConfigUiUrl",
+                table: "SystemSettings");
+
+            migrationBuilder.DropColumn(
+                name: "SubmitTestServerStatsUrl",
+                table: "SystemSettings");
+        }
+    }
+}
diff --git a/src/ClientServer/Migrations/YapexDbContextModelSnapshot.cs b/src/ClientServer/Migrations/YapexDbContextModelSnapshot.cs
index 8b3d9b7c9e972f731a00fd99322893af87f14ebb..e69dd37cd59428f13cdd344edb5b71fa5e6891de 100755
--- a/src/ClientServer/Migrations/YapexDbContextModelSnapshot.cs
+++ b/src/ClientServer/Migrations/YapexDbContextModelSnapshot.cs
@@ -1560,6 +1560,12 @@ namespace ClientServer.Migrations
 
                     b.Property<int>("MaxNumberOfTestsWithOneRequestSubmitTestServer");
 
+                    b.Property<string>("SubmitTestServerConfigUiUrl")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("SubmitTestServerStatsUrl")
+                        .HasMaxLength(2000);
+
                     b.Property<int>("SubmitTestServerTimeoutInMs");
 
                     b.Property<string>("SubmitTestServerUrl")
@@ -1573,6 +1579,9 @@ namespace ClientServer.Migrations
 
                     b.Property<int>("TestServerTimeoutInMs");
 
+                    b.Property<string>("TestServerTraceLogApiUrl")
+                        .HasMaxLength(2000);
+
                     b.Property<string>("TestServerUrl")
                         .HasMaxLength(2000);
 
diff --git a/src/ClientServer/Models/Users/SystemSetting.cs b/src/ClientServer/Models/Users/SystemSetting.cs
index 1998d68fddb1fcad5de93383a085c4b3957ccedb..24227f5ee0e5df0e4e7c2b96060c39385c03e4c5 100644
--- a/src/ClientServer/Models/Users/SystemSetting.cs
+++ b/src/ClientServer/Models/Users/SystemSetting.cs
@@ -73,10 +73,24 @@ namespace ClientServer.Models.Users
         /// we then append  <see cref="Constants.TestServerPublicStatsUrlPart"/> or <see cref="Constants.TestServerPrivateStatsUrlPart"/>
         /// via <see cref="UrlHelper.GetTestServerStatsUrl"/>
         ///
-        /// NOT NOW we only use on test server but we might to add a SubmitTestServerStatsUrl at some point...
         /// </summary>
         [MaxLength(YapexDbContext.DefaultMaxStringLength)]
         public string TestServerStatsUrl { get; set; }
+
+        /// <summary>
+        /// the test server stats url ending with / or without (so this is just a base path)
+        /// we then append  <see cref="Constants.TestServerPublicStatsUrlPart"/> or <see cref="Constants.TestServerPrivateStatsUrlPart"/>
+        /// via <see cref="UrlHelper.GetTestServerStatsUrl"/>
+        ///
+        /// </summary>
+        [MaxLength(YapexDbContext.DefaultMaxStringLength)]
+        public string SubmitTestServerStatsUrl { get; set; }
+        
+        /// <summary>
+        /// the test server trace log api url
+        /// </summary>
+        [MaxLength(YapexDbContext.DefaultMaxStringLength)]
+        public string TestServerTraceLogApiUrl { get; set; }
        
         
         /// <summary>
@@ -97,6 +111,12 @@ namespace ClientServer.Models.Users
         /// </summary>
         [MaxLength(YapexDbContext.DefaultMaxStringLength)]
         public string TestServerConfigUiUrl { get; set; }
+        
+        /// <summary>
+        /// the url to the ui to configure the submit test server
+        /// </summary>
+        [MaxLength(YapexDbContext.DefaultMaxStringLength)]
+        public string SubmitTestServerConfigUiUrl { get; set; }
 
         /// <summary>
         ///  the timeout in ms to wait for a response from the test server before returning a testserver connection error
diff --git a/src/ClientServer/Program.cs b/src/ClientServer/Program.cs
index 497b12e3451a42e71bfa47977cec97bd61fcc7fd..b7a1594106c1ddbb4b694800f8437c02ad21b3e0 100644
--- a/src/ClientServer/Program.cs
+++ b/src/ClientServer/Program.cs
@@ -47,6 +47,9 @@ namespace ClientServer
                 //delete all files that are (still) in the file system but not in the db
                 FileWorker.NextRun(); //this is sync (because fast)
                 FileWorker.Start();
+                
+                TestServerTraceLogWorker.NextRun(); //this is sync
+                TestServerTraceLogWorker.Start();
             }
 
             host.Run();
diff --git a/src/ClientServer/Workers/SubmissionAssessmentWorker.cs b/src/ClientServer/Workers/SubmissionAssessmentWorker.cs
index a31984c2fcfb1dd91ca4c78b96f35301c7da5976..c720755ff76f9b9112ca1598dc0e14f477d52b82 100644
--- a/src/ClientServer/Workers/SubmissionAssessmentWorker.cs
+++ b/src/ClientServer/Workers/SubmissionAssessmentWorker.cs
@@ -177,14 +177,14 @@ namespace ClientServer.Schedulers
                     //Console.WriteLine("Assessment scheduler run # " + runNumber + " running at: " + now.ToLocalTime());
                 }
 
-                var optionsBuilder = new DbContextOptionsBuilder<YapexDbContext>();
-                optionsBuilder.UseNpgsql(AppConfiguration.DbConnectionString);
-
                 int assessedReleases = 0;
 
 
                 try
                 {
+                    var optionsBuilder = new DbContextOptionsBuilder<YapexDbContext>();
+                    optionsBuilder.UseNpgsql(AppConfiguration.DbConnectionString);
+                    
                     using (var context = new YapexDbContext(optionsBuilder.Options))
                     {
                         var systemSettings = context.SystemSettings.FirstOrDefault();
@@ -192,7 +192,7 @@ namespace ClientServer.Schedulers
                         if (systemSettings == null)
                         {
                             Console.WriteLine(
-                                "ERROR system settings not found, cannot run submissions scheduler.NextRun");
+                                "ERROR system settings not found, cannot run submissions worker.NextRun");
                             return;
                         }
 
@@ -251,7 +251,7 @@ namespace ClientServer.Schedulers
                 }
                 catch (Exception ex)
                 {
-                    Console.WriteLine("ERROR: " + ex);
+                    Console.WriteLine("ERROR submission assessment worker NextRun: " + ex);
                 }
 
                 if (AppConfiguration.IsDebugMode && assessedReleases > 0)
@@ -985,7 +985,9 @@ namespace ClientServer.Schedulers
                             testParts,
                             solution.PLang,
                             systemSettings.SubmitTestServerUrl, true, runNumber,
-                            systemSettings); //we assess so always use the submit test server
+                            systemSettings,
+                            $"SubmissionAssessmentWorker_normalTests_{TraceStringHelper.GetTraceStringPartSolution(solution)}_normalTests:{TraceStringHelper.GetTraceStringPartFromTests(testParts)}"
+                            ); //we assess so always use the submit test server
                     }
                     catch (Exception ex)
                     {
@@ -1132,7 +1134,9 @@ namespace ClientServer.Schedulers
                         submitAnswersFromTestServer = await testingController._RunTestOnTestServer(solution,
                             testParts,
                             solution.PLang,
-                            systemSettings.SubmitTestServerUrl, true, runNumber, systemSettings);
+                            systemSettings.SubmitTestServerUrl, true, runNumber, systemSettings,
+                            $"SubmissionAssessmentWorker_submitTests_{TraceStringHelper.GetTraceStringPartSolution(solution)}_submitTests:{TraceStringHelper.GetTraceStringPartFromTests(testParts)}"
+                            );
                     }
                     catch (Exception ex)
                     {
diff --git a/src/ClientServer/Workers/TestServerTraceLogWorker.cs b/src/ClientServer/Workers/TestServerTraceLogWorker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b0094f109cee2561a84f690b71e0aa4a8f5bd746
--- /dev/null
+++ b/src/ClientServer/Workers/TestServerTraceLogWorker.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Linq;
+using System.Net.Http;
+using System.Reactive.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using ClientServer.Controllers.Core.Exercises;
+using ClientServer.Controllers.Core.Testing;
+using ClientServer.Db;
+using ClientServer.Helpers;
+using ClientServer.Models.Users;
+using Microsoft.EntityFrameworkCore;
+
+namespace ClientServer.Workers
+{
+    /// <summary>
+    /// a worker to request deletion of old trace logs on the test server
+    /// </summary>
+    public static class TestServerTraceLogWorker
+    {
+
+        private static bool _isRunning = false;
+        private static readonly Object Locker = new object();
+        
+        
+        public static void Start()
+        {
+            Observable
+                .Interval(TimeSpan.FromMinutes(AppConfiguration.TestServerTraceLogWorkerIntervalInMinutes))
+                .Subscribe((min) => { NextRun(); });
+        }
+
+        public static void NextRun()
+        {
+
+            if (_isRunning)
+            {
+                return;
+            }
+
+            lock (Locker)
+            {
+                _isRunning = true;
+
+                try
+                {
+                    
+                    var optionsBuilder = new DbContextOptionsBuilder<YapexDbContext>();
+                    optionsBuilder.UseNpgsql(AppConfiguration.DbConnectionString);
+
+                    SystemSetting systemSettings = null;
+
+                    using (var context = new YapexDbContext(optionsBuilder.Options))
+                    {
+                        systemSettings = context.SystemSettings.FirstOrDefault();
+
+                        if (systemSettings == null)
+                        {
+                            Console.WriteLine(
+                                "ERROR system settings not found, cannot run trace log worker.NextRun");
+                            return;
+                        }
+                    }
+
+
+                    if (string.IsNullOrEmpty(systemSettings.TestServerTraceLogApiUrl))
+                    {
+                        Console.WriteLine("WARNING trace log worker url was empty!");
+                        return;
+                    }
+
+                    var reqObj = new TestServerRquestDelteOldTraceLogs()
+                    {
+                        DeleteTraceLogOlderThanMinutes = AppConfiguration.TestServerTraceLogDeleteTraceLogOlderThanMinutes
+                    };
+            
+                    ResponseFromTestServer answerFromTestServer = null;
+
+                    var requestPayload = new StringContent(Jc.SerializePlain(reqObj), SubmissionController.UTF8WithoutBom,
+                        "application/json");
+            
+            
+                    HttpResponseMessage jsonResponse = null;
+                    var tokenSource = new CancellationTokenSource();
+
+                    using (var client = new HttpClient())
+                    {
+                        client.Timeout = new TimeSpan(0,0,0,0,AppConfiguration.TestServerTraceLogDeleteTraceLogTimeoutInMs);
+                        tokenSource.CancelAfter(new TimeSpan(0,0,0,0,AppConfiguration.TestServerTraceLogDeleteTraceLogTimeoutInMs));
+
+                        try
+                        {
+                            jsonResponse = client.PostAsync(systemSettings.TestServerTraceLogApiUrl, requestPayload, tokenSource.Token).Result;
+                        }
+                        catch (Exception ex)
+                        {
+                            if (ex is TaskCanceledException)
+                            {
+                                //timeout hit...
+                                Console.WriteLine("ERROR timeout deleting trace logs on test server");
+                            }
+                            else
+                            {
+                                Console.WriteLine("ERROR deleting trace logs on test server: " + ex);
+                            }                 
+                        }
+                    }
+                    
+                    string contentResult = null;
+                    
+                    if (jsonResponse != null)
+                        contentResult = jsonResponse.Content.ReadAsStringAsync().Result;
+                    
+                    tokenSource.Dispose();
+
+                    try
+                    {
+                        answerFromTestServer = Jc.Deserialize<ResponseFromTestServer>(contentResult);
+                        
+                        if (answerFromTestServer != null)
+                        {
+                            if (answerFromTestServer.ResponseCode != (int) TestServerResponseCode.Ok && AppConfiguration.IsDebugMode)
+                            {
+                                Console.WriteLine("[WARNING] not ok response code from test server (trace log worker), content: " + contentResult);
+                            }
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        Console.WriteLine("ERROR trace log worker: deserializing result, message: " + ex);
+                    }
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine("ERROR trace log worker NextRun: " + ex);
+                }
+
+                _isRunning = false;
+            }
+            
+        }
+    }
+
+    class TestServerRquestDelteOldTraceLogs
+    {
+        public int DeleteTraceLogOlderThanMinutes { get; set; }
+    }
+}
diff --git a/src/ClientServer/appsettings_example.json b/src/ClientServer/appsettings_example.json
index 003c88244a9a046309cbec4b99fe0a7207011d51..c7a73a54fd1e96ca67ffce03494dbe98697fca23 100644
--- a/src/ClientServer/appsettings_example.json
+++ b/src/ClientServer/appsettings_example.json
@@ -23,6 +23,9 @@
   "EnsureFileUploadDirStructure": true,
   "OnlySecureFlaggedCookies": false,
   "IsInitControllerEnabled": true,
-  "MaxUploadFileSizeInByte": "1048576"
+  "MaxUploadFileSizeInByte": "1048576",
+  "TestServerTraceLogWorkerIntervalInMinutes": 1440,
+  "TestServerTraceLogDeleteTraceLogOlderThanMinutes" : 21600,
+  "TestServerTraceLogDeleteTraceLogTimeoutInMs": 60000
 }