diff --git a/.gitignore b/.gitignore
index 40f55760b0..204ca95f52 100755
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,5 @@ view/target
 *.log
 fitnesse/target/
 daisy-integration/target/
+war/target/
+api/target/
diff --git a/GetToken.java b/GetToken.java
new file mode 100644
index 0000000000..68c0dee549
--- /dev/null
+++ b/GetToken.java
@@ -0,0 +1,101 @@
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpServer;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Authenticator;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class GetToken {
+    public static void main(String[] args) throws IOException {
+        URI baseUri = URI.create("http://localhost:59733");
+        String clientId = "get-token";
+        String clientSecret = "get-token-secret";
+
+        System.out.println("Browse to " + baseUri.resolve("authorize?response_type=code&client_id=" + clientId));
+
+        HttpClient httpClient = HttpClient.newBuilder()
+                .authenticator(new Authenticator() {
+                    @Override
+                    protected PasswordAuthentication getPasswordAuthentication() {
+                        return new PasswordAuthentication(clientId, clientSecret.toCharArray());
+                    }
+                })
+                .build();
+
+        HttpServer httpServer = HttpServer.create();
+        httpServer.bind(new InetSocketAddress(59732), 0);
+
+        Thread thread = Thread.currentThread();
+
+        httpServer.createContext("/", exchange -> {
+            exchange.sendResponseHeaders(200, 0);
+            try (OutputStream responseBody = exchange.getResponseBody()) {
+                responseBody.write("All done, close tab".getBytes(StandardCharsets.UTF_8));
+            }
+
+            Map<String, List<String>> queryParams = getQueryParams(exchange);
+            String code = queryParams.get("code").get(0);
+            HttpRequest httpRequest = HttpRequest.newBuilder()
+                    .uri(baseUri.resolve("exchange"))
+                    .header("Content-Type", "application/x-www-form-urlencoded")
+                    .POST(HttpRequest.BodyPublishers.ofString("grant_type=authorization_code&code=" + code))
+                    .build();
+            try {
+                HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
+                System.out.println(response.body());
+
+                // Try to copy the access token to the clipboard
+                Matcher matcher = Pattern.compile("access_token\":\"([^\"]+)\"")
+                        .matcher(response.body());
+                if (matcher.find()) {
+                    StringSelection clipboardData = new StringSelection(matcher.group(1));
+                    Toolkit.getDefaultToolkit()
+                            .getSystemClipboard()
+                            .setContents(clipboardData, clipboardData);
+                    try { Thread.sleep(1_000L); } catch (InterruptedException e) { }
+                    System.out.println("Access token copied to clipboard (probably)");
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                thread.interrupt();
+            }
+        });
+
+        httpServer.start();
+        try {
+            Thread.sleep(Duration.ofMinutes(1L).toMillis());
+            System.out.println("No authorization within one minute, exiting.");
+            System.exit(1);
+        } catch (InterruptedException ignored) {
+            // expected
+        }
+        httpServer.stop(0);
+    }
+
+    private static Map<String, List<String>> getQueryParams(final HttpExchange exchange) {
+        String query = exchange.getRequestURI()
+                .getQuery();
+        return Arrays.stream(query.split("&"))
+                .map(s -> s.split("="))
+                .collect(Collectors.groupingBy(
+                        split -> split[0],
+                        Collectors.mapping(split -> split[1], Collectors.toList())));
+    }
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..749d07cb72
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+## Working with the API
+The API is protected by OAuth 2 acting as a [resource server](https://www.oauth.com/oauth2-servers/the-resource-server/)
+verifying tokens using [token introspection](https://datatracker.ietf.org/doc/html/rfc7662).
+
+When developing it uses a locally running instance of an
+[authorization server](https://datatracker.ietf.org/doc/html/rfc6749#section-1.1)
+that is run inside [Docker](https://www.docker.com). It can be started with `docker compose -f docker-compose.yml up`.
+Since there is no frontend to interact with the authorization server there's a helper script in
+[GetToken.java](GetToken.java) that can be run directly with `java GetToken.java` to run through the authorization flow
+and get an access token.
+
+Once the token has been obtained go to the [Swagger UI](http://localhost:8080/api/swagger) to interact with the API.
+Click the "Authorize" button in the top right and paste the access token to log in.
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000000..35c607e1b1
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>se.su.dsv.scipro</groupId>
+        <artifactId>SciPro</artifactId>
+        <version>0.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>api</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>se.su.dsv.scipro</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/api/src/main/java/se/su/dsv/scipro/api/ApiController.java b/api/src/main/java/se/su/dsv/scipro/api/ApiController.java
new file mode 100644
index 0000000000..8059cdde66
--- /dev/null
+++ b/api/src/main/java/se/su/dsv/scipro/api/ApiController.java
@@ -0,0 +1,29 @@
+package se.su.dsv.scipro.api;
+
+import jakarta.inject.Inject;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.system.UserService;
+
+import java.util.Optional;
+
+@RestController
+public class ApiController {
+    private final UserService userService;
+
+    @Inject
+    public ApiController(UserService userService) {
+        this.userService = userService;
+    }
+
+    @GetMapping("/hello-world")
+    public String helloWorld(@RequestParam(value = "username", required = false) String username) {
+        String name = Optional.ofNullable(username)
+                .map(userService::findByUsername)
+                .map(User::getFullName)
+                .orElse("World");
+        return "Hello, " + name + "!";
+    }
+}
diff --git a/core/pom.xml b/core/pom.xml
index df548c1fad..a3c2a1a1e9 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -12,14 +12,6 @@
     <artifactId>core</artifactId>
 
     <dependencies>
-        <dependency>
-            <groupId>com.google.inject</groupId>
-            <artifactId>guice</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.google.inject.extensions</groupId>
-            <artifactId>guice-persist</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
@@ -62,12 +54,9 @@
             <groupId>org.glassfish.jersey.inject</groupId>
             <artifactId>jersey-hk2</artifactId>
         </dependency>
-
-        <!--Database stuff-->
         <dependency>
-            <groupId>org.hsqldb</groupId>
-            <artifactId>hsqldb</artifactId>
-            <scope>test</scope>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
         </dependency>
 
         <!--QueryDSL-->
@@ -87,10 +76,19 @@
             <groupId>jakarta.persistence</groupId>
             <artifactId>jakarta.persistence-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>jakarta.transaction</groupId>
+            <artifactId>jakarta.transaction-api</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.hibernate.orm</groupId>
             <artifactId>hibernate-core</artifactId>
-            <scope>runtime</scope>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hsqldb</groupId>
+            <artifactId>hsqldb</artifactId>
+            <scope>test</scope>
         </dependency>
 
         <!--Additional stuff-->
@@ -130,8 +128,6 @@
             <version>4.0.5</version>
             <scope>runtime</scope>
         </dependency>
-
-
     </dependencies>
 
     <build>
diff --git a/core/src/main/java/modules/CoreModule.java b/core/src/main/java/modules/CoreModule.java
deleted file mode 100644
index 075c6e9ed8..0000000000
--- a/core/src/main/java/modules/CoreModule.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package modules;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.multibindings.Multibinder;
-import com.google.inject.multibindings.OptionalBinder;
-import se.su.dsv.scipro.activityplan.*;
-import se.su.dsv.scipro.checklist.*;
-import se.su.dsv.scipro.date.DateService;
-import se.su.dsv.scipro.date.DateServiceImpl;
-import se.su.dsv.scipro.events.EventModule;
-import se.su.dsv.scipro.finalseminar.*;
-import se.su.dsv.scipro.finalthesis.FinalThesisService;
-import se.su.dsv.scipro.finalthesis.FinalThesisServiceImpl;
-import se.su.dsv.scipro.finalthesis.PublishingConsentService;
-import se.su.dsv.scipro.finalthesis.PublishingConsentUnavailable;
-import se.su.dsv.scipro.firstmeeting.FirstMeetingService;
-import se.su.dsv.scipro.firstmeeting.FirstMeetingServiceImpl;
-import se.su.dsv.scipro.forum.ForumModule;
-import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
-import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsServiceImpl;
-import se.su.dsv.scipro.group.GroupFacade;
-import se.su.dsv.scipro.group.GroupFacadeImpl;
-import se.su.dsv.scipro.group.GroupService;
-import se.su.dsv.scipro.group.GroupServiceImpl;
-import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepository;
-import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepositoryImpl;
-import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepository;
-import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepositoryImpl;
-import se.su.dsv.scipro.mail.MailModule;
-import se.su.dsv.scipro.match.ApplicationPeriodFacade;
-import se.su.dsv.scipro.match.ApplicationPeriodFacadeImpl;
-import se.su.dsv.scipro.match.MatchModule;
-import se.su.dsv.scipro.milestones.service.*;
-import se.su.dsv.scipro.milestones.service.impl.MilestoneActivityTemplateServiceImpl;
-import se.su.dsv.scipro.milestones.service.impl.MilestonePhaseTemplateServiceImpl;
-import se.su.dsv.scipro.milestones.service.impl.MilestoneServiceImpl;
-import se.su.dsv.scipro.milestones.service.impl.MilestoneStatisticsServiceImpl;
-import se.su.dsv.scipro.misc.DaysService;
-import se.su.dsv.scipro.misc.DaysServiceImpl;
-import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodService;
-import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodServiceImpl;
-import se.su.dsv.scipro.notes.NoteService;
-import se.su.dsv.scipro.notes.NoteServiceImpl;
-import se.su.dsv.scipro.notifications.NotificationModule;
-import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationService;
-import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationServiceImpl;
-import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationService;
-import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl;
-import se.su.dsv.scipro.peer.*;
-import se.su.dsv.scipro.plagiarism.*;
-import se.su.dsv.scipro.project.ProjectNoteService;
-import se.su.dsv.scipro.project.ProjectPeopleStatisticsService;
-import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl;
-import se.su.dsv.scipro.project.ProjectService;
-import se.su.dsv.scipro.project.ProjectServiceImpl;
-import se.su.dsv.scipro.projectpartner.ProjectPartnerRepository;
-import se.su.dsv.scipro.projectpartner.ProjectPartnerRepositoryImpl;
-import se.su.dsv.scipro.projectpartner.ProjectPartnerService;
-import se.su.dsv.scipro.projectpartner.ProjectPartnerServiceImpl;
-import se.su.dsv.scipro.reflection.ReflectionModule;
-import se.su.dsv.scipro.report.*;
-import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsService;
-import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsServiceImpl;
-import se.su.dsv.scipro.springdata.serviceimpls.SupervisorServiceImpl;
-import se.su.dsv.scipro.springdata.serviceimpls.UnitServiceImpl;
-import se.su.dsv.scipro.springdata.serviceimpls.UserProfileServiceImpl;
-import se.su.dsv.scipro.springdata.services.SupervisorService;
-import se.su.dsv.scipro.springdata.services.UnitService;
-import se.su.dsv.scipro.springdata.services.UserProfileService;
-import se.su.dsv.scipro.system.*;
-import se.su.dsv.scipro.thesislink.ExternalLinkService;
-import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl;
-
-public class CoreModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        install(new RepositoryModule());
-        bind(FooterLinkService.class).to(FooterLinkServiceImpl.class);
-        bind(ActivityThreadRepository.class).to(ActivityThreadRepositoryImpl.class);
-        bind(ActivityFinalSeminarRepository.class).to(ActivityFinalSeminarRepositoryImpl.class);
-        bind(UserService.class).to(UserServiceImpl.class);
-        bind(MergeService.class).to(MergeServiceImpl.class);
-        bind(PasswordService.class).to(PasswordServiceImpl.class);
-        bind(GeneralSystemSettingsService.class).to(GeneralSystemSettingsServiceImpl.class);
-        bind(ProjectTypeService.class).to(ProjectTypeServiceImpl.class);
-        bind(UnitService.class).to(UnitServiceImpl.class);
-        bind(ResearchAreaService.class).to(ResearchAreaServiceImpl.class);
-        bind(DateService.class).to(DateServiceImpl.class);
-        bind(ActivityPlanFacade.class).to(ActivityPlanFacadeImpl.class);
-        bind(ProjectService.class).to(ProjectServiceImpl.class);
-        bind(ProjectFinalSeminarStatisticsService.class).to(ProjectFinalSeminarStatisticsServiceImpl.class);
-        bind(ProjectPeopleStatisticsService.class).to(ProjectPeopleStatisticsServiceImpl.class);
-        bind(DeliveryConfigurationService.class).to(DeliveryConfigurationServiceImpl.class);
-        bind(ReceiverConfigurationService.class).to(ReceiverConfigurationServiceImpl.class);
-        bind(ActivityService.class).to(ActivityServiceImpl.class);
-        bind(ActivityPlanService.class).to(ActivityPlanServiceImpl.class);
-        bind(ActivityPlanTemplateService.class).to(ActivityPlanTemplateServiceImpl.class);
-        bind(ChecklistService.class).to(ChecklistServiceImpl.class);
-        bind(UserProfileService.class).to(UserProfileServiceImpl.class);
-        bind(FinalSeminarService.class).to(FinalSeminarServiceImpl.class);
-        bind(FinalSeminarSettingsService.class).to(FinalSeminarSettingsServiceImpl.class);
-        bind(SupervisorService.class).to(SupervisorServiceImpl.class);
-        bind(DaysService.class).to(DaysServiceImpl.class);
-        bind(NonWorkDayPeriodService.class).to(NonWorkDayPeriodServiceImpl.class);
-        bind(FinalSeminarOppositionService.class).to(FinalSeminarOppositionServiceImpl.class);
-        bind(AuthorRepository.class).to(AuthorRepositoryImpl.class);
-        bind(OppositionReportService.class).to(OppositionReportServiceImpl.class);
-        bind(ApplicationPeriodFacade.class).to(ApplicationPeriodFacadeImpl.class);
-        bind(GroupFacade.class).to(GroupFacadeImpl.class);
-        bind(ExternalLinkService.class).to(ExternalLinkServiceImpl.class);
-        bind(PeerRequestService.class).to(PeerRequestServiceImpl.class);
-        bind(PeerReviewService.class).to(PeerReviewServiceImpl.class);
-        bind(MilestoneActivityTemplateService.class).to(MilestoneActivityTemplateServiceImpl.class);
-        bind(FinalThesisService.class).to(FinalThesisServiceImpl.class);
-        OptionalBinder.newOptionalBinder(binder(), PublishingConsentService.class)
-                        .setDefault().to(PublishingConsentUnavailable.class);
-        bind(ChecklistTemplateService.class).to(ChecklistTemplateServiceImpl.class);
-        bind(PeerPortal.class).to(PeerPortalImpl.class);
-        bind(FinalSeminarRespondentService.class).to(FinalSeminarRespondentServiceImpl.class);
-        bind(ProjectPartnerService.class).to(ProjectPartnerServiceImpl.class);
-        bind(GradingReportService.class).to(GradingReportServiceImpl.class);
-        bind(GradeCalculatorService.class).to(GradeCalculatorServiceImpl.class);
-        bind(UserNameService.class).to(UserNameServiceImpl.class);
-        bind(MileStoneService.class).to(MilestoneServiceImpl.class);
-        bind(MilestoneStatisticsService.class).to(MilestoneStatisticsServiceImpl.class);
-        bind(MilestonePhaseTemplateService.class).to(MilestonePhaseTemplateServiceImpl.class);
-        bind(ReportService.class).to(ReportServiceImpl.class);
-        bind(CommentThreadService.class).to(CommentThreadServiceImpl.class);
-        bind(CommentService.class).to(CommentServiceImpl.class);
-        bind(PerformReviewService.class).to(PeerPortalImpl.class);
-        bind(EventService.class).to(EventServiceImpl.class);
-        bind(ChecklistAnswerService.class).to(ChecklistAnswerServiceImpl.class);
-        bind(FinalSeminarUploadController.class).to(FinalSeminarUploadControllerImpl.class);
-        bind(FinalSeminarActiveParticipationService.class).to(FinalSeminarActiveParticipationServiceImpl.class);
-        bind(ExternalResourceService.class).to(ExternalResourceServiceImpl.class);
-        bind(GroupService.class).to(GroupServiceImpl.class);
-        bind(NoteService.class).to(NoteServiceImpl.class);
-        bind(MilestoneActivator.class).asEagerSingleton();
-        bind(ActivateCompletedMilestonesOnNewProjects.class).asEagerSingleton();
-        bind(FirstMeetingService.class).to(FirstMeetingServiceImpl.class);
-        bind(FinalSeminarCreationSubscribers.class).asEagerSingleton();
-        bind(ProjectPartnerRepository.class).to(ProjectPartnerRepositoryImpl.class);
-        bind(ProjectNoteService.class).to(ProjectServiceImpl.class);
-
-        install(new PlagiarismModule());
-        install(new NotificationModule());
-        install(new ProfileModule());
-        install(new EventModule());
-        install(new MatchModule());
-        install(new MailModule());
-        install(new ForumModule());
-        install(new ReflectionModule());
-
-        Multibinder.newSetBinder(binder(), UserImportService.class);
-        bind(UserSearchService.class).to(AggregateUserSearch.class);
-        Multibinder.newSetBinder(binder(), UserSearchProvider.class)
-                .addBinding().to(LocalUserSearch.class);
-
-    }
-}
diff --git a/core/src/main/java/modules/ProfileModule.java b/core/src/main/java/modules/ProfileModule.java
deleted file mode 100644
index 16d276dba8..0000000000
--- a/core/src/main/java/modules/ProfileModule.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package modules;
-
-import com.google.inject.Key;
-import com.google.inject.PrivateModule;
-import com.google.inject.name.Names;
-import se.su.dsv.scipro.profiles.CurrentProfile;
-
-public class ProfileModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        requireBinding(Key.get(String.class, Names.named("profile")));
-        bind(CurrentProfile.class).asEagerSingleton();
-        expose(CurrentProfile.class);
-    }
-}
diff --git a/core/src/main/java/modules/RepositoryModule.java b/core/src/main/java/modules/RepositoryModule.java
deleted file mode 100644
index 2ae13bc0cb..0000000000
--- a/core/src/main/java/modules/RepositoryModule.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package modules;
-
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.checklist.ChecklistCategoryRepo;
-import se.su.dsv.scipro.checklist.ChecklistCategoryRepoImpl;
-import se.su.dsv.scipro.checklist.ChecklistQuestionRepo;
-import se.su.dsv.scipro.checklist.ChecklistQuestionRepoImpl;
-import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository;
-import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepositoryImpl;
-import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepo;
-import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepoImpl;
-import se.su.dsv.scipro.finalseminar.FinalSeminarRepository;
-import se.su.dsv.scipro.finalseminar.FinalSeminarRepositoryImpl;
-import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepository;
-import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepositoryImpl;
-import se.su.dsv.scipro.peer.CommentThreadRepo;
-import se.su.dsv.scipro.peer.CommentThreadRepoImpl;
-import se.su.dsv.scipro.peer.PeerRequestRepository;
-import se.su.dsv.scipro.peer.PeerRequestRepositoryImpl;
-import se.su.dsv.scipro.peer.PeerReviewRepository;
-import se.su.dsv.scipro.peer.PeerReviewRepositoryImpl;
-import se.su.dsv.scipro.project.ProjectRepo;
-import se.su.dsv.scipro.project.ProjectRepoImpl;
-import se.su.dsv.scipro.report.GradingReportTemplateRepo;
-import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl;
-import se.su.dsv.scipro.report.OppositionReportRepo;
-import se.su.dsv.scipro.report.OppositionReportRepoImpl;
-import se.su.dsv.scipro.report.SupervisorGradingReportRepository;
-import se.su.dsv.scipro.report.SupervisorGradingReportRepositoryImpl;
-import se.su.dsv.scipro.reviewing.DecisionRepository;
-import se.su.dsv.scipro.reviewing.DecisionRepositoryImpl;
-import se.su.dsv.scipro.reviewing.ReviewerTargetRepository;
-import se.su.dsv.scipro.reviewing.ReviewerTargetRepositoryImpl;
-import se.su.dsv.scipro.system.FooterAddressRepo;
-import se.su.dsv.scipro.system.FooterAddressRepoImpl;
-import se.su.dsv.scipro.system.FooterLinkRepo;
-import se.su.dsv.scipro.system.FooterLinkRepoImpl;
-import se.su.dsv.scipro.system.PasswordRepo;
-import se.su.dsv.scipro.system.PasswordRepoImpl;
-import se.su.dsv.scipro.system.UserRepo;
-import se.su.dsv.scipro.system.UserRepoImpl;
-
-public class RepositoryModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(ChecklistQuestionRepo.class).to(ChecklistQuestionRepoImpl.class);
-        bind(FinalSeminarOppositionRepo.class).to(FinalSeminarOppositionRepoImpl.class);
-        bind(FinalSeminarActiveParticipationRepository.class).to(FinalSeminarActiveParticipationRepositoryImpl.class);
-        bind(GradingReportTemplateRepo.class).to(GradingReportTemplateRepoImpl.class);
-        bind(MilestoneActivityTemplateRepository.class).to(MilestoneActivityTemplateRepositoryImpl.class);
-        bind(OppositionReportRepo.class).to(OppositionReportRepoImpl.class);
-        bind(PasswordRepo.class).to(PasswordRepoImpl.class);
-        bind(ProjectRepo.class).to(ProjectRepoImpl.class);
-        bind(UserRepo.class).to(UserRepoImpl.class);
-        bind(PeerReviewRepository.class).to(PeerReviewRepositoryImpl.class);
-        bind(PeerRequestRepository.class).to(PeerRequestRepositoryImpl.class);
-        bind(ChecklistCategoryRepo.class).to(ChecklistCategoryRepoImpl.class);
-        bind(CommentThreadRepo.class).to(CommentThreadRepoImpl.class);
-        bind(FooterLinkRepo.class).to(FooterLinkRepoImpl.class);
-        bind(FooterAddressRepo.class).to(FooterAddressRepoImpl.class);
-        bind(FinalSeminarRepository.class).to(FinalSeminarRepositoryImpl.class);
-        bind(ReviewerTargetRepository.class).to(ReviewerTargetRepositoryImpl.class);
-        bind(DecisionRepository.class).to(DecisionRepositoryImpl.class);
-        bind(SupervisorGradingReportRepository.class).to(SupervisorGradingReportRepositoryImpl.class);
-    }
-}
\ No newline at end of file
diff --git a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
new file mode 100644
index 0000000000..918df6478f
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
@@ -0,0 +1,1025 @@
+package se.su.dsv.scipro;
+
+import com.google.common.eventbus.EventBus;
+import jakarta.inject.Provider;
+import jakarta.persistence.EntityManager;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import se.su.dsv.scipro.activityplan.ActivityPlanFacade;
+import se.su.dsv.scipro.activityplan.ActivityPlanFacadeImpl;
+import se.su.dsv.scipro.activityplan.ActivityPlanServiceImpl;
+import se.su.dsv.scipro.activityplan.ActivityPlanTemplateServiceImpl;
+import se.su.dsv.scipro.activityplan.ActivityServiceImpl;
+import se.su.dsv.scipro.checklist.ChecklistAnswerServiceImpl;
+import se.su.dsv.scipro.checklist.ChecklistServiceImpl;
+import se.su.dsv.scipro.checklist.ChecklistTemplateService;
+import se.su.dsv.scipro.checklist.ChecklistTemplateServiceImpl;
+import se.su.dsv.scipro.daisyExternal.http.DaisyAPIImpl;
+import se.su.dsv.scipro.date.DateServiceImpl;
+import se.su.dsv.scipro.file.FileDescriptionRepo;
+import se.su.dsv.scipro.file.FileReferenceRepository;
+import se.su.dsv.scipro.file.FileService;
+import se.su.dsv.scipro.file.FileServiceImpl;
+import se.su.dsv.scipro.file.FileStore;
+import se.su.dsv.scipro.file.ProjectFileRepository;
+import se.su.dsv.scipro.file.ProjectFileService;
+import se.su.dsv.scipro.file.ProjectFileServiceImpl;
+import se.su.dsv.scipro.finalseminar.AuthorRepository;
+import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepository;
+import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationServiceImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarCreationSubscribers;
+import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepo;
+import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionServiceImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarRepository;
+import se.su.dsv.scipro.finalseminar.FinalSeminarRespondentServiceImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarService;
+import se.su.dsv.scipro.finalseminar.FinalSeminarServiceImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarSettingsService;
+import se.su.dsv.scipro.finalseminar.FinalSeminarSettingsServiceImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarUploadControllerImpl;
+import se.su.dsv.scipro.finalthesis.FinalThesisService;
+import se.su.dsv.scipro.finalthesis.FinalThesisServiceImpl;
+import se.su.dsv.scipro.firstmeeting.FirstMeetingServiceImpl;
+import se.su.dsv.scipro.forum.AbstractThreadRepository;
+import se.su.dsv.scipro.forum.BasicForumService;
+import se.su.dsv.scipro.forum.BasicForumServiceImpl;
+import se.su.dsv.scipro.forum.ForumPostReadStateRepository;
+import se.su.dsv.scipro.forum.ForumPostRepository;
+import se.su.dsv.scipro.forum.GroupForumService;
+import se.su.dsv.scipro.forum.GroupForumServiceImpl;
+import se.su.dsv.scipro.forum.GroupThreadRepository;
+import se.su.dsv.scipro.forum.ProjectForumService;
+import se.su.dsv.scipro.forum.ProjectForumServiceImpl;
+import se.su.dsv.scipro.forum.ProjectThreadRepository;
+import se.su.dsv.scipro.forum.notifications.ForumNotificationRepository;
+import se.su.dsv.scipro.forum.notifications.ForumNotifications;
+import se.su.dsv.scipro.gdpr.ZipReporter;
+import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
+import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsServiceImpl;
+import se.su.dsv.scipro.grading.GradingHistory;
+import se.su.dsv.scipro.grading.GradingHistoryEventRepository;
+import se.su.dsv.scipro.grading.GradingServiceImpl;
+import se.su.dsv.scipro.grading.NationalSubjectCategoryRepository;
+import se.su.dsv.scipro.grading.NationalSubjectCategoryServiceImpl;
+import se.su.dsv.scipro.grading.PublicationMetadataRepository;
+import se.su.dsv.scipro.grading.PublicationMetadataServiceImpl;
+import se.su.dsv.scipro.grading.ThesisSubmissionHistoryService;
+import se.su.dsv.scipro.group.GroupFacadeImpl;
+import se.su.dsv.scipro.group.GroupService;
+import se.su.dsv.scipro.group.GroupServiceImpl;
+import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepository;
+import se.su.dsv.scipro.integration.activityfinalseminar.FinalSeminarActivityHandler;
+import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepository;
+import se.su.dsv.scipro.integration.activityforum.PostActivityUploadToForum;
+import se.su.dsv.scipro.mail.MailEventService;
+import se.su.dsv.scipro.mail.MailEventServiceImpl;
+import se.su.dsv.scipro.match.AddActivityPlanOnProjectStart;
+import se.su.dsv.scipro.match.ApplicationPeriodFacadeImpl;
+import se.su.dsv.scipro.match.ApplicationPeriodProjectTypeServiceImpl;
+import se.su.dsv.scipro.match.ApplicationPeriodService;
+import se.su.dsv.scipro.match.ApplicationPeriodServiceImpl;
+import se.su.dsv.scipro.match.FirstMeetingRepository;
+import se.su.dsv.scipro.match.IdeaFacade;
+import se.su.dsv.scipro.match.IdeaRepository;
+import se.su.dsv.scipro.match.IdeaService;
+import se.su.dsv.scipro.match.IdeaServiceImpl;
+import se.su.dsv.scipro.match.KeywordServiceImpl;
+import se.su.dsv.scipro.match.MatchFollowUpServiceImpl;
+import se.su.dsv.scipro.match.MatchServiceImpl;
+import se.su.dsv.scipro.match.PreliminaryMatchServiceImpl;
+import se.su.dsv.scipro.match.ProgramServiceImpl;
+import se.su.dsv.scipro.match.ProjectStartNotifier;
+import se.su.dsv.scipro.match.TargetRepository;
+import se.su.dsv.scipro.match.TargetServiceImpl;
+import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepository;
+import se.su.dsv.scipro.milestones.service.ActivateCompletedMilestonesOnNewProjects;
+import se.su.dsv.scipro.milestones.service.MilestoneActivityTemplateService;
+import se.su.dsv.scipro.milestones.service.impl.MilestoneActivityTemplateServiceImpl;
+import se.su.dsv.scipro.milestones.service.impl.MilestonePhaseTemplateServiceImpl;
+import se.su.dsv.scipro.milestones.service.impl.MilestoneServiceImpl;
+import se.su.dsv.scipro.milestones.service.impl.MilestoneStatisticsServiceImpl;
+import se.su.dsv.scipro.misc.DaysService;
+import se.su.dsv.scipro.misc.DaysServiceImpl;
+import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodService;
+import se.su.dsv.scipro.nonworkperiod.NonWorkDayPeriodServiceImpl;
+import se.su.dsv.scipro.notes.NoteServiceImpl;
+import se.su.dsv.scipro.notifications.NotificationController;
+import se.su.dsv.scipro.notifications.NotificationControllerImpl;
+import se.su.dsv.scipro.notifications.NotificationEventRepository;
+import se.su.dsv.scipro.notifications.NotificationEventServiceImpl;
+import se.su.dsv.scipro.notifications.NotificationService;
+import se.su.dsv.scipro.notifications.NotificationServiceImpl;
+import se.su.dsv.scipro.notifications.Notifications;
+import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter;
+import se.su.dsv.scipro.notifications.interfaces.impl.NotificationMailFormatterImpl;
+import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationService;
+import se.su.dsv.scipro.notifications.settings.service.DeliveryConfigurationServiceImpl;
+import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationService;
+import se.su.dsv.scipro.notifications.settings.service.ReceiverConfigurationServiceImpl;
+import se.su.dsv.scipro.oauth.OAuthServiceImpl;
+import se.su.dsv.scipro.oauth.OAuthSettings;
+import se.su.dsv.scipro.peer.CommentServiceImpl;
+import se.su.dsv.scipro.peer.CommentThreadRepo;
+import se.su.dsv.scipro.peer.CommentThreadServiceImpl;
+import se.su.dsv.scipro.peer.PeerPortalImpl;
+import se.su.dsv.scipro.peer.PeerRequestRepository;
+import se.su.dsv.scipro.peer.PeerRequestService;
+import se.su.dsv.scipro.peer.PeerRequestServiceImpl;
+import se.su.dsv.scipro.peer.PeerReviewRepository;
+import se.su.dsv.scipro.peer.PeerReviewService;
+import se.su.dsv.scipro.peer.PeerReviewServiceImpl;
+import se.su.dsv.scipro.plagiarism.PlagiarismControl;
+import se.su.dsv.scipro.plagiarism.PlagiarismControlImpl;
+import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepository;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundApi;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundApiImpl;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundServiceImpl;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepository;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepository;
+import se.su.dsv.scipro.project.ProjectPeopleStatisticsServiceImpl;
+import se.su.dsv.scipro.project.ProjectRepo;
+import se.su.dsv.scipro.project.ProjectService;
+import se.su.dsv.scipro.project.ProjectServiceImpl;
+import se.su.dsv.scipro.projectpartner.ProjectPartnerServiceImpl;
+import se.su.dsv.scipro.reflection.ReflectionService;
+import se.su.dsv.scipro.reflection.ReflectionServiceImpl;
+import se.su.dsv.scipro.report.GradeCalculatorServiceImpl;
+import se.su.dsv.scipro.report.GradingReportService;
+import se.su.dsv.scipro.report.GradingReportServiceImpl;
+import se.su.dsv.scipro.report.GradingReportTemplateRepo;
+import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl;
+import se.su.dsv.scipro.report.OppositionReportRepo;
+import se.su.dsv.scipro.report.OppositionReportServiceImpl;
+import se.su.dsv.scipro.report.ReportServiceImpl;
+import se.su.dsv.scipro.report.SupervisorGradingReportRepository;
+import se.su.dsv.scipro.reviewing.DecisionRepository;
+import se.su.dsv.scipro.reviewing.FinalSeminarApprovalService;
+import se.su.dsv.scipro.reviewing.FinalSeminarApprovalServiceImpl;
+import se.su.dsv.scipro.reviewing.ProjectFinalSeminarStatisticsServiceImpl;
+import se.su.dsv.scipro.reviewing.ReviewerAssignedDeadline;
+import se.su.dsv.scipro.reviewing.ReviewerCapacityServiceImpl;
+import se.su.dsv.scipro.reviewing.ReviewerDeadlineFollowupServiceImpl;
+import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsRepository;
+import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsService;
+import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsServiceImpl;
+import se.su.dsv.scipro.reviewing.ReviewerInteractionService;
+import se.su.dsv.scipro.reviewing.ReviewerInteractionServiceImpl;
+import se.su.dsv.scipro.reviewing.ReviewerTargetRepository;
+import se.su.dsv.scipro.reviewing.ReviewerThreadRepository;
+import se.su.dsv.scipro.reviewing.ReviewingServiceImpl;
+import se.su.dsv.scipro.reviewing.RoughDraftApprovalService;
+import se.su.dsv.scipro.reviewing.RoughDraftApprovalServiceImpl;
+import se.su.dsv.scipro.security.auth.AuthenticationProvider;
+import se.su.dsv.scipro.security.auth.AuthenticationServiceImpl;
+import se.su.dsv.scipro.security.auth.LocalAuthentication;
+import se.su.dsv.scipro.springdata.serviceimpls.SupervisorServiceImpl;
+import se.su.dsv.scipro.springdata.serviceimpls.UnitServiceImpl;
+import se.su.dsv.scipro.springdata.serviceimpls.UserProfileServiceImpl;
+import se.su.dsv.scipro.springdata.services.UserProfileService;
+import se.su.dsv.scipro.sukat.LDAP;
+import se.su.dsv.scipro.sukat.Sukat;
+import se.su.dsv.scipro.survey.QuestionRepository;
+import se.su.dsv.scipro.survey.SurveyRepository;
+import se.su.dsv.scipro.survey.SurveyServiceImpl;
+import se.su.dsv.scipro.system.CurrentUser;
+import se.su.dsv.scipro.system.EventServiceImpl;
+import se.su.dsv.scipro.system.ExternalResourceServiceImpl;
+import se.su.dsv.scipro.system.FooterLinkRepo;
+import se.su.dsv.scipro.system.FooterLinkServiceImpl;
+import se.su.dsv.scipro.system.LocalUserSearch;
+import se.su.dsv.scipro.system.PasswordRepo;
+import se.su.dsv.scipro.system.PasswordService;
+import se.su.dsv.scipro.system.PasswordServiceImpl;
+import se.su.dsv.scipro.system.ProjectTypeService;
+import se.su.dsv.scipro.system.ProjectTypeServiceImpl;
+import se.su.dsv.scipro.system.ResearchAreaServiceImpl;
+import se.su.dsv.scipro.system.UserNameServiceImpl;
+import se.su.dsv.scipro.system.UserRepo;
+import se.su.dsv.scipro.system.UserService;
+import se.su.dsv.scipro.system.UserServiceImpl;
+import se.su.dsv.scipro.thesislink.ExternalLinkServiceImpl;
+import se.su.dsv.scipro.workerthreads.WorkerDataServiceImpl;
+
+import java.time.Clock;
+import java.util.Set;
+
+@Configuration(proxyBeanMethods = false)
+public class CoreConfig {
+    @Bean
+    public EventBus eventBus() {
+        return new EventBus();
+    }
+
+    @Bean
+    public GradingHistory gradingHistory(GradingHistoryEventRepository gradingHistoryEventRepository) {
+        return new GradingHistory(gradingHistoryEventRepository);
+    }
+
+    @Bean
+    public OAuthSettings oAuthSettings(
+            @Value("${oauth.uri}") String uri,
+            @Value("${oauth.redirectUri}") String redirectUri,
+            @Value("${oauth.clientId}") String clientId,
+            @Value("${oauth.clientSecret}") String clientSecret)
+    {
+        return new OAuthSettings(uri, redirectUri, clientId, clientSecret);
+    }
+
+    @Bean
+    public Sukat sukat() {
+        return new LDAP();
+    }
+
+    @Bean
+    public DaisyAPIImpl daisyAPI(
+            @Value("${daisy.api.url}") final String baseUrl,
+            @Value("${daisy.api.username}") final String user,
+            @Value("${daisy.api.password}") final String password)
+    {
+        return new DaisyAPIImpl(baseUrl, user, password);
+    }
+
+    @Bean
+    public GradingServiceImpl gradingService(@Value("${service.grading.url}") final String url) {
+        return new GradingServiceImpl(url);
+    }
+
+    @Bean
+    public OAuthServiceImpl oAuthService(OAuthSettings settings) {
+        return new OAuthServiceImpl(settings);
+    }
+
+    @Bean
+    public FinalSeminarApprovalServiceImpl finalSeminarApprovalService(
+            Provider<EntityManager> em,
+            FileService fileDescriptionService,
+            EventBus eventBus,
+            DaysService daysService,
+            ReviewerDeadlineSettingsService reviewerDeadlineSettingsService)
+    {
+        return new FinalSeminarApprovalServiceImpl(em, fileDescriptionService, eventBus, daysService, reviewerDeadlineSettingsService);
+    }
+
+    @Bean
+    public RoughDraftApprovalServiceImpl roughDraftApprovalService(
+            Provider<EntityManager> em,
+            FileService fileDescriptionService,
+            EventBus eventBus,
+            DaysService daysService,
+            ReviewerDeadlineSettingsService reviewerDeadlineSettingsService)
+    {
+        return new RoughDraftApprovalServiceImpl(em, eventBus, fileDescriptionService, daysService, reviewerDeadlineSettingsService);
+    }
+
+    @Bean
+    public ActivityPlanServiceImpl activityPlanService(Provider<EntityManager> em) {
+        return new ActivityPlanServiceImpl(em);
+    }
+
+    @Bean
+    public ActivityPlanTemplateServiceImpl activityPlanTemplateService(Provider<EntityManager> em) {
+        return new ActivityPlanTemplateServiceImpl(em);
+    }
+
+    @Bean
+    public ActivityServiceImpl activityService(Provider<EntityManager> em) {
+        return new ActivityServiceImpl(em);
+    }
+
+    @Bean
+    public ActivityPlanFacadeImpl activityPlanFacade(
+            EventBus eventBus,
+            ProjectFileService projectFileService,
+            ChecklistTemplateService checklistTemplateService,
+            DaysService daysService,
+            FileService fileService
+    )
+    {
+        return new ActivityPlanFacadeImpl(eventBus, projectFileService, checklistTemplateService, daysService,
+                fileService);
+    }
+
+    @Bean
+    public ApplicationPeriodFacadeImpl applicationPeriodFacade() {
+        return new ApplicationPeriodFacadeImpl();
+    }
+
+    @Bean
+    public ApplicationPeriodProjectTypeServiceImpl applicationPeriodProjectTypeService(Provider<EntityManager> em) {
+        return new ApplicationPeriodProjectTypeServiceImpl(em);
+    }
+
+    @Bean
+    public ApplicationPeriodServiceImpl applicationPeriodService(Provider<EntityManager> em, Clock clock) {
+        return new ApplicationPeriodServiceImpl(em, clock);
+    }
+
+    @Bean
+    public AuthenticationServiceImpl authenticationService(Set<AuthenticationProvider> authenticationProviders) {
+        return new AuthenticationServiceImpl(authenticationProviders);
+    }
+
+    @Bean
+    public LocalAuthentication localAuthentication(
+            UserService userService,
+            PasswordService passwordService)
+    {
+        return new LocalAuthentication(userService, passwordService);
+    }
+
+    @Bean
+    public BasicForumServiceImpl basicForumService(
+            ForumPostRepository forumPostRepository,
+            ForumPostReadStateRepository readStateRepository,
+            AbstractThreadRepository threadRepository,
+            FileService fileService,
+            EventBus eventBus)
+    {
+        return new BasicForumServiceImpl(forumPostRepository, readStateRepository, threadRepository, fileService,
+                eventBus);
+    }
+
+    @Bean
+    public ChecklistAnswerServiceImpl checklistAnswerService(Provider<EntityManager> em) {
+        return new ChecklistAnswerServiceImpl(em);
+    }
+
+    @Bean
+    public ChecklistServiceImpl checklistService(Provider<EntityManager> em) {
+        return new ChecklistServiceImpl(em);
+    }
+
+    @Bean
+    public ChecklistTemplateServiceImpl checklistTemplateService(Provider<EntityManager> em) {
+        return new ChecklistTemplateServiceImpl(em);
+    }
+
+    @Bean
+    public CommentServiceImpl commentService(Provider<EntityManager> em) {
+        return new CommentServiceImpl(em);
+    }
+
+    @Bean
+    public DateServiceImpl dateService() {
+        return new DateServiceImpl();
+    }
+
+    @Bean
+    public DaysServiceImpl daysService(NonWorkDayPeriodService nonWorkDayPeriodService) {
+        return new DaysServiceImpl(nonWorkDayPeriodService);
+    }
+
+    @Bean
+    public DeliveryConfigurationServiceImpl deliveryConfigurationService(
+            Provider<EntityManager> em,
+            UserProfileService userProfileService)
+    {
+        return new DeliveryConfigurationServiceImpl(em, userProfileService);
+    }
+
+    @Bean
+    public EventServiceImpl eventService(Provider<EntityManager> em) {
+        return new EventServiceImpl(em);
+    }
+
+    @Bean
+    public ExternalLinkServiceImpl externalLinkService(Provider<EntityManager> em) {
+        return new ExternalLinkServiceImpl(em);
+    }
+
+    @Bean
+    public ExternalResourceServiceImpl externalResourceService(Provider<EntityManager> em) {
+        return new ExternalResourceServiceImpl(em);
+    }
+
+    @Bean
+    public FileServiceImpl fileService(
+            Provider<EntityManager> em,
+            FileStore fileStore,
+            FileReferenceRepository fileReferenceRepository,
+            FileDescriptionRepo fileDescriptionRepository)
+    {
+        return new FileServiceImpl(em, fileReferenceRepository, fileDescriptionRepository, fileStore);
+    }
+
+    @Bean
+    public FinalSeminarActiveParticipationServiceImpl finalSeminarActiveParticipationService(Provider<EntityManager> em) {
+        return new FinalSeminarActiveParticipationServiceImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarOppositionServiceImpl finalSeminarOppositionService(Provider<EntityManager> em) {
+        return new FinalSeminarOppositionServiceImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarRespondentServiceImpl finalSeminarRespondentService(Provider<EntityManager> em) {
+        return new FinalSeminarRespondentServiceImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarServiceImpl finalSeminarService(
+            Provider<EntityManager> em,
+            EventBus eventBus,
+            FileService fileService,
+            AuthorRepository authorRepository,
+            FinalSeminarOppositionRepo finalSeminarOppositionRepository,
+            FinalSeminarActiveParticipationRepository finalSeminarActiveParticipationRepository,
+            FinalSeminarRepository finalSeminarRepository,
+            Clock clock,
+            RoughDraftApprovalService roughDraftApprovalService)
+    {
+        return new FinalSeminarServiceImpl(
+                em,
+                eventBus,
+                authorRepository,
+                fileService,
+                finalSeminarOppositionRepository,
+                finalSeminarActiveParticipationRepository,
+                finalSeminarRepository,
+                clock,
+                roughDraftApprovalService);
+    }
+
+    @Bean
+    public FinalSeminarSettingsServiceImpl finalSeminarSettingsService(Provider<EntityManager> em) {
+        return new FinalSeminarSettingsServiceImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarUploadControllerImpl finalSeminarUploadController(
+            EventBus eventBus,
+            FileService fileService,
+            FinalSeminarService finalSeminarService,
+            ProjectFileService projectFileService,
+            ProjectService projectService,
+            FinalSeminarSettingsService finalSeminarSettingsService,
+            PlagiarismControl plagiarismControl)
+    {
+        return new FinalSeminarUploadControllerImpl(projectService, fileService, finalSeminarSettingsService,
+                finalSeminarService, eventBus, projectFileService, plagiarismControl);
+    }
+
+    @Bean
+    public FinalThesisServiceImpl finalThesisService(
+            Provider<EntityManager> em,
+            NotificationController notification,
+            ProjectFileService projectFile,
+            FileService fileService,
+            EventBus eventBus,
+            PlagiarismControl plagiarismControl,
+            GradingReportService gradingReportService)
+    {
+        return new FinalThesisServiceImpl(em, notification, projectFile,
+                fileService, eventBus, plagiarismControl, gradingReportService);
+    }
+
+    @Bean
+    public FirstMeetingServiceImpl firstMeetingService(
+            Provider<EntityManager> em,
+            ActivityPlanFacade activityPlanFacade)
+    {
+        return new FirstMeetingServiceImpl(em, activityPlanFacade);
+    }
+
+    @Bean
+    public FooterLinkServiceImpl footerLinkService(FooterLinkRepo footerLinkRepository) {
+        return new FooterLinkServiceImpl(footerLinkRepository);
+    }
+
+    @Bean
+    public GeneralSystemSettingsServiceImpl generalSystemSettingsService(Provider<EntityManager> em) {
+        return new GeneralSystemSettingsServiceImpl(em);
+    }
+
+    @Bean
+    public GradeCalculatorServiceImpl gradeCalculatorService(GradingReportService gradingReportService) {
+        return new GradeCalculatorServiceImpl(gradingReportService);
+    }
+
+    @Bean
+    public GradingReportServiceImpl gradingReportService(
+            EventBus eventBus,
+            ThesisSubmissionHistoryService thesisSubmissionHistoryService,
+            Clock clock,
+            SupervisorGradingReportRepository supervisorGradingReportRepository,
+            GradingReportTemplateRepoImpl gradingReportTemplateRepo,
+            ProjectTypeService projectTypeService)
+    {
+        return new GradingReportServiceImpl(
+                eventBus,
+                thesisSubmissionHistoryService,
+                clock,
+                supervisorGradingReportRepository,
+                gradingReportTemplateRepo,
+                projectTypeService);
+    }
+
+    @Bean
+    public GroupForumServiceImpl groupForumService(
+            EventBus eventBus,
+            GroupThreadRepository groupThreadRepository,
+            BasicForumService basicForumService)
+    {
+        return new GroupForumServiceImpl(groupThreadRepository, basicForumService, eventBus);
+    }
+
+    @Bean
+    public GroupServiceImpl groupService(Provider<EntityManager> em) {
+        return new GroupServiceImpl(em);
+    }
+
+    @Bean
+    public IdeaServiceImpl ideaService(
+            Provider<EntityManager> em,
+            ApplicationPeriodService applicationPeriodService,
+            FirstMeetingRepository firstMeetingRepository,
+            NotificationController notificationController,
+            ProjectService projectService,
+            GeneralSystemSettingsService generalSystemSettingsService,
+            TargetRepository targetRepository,
+            IdeaRepository ideaRepository,
+            Clock clock)
+    {
+        return new IdeaServiceImpl(em, applicationPeriodService, firstMeetingRepository, notificationController,
+                projectService, generalSystemSettingsService, targetRepository, ideaRepository, clock);
+    }
+
+    @Bean
+    public KeywordServiceImpl keywordService(Provider<EntityManager> em) {
+        return new KeywordServiceImpl(em);
+    }
+
+    @Bean
+    public LocalUserSearch localUserSearch(UserRepo userRepository) {
+        return new LocalUserSearch(userRepository);
+    }
+
+    @Bean
+    public MailEventServiceImpl mailEventService(Provider<EntityManager> em) {
+        return new MailEventServiceImpl(em);
+    }
+
+    @Bean
+    public MatchFollowUpServiceImpl matchFollowUpService(Provider<EntityManager> em) {
+        return new MatchFollowUpServiceImpl(em);
+    }
+
+    @Bean
+    public MatchServiceImpl matchService(Provider<EntityManager> em) {
+        return new MatchServiceImpl(em);
+    }
+
+    @Bean
+    public MilestoneActivityTemplateServiceImpl milestoneActivityTemplateService(
+            MilestoneActivityTemplateRepository milestoneActivityTemplateRepository)
+    {
+        return new MilestoneActivityTemplateServiceImpl(milestoneActivityTemplateRepository);
+    }
+
+    @Bean
+    public MilestonePhaseTemplateServiceImpl milestonePhaseTemplateService(Provider<EntityManager> em) {
+        return new MilestonePhaseTemplateServiceImpl(em);
+    }
+
+    @Bean
+    public MilestoneServiceImpl milestoneService(
+            Provider<EntityManager> em,
+            NotificationController notificationController)
+    {
+        return new MilestoneServiceImpl(notificationController, em);
+    }
+
+    @Bean
+    public MilestoneStatisticsServiceImpl milestoneStatisticsService(Provider<EntityManager> em) {
+        return new MilestoneStatisticsServiceImpl(em);
+    }
+
+    @Bean
+    public NationalSubjectCategoryServiceImpl nationalSubjectCategoryService(
+            NationalSubjectCategoryRepository nationalSubjectCategoryRepository)
+    {
+        return new NationalSubjectCategoryServiceImpl(nationalSubjectCategoryRepository);
+    }
+
+    @Bean
+    public NonWorkDayPeriodServiceImpl nonWorkDayPeriodService(Provider<EntityManager> em) {
+        return new NonWorkDayPeriodServiceImpl(em);
+    }
+
+    @Bean
+    public NoteServiceImpl noteService(Provider<EntityManager> em) {
+        return new NoteServiceImpl(em);
+    }
+
+    @Bean
+    public NotificationServiceImpl notificationService(Provider<EntityManager> em) {
+        return new NotificationServiceImpl(em);
+    }
+
+    @Bean
+    public OppositionReportServiceImpl oppositionReportService(
+            OppositionReportRepo oppositionReportRepository,
+            GradingReportTemplateRepo gradingReportTemplateRepository,
+            FileService fileService,
+            FinalSeminarOppositionRepo finalSeminarOppositionRepository)
+    {
+        return new OppositionReportServiceImpl(oppositionReportRepository, gradingReportTemplateRepository,
+                fileService, finalSeminarOppositionRepository);
+    }
+
+    @Bean
+    public PasswordServiceImpl passwordService(PasswordRepo passwordRepo) {
+        return new PasswordServiceImpl(passwordRepo);
+    }
+
+    @Bean
+    public PeerPortalImpl peerPortal(
+            FileService fileService,
+            PeerReviewRepository peerReviewRepository,
+            PeerRequestRepository peerRequestRepository,
+            EventBus eventBus,
+            ProjectFileService projectFileService,
+            DaysService daisyService,
+            Clock clock)
+    {
+        return new PeerPortalImpl(fileService, peerReviewRepository, peerRequestRepository,
+                eventBus, projectFileService, daisyService, clock);
+    }
+
+    @Bean
+    public PeerRequestServiceImpl peerRequestService(
+            Provider<EntityManager> em,
+            EventBus eventBus,
+            FileService fileService)
+    {
+        return new PeerRequestServiceImpl(em, eventBus, fileService);
+    }
+
+    @Bean
+    public PeerReviewServiceImpl peerReviewService(
+            Provider<EntityManager> em,
+            PeerReviewRepository peerReviewRepository)
+    {
+        return new PeerReviewServiceImpl(em, peerReviewRepository);
+    }
+
+    @Bean
+    public PlagiarismControlImpl plagiarismControl(
+            FileService fileService,
+            PlagiarismRequestRepository plagiarismRequestRepository,
+            UrkundSubmissionRepository urkundSubmissionRepository)
+    {
+        return new PlagiarismControlImpl(plagiarismRequestRepository, urkundSubmissionRepository, fileService);
+    }
+
+    @Bean
+    public PreliminaryMatchServiceImpl preliminaryMatchService(Provider<EntityManager> em, IdeaService ideaService) {
+        return new PreliminaryMatchServiceImpl(em, ideaService);
+    }
+
+    @Bean
+    public ProgramServiceImpl programService(Provider<EntityManager> em) {
+        return new ProgramServiceImpl(em);
+    }
+
+    @Bean
+    public ProjectFileServiceImpl projectFileService(
+            FileService fileService,
+            ProjectFileRepository projectFileRepository)
+    {
+        return new ProjectFileServiceImpl(fileService, projectFileRepository);
+    }
+
+    @Bean
+    public ProjectFinalSeminarStatisticsServiceImpl projectFinalSeminarStatisticsService(Provider<EntityManager> em) {
+        return new ProjectFinalSeminarStatisticsServiceImpl(em);
+    }
+
+    @Bean
+    public ProjectForumServiceImpl projectForumService(
+            EventBus eventBus,
+            BasicForumService basicForumService,
+            ProjectThreadRepository projectThreadRepository,
+            ForumPostRepository postRepository,
+            ProjectFileService projectFileService)
+    {
+        return new ProjectForumServiceImpl(projectThreadRepository,
+                postRepository, projectFileService, basicForumService, eventBus);
+    }
+
+    @Bean
+    public ProjectPartnerServiceImpl projectPartnerService(Provider<EntityManager> em) {
+        return new ProjectPartnerServiceImpl(em);
+    }
+
+    @Bean
+    public ProjectPeopleStatisticsServiceImpl projectPeopleStatisticsService(Provider<EntityManager> em) {
+        return new ProjectPeopleStatisticsServiceImpl(em);
+    }
+
+    @Bean
+    public ProjectServiceImpl projectService(
+            Provider<EntityManager> em,
+            EventBus eventBus,
+            ProjectRepo projectRepo,
+            Clock clock)
+    {
+        return new ProjectServiceImpl(projectRepo, clock, eventBus, em);
+    }
+
+    @Bean
+    public ProjectTypeServiceImpl projectTypeService(Provider<EntityManager> em) {
+        return new ProjectTypeServiceImpl(em);
+    }
+
+    @Bean
+    public PublicationMetadataServiceImpl publicationMetadataService(
+            PublicationMetadataRepository publicationMetadataRepository)
+    {
+        return new PublicationMetadataServiceImpl(publicationMetadataRepository);
+    }
+
+    @Bean
+    public ReflectionServiceImpl reflectionService(
+            AuthorRepository authorRepository,
+            FinalSeminarServiceImpl finalSeminarService,
+            EventBus eventBus)
+    {
+        return new ReflectionServiceImpl(authorRepository, finalSeminarService, eventBus);
+    }
+
+    @Bean
+    public ReceiverConfigurationServiceImpl receiverConfigurationService(Provider<EntityManager> em) {
+        return new ReceiverConfigurationServiceImpl(em);
+    }
+
+    @Bean
+    public ReviewerDeadlineFollowupServiceImpl reviewerDeadlineFollowupService(Provider<EntityManager> em) {
+        return new ReviewerDeadlineFollowupServiceImpl(em);
+    }
+
+    @Bean
+    public ZipReporter reporter(
+            FileService fileService,
+            ProjectService projectService,
+            FinalSeminarService finalSeminarService,
+            ProjectForumService projectForumService,
+            PeerReviewService peerReviewService,
+            PeerRequestService peerRequestService,
+            GroupService groupService,
+            GroupForumService groupForumService,
+            IdeaService ideaService,
+            GradingReportService gradingReportService,
+            ReviewerInteractionService reviewerInteractionService,
+            RoughDraftApprovalService roughDraftApprovalService,
+            FinalSeminarApprovalService finalSeminarApprovalService)
+    {
+        return new ZipReporter(fileService, projectService, finalSeminarService, projectForumService, peerReviewService,
+                peerRequestService, groupService, groupForumService, ideaService, gradingReportService,
+                reviewerInteractionService, roughDraftApprovalService, finalSeminarApprovalService);
+    }
+
+    @Bean
+    public ReportServiceImpl reportService(Provider<EntityManager> em, FileService fileService) {
+        return new ReportServiceImpl(em, fileService);
+    }
+
+    @Bean
+    public ResearchAreaServiceImpl researchAreaService(Provider<EntityManager> em) {
+        return new ResearchAreaServiceImpl(em);
+    }
+
+    @Bean
+    public ReviewerInteractionServiceImpl reviewerInteractionService(
+            ReviewerThreadRepository reviewerThreadRepository,
+            BasicForumService forumService,
+            EventBus eventBus)
+    {
+        return new ReviewerInteractionServiceImpl(reviewerThreadRepository, forumService, eventBus);
+    }
+
+    @Bean
+    public ReviewingServiceImpl reviewingService(
+            Provider<EntityManager> em,
+            EventBus eventBus,
+            FileService fileService)
+    {
+        return new ReviewingServiceImpl(em, fileService, eventBus);
+    }
+
+    @Bean
+    public ReviewerCapacityServiceImpl reviewerCapacityService(
+            ReviewerTargetRepository reviewerTargetRepository,
+            DecisionRepository decisionRepository,
+            UserService userService,
+            ProjectService projectService,
+            EventBus eventBus)
+    {
+        return new ReviewerCapacityServiceImpl(reviewerTargetRepository, decisionRepository, userService,
+                projectService, eventBus);
+    }
+
+    @Bean
+    public ReviewerDeadlineSettingsServiceImpl reviewerDeadlineSettingsService(
+            ReviewerDeadlineSettingsRepository reviewerDeadlineSettingsRepository)
+    {
+        return new ReviewerDeadlineSettingsServiceImpl(reviewerDeadlineSettingsRepository);
+    }
+
+    @Bean
+    public SupervisorServiceImpl supervisorService(Provider<EntityManager> em) {
+        return new SupervisorServiceImpl(em);
+    }
+
+    @Bean
+    public SurveyServiceImpl surveyService(
+            SurveyRepository surveyRepository,
+            QuestionRepository questionRepository,
+            FinalThesisService finalThesisService,
+            GeneralSystemSettingsService generalSystemSettingsService,
+            ReflectionService reflectionService)
+    {
+        return new SurveyServiceImpl(surveyRepository, questionRepository, finalThesisService,
+                generalSystemSettingsService, reflectionService);
+    }
+
+    @Bean
+    public TargetServiceImpl targetService(Provider<EntityManager> em, IdeaService ideaService) {
+        return new TargetServiceImpl(em, ideaService);
+    }
+
+    @Bean
+    public UnitServiceImpl unitService(Provider<EntityManager> em) {
+        return new UnitServiceImpl(em);
+    }
+
+    @Bean
+    public UrkundApiImpl urkundApi(
+            UrkundSettingsRepository urkundSettingsRepository,
+            FileService fileService)
+    {
+        return new UrkundApiImpl(urkundSettingsRepository, fileService);
+    }
+
+    @Bean
+    public UrkundServiceImpl urkundService(
+            UrkundApi urkundApi,
+            UrkundSubmissionRepository urkundSubmissionRepository,
+            Sukat sukat,
+            FileService fileService)
+    {
+        return new UrkundServiceImpl(urkundApi, urkundSubmissionRepository, sukat, fileService);
+    }
+
+    @Bean
+    public UserNameServiceImpl userNameService(Provider<EntityManager> em) {
+        return new UserNameServiceImpl(em);
+    }
+
+    @Bean
+    public UserProfileServiceImpl userProfileService(Provider<EntityManager> em) {
+        return new UserProfileServiceImpl(em);
+    }
+
+    @Bean
+    public UserServiceImpl userService(Provider<EntityManager> em) {
+        return new UserServiceImpl(em);
+    }
+
+    @Bean
+    public WorkerDataServiceImpl workerDataService(Provider<EntityManager> em) {
+        return new WorkerDataServiceImpl(em);
+    }
+
+    @Bean
+    public NotificationControllerImpl notificationController(
+            NotificationServiceImpl notificationService,
+            NotificationMailFormatter notificationMailFormatter,
+            MailEventService mailEventService,
+            ReceiverConfigurationService receiverConfigurationService,
+            DeliveryConfigurationService deliveryConfigurationService,
+            Provider<CurrentUser> currentUserProvider)
+    {
+        return new NotificationControllerImpl(notificationService,
+                notificationMailFormatter,
+                mailEventService, receiverConfigurationService, deliveryConfigurationService, currentUserProvider);
+    }
+
+    @Bean
+    public NotificationMailFormatterImpl notificationMailFormatter() {
+        return new NotificationMailFormatterImpl();
+    }
+
+    @Bean
+    public ReviewerAssignedDeadline reviewerAssignedDeadline(
+            EventBus eventBus,
+            ReviewerDeadlineSettingsService reviewerDeadlineSettingsService,
+            RoughDraftApprovalService roughDraftApprovalService,
+            FinalSeminarApprovalService finalSeminarApprovalService,
+            DaysService daysService,
+            Clock clock)
+    {
+        return new ReviewerAssignedDeadline(roughDraftApprovalService, finalSeminarApprovalService,
+                reviewerDeadlineSettingsService, daysService, eventBus, clock);
+    }
+
+    @Bean
+    public DataInitializer dataInitializer() {
+        return new DataInitializer();
+    }
+
+    @Bean
+    public FinalSeminarActivityHandler finalSeminarActivityHandler(
+            ActivityPlanFacade activityPlanFacade,
+            ActivityFinalSeminarRepository activityFinalSeminarRepository,
+            EventBus eventBus)
+    {
+        return new FinalSeminarActivityHandler(activityPlanFacade, activityFinalSeminarRepository, eventBus);
+    }
+
+    @Bean
+    public PostActivityUploadToForum postActivityUploadToForum(
+            EventBus eventBus,
+            ProjectForumService projectForumService,
+            ActivityThreadRepository activityThreadRepository)
+    {
+        return new PostActivityUploadToForum(projectForumService, activityThreadRepository, eventBus);
+    }
+
+    @Bean
+    public ForumNotifications forumNotifications(
+            EventBus eventBus,
+            NotificationController notificationController,
+            ForumNotificationRepository forumNotificationRepository,
+            NotificationService notificationService)
+    {
+        return new ForumNotifications(eventBus, notificationController, forumNotificationRepository,
+                notificationService);
+    }
+
+    @Bean
+    public ActivateCompletedMilestonesOnNewProjects activateCompletedMilestonesOnNewProjects(
+            EventBus eventBus,
+            MilestoneServiceImpl milestoneService,
+            PeerReviewService peerReviewService,
+            MilestoneActivityTemplateService milestoneActivityTemplateService,
+            FinalSeminarService finalSeminarService)
+    {
+        return new ActivateCompletedMilestonesOnNewProjects(peerReviewService, milestoneActivityTemplateService,
+                milestoneService, eventBus, finalSeminarService);
+    }
+
+    @Bean
+    public FinalSeminarCreationSubscribers finalSeminarCreationSubscribers(
+            EventBus eventBus,
+            FinalSeminarServiceImpl finalSeminarService,
+            NotificationController notificationController,
+            AuthorRepository authorRepository)
+    {
+        return new FinalSeminarCreationSubscribers(authorRepository, finalSeminarService, notificationController, eventBus);
+    }
+
+    @Bean
+    public ProjectStartNotifier projectStartNotifier(EventBus eventBus, NotificationController notificationController) {
+        return new ProjectStartNotifier(eventBus, notificationController);
+    }
+
+    @Bean
+    public AddActivityPlanOnProjectStart addActivityPlanOnProjectStart(
+            ActivityPlanFacade activityPlanFacade,
+            EventBus eventBus)
+    {
+        return new AddActivityPlanOnProjectStart(activityPlanFacade, eventBus);
+    }
+
+    @Bean
+    public Notifications notifications(
+            EventBus eventBus,
+            NotificationController notificationController,
+            NotificationService notificationService)
+    {
+        return new Notifications(notificationController, notificationService, eventBus);
+    }
+
+    @Bean
+    public CommentThreadServiceImpl commentThreadService(CommentThreadRepo commentThreadRepository) {
+        return new CommentThreadServiceImpl(commentThreadRepository);
+    }
+
+    @Bean
+    public NotificationEventServiceImpl notificationEventService(NotificationEventRepository notificationEventRepository) {
+        return new NotificationEventServiceImpl(notificationEventRepository);
+    }
+
+    @Bean
+    public IdeaFacade ideaFacade() {
+        return new IdeaFacade();
+    }
+
+    @Bean
+    public GroupFacadeImpl groupFacade() {
+        return new GroupFacadeImpl();
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/DataInitializer.java b/core/src/main/java/se/su/dsv/scipro/DataInitializer.java
index 6720ffac7e..762ea0c32a 100644
--- a/core/src/main/java/se/su/dsv/scipro/DataInitializer.java
+++ b/core/src/main/java/se/su/dsv/scipro/DataInitializer.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.checklist.ChecklistCategory;
 import se.su.dsv.scipro.match.ApplicationPeriod;
 import se.su.dsv.scipro.match.Keyword;
diff --git a/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java b/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java
new file mode 100644
index 0000000000..6a2167bc1f
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/RepositoryConfiguration.java
@@ -0,0 +1,285 @@
+package se.su.dsv.scipro;
+
+import jakarta.inject.Provider;
+import jakarta.persistence.EntityManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import se.su.dsv.scipro.checklist.ChecklistCategoryRepoImpl;
+import se.su.dsv.scipro.checklist.ChecklistQuestionRepoImpl;
+import se.su.dsv.scipro.file.FileDescriptionRepoImpl;
+import se.su.dsv.scipro.file.FileReferenceRepositoryImpl;
+import se.su.dsv.scipro.file.ProjectFileRepositoryImpl;
+import se.su.dsv.scipro.finalseminar.AuthorRepositoryImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarActiveParticipationRepositoryImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarOppositionRepoImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarRepositoryImpl;
+import se.su.dsv.scipro.forum.AbstractThreadRepositoryImpl;
+import se.su.dsv.scipro.forum.ForumPostReadStateRepositoryImpl;
+import se.su.dsv.scipro.forum.ForumPostRepositoryImpl;
+import se.su.dsv.scipro.forum.GroupThreadRepositoryImpl;
+import se.su.dsv.scipro.forum.ProjectThreadRepositoryImpl;
+import se.su.dsv.scipro.forum.notifications.ForumNotificationRepositoryImpl;
+import se.su.dsv.scipro.grading.GradingHistoryEventRepositoryImpl;
+import se.su.dsv.scipro.grading.NationalSubjectCategoryRepositoryImpl;
+import se.su.dsv.scipro.grading.PublicationMetadataRepositoryImpl;
+import se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarRepositoryImpl;
+import se.su.dsv.scipro.integration.activityforum.ActivityThreadRepositoryImpl;
+import se.su.dsv.scipro.match.FirstMeetingRepositoryImpl;
+import se.su.dsv.scipro.match.IdeaRepositoryImpl;
+import se.su.dsv.scipro.match.TargetRepositoryImpl;
+import se.su.dsv.scipro.milestones.MilestoneActivityTemplateRepositoryImpl;
+import se.su.dsv.scipro.notifications.NotificationEventRepositoryImpl;
+import se.su.dsv.scipro.peer.CommentThreadRepoImpl;
+import se.su.dsv.scipro.peer.PeerRequestRepositoryImpl;
+import se.su.dsv.scipro.peer.PeerReviewRepositoryImpl;
+import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepositoryImpl;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepositoryImpl;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepositoryImpl;
+import se.su.dsv.scipro.project.ProjectRepoImpl;
+import se.su.dsv.scipro.projectpartner.ProjectPartnerRepositoryImpl;
+import se.su.dsv.scipro.report.GradingReportTemplateRepoImpl;
+import se.su.dsv.scipro.report.OppositionReportRepoImpl;
+import se.su.dsv.scipro.report.SupervisorGradingReportRepositoryImpl;
+import se.su.dsv.scipro.reviewing.DecisionRepositoryImpl;
+import se.su.dsv.scipro.reviewing.ReviewerDeadlineSettingsRepositoryImpl;
+import se.su.dsv.scipro.reviewing.ReviewerTargetRepositoryImpl;
+import se.su.dsv.scipro.reviewing.ReviewerThreadRepositoryImpl;
+import se.su.dsv.scipro.survey.QuestionRepositoryImpl;
+import se.su.dsv.scipro.survey.SurveyRepositoryImpl;
+import se.su.dsv.scipro.system.FooterAddressRepoImpl;
+import se.su.dsv.scipro.system.FooterLinkRepoImpl;
+import se.su.dsv.scipro.system.PasswordRepoImpl;
+import se.su.dsv.scipro.system.UserRepoImpl;
+
+@Configuration(proxyBeanMethods = false)
+public class RepositoryConfiguration {
+    @Bean
+    public GradingHistoryEventRepositoryImpl gradingHistoryEventRepository(Provider<EntityManager> em) {
+        return new GradingHistoryEventRepositoryImpl(em);
+    }
+
+    @Bean
+    public AbstractThreadRepositoryImpl abstractThreadRepository(Provider<EntityManager> em) {
+        return new AbstractThreadRepositoryImpl(em);
+    }
+
+    @Bean
+    public ActivityFinalSeminarRepositoryImpl activityFinalSeminarRepository(Provider<EntityManager> em) {
+        return new ActivityFinalSeminarRepositoryImpl(em);
+    }
+
+    @Bean
+    public ActivityThreadRepositoryImpl activityThreadRepository(Provider<EntityManager> em) {
+        return new ActivityThreadRepositoryImpl(em);
+    }
+
+    @Bean
+    public AuthorRepositoryImpl authorRepository(Provider<EntityManager> em) {
+        return new AuthorRepositoryImpl(em);
+    }
+
+    @Bean
+    public ChecklistCategoryRepoImpl checklistCategoryRepo(Provider<EntityManager> em) {
+        return new ChecklistCategoryRepoImpl(em);
+    }
+
+    @Bean
+    public ChecklistQuestionRepoImpl checklistQuestionRepo(Provider<EntityManager> em) {
+        return new ChecklistQuestionRepoImpl(em);
+    }
+
+    @Bean
+    public CommentThreadRepoImpl commentThreadRepo(Provider<EntityManager> em) {
+        return new CommentThreadRepoImpl(em);
+    }
+
+    @Bean
+    public DecisionRepositoryImpl decisionRepository(Provider<EntityManager> em) {
+        return new DecisionRepositoryImpl(em);
+    }
+
+    @Bean
+    public FileDescriptionRepoImpl fileDescriptionRepo(Provider<EntityManager> em) {
+        return new FileDescriptionRepoImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarActiveParticipationRepositoryImpl finalSeminarActiveParticipationRepository(Provider<EntityManager> em) {
+        return new FinalSeminarActiveParticipationRepositoryImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarRepositoryImpl finalSeminarRepository(Provider<EntityManager> em) {
+        return new FinalSeminarRepositoryImpl(em);
+    }
+
+    @Bean
+    public FileReferenceRepositoryImpl fileReferenceRepository(Provider<EntityManager> em) {
+        return new FileReferenceRepositoryImpl(em);
+    }
+
+    @Bean
+    public FinalSeminarOppositionRepoImpl finalSeminarOppositionRepo(Provider<EntityManager> em) {
+        return new FinalSeminarOppositionRepoImpl(em);
+    }
+
+    @Bean
+    public FirstMeetingRepositoryImpl firstMeetingRepository(Provider<EntityManager> em) {
+        return new FirstMeetingRepositoryImpl(em);
+    }
+
+    @Bean
+    public FooterAddressRepoImpl footerAddressRepo(Provider<EntityManager> em) {
+        return new FooterAddressRepoImpl(em);
+    }
+
+    @Bean
+    public FooterLinkRepoImpl footerLinkRepo(Provider<EntityManager> em) {
+        return new FooterLinkRepoImpl(em);
+    }
+
+    @Bean
+    public ForumNotificationRepositoryImpl forumNotificationRepository(Provider<EntityManager> em) {
+        return new ForumNotificationRepositoryImpl(em);
+    }
+
+    @Bean
+    public ForumPostReadStateRepositoryImpl forumPostReadStateRepository(Provider<EntityManager> em) {
+        return new ForumPostReadStateRepositoryImpl(em);
+    }
+
+    @Bean
+    public ForumPostRepositoryImpl forumPostRepository(Provider<EntityManager> em) {
+        return new ForumPostRepositoryImpl(em);
+    }
+
+    @Bean
+    public GradingReportTemplateRepoImpl gradingReportTemplateRepo(Provider<EntityManager> em) {
+        return new GradingReportTemplateRepoImpl(em);
+    }
+
+    @Bean
+    public GroupThreadRepositoryImpl groupThreadRepository(Provider<EntityManager> em) {
+        return new GroupThreadRepositoryImpl(em);
+    }
+
+    @Bean
+    public IdeaRepositoryImpl ideaRepository(Provider<EntityManager> em) {
+        return new IdeaRepositoryImpl(em);
+    }
+
+    @Bean
+    public MilestoneActivityTemplateRepositoryImpl milestoneActivityTemplateRepository(Provider<EntityManager> em) {
+        return new MilestoneActivityTemplateRepositoryImpl(em);
+    }
+
+    @Bean
+    public NationalSubjectCategoryRepositoryImpl nationalSubjectCategoryRepository(Provider<EntityManager> em) {
+        return new NationalSubjectCategoryRepositoryImpl(em);
+    }
+
+    @Bean
+    public OppositionReportRepoImpl oppositionReportRepo(Provider<EntityManager> em) {
+        return new OppositionReportRepoImpl(em);
+    }
+
+    @Bean
+    public PasswordRepoImpl passwordRepo(Provider<EntityManager> em) {
+        return new PasswordRepoImpl(em);
+    }
+
+    @Bean
+    public PeerRequestRepositoryImpl peerRequestRepository(Provider<EntityManager> em) {
+        return new PeerRequestRepositoryImpl(em);
+    }
+
+    @Bean
+    public PeerReviewRepositoryImpl peerReviewRepository(Provider<EntityManager> em) {
+        return new PeerReviewRepositoryImpl(em);
+    }
+
+    @Bean
+    public ProjectPartnerRepositoryImpl projectPartnerRepository(Provider<EntityManager> em) {
+        return new ProjectPartnerRepositoryImpl(em);
+    }
+
+    @Bean
+    public ProjectRepoImpl projectRepo(Provider<EntityManager> em) {
+        return new ProjectRepoImpl(em);
+    }
+
+    @Bean
+    public ProjectThreadRepositoryImpl projectThreadRepository(Provider<EntityManager> em) {
+        return new ProjectThreadRepositoryImpl(em);
+    }
+
+    @Bean
+    public PublicationMetadataRepositoryImpl publicationMetadataRepository(Provider<EntityManager> em) {
+        return new PublicationMetadataRepositoryImpl(em);
+    }
+
+    @Bean
+    public QuestionRepositoryImpl questionRepository(Provider<EntityManager> em) {
+        return new QuestionRepositoryImpl(em);
+    }
+
+    @Bean
+    public ReviewerDeadlineSettingsRepositoryImpl reviewerDeadlineSettingsRepository(Provider<EntityManager> em) {
+        return new ReviewerDeadlineSettingsRepositoryImpl(em);
+    }
+
+    @Bean
+    public ReviewerTargetRepositoryImpl reviewerTargetRepository(Provider<EntityManager> em) {
+        return new ReviewerTargetRepositoryImpl(em);
+    }
+
+    @Bean
+    public ReviewerThreadRepositoryImpl reviewerThreadRepository(Provider<EntityManager> em) {
+        return new ReviewerThreadRepositoryImpl(em);
+    }
+
+    @Bean
+    public SurveyRepositoryImpl surveyRepository(Provider<EntityManager> em) {
+        return new SurveyRepositoryImpl(em);
+    }
+
+    @Bean
+    public TargetRepositoryImpl targetRepository(Provider<EntityManager> em) {
+        return new TargetRepositoryImpl(em);
+    }
+
+    @Bean
+    public UrkundSettingsRepositoryImpl urkundSettingsRepository(Provider<EntityManager> em) {
+        return new UrkundSettingsRepositoryImpl(em);
+    }
+
+    @Bean
+    public UrkundSubmissionRepositoryImpl urkundSubmissionRepository(Provider<EntityManager> em) {
+        return new UrkundSubmissionRepositoryImpl(em);
+    }
+
+    @Bean
+    public UserRepoImpl userRepo(Provider<EntityManager> em) {
+        return new UserRepoImpl(em);
+    }
+
+    @Bean
+    public PlagiarismRequestRepositoryImpl plagiarismRequestRepository(Provider<EntityManager> em) {
+        return new PlagiarismRequestRepositoryImpl(em);
+    }
+
+    @Bean
+    public ProjectFileRepositoryImpl projectFileRepository(Provider<EntityManager> em) {
+        return new ProjectFileRepositoryImpl(em);
+    }
+
+    @Bean
+    public NotificationEventRepositoryImpl notificationEventRepository(Provider<EntityManager> em) {
+        return new NotificationEventRepositoryImpl(em);
+    }
+
+    @Bean
+    public SupervisorGradingReportRepositoryImpl supervisorGradingReportRepository(Provider<EntityManager> em) {
+        return new SupervisorGradingReportRepositoryImpl(em);
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java b/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java
index 1f5182ca05..28e834f5ef 100755
--- a/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java
+++ b/core/src/main/java/se/su/dsv/scipro/activityplan/Activity.java
@@ -1,140 +1,164 @@
 package se.su.dsv.scipro.activityplan;
 
 import com.querydsl.core.annotations.QueryInit;
-import jakarta.persistence.GenerationType;
-import se.su.dsv.scipro.checklist.Checklist;
-import se.su.dsv.scipro.file.FileReference;
-import se.su.dsv.scipro.system.LazyDeletableDomainObject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Table;
 import jakarta.persistence.Cacheable;
 import jakarta.persistence.CascadeType;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.EnumType;
 import jakarta.persistence.Enumerated;
+import jakarta.persistence.GenerationType;
 import jakarta.persistence.GeneratedValue;
 import jakarta.persistence.Id;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.OneToOne;
+
+import se.su.dsv.scipro.checklist.Checklist;
+import se.su.dsv.scipro.file.FileReference;
+import se.su.dsv.scipro.system.LazyDeletableDomainObject;
+
 import java.io.Serializable;
-import java.util.*;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Objects;
 
 @Entity
+@Table(name = "activity")
 @Cacheable(true)
 public class Activity extends LazyDeletableDomainObject {
-	@Id
+
+    public static IActivityPlan builder(){
+        return new Builder();
+    }
+
+    //<editor-fold desc="Basic JPA-mappings">
+    @Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 
-	@ManyToOne(optional=false)
-	@JoinColumn (name="activityTemplate_id")
-    @QueryInit("project")
-	private ActivityPlan activityPlan;
+    @Basic
+    @Column(name = "title", nullable=false)
+    private String title;
 
-	@Column(nullable=false)
-	private Date date;
+    @Basic
+    @Column(name = "date", nullable=false)
+    private Date date;
 
-	@Column(nullable=false)
-	private String title;
-
-	private String description;
-
-	@OneToOne(optional = true, cascade = CascadeType.ALL)
-    @JoinColumn(name = "file_upload_reference_id")
-	private FileReference fileUpload;
-
-	@ManyToOne
-	private Checklist checklist;
+    @Basic
+    @Column(name = "description")
+    private String description;
 
+    @Basic
+    @Column(name = "editable")
     private boolean editable = true;
 
     @Enumerated(EnumType.STRING)
+    @Column(name = "action")
     private Action action = Action.NONE;
-	
+    //</editor-fold>
+
+    //<editor-fold desc="JPA-mappings of foreign keys in this table (activity) referencing other tables.">
+    @ManyToOne(optional = false)
+	@JoinColumn(name = "activity_plan_id", referencedColumnName = "id")
+    @QueryInit("project")
+	private ActivityPlan activityPlan;
+
+    @ManyToOne
+    @JoinColumn(name = "checklist_id", referencedColumnName = "id")
+    private Checklist checklist;
+
+	@OneToOne(optional = true, cascade = CascadeType.ALL)
+    @JoinColumn(name = "upload_file_reference_id", referencedColumnName = "id")
+	private FileReference fileUpload;
+    //</editor-fold>
+
+    //<editor-fold desc="Constructor">
 	public Activity() {
 		this.title = "";
 		this.description = "";
 	}
+    //</editor-fold>
 
-	@Override
-	public String toString(){
-		return "Event: "+ getTitle()+"@"+getDate();
-	}
-
-	@Override
+    //<editor-fold desc="Properties (Getters and Setters)">
+    @Override
     public Long getId() {
         return this.id;
     }
 
-    public ActivityPlan getActivityPlan() {
-        return this.activityPlan;
-    }
-
-    public Date getDate() {
-        return this.date;
-    }
-
-    public String getTitle() {
-        return this.title;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public FileReference getFileUpload() {
-        return this.fileUpload;
-    }
-
-    public Checklist getChecklist() {
-        return this.checklist;
-    }
-
-    public boolean isEditable() {
-        return this.editable;
-    }
-
-    public Action getAction() {
-        return this.action;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setActivityPlan(ActivityPlan activityPlan) {
-        this.activityPlan = activityPlan;
-    }
-
-    public void setDate(Date date) {
-        this.date = date;
+    public String getTitle() {
+        return this.title;
     }
 
     public void setTitle(String title) {
         this.title = title;
     }
 
+    public Date getDate() {
+        return this.date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
 
-    public void setFileUpload(FileReference fileUpload) {
-        this.fileUpload = fileUpload;
-    }
-
-    public void setChecklist(Checklist checklist) {
-        this.checklist = checklist;
+    public boolean isEditable() {
+        return this.editable;
     }
 
     public void setEditable(boolean editable) {
         this.editable = editable;
     }
 
+    public Action getAction() {
+        return this.action;
+    }
+
     public void setAction(Action action) {
         this.action = action;
     }
 
+    public ActivityPlan getActivityPlan() {
+        return this.activityPlan;
+    }
+
+    public void setActivityPlan(ActivityPlan activityPlan) {
+        this.activityPlan = activityPlan;
+    }
+
+    public Checklist getChecklist() {
+        return this.checklist;
+    }
+
+    public void setChecklist(Checklist checklist) {
+        this.checklist = checklist;
+    }
+
+    public FileReference getFileUpload() {
+        return this.fileUpload;
+    }
+
+    public void setFileUpload(FileReference fileUpload) {
+        this.fileUpload = fileUpload;
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Methods Common To All Objects">
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -144,15 +168,24 @@ public class Activity extends LazyDeletableDomainObject {
                 && Objects.equals(this.getId(), other.getId());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof Activity;
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(getId());
     }
 
     @Override
-    public int hashCode() {
-	    return Objects.hashCode(getId());
-    }
+	public String toString(){
+		return "Event: "+ getTitle()+"@"+getDate();
+	}
+    //</editor-fold>
 
+    //<editor-fold desc="Other methods">
+    protected boolean canEqual(final Object other) {
+        return other instanceof Activity;
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Nested types">
     public static class ByDateComparator implements Comparator<Activity>, Serializable {
         @Override
         public int compare(Activity o1, Activity o2) {
@@ -209,10 +242,6 @@ public class Activity extends LazyDeletableDomainObject {
         }
     }
 
-    public static IActivityPlan builder(){
-        return new Builder();
-    }
-
     public interface IActivityPlan {
         IDate activityPlan(ActivityPlan activityPlan);
     }
@@ -233,4 +262,5 @@ public class Activity extends LazyDeletableDomainObject {
         IBuild editable(boolean editable);
         Activity build();
     }
+    //</editor-fold>
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java
index 2ff8883bea..8af7cd3374 100755
--- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java
+++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlan.java
@@ -1,67 +1,92 @@
 package se.su.dsv.scipro.activityplan;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Date;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 
 @Entity
+@Table(name ="activity_plan")
 @Cacheable(true)
 public class ActivityPlan extends DomainObject {
+
+    public static IProject builder() {
+        return new Builder();
+    }
+
+    //<editor-fold desc="Basic JPA-mappings">
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
-	
+
+    @Basic
+    @Column(name = "start_date")
+    private Date startDate;
+    //</editor-fold>
+
+    //<editor-fold desc="JPA-mappings of foreign keys in this table (activity_plan) referencing other tables">
+    @OneToOne(optional=false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+    //</editor-fold>
+
+    //<editor-fold desc="JPA-mappings of other tables referencing to this table "activity_plan">
 	@OneToMany(mappedBy= "activityPlan",cascade=CascadeType.PERSIST, orphanRemoval = true)
 	private Set<Activity> activities = new TreeSet<>(new Activity.ByDateComparator());
-		
-	@OneToOne(optional=false)
-	private Project project;
-
-	private Date startDate;
+    //</editor-fold>
 
+    //<editor-fold desc="Properties (Getters and Setters)">
 	@Override
     public Long getId() {
         return this.id;
     }
 
-    public Set<Activity> getActivities() {
-        return this.activities;
-    }
-
-    public Project getProject() {
-        return this.project;
-    }
-
-    public Date getStartDate() {
-        return this.startDate;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setActivities(Set<Activity> activities) {
-        this.activities = activities;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
+    public Date getStartDate() {
+        return this.startDate;
     }
 
     public void setStartDate(Date startDate) {
         this.startDate = startDate;
     }
 
-    @Override
-    public String toString() {
-        return "ActivityPlan(id=" + this.getId() + ", activities=" + this.getActivities() + ", project=" + this.getProject() + ", startDate=" + this.getStartDate() + ")";
+    public Project getProject() {
+        return this.project;
     }
 
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public Set<Activity> getActivities() {
+        return this.activities;
+    }
+
+    public void setActivities(Set<Activity> activities) {
+        this.activities = activities;
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Methods Common To All Objects">
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -74,15 +99,25 @@ public class ActivityPlan extends DomainObject {
                 && Objects.equals(this.getStartDate(), other.getStartDate());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ActivityPlan;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getActivities(), this.getProject(), this.getStartDate());
     }
 
+    @Override
+    public String toString() {
+        return "ActivityPlan(id=" + this.getId() + ", activities=" + this.getActivities() + ", project=" +
+                this.getProject() + ", startDate=" + this.getStartDate() + ")";
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Other methods">
+    protected boolean canEqual(final Object other) {
+        return other instanceof ActivityPlan;
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Nested types"
     private static class Builder implements IProject, IBuild {
         private Project project;
 
@@ -100,10 +135,6 @@ public class ActivityPlan extends DomainObject {
         }
     }
 
-    public static IProject builder() {
-        return new Builder();
-    }
-
     public interface IProject {
         IBuild project(Project project);
     }
@@ -111,4 +142,5 @@ public class ActivityPlan extends DomainObject {
     public interface IBuild {
         ActivityPlan build();
     }
+    //</editor-fold>
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java
index d211c1cbac..4f7955f835 100755
--- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanFacadeImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.activityplan;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import se.su.dsv.scipro.system.Pageable;
diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java
index 650393135d..b91217a705 100755
--- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityPlanTemplate.java
@@ -1,98 +1,117 @@
 package se.su.dsv.scipro.activityplan;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OrderColumn;
+
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.*;
-
 @Entity
+@Table(name = "activity_plan_template")
 @Cacheable(true)
 public class ActivityPlanTemplate extends DomainObject {
 
+	//<editor-fold desc="Basic JPA-mappings">
     @Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 
-    @OrderColumn(name = "numberInOrder")
-	@OneToMany(mappedBy="activityPlanTemplate", orphanRemoval=true, cascade=CascadeType.ALL)
-	private List<ActivityTemplate> activityTemplates = new ArrayList<>();
-
-    public List<ActivityTemplate> getActivityTemplates(){
-        return Collections.unmodifiableList(activityTemplates);
-    }
-
-    public void setActivityTemplates(List<ActivityTemplate> activityTemplates){
-        this.activityTemplates = new ArrayList<>(activityTemplates);
-    }
-	
-	@ManyToOne(optional=false)
-	private User creator;
-
-	@Column(nullable=false)
-	private String title;
-	
-	@Lob
-	private String description;
-	
-	@Column(nullable=false)
+	@Basic
+	@Column(name = "is_sys_admin_template", nullable=false)
 	private boolean isSysAdminTemplate = false;
 
-	public void addActivity(ActivityTemplate activity){
-		activity.setActivityPlanTemplate(this);
-        activity.setNumberInOrder(activityTemplates.size());
-		activityTemplates.add(activity);
-	}
+	@Basic
+	@Column(name = "title", nullable = false)
+	private String title;
 
-    public void clearActivities(){
-        activityTemplates.clear();
-    }
+	@Basic
+	@Column(name = "description")
+	@Lob
+	private String description;
+	//</editor-fold>
 
-    public void addActivities(final Collection<ActivityTemplate> activities){
-        activityTemplates.addAll(activities);
-    }
+	//<editor-fold desc="JPA-mappings of foreign keys in this table (activity_plan_template) referencing other tables.">
+	@ManyToOne(optional = false)
+	@JoinColumn(name = "creator_user_id", referencedColumnName = "id")
+	private User creator;
+	//</editor-fold>
 
-    @Override
+	//<editor-fold desc="JPA-mappings of other tables referencing to this table 'activity_plan_template'">
+	@OneToMany(mappedBy="activityPlanTemplate", orphanRemoval=true, cascade=CascadeType.ALL)
+	@OrderColumn(name = "number_in_order")
+	private List<ActivityTemplate> activityTemplates = new ArrayList<>();
+	//</editor-fold>
+
+	//<editor-fold desc="Properties (Getters and Setters)">
+	@Override
 	public Long getId() {
 		return this.id;
 	}
 
-	public User getCreator() {
-		return this.creator;
-	}
-
-	public String getTitle() {
-		return this.title;
-	}
-
-	public String getDescription() {
-		return this.description;
-	}
-
-	public boolean isSysAdminTemplate() {
-		return this.isSysAdminTemplate;
-	}
-
 	public void setId(Long id) {
 		this.id = id;
 	}
 
-	public void setCreator(User creator) {
-		this.creator = creator;
-	}
-
-	public void setTitle(String title) {
-		this.title = title;
-	}
-
-	public void setDescription(String description) {
-		this.description = description;
+	public boolean isSysAdminTemplate() {
+		return this.isSysAdminTemplate;
 	}
 
 	public void setSysAdminTemplate(boolean isSysAdminTemplate) {
 		this.isSysAdminTemplate = isSysAdminTemplate;
 	}
 
+	public String getTitle() {
+		return this.title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getDescription() {
+		return this.description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public User getCreator() {
+		return this.creator;
+	}
+
+	public void setCreator(User creator) {
+		this.creator = creator;
+	}
+
+	public List<ActivityTemplate> getActivityTemplates(){
+		return Collections.unmodifiableList(activityTemplates);
+	}
+
+	public void setActivityTemplates(List<ActivityTemplate> activityTemplates){
+		this.activityTemplates = new ArrayList<>(activityTemplates);
+	}
+	//</editor-fold>
+
+	//<editor-fold desc="Methods Common To All Objects">
 	@Override
 	public boolean equals(final Object o) {
 		if (o == this) return true;
@@ -119,6 +138,25 @@ public class ActivityPlanTemplate extends DomainObject {
 
 	@Override
 	public String toString() {
-		return "ActivityPlanTemplate(id=" + this.getId() + ", creator=" + this.getCreator() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", isSysAdminTemplate=" + this.isSysAdminTemplate() + ")";
+		return "ActivityPlanTemplate(id=" + this.getId() + ", creator=" + this.getCreator() +
+				", title=" + this.getTitle() + ", description=" + this.getDescription() +
+				", isSysAdminTemplate=" + this.isSysAdminTemplate() + ")";
 	}
+	//</editor-fold>
+
+	//<editor-fold desc="Other methods">
+	public void addActivity(ActivityTemplate activity){
+		activity.setActivityPlanTemplate(this);
+		activity.setNumberInOrder(activityTemplates.size());
+		activityTemplates.add(activity);
+	}
+
+	public void clearActivities(){
+		activityTemplates.clear();
+	}
+
+	public void addActivities(final Collection<ActivityTemplate> activities){
+		activityTemplates.addAll(activities);
+	}
+	//</editor-fold>
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java
index c43c8a237c..6671bea897 100755
--- a/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/activityplan/ActivityTemplate.java
@@ -1,116 +1,142 @@
 package se.su.dsv.scipro.activityplan;
 
+import java.util.Objects;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.checklist.ChecklistTemplate;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
-import java.util.Objects;
-
 @Entity
+@Table(name = "activity_template")
 public class ActivityTemplate extends DomainObject {
 
+    //<editor-fold desc="Basic JPA-mappings">
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "title", nullable = false)
     private String title;
 
+    @Basic
+    @Column(name = "description")
     @Lob
     private String description;
 
-    @ManyToOne
-    private ActivityPlanTemplate activityPlanTemplate;
-
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "days_offset", nullable = false)
     private int daysOffset;
 
+    @Basic
+    @Column(name = "action")
     @Enumerated(EnumType.STRING)
     private Action action = Action.NONE;
 
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "number_in_order", nullable = false)
     private int numberInOrder = Integer.MAX_VALUE;
+    //</editor-fold>
+
+    //<editor-fold desc="JPA-mappings of foreign keys in this table (activity_template) referencing other tables.">
+    @ManyToOne
+    @JoinColumn(name = "activity_plan_template_id", referencedColumnName = "id")
+    private ActivityPlanTemplate activityPlanTemplate;
 
     @ManyToOne(optional = true)
+    @JoinColumn(name = "checklist_template_id", referencedColumnName = "id")
     private ChecklistTemplate checklistTemplate;
+    //</editor-fold>
 
+    //<editor-fold desc="Constructors">
     public ActivityTemplate() {
     }
 
     public ActivityTemplate(int daysOffset) {
         this.daysOffset = daysOffset;
     }
+    //</editor-fold>
 
-    public int getDaysOffset() {
-        return daysOffset;
-    }
-
-    public int getNumberInOrder() {
-        return numberInOrder;
-    }
-
+    //<editor-fold desc="Properties (Getters and Setters">
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public String getTitle() {
-        return this.title;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public ActivityPlanTemplate getActivityPlanTemplate() {
-        return this.activityPlanTemplate;
-    }
-
-    public Action getAction() {
-        return this.action;
-    }
-
-    public ChecklistTemplate getChecklistTemplate() {
-        return this.checklistTemplate;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
+    public String getTitle() {
+        return this.title;
+    }
+
     public void setTitle(String title) {
         this.title = title;
     }
 
+    public String getDescription() {
+        return this.description;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
 
-    public void setActivityPlanTemplate(ActivityPlanTemplate activityPlanTemplate) {
-        this.activityPlanTemplate = activityPlanTemplate;
+    public int getDaysOffset() {
+        return daysOffset;
     }
 
     public void setDaysOffset(int daysOffset) {
         this.daysOffset = daysOffset;
     }
 
+    public Action getAction() {
+        return this.action;
+    }
+
     public void setAction(Action action) {
         this.action = action;
     }
 
+    public int getNumberInOrder() {
+        return numberInOrder;
+    }
+
     public void setNumberInOrder(int numberInOrder) {
         this.numberInOrder = numberInOrder;
     }
 
+    public ActivityPlanTemplate getActivityPlanTemplate() {
+        return this.activityPlanTemplate;
+    }
+
+    public void setActivityPlanTemplate(ActivityPlanTemplate activityPlanTemplate) {
+        this.activityPlanTemplate = activityPlanTemplate;
+    }
+
+    public ChecklistTemplate getChecklistTemplate() {
+        return this.checklistTemplate;
+    }
+
     public void setChecklistTemplate(ChecklistTemplate checklistTemplate) {
         this.checklistTemplate = checklistTemplate;
     }
+    //</editor-fold>
 
-    @Override
-    public String toString() {
-        return "ActivityTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", activityPlanTemplate=" + this.getActivityPlanTemplate() + ", daysOffset=" + this.getDaysOffset() + ", action=" + this.getAction() + ", numberInOrder=" + this.getNumberInOrder() + ", checklistTemplate=" + this.getChecklistTemplate() + ")";
-    }
-
+    //<editor-fold desc="Methods Common To All Objects">
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -120,12 +146,24 @@ public class ActivityTemplate extends DomainObject {
                 && Objects.equals(this.getId(), other.getId());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ActivityTemplate;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hashCode(this.getId());
     }
-}
\ No newline at end of file
+
+    @Override
+    public String toString() {
+        return "ActivityTemplate(id=" + this.getId() + ", title=" + this.getTitle() +
+                ", description=" + this.getDescription() + ", activityPlanTemplate=" +
+                this.getActivityPlanTemplate() + ", daysOffset=" + this.getDaysOffset() + ", action=" +
+                this.getAction() + ", numberInOrder=" + this.getNumberInOrder() + ", checklistTemplate=" +
+                this.getChecklistTemplate() + ")";
+    }
+    //</editor-fold>
+
+    //<editor-fold desc="Other methods">
+    protected boolean canEqual(final Object other) {
+        return other instanceof ActivityTemplate;
+    }
+    //</editor-fold>
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java b/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java
index 3d25b8b1c1..d4c7044f52 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/Checklist.java
@@ -1,12 +1,33 @@
 package se.su.dsv.scipro.checklist;
 
-
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapKeyJoinColumn;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 @Entity
 @Table(name = "checklist")
@@ -17,6 +38,7 @@ public class Checklist extends DomainObject {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
     @Column(nullable = false)
     private String name;
 
@@ -28,15 +50,26 @@ public class Checklist extends DomainObject {
      */
     @Deprecated
     @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id")
     private Project project;
 
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
+    @JoinTable(name = "checklist_checklist_question",
+            joinColumns = @JoinColumn(name = "checklist_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "checklist_question_id", referencedColumnName = "id"))
     private List<ChecklistQuestion> questions = new ArrayList<>();
 
     @ManyToMany
+    @JoinTable(name = "checklist_checklist_category",
+            joinColumns = @JoinColumn(name = "checklist_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "checklist_category_id", referencedColumnName = "id"))
     private List<se.su.dsv.scipro.checklist.ChecklistCategory> categories = new ArrayList<>();
 
     @ElementCollection(fetch = FetchType.EAGER)
+    @CollectionTable(name = "checklist_user_last_open_date", joinColumns = @JoinColumn(name = "checklist_id"))
+    @Column(name = "last_open_date")
+    @SuppressWarnings("JpaDataSourceORMInspection")  // false warning from IntelliJ for the @MapKeyJoinColumn
+    @MapKeyJoinColumn(name = "user_id")
     private Map<User, Date> userLastOpenDate = new HashMap<>();
 
     protected Checklist() {
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java
index 05d756e6a1..704f907f40 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswer.java
@@ -1,29 +1,54 @@
 package se.su.dsv.scipro.checklist;
 
+import java.util.Objects;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.Objects;
-
 @Entity
 @Table(name = "checklist_answer")
 public class ChecklistAnswer extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
+    @Column(name = "answer", nullable = false)
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
     private ChecklistAnswerEnum answer;
 
-    @ManyToOne(optional = false)
-    private User user;
-
+    @Basic
+    @Column(name = "comment")
     @Lob
-    @Column
     private String comment;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (checklist_answer) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected ChecklistAnswer() {
     }
 
@@ -36,44 +61,45 @@ public class ChecklistAnswer extends DomainObject {
         this.answer = answer != null ? answer : ChecklistAnswerEnum.NO_ANSWER;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public ChecklistAnswerEnum getAnswer() {
-        return this.answer;
-    }
-
-    public User getUser() {
-        return this.user;
-    }
-
-    public String getComment() {
-        return this.comment;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
+    public ChecklistAnswerEnum getAnswer() {
+        return this.answer;
+    }
+
     public void setAnswer(ChecklistAnswerEnum answer) {
         this.answer = answer;
     }
 
-    public void setUser(User user) {
-        this.user = user;
+    public String getComment() {
+        return this.comment;
     }
 
     public void setComment(String comment) {
         this.comment = comment;
     }
 
-    @Override
-    public String toString() {
-        return "ChecklistAnswer(id=" + this.getId() + ", answer=" + this.getAnswer() + ", user=" + this.getUser() + ", comment=" + this.getComment() + ")";
+    public User getUser() {
+        return this.user;
     }
 
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -83,12 +109,21 @@ public class ChecklistAnswer extends DomainObject {
                 && Objects.equals(this.getId(), other.getId());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ChecklistAnswer;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hashCode(this.getId());
     }
+
+    @Override
+    public String toString() {
+        return "ChecklistAnswer(id=" + this.getId() + ", answer=" + this.getAnswer() + ", user=" + this.getUser() +
+                ", comment=" + this.getComment() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ChecklistAnswer;
+    }
 }
\ No newline at end of file
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java
index 796d0ddeeb..e806794440 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerEnum.java
@@ -4,6 +4,6 @@ public enum ChecklistAnswerEnum {
 	RED,
 	GREEN,
 	YELLOW,
-    NOT_APLICABLE,
+	NOT_APPLICABLE,
 	NO_ANSWER
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java
index 1e1893ccda..20a612c25f 100644
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistAnswerServiceImpl.java
@@ -9,7 +9,7 @@ import jakarta.persistence.EntityManager;
 public class ChecklistAnswerServiceImpl extends AbstractServiceImpl<ChecklistAnswer, Long> implements ChecklistAnswerService {
 
     @Inject
-    protected ChecklistAnswerServiceImpl(Provider<EntityManager> em) {
+    public ChecklistAnswerServiceImpl(Provider<EntityManager> em) {
         super(em, ChecklistAnswer.class, QChecklistAnswer.checklistAnswer);
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java
index ed0f76c658..c3589be745 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategory.java
@@ -1,13 +1,17 @@
-/**
- * 
- */
 package se.su.dsv.scipro.checklist;
 
-import se.su.dsv.scipro.system.DomainObject;
-
-import jakarta.persistence.*;
 import java.util.Objects;
 
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+
+import se.su.dsv.scipro.system.DomainObject;
+
 @Entity
 @Table(name="checklist_category")
 @Cacheable(true)
@@ -16,7 +20,7 @@ public class ChecklistCategory extends DomainObject {
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 	
-	@Column(unique=true)
+	@Column(name = "category_name", unique = true)
 	private String categoryName;
 
 	protected ChecklistCategory() {
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java
index 9b5883089e..64b595d29e 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistCategoryRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.checklist;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java
index 337551dc04..3678024780 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestion.java
@@ -1,13 +1,26 @@
 package se.su.dsv.scipro.checklist;
 
-import se.su.dsv.scipro.system.DomainObject;
-import se.su.dsv.scipro.system.User;
-
-import jakarta.persistence.*;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.Lob;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
+
+import se.su.dsv.scipro.system.DomainObject;
+import se.su.dsv.scipro.system.User;
+
 @Entity
 @Table(name = "checklist_question")
 @Cacheable(true)
@@ -20,13 +33,15 @@ public class ChecklistQuestion extends DomainObject {
     @Column(nullable = false)
     private String question;
 
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "question_number", nullable = false)
     private int questionNumber;
 
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
     @JoinTable(
-            joinColumns = @JoinColumn(name = "checklist_question_id")
-    )
+            name = "checklist_question_checklist_answer",
+            joinColumns = @JoinColumn(name = "checklist_question_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "checklist_answer_id", referencedColumnName = "id"))
     private List<ChecklistAnswer> answers = new ArrayList<>();
 
     protected ChecklistQuestion() {
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java
index 410c90439a..3fb6407ebc 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistQuestionRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.checklist;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java
index cba683c25a..9a9a9c234e 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.checklist;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.activityplan.QActivity;
 import se.su.dsv.scipro.activityplan.QActivityPlan;
 import se.su.dsv.scipro.project.Project;
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java
index 05b09733b1..12ad047041 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplate.java
@@ -1,11 +1,27 @@
 package se.su.dsv.scipro.checklist;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
 
 @Entity
 @Table(name = "checklist_template")
@@ -17,35 +33,42 @@ public class ChecklistTemplate extends DomainObject {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
     @Column(nullable = false)
     private String name;
 
     @Basic(optional = true)
+    @Column(name = "description")
     private String description;
 
-    @Column
+    @Basic
+    @Column(name = "template_number")
     private int templateNumber = DEFAULT_TEMPLATE_NUMBER;
 
-    @Lob
     @ElementCollection
+    @CollectionTable(name = "checklist_template_question",
+            joinColumns = @JoinColumn(name = "checklist_template_id"))
+    @Column(name = "question")
     private List<String> questions = new ArrayList<>(1);
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "creator_user_id", referencedColumnName = "id")
     private User creator;
 
     @ManyToMany
-    @JoinTable(
-            joinColumns = @JoinColumn(name = "checklist_template_id")
-    )
+    @JoinTable(name = "checklist_template_checklist_category",
+            joinColumns = @JoinColumn(name = "checklist_template_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "checklist_category_id", referencedColumnName = "id"))
     private List<ChecklistCategory> categories = new ArrayList<>();
 
     @ManyToMany
-    @JoinTable(name = "checklist_template_ProjectType",
+    @JoinTable(name = "checklist_template_project_type",
             joinColumns = {@JoinColumn(name = "checklist_template_id")},
-            inverseJoinColumns = {@JoinColumn(name = "projectType_id")})
+            inverseJoinColumns = {@JoinColumn(name = "project_type_id")})
     private Collection<ProjectType> projectTypes = new HashSet<>();
 
     public ChecklistTemplate() {
+
     }
 
     public ChecklistTemplate(String name, User creator) {
diff --git a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java
index 0e43b8c13d..336d0e8b58 100755
--- a/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/checklist/ChecklistTemplateServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.checklist;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import se.su.dsv.scipro.system.Pageable;
 import se.su.dsv.scipro.project.Project;
diff --git a/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java b/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java
deleted file mode 100644
index 63de05fdfb..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/daisyExternal/DaisyExternalModule.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package se.su.dsv.scipro.daisyExternal;
-
-import com.google.inject.Key;
-import com.google.inject.PrivateModule;
-import com.google.inject.Scopes;
-import com.google.inject.name.Names;
-import se.su.dsv.scipro.daisyExternal.http.DaisyAPI;
-import se.su.dsv.scipro.daisyExternal.http.DaisyAPIImpl;
-
-public class DaisyExternalModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        requireBinding(Key.get(String.class, Names.named("daisy.api.url")));
-        requireBinding(Key.get(String.class, Names.named("daisy.api.username")));
-        requireBinding(Key.get(String.class, Names.named("daisy.api.password")));
-
-        bind(DaisyAPI.class).to(DaisyAPIImpl.class).in(Scopes.SINGLETON);
-        expose(DaisyAPI.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/events/EventModule.java b/core/src/main/java/se/su/dsv/scipro/events/EventModule.java
deleted file mode 100644
index 61fb042f87..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/events/EventModule.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package se.su.dsv.scipro.events;
-
-import com.google.common.eventbus.EventBus;
-import com.google.inject.AbstractModule;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class EventModule extends AbstractModule {
-    private static final Logger LOGGER = LoggerFactory.getLogger(EventModule.class);
-
-    @Override
-    protected void configure() {
-        bind(EventBus.class).toInstance(new EventBus((throwable, context) -> LOGGER.error("Could not dispatch event: " + context.getSubscriber() + " to " + context.getSubscriberMethod(), throwable)));
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java b/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java
index 7b4060922b..ac42cab487 100755
--- a/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileDescription.java
@@ -33,25 +33,40 @@ public class FileDescription extends DomainObject {
     public static final int FILES_PER_SUBDIRECTORY = 1000;
     public static final String FILE_ROOT = "/scipro-files";
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Column
+    @Basic
+    @Column(name = "name")
     private String name;
 
-    @Column
+    @Basic
+    @Column(name = "mime_type")
     private String mimeType;
 
-    @Column
-    private String identifier;
-
-    @ManyToOne
-    @JoinColumn(name = "userId")
-    private User uploader;
-
+    @Basic
+    @Column(name = "size")
     private long size;
 
+    @Basic
+    @Column(name = "file_identifier")
+    private String identifier;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (file_description) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User uploader;
+
+    // ----------------------------------------------------------------------------------
+    // JPA lifecycle methods
+    // ----------------------------------------------------------------------------------
     @PostRemove
     void removeActualData() {
         try {
@@ -63,6 +78,96 @@ public class FileDescription extends DomainObject {
         }
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getMimeType() {
+        return this.mimeType;
+    }
+
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+    }
+
+    public long getSize() {
+        return this.size;
+    }
+
+    public void setSize(long size) {
+        this.size = size;
+    }
+
+    public String getIdentifier() {
+        return this.identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+    public User getUploader() {
+        return this.uploader;
+    }
+
+    public void setUploader(User uploader) {
+        this.uploader = uploader;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof FileDescription)) return false;
+        final FileDescription other = (FileDescription) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 59;
+        int result = 1;
+        final Object $id = this.getId();
+        result = result * PRIME + ($id == null ? 43 : $id.hashCode());
+        return result;
+    }
+
+    // Todo
+    @Override
+    public String toString() {
+        if (name != null) {
+            return name;
+        } else {
+            return super.toString();
+        }
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof FileDescription;
+    }
+
     public Path getPath0() {
         return FileSystems.getDefault().getPath(FILE_ROOT, getSubdirectory(), Long.toString(id));
     }
@@ -78,85 +183,4 @@ public class FileDescription extends DomainObject {
     public InputStream getData() throws IOException {
         return Files.newInputStream(getPath0());
     }
-
-    public String getName() {
-        return name;
-    }
-
-    // Todo
-    @Override
-    public String toString() {
-        if (name != null) {
-            return name;
-        } else {
-            return super.toString();
-        }
-    }
-
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public String getMimeType() {
-        return this.mimeType;
-    }
-
-    public String getIdentifier() {
-        return this.identifier;
-    }
-
-    public User getUploader() {
-        return this.uploader;
-    }
-
-    public long getSize() {
-        return this.size;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public void setMimeType(String mimeType) {
-        this.mimeType = mimeType;
-    }
-
-    public void setIdentifier(String identifier) {
-        this.identifier = identifier;
-    }
-
-    public void setUploader(User uploader) {
-        this.uploader = uploader;
-    }
-
-    public void setSize(long size) {
-        this.size = size;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof FileDescription)) return false;
-        final FileDescription other = (FileDescription) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof FileDescription;
-    }
-
-    @Override
-    public int hashCode() {
-        final int PRIME = 59;
-        int result = 1;
-        final Object $id = this.getId();
-        result = result * PRIME + ($id == null ? 43 : $id.hashCode());
-        return result;
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java b/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java
index eccb9da1eb..c649d10bfe 100755
--- a/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileDescriptionRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.file;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileModule.java b/core/src/main/java/se/su/dsv/scipro/file/FileModule.java
deleted file mode 100644
index 82cc9172ea..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/file/FileModule.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package se.su.dsv.scipro.file;
-
-import com.google.inject.AbstractModule;
-
-public class FileModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(FileService.class).to(FileServiceImpl.class);
-        bind(ProjectFileService.class).to(ProjectFileServiceImpl.class);
-        bind(ProjectFileRepository.class).to(ProjectFileRepositoryImpl.class);
-        bind(FileReferenceRepository.class).to(FileReferenceRepositoryImpl.class);
-        bind(FileDescriptionRepo.class).to(FileDescriptionRepoImpl.class);
-
-        requireBinding(FileStore.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReference.java b/core/src/main/java/se/su/dsv/scipro/file/FileReference.java
index 34f7ce0beb..4858d090db 100644
--- a/core/src/main/java/se/su/dsv/scipro/file/FileReference.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileReference.java
@@ -9,7 +9,7 @@ import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.Table;
 import java.io.Serializable;
-import java.util.*;
+import java.util.Objects;
 
 /**
  * A reference to a file.
@@ -29,7 +29,7 @@ public class FileReference implements Serializable {
     private Long id;
 
     @ManyToOne(cascade = CascadeType.PERSIST)
-    @JoinColumn(name = "file_description_id")
+    @JoinColumn(name = "file_description_id", referencedColumnName = "id")
     private FileDescription fileDescription;
 
     public Long getId() {
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java
index a942b50e60..3264448133 100644
--- a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.file;
 
-interface FileReferenceRepository {
+public interface FileReferenceRepository {
     FileReference create(FileReference fileReference);
 
     void delete(FileReference fileReference);
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java
index cacc3f7a16..25e00cf450 100644
--- a/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileReferenceRepositoryImpl.java
@@ -1,16 +1,16 @@
 package se.su.dsv.scipro.file;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractRepository;
 
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 import jakarta.persistence.EntityManager;
 
-class FileReferenceRepositoryImpl extends AbstractRepository implements FileReferenceRepository {
+public class FileReferenceRepositoryImpl extends AbstractRepository implements FileReferenceRepository {
 
     @Inject
-    FileReferenceRepositoryImpl(final Provider<EntityManager> em) {
+    public FileReferenceRepositoryImpl(final Provider<EntityManager> em) {
         super(em);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java
index 2fe1f634d6..c6643f50ad 100755
--- a/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/FileServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.file;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractServiceImpl;
 
 import jakarta.inject.Inject;
diff --git a/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java b/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java
index d63c05d4d0..ba57470626 100644
--- a/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/ProjectFile.java
@@ -1,71 +1,88 @@
 package se.su.dsv.scipro.file;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name = "project_file")
 public class ProjectFile extends DomainObject {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    private Project project;
-
+    @Basic
+    @Column(name = "file_source")
     @Enumerated(EnumType.STRING)
     private FileSource fileSource = FileSource.FILES;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_file) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
     @OneToOne
-    @JoinColumn(name = "file_reference_id")
+    @JoinColumn(name = "file_reference_id", referencedColumnName = "id")
     private FileReference fileReference;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public Project getProject() {
-        return this.project;
-    }
-
-    public FileSource getFileSource() {
-        return this.fileSource;
-    }
-
-    public FileDescription getFileDescription() {
-        return this.fileReference.getFileDescription();
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setProject(Project project) {
-        this.project = project;
+    public FileSource getFileSource() {
+        return this.fileSource;
     }
 
     public void setFileSource(FileSource fileSource) {
         this.fileSource = fileSource;
     }
 
-    public void setFileReference(FileReference fileReference) {
-        this.fileReference = fileReference;
-    }
-
     public FileReference getFileReference() {
         return this.fileReference;
     }
 
-    @Override
-    public String toString() {
-        return "ProjectFile(id=" + this.getId() + ", project=" + this.getProject() + ", fileSource=" + this.getFileSource() + ", fileDescription=" + this.getFileDescription() + ")";
+    public void setFileReference(FileReference fileReference) {
+        this.fileReference = fileReference;
     }
 
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -79,12 +96,24 @@ public class ProjectFile extends DomainObject {
                 && Objects.equals(this.getFileDescription(), other.getFileDescription());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ProjectFile;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getProject(), this.getFileSource(), this.getFileDescription());
     }
+
+    @Override
+    public String toString() {
+        return "ProjectFile(id=" + this.getId() + ", project=" + this.getProject() + ", fileSource=" + this.getFileSource() + ", fileDescription=" + this.getFileDescription() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ProjectFile;
+    }
+
+    public FileDescription getFileDescription() {
+        return this.fileReference.getFileDescription();
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java
index e995fd1831..db099d6323 100644
--- a/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/file/ProjectFileServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.file;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.Pageable;
 import se.su.dsv.scipro.project.Project;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java
index 461be0f88c..1679e993a0 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminar.java
@@ -23,7 +23,15 @@ import jakarta.persistence.JoinColumn;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.Table;
-import java.util.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
 @Entity
 @Table(name = "final_seminar")
@@ -35,27 +43,69 @@ public class FinalSeminar extends LazyDeletableDomainObject {
     public static final int DEFAULT_MAX_PARTICIPANTS = 5;
     public static final String FINAL_SEMINAR = "finalSeminar";
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToOne(optional = false)
-    @QueryInit({"projectType", "headSupervisor"})
-    private Project project;
-
     @Basic(optional = false)
+    @Column(name = "start_date")
     private Date startDate;
 
     @Basic(optional = false)
+    @Column(name = "room")
     private String room;
 
+    @Basic
+    @Column(name = "max_opponents")
+    private int maxOpponents = DEFAULT_MAX_OPPONENTS;
+
+    @Basic
+    @Column(name = "max_participants")
+    private int maxParticipants = DEFAULT_MAX_PARTICIPANTS;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "presentation_lang")
+    private Language presentationLanguage;
+
+    @Basic
+    @Column(name = "document_upload_date")
+    private Date documentUploadDate;
+
     @Basic
     @Column(name = "extra_info")
     private String extraInfo;
 
     @Basic
+    @Column(name = "creation_reason")
+    private String creationReason;
+
+    @Basic
+    @Column(name = "manual_participants")
     private Boolean manualParticipants = false;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (final_seminar) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    /*
+     * Cascading delete, set document to nul will delete the filedescription but
+     * not the actual file. Use FinarSeminarUploadController.deleteSeminarReport
+     * to delete the document
+     */
+    @OneToOne(cascade = CascadeType.ALL)
+    @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id")
+    private FileReference document;
+
+    @OneToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    @QueryInit({"projectType", "headSupervisor"})
+    private Project project;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "final_seminar"
+    // ----------------------------------------------------------------------------------
     @OneToMany(mappedBy = FINAL_SEMINAR, orphanRemoval = true, cascade = CascadeType.ALL)
     private Set<FinalSeminarActiveParticipation> activeParticipations = new HashSet<>();
 
@@ -65,28 +115,10 @@ public class FinalSeminar extends LazyDeletableDomainObject {
     @OneToMany(mappedBy = FINAL_SEMINAR, orphanRemoval = true, cascade = CascadeType.ALL)
     private Set<FinalSeminarRespondent> respondents = new HashSet<>();
 
-    /*
-     * Cascading delete, set document to nul will delete the filedescription but
-     * not the actual file. Use FinarSeminarUploadController.deleteSeminarReport
-     * to delete the document
-     */
-    @OneToOne(cascade = CascadeType.ALL)
-    @JoinColumn(name = "document_reference_id")
-    private FileReference document;
-
-    private Date documentUploadDate;
-
-    @Enumerated(EnumType.STRING)
-    private Language presentationLanguage;
-
-    private int maxOpponents = DEFAULT_MAX_OPPONENTS;
-    private int maxParticipants = DEFAULT_MAX_PARTICIPANTS;
-
-    @Basic
-    private String creationReason;
-
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public FinalSeminar() {
-
     }
 
     public FinalSeminar(int maxOpponents, int maxParticipants) {
@@ -99,6 +131,90 @@ public class FinalSeminar extends LazyDeletableDomainObject {
         this.project = project;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public boolean isCancelled() {
+        return isDeleted();
+    }
+
+    public void setCancelled(boolean cancelled) {
+        setDeleted(cancelled);
+    }
+
+    public Date getStartDate() {
+        return this.startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = (Date) startDate.clone();
+    }
+
+    public String getRoom() {
+        return this.room;
+    }
+
+    public void setRoom(String room) {
+        this.room = room;
+    }
+
+    public int getMaxOpponents() {
+        return this.maxOpponents;
+    }
+
+    public void setMaxOpponents(int maxOpponents) {
+        this.maxOpponents = maxOpponents;
+    }
+
+    public int getMaxParticipants() {
+        return this.maxParticipants;
+    }
+
+    public void setMaxParticipants(int maxParticipants) {
+        this.maxParticipants = maxParticipants;
+    }
+
+    public Language getPresentationLanguage() {
+        return this.presentationLanguage;
+    }
+
+    public void setPresentationLanguage(Language presentationLanguage) {
+        this.presentationLanguage = presentationLanguage;
+    }
+
+    public Date getDocumentUploadDate() {
+        return this.documentUploadDate;
+    }
+
+    public void setDocumentUploadDate(Date documentUploadDate) {
+        this.documentUploadDate = documentUploadDate;
+    }
+
+    public String getExtraInfo() {
+        return extraInfo;
+    }
+
+    public void setExtraInfo(String extraInfo) {
+        this.extraInfo = extraInfo;
+    }
+
+    public String getCreationReason() {
+        return this.creationReason;
+    }
+
+    public void setCreationReason(String creationReason) {
+        this.creationReason = creationReason;
+    }
+
     public Boolean getManualParticipants() {
         return manualParticipants;
     }
@@ -107,21 +223,83 @@ public class FinalSeminar extends LazyDeletableDomainObject {
         this.manualParticipants = manualParticipants;
     }
 
-    public void setStartDate(Date startDate) {
-        this.startDate = (Date) startDate.clone();
+    public FileReference getDocument() {
+        return this.document;
+    }
+
+    public void setDocument(FileReference document) {
+        this.document = document;
     }
 
     public Project getProject() {
         return project;
     }
 
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public Set<FinalSeminarActiveParticipation> getActiveParticipations() {
+        return Collections.unmodifiableSet(activeParticipations);
+    }
+
     public void setActiveParticipations(Collection<FinalSeminarActiveParticipation> activeParticipations) {
         this.activeParticipations.clear();
         this.activeParticipations.addAll(activeParticipations);
     }
 
-    public Set<FinalSeminarActiveParticipation> getActiveParticipations() {
-        return Collections.unmodifiableSet(activeParticipations);
+    public Set<FinalSeminarOpposition> getOppositions() {
+        return Collections.unmodifiableSet(oppositions);
+    }
+
+    public void setOppositions(Collection<FinalSeminarOpposition> oppositions) {
+        this.oppositions.clear();
+        this.oppositions.addAll(oppositions);
+    }
+
+    public Set<FinalSeminarRespondent> getRespondents() {
+        return this.respondents;
+    }
+
+    public void setRespondents(Set<FinalSeminarRespondent> respondents) {
+        this.respondents = respondents;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof FinalSeminar)) return false;
+        final FinalSeminar other = (FinalSeminar) o;
+        return other.canEqual(this)
+                && super.equals(o)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
+    }
+
+    @Override
+    public String toString() {
+        return "FinalSeminar(id=" + this.getId() + ", project=" + this.getProject() + ", startDate=" +
+                this.getStartDate() + ", room=" + this.getRoom() + ", activeParticipations=" +
+                this.getActiveParticipations() + ", oppositions=" + this.getOppositions() +
+                ", respondents=" + this.getRespondents() + ", document=" + this.getDocument() +
+                ", documentUploadDate=" + this.getDocumentUploadDate() + ", presentationLanguage=" +
+                this.getPresentationLanguage() + ", maxOpponents=" + this.getMaxOpponents() +
+                ", maxParticipants=" + this.getMaxParticipants() + ", creationReason=" +
+                this.getCreationReason() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof FinalSeminar;
     }
 
     public void addActiveParticipant(FinalSeminarActiveParticipation participation) {
@@ -132,25 +310,62 @@ public class FinalSeminar extends LazyDeletableDomainObject {
         this.activeParticipations.remove(participation);
     }
 
-    public void setOppositions(Collection<FinalSeminarOpposition> oppositions) {
-        this.oppositions.clear();
-        this.oppositions.addAll(oppositions);
+    public void removeActiveParticipant(User user) {
+        activeParticipations.removeIf(next -> next.getUser().equals(user));
     }
 
-    public Set<FinalSeminarOpposition> getOppositions() {
-        return Collections.unmodifiableSet(oppositions);
+    public Set<User> getActiveParticipants(){
+        Set<User> activeParticipants = new HashSet<>();
+        for (FinalSeminarActiveParticipation fsap : activeParticipations){
+            activeParticipants.add(fsap.getUser());
+        }
+        return activeParticipants;
+    }
+
+    public Collection<User> getNotGradedActiveParticipations() {
+        return getNotGradedParticipations(activeParticipations);
     }
 
     public void addOpposition(FinalSeminarOpposition opposition) {
         this.oppositions.add(opposition);
     }
 
+    public void removeOpposition(FinalSeminarOpposition opposition) {
+        this.oppositions.remove(opposition);
+    }
+
+    public Set<User> getOpponents(){
+        Set<User> opponents = new HashSet<>();
+        for (FinalSeminarOpposition fso : oppositions){
+            opponents.add(fso.getUser());
+        }
+        return opponents;
+    }
+
+    public Collection<User> getNotGradedOpponents() {
+        return getNotGradedParticipations(oppositions);
+    }
+
+    public Collection<User> getNotGradedRespondents() {
+        return getNotGradedParticipations(respondents);
+    }
+
+    private Collection<User> getNotGradedParticipations(Set<? extends FinalSeminarParticipation> participations) {
+        List<User> result = new ArrayList<>();
+        for (FinalSeminarParticipation participation : participations) {
+            if(participation.getGrade() == null) {
+                result.add(participation.getUser());
+            }
+        }
+        return result;
+    }
+
     public int getMinOpponents() {
-        return project.getMinOpponentsOnFinalSeminar();
+        return getProject().getMinOpponentsOnFinalSeminar();
     }
 
     public int getMinActiveParticipants() {
-        return project.getMinFinalSeminarActiveParticipation();
+        return getProject().getMinFinalSeminarActiveParticipation();
     }
 
     public List<Member> getMembers() {
@@ -172,177 +387,10 @@ public class FinalSeminar extends LazyDeletableDomainObject {
     }
 
     public ProjectType getProjectType() {
-        return project.getProjectType();
+        return getProject().getProjectType();
     }
 
     public String getProjectTitle() {
-        return project.getTitle();
+        return getProject().getTitle();
     }
-
-    public void setCancelled(boolean cancelled) {
-        setDeleted(cancelled);
-    }
-
-    public boolean isCancelled() {
-        return isDeleted();
-    }
-
-    public void removeOpposition(FinalSeminarOpposition opposition) {
-        this.oppositions.remove(opposition);
-    }
-
-    public Collection<User> getNotGradedOpponents() {
-        return getNotGradedParticipations(oppositions);
-    }
-
-    public Collection<User> getNotGradedActiveParticipations() {
-        return getNotGradedParticipations(activeParticipations);
-    }
-
-    public Collection<User> getNotGradedRespondents() {
-        return getNotGradedParticipations(respondents);
-    }
-
-    private Collection<User> getNotGradedParticipations(Set<? extends FinalSeminarParticipation> participations) {
-        List<User> result = new ArrayList<>();
-        for (FinalSeminarParticipation participation : participations) {
-            if(participation.getGrade() == null) {
-                result.add(participation.getUser());
-            }
-        }
-        return result;
-    }
-
-    public Set<User> getOpponents(){
-        Set<User> opponents = new HashSet<>();
-        for (FinalSeminarOpposition fso : oppositions){
-            opponents.add(fso.getUser());
-        }
-        return opponents;
-    }
-
-    public Set<User> getActiveParticipants(){
-        Set<User> activeParticipants = new HashSet<>();
-        for (FinalSeminarActiveParticipation fsap : activeParticipations){
-            activeParticipants.add(fsap.getUser());
-        }
-        return activeParticipants;
-    }
-
-    public void removeActiveParticipant(User user) {
-        activeParticipations.removeIf(next -> next.getUser().equals(user));
-    }
-
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public Date getStartDate() {
-        return this.startDate;
-    }
-
-    public String getRoom() {
-        return this.room;
-    }
-
-    public Set<FinalSeminarRespondent> getRespondents() {
-        return this.respondents;
-    }
-
-    public FileReference getDocument() {
-        return this.document;
-    }
-
-    public Date getDocumentUploadDate() {
-        return this.documentUploadDate;
-    }
-
-    public Language getPresentationLanguage() {
-        return this.presentationLanguage;
-    }
-
-    public int getMaxOpponents() {
-        return this.maxOpponents;
-    }
-
-    public int getMaxParticipants() {
-        return this.maxParticipants;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public void setRoom(String room) {
-        this.room = room;
-    }
-
-    public void setRespondents(Set<FinalSeminarRespondent> respondents) {
-        this.respondents = respondents;
-    }
-
-    public void setDocument(FileReference document) {
-        this.document = document;
-    }
-
-    public void setDocumentUploadDate(Date documentUploadDate) {
-        this.documentUploadDate = documentUploadDate;
-    }
-
-    public void setPresentationLanguage(Language presentationLanguage) {
-        this.presentationLanguage = presentationLanguage;
-    }
-
-    public void setMaxOpponents(int maxOpponents) {
-        this.maxOpponents = maxOpponents;
-    }
-
-    public void setMaxParticipants(int maxParticipants) {
-        this.maxParticipants = maxParticipants;
-    }
-
-    public void setCreationReason(String creationReason) {
-        this.creationReason = creationReason;
-    }
-
-    public String getExtraInfo() {
-        return extraInfo;
-    }
-
-    public void setExtraInfo(String extraInfo) {
-        this.extraInfo = extraInfo;
-    }
-
-    @Override
-    public String toString() {
-        return "FinalSeminar(id=" + this.getId() + ", project=" + this.getProject() + ", startDate=" + this.getStartDate() + ", room=" + this.getRoom() + ", activeParticipations=" + this.getActiveParticipations() + ", oppositions=" + this.getOppositions() + ", respondents=" + this.getRespondents() + ", document=" + this.getDocument() + ", documentUploadDate=" + this.getDocumentUploadDate() + ", presentationLanguage=" + this.getPresentationLanguage() + ", maxOpponents=" + this.getMaxOpponents() + ", maxParticipants=" + this.getMaxParticipants() + ", creationReason=" + this.getCreationReason() + ")";
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof FinalSeminar)) return false;
-        final FinalSeminar other = (FinalSeminar) o;
-        return other.canEqual(this)
-                && super.equals(o)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof FinalSeminar;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getId());
-    }
-
-    public String getCreationReason() {
-        return this.creationReason;
-    }
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java
index 4930b37979..fdc7bf1429 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarActiveParticipation.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.finalseminar;
 
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.project.Project;
 
 import jakarta.persistence.Cacheable;
@@ -9,13 +10,20 @@ import jakarta.persistence.Table;
 import java.util.Objects;
 
 @Entity
-@Cacheable(true)
 @Table(name = "final_seminar_active_participation")
+@Cacheable(true)
 public class FinalSeminarActiveParticipation extends FinalSeminarParticipation {
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (final_seminar_active_participation)
+    // referencing other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
     private Project project;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Project getProject() {
         return this.project;
     }
@@ -24,6 +32,9 @@ public class FinalSeminarActiveParticipation extends FinalSeminarParticipation {
         this.project = project;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -34,13 +45,16 @@ public class FinalSeminarActiveParticipation extends FinalSeminarParticipation {
                 && Objects.equals(this.project, other.project);
     }
 
-    @Override
-    protected boolean canEqual(final Object other) {
-        return other instanceof FinalSeminarActiveParticipation;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(), this.getProject());
     }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    @Override
+    protected boolean canEqual(final Object other) {
+        return other instanceof FinalSeminarActiveParticipation;
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java
index 65cf89e756..de9c6cd3a4 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOpposition.java
@@ -13,73 +13,90 @@ import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.Table;
-import java.util.*;
+
+import java.util.Objects;
 
 @Entity
 @Table(name="final_seminar_opposition")
 public class FinalSeminarOpposition extends FinalSeminarParticipation {
-    public static final int FEEDBACK_LENGTH = 2000;
-    @ManyToOne(optional = false)
-    private Project project;
-
-    @OneToOne
-    @JoinColumn(name = "opponent_report_reference_id")
-    private FileReference opponentReport;
-
-    @OneToOne(optional = true, orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "finalSeminarOpposition")
-    private OppositionReport oppositionReport;
+    private static final int FEEDBACK_LENGTH = 2000;
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Basic
+    @Column(name = "points")
     private Integer points;
 
     @Basic
-    @Column(length = FEEDBACK_LENGTH)
+    @Column(name = "feedback", length = FEEDBACK_LENGTH)
     private String feedback;
 
-    public ProjectType getProjectType() {
-        return getFinalSeminar().getProject().getProjectType();
-    }
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (final_seminar_opposition) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne
+    @JoinColumn(name = "opponent_report_file_reference_id", referencedColumnName = "id")
+    private FileReference opponentReport;
 
-    public void setProject(final Project project) {
-        this.project = project;
-    }
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
 
-    public Project getProject() {
-        return this.project;
-    }
-
-    public FileReference getOpponentReport() {
-        return this.opponentReport;
-    }
-
-    public OppositionReport getOppositionReport() {
-        return this.oppositionReport;
-    }
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table (final_seminar_opposition)
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = true, orphanRemoval = true, cascade = CascadeType.ALL,
+            mappedBy = "finalSeminarOpposition")
+    private OppositionReport oppositionReport;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Integer getPoints() {
         return this.points;
     }
 
-    public String getFeedback() {
-        return this.feedback;
-    }
-
-    public void setOpponentReport(FileReference opponentReport) {
-        this.opponentReport = opponentReport;
-    }
-
-    public void setOppositionReport(OppositionReport oppositionReport) {
-        this.oppositionReport = oppositionReport;
-    }
-
     public void setPoints(Integer points) {
         this.points = points;
     }
 
+    public String getFeedback() {
+        return this.feedback;
+    }
+
     public void setFeedback(String feedback) {
         this.feedback = feedback;
     }
 
+    public FileReference getOpponentReport() {
+        return this.opponentReport;
+    }
+
+    public void setOpponentReport(FileReference opponentReport) {
+        this.opponentReport = opponentReport;
+    }
+
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(final Project project) {
+        this.project = project;
+    }
+
+    public OppositionReport getOppositionReport() {
+        return this.oppositionReport;
+    }
+
+    public void setOppositionReport(OppositionReport oppositionReport) {
+        this.oppositionReport = oppositionReport;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -90,13 +107,20 @@ public class FinalSeminarOpposition extends FinalSeminarParticipation {
                 && Objects.equals(this.getProject(), other.getProject());
     }
 
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), this.getProject());
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
     @Override
     protected boolean canEqual(final Object other) {
         return other instanceof FinalSeminarOpposition;
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), this.getProject());
+    public ProjectType getProjectType() {
+        return getFinalSeminar().getProject().getProjectType();
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java
index 7def75b680..46957a9678 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarOppositionRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.finalseminar;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.system.ProjectType;
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java
index 43d94e05e8..8d97c21020 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarParticipation.java
@@ -1,64 +1,66 @@
 package se.su.dsv.scipro.finalseminar;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MappedSuperclass;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @MappedSuperclass
 public abstract class FinalSeminarParticipation extends DomainObject {
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne(optional = false)
-    private User user;
+    @Basic
+    @Enumerated(EnumType.STRING)
+    @Column(name = "grade")
+    private FinalSeminarGrade grade = null;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in tables whose entity class inherits from
+    // FinalSeminarParticipation class (such as final_seminar_active_participation,
+    // final_seminar_opposition, final_seminar_respondent) referencing other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
+    @JoinColumn(name = "final_seminar_id", referencedColumnName = "id")
     private FinalSeminar finalSeminar;
 
-    @Enumerated(EnumType.STRING)
-    private FinalSeminarGrade grade = null;
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
+    protected FinalSeminarParticipation() {
+    }
 
     protected FinalSeminarParticipation(User user, FinalSeminar finalSeminar) {
         this.user = user;
         this.finalSeminar = finalSeminar;
     }
 
-    protected FinalSeminarParticipation() {
-    }
-
-    public boolean isApproved() {
-        return grade == FinalSeminarGrade.APPROVED;
-    }
-
-    public boolean hasGrade() {
-        return (grade != null);
-    }
-
-    public void setUser(final User user) {
-        this.user = user;
-    }
-
-    public void setFinalSeminar(final FinalSeminar finalSeminar) {
-        this.finalSeminar = finalSeminar;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public User getUser() {
-        return this.user;
-    }
-
-    public FinalSeminar getFinalSeminar() {
-        return this.finalSeminar;
-    }
-
     public FinalSeminarGrade getGrade() {
         return this.grade;
     }
@@ -67,6 +69,29 @@ public abstract class FinalSeminarParticipation extends DomainObject {
         this.grade = grade;
     }
 
+    public boolean hasGrade() {
+        return (grade != null);
+    }
+
+    public FinalSeminar getFinalSeminar() {
+        return this.finalSeminar;
+    }
+
+    public void setFinalSeminar(final FinalSeminar finalSeminar) {
+        this.finalSeminar = finalSeminar;
+    }
+
+    public User getUser() {
+        return this.user;
+    }
+
+    public void setUser(final User user) {
+        this.user = user;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -77,12 +102,20 @@ public abstract class FinalSeminarParticipation extends DomainObject {
                 && Objects.equals(this.getFinalSeminar(), other.getFinalSeminar());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof FinalSeminarParticipation;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getUser(), this.getFinalSeminar());
     }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+
+    protected boolean canEqual(final Object other) {
+        return other instanceof FinalSeminarParticipation;
+    }
+
+    public boolean isApproved() {
+        return grade == FinalSeminarGrade.APPROVED;
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java
index f17e41be75..40e72964a7 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.finalseminar;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.EntityManager;
 import se.su.dsv.scipro.system.AbstractRepository;
 
@@ -9,7 +9,7 @@ import jakarta.inject.Provider;
 
 public class FinalSeminarRepositoryImpl extends AbstractRepository implements FinalSeminarRepository {
     @Inject
-    protected FinalSeminarRepositoryImpl(Provider<EntityManager> em) {
+    public FinalSeminarRepositoryImpl(Provider<EntityManager> em) {
         super(em);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java
index 2178db68c1..92bf8ee457 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondent.java
@@ -8,17 +8,17 @@ import jakarta.persistence.Entity;
 import jakarta.persistence.Table;
 
 @Entity
-@Cacheable(true)
 @Table(name = "final_seminar_respondent")
+@Cacheable(true)
 public class FinalSeminarRespondent extends FinalSeminarParticipation {
 
+    protected FinalSeminarRespondent() {
+    }
+
     public FinalSeminarRespondent(User student, FinalSeminar finalSeminar) {
         super(student, finalSeminar);
     }
 
-    protected FinalSeminarRespondent() {
-    }
-
     public Project getProject() {
         return getFinalSeminar().getProject();
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java
index ee7478c33c..f532f0289d 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarRespondentServiceImpl.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.finalseminar;
 
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractServiceImpl;
 import se.su.dsv.scipro.system.User;
 
@@ -33,6 +34,7 @@ public class FinalSeminarRespondentServiceImpl extends AbstractServiceImpl<Final
     }
 
     @Override
+    @Transactional
     public List<FinalSeminarRespondent> findOrCreate(FinalSeminar finalSeminar) {
         if(finalSeminar.getId() == null) {
             return new ArrayList<>();
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java
index e3510ddfae..b5514bcd3e 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.finalseminar;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import jakarta.persistence.EntityManager;
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java
index b95f64e994..7a62ea83e9 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettings.java
@@ -7,6 +7,7 @@ import java.util.Objects;
 
 @Entity
 @Cacheable(true)
+@Table(name = "final_seminar_settings")
 public class FinalSeminarSettings extends DomainObject {
     public static final int DEFAULT_DAYS_AHEAD_TO_UPLOAD_THESIS = 10;
     public static final int DEFAULT_DAYS_AHEAD_TO_REGISTER_OPPOSITION = 3;
@@ -22,25 +23,26 @@ public class FinalSeminarSettings extends DomainObject {
         this.id = id;
     }
 
-    @Basic(optional = false)
+    @Column(name = "days_ahead_to_create", nullable = false)
     private int daysAheadToCreate;
 
-    @Basic(optional = false)
+    @Column(name = "days_ahead_to_register_participation", nullable = false)
     private int daysAheadToRegisterParticipation = DEFAULT_DAYS_AHEAD_TO_REGISTER_PARTICIPATION;
 
-    @Basic(optional = false)
+    @Column(name = "days_ahead_to_register_opposition", nullable = false)
     private int daysAheadToRegisterOpposition = DEFAULT_DAYS_AHEAD_TO_REGISTER_OPPOSITION;
 
-    @Basic(optional = false)
+    @Column(name = "days_ahead_to_upload_thesis", nullable = false)
     private int daysAheadToUploadThesis = DEFAULT_DAYS_AHEAD_TO_UPLOAD_THESIS;
 
-    @Basic(optional = false)
+    @Column(name = "thesis_must_be_pdf", nullable = false)
     private boolean thesisMustBePDF = false;
 
-    @Basic(optional = true)
+    @Column(name = "evaluation_url", nullable = true)
     private String evaluationURL;
 
     @Basic(optional = false)
+    @Column(name = "opposition_priority_days", nullable = false)
     private int oppositionPriorityDays;
 
     public boolean getThesisMustBePDF() {
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java
index 24aa74c59e..c912f35abb 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarSettingsServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.finalseminar;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractServiceImpl;
 
 import jakarta.inject.Inject;
diff --git a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java
index 5feff42af2..2613d77c32 100755
--- a/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalseminar/FinalSeminarUploadControllerImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.finalseminar;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import se.su.dsv.scipro.file.*;
diff --git a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java
index 894e798a5f..818bfc2b0c 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesis.java
@@ -21,50 +21,67 @@ import jakarta.persistence.Table;
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.ZoneId;
-import java.util.*;
+import java.util.Date;
+import java.util.Objects;
 
 @Entity
-@Table
+@Table(name = "final_thesis")
 public class FinalThesis extends DomainObject {
 
-    public enum Status {
-        APPROVED, REJECTED, NO_DECISION
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "document_reference_id")
-    private FileReference document;
+    @Basic
+    @Column(name = "title_sv")
+    private String swedishTitle;
 
-    @ManyToOne(optional = true)
-    @JoinColumn(name = "text_matching_document_reference_id")
-    private FileReference textMatchingDocument;
+    @Basic
+    @Column(name = "title_en")
+    private String englishTitle;
+
+    @Basic
+    @Column(name = "status")
+    @Enumerated(EnumType.STRING)
+    private Status status = Status.NO_DECISION;
+
+    @Basic
+    @Column(name = "date_approved")
+    private Date dateApproved;
+
+    @Basic
+    @Column(name = "date_rejected")
+    private Date dateRejected;
+
+    @Basic
+    @Column(name = "rejection_comment")
+    private String rejectionComment;
 
     @Basic
     @Column(name = "text_matching_analysis")
     private String textMatchingAnalysis;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (final_thesis) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "text_matching_document_reference_id", referencedColumnName = "id")
+    private FileReference textMatchingDocument;
+
     @ManyToOne(optional = false)
-    @JoinColumn(name = "project_id")
+    @JoinColumn(name = "document_reference_id", referencedColumnName = "id")
+    private FileReference document;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
     private Project project;
 
-    @Enumerated(EnumType.STRING)
-    private Status status = Status.NO_DECISION;
-
-    private Date dateApproved;
-
-    private Date dateRejected;
-
-    private String englishTitle;
-
-    private String swedishTitle;
-
-    @Column(name = "rejection_comment")
-    private String rejectionComment;
-
+    // ----------------------------------------------------------------------------------
+    // JPA lifecycle method
+    // ----------------------------------------------------------------------------------
     @PrePersist
     @PreUpdate
     void cleanTitle() {
@@ -72,6 +89,126 @@ public class FinalThesis extends DomainObject {
         this.swedishTitle = clean(this.swedishTitle);
     }
 
+
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getEnglishTitle() {
+        return this.englishTitle;
+    }
+
+    public void setEnglishTitle(String englishTitle) {
+        this.englishTitle = englishTitle;
+    }
+
+    public String getSwedishTitle() {
+        return this.swedishTitle;
+    }
+
+    public void setSwedishTitle(String swedishTitle) {
+        this.swedishTitle = swedishTitle;
+    }
+
+    public Status getStatus() {
+        return this.status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    public Date getDateApproved() {
+        return dateApproved;
+    }
+
+    public void setDateApproved(Date dateApproved) {
+        this.dateApproved = dateApproved;
+    }
+
+    public Date getDateRejected() {
+        return dateRejected;
+    }
+
+    public void setDateRejected(Date dateRejected) {
+        this.dateRejected = dateRejected;
+    }
+
+    public String getRejectionComment() {
+        return rejectionComment;
+    }
+
+    public void setRejectionComment(String rejectionComment) {
+        this.rejectionComment = rejectionComment;
+    }
+
+    public String getTextMatchingAnalysis() {
+        return textMatchingAnalysis;
+    }
+
+    public void setTextMatchingAnalysis(String textMatchingAnalysis) {
+        this.textMatchingAnalysis = textMatchingAnalysis;
+    }
+
+    public FileReference getTextMatchingDocument() {
+        return this.textMatchingDocument;
+    }
+
+    public void setTextMatchingDocument(FileReference textMatchingDocument) {
+        this.textMatchingDocument = textMatchingDocument;
+    }
+
+    public FileReference getDocument() {
+        return this.document;
+    }
+
+    public void setDocument(FileReference fileDescription) {
+        this.document = fileDescription;
+    }
+
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof FinalThesis)) return false;
+        final FinalThesis other = (FinalThesis) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getDocument(), other.getDocument())
+                && Objects.equals(this.getProject(), other.getProject());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.getDocument(), this.getProject());
+    }
+
+    @Override
+    public String toString() {
+        return "FinalThesis(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", textMatchingDocument=" + this.getTextMatchingDocument() + ", project=" + this.getProject() + ", status=" + this.getStatus() + ", dateApproved=" + this.getDateApproved() + ", dateRejected=" + this.getDateRejected() + ", englishTitle=" + this.getEnglishTitle() + ", swedishTitle=" + this.getSwedishTitle() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
     private String clean(String str) {
         if (str == null) {
             return null;
@@ -83,125 +220,23 @@ public class FinalThesis extends DomainObject {
                 .trim();
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public FileReference getDocument() {
-        return this.document;
-    }
-
-    public FileReference getTextMatchingDocument() {
-        return this.textMatchingDocument;
-    }
-
-    public Project getProject() {
-        return this.project;
-    }
-
-    public Status getStatus() {
-        return this.status;
-    }
-
-    public String getEnglishTitle() {
-        return this.englishTitle;
-    }
-
-    public String getSwedishTitle() {
-        return this.swedishTitle;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setDocument(FileReference fileDescription) {
-        this.document = fileDescription;
-    }
-
-    public void setTextMatchingDocument(FileReference textMatchingDocument) {
-        this.textMatchingDocument = textMatchingDocument;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public void setStatus(Status status) {
-        this.status = status;
-    }
-
-    public void setDateApproved(Date dateApproved) {
-        this.dateApproved = dateApproved;
-    }
-
-    public void setDateRejected(Date dateRejected) {
-        this.dateRejected = dateRejected;
-    }
-
-    public void setEnglishTitle(String englishTitle) {
-        this.englishTitle = englishTitle;
-    }
-
-    public void setSwedishTitle(String swedishTitle) {
-        this.swedishTitle = swedishTitle;
-    }
-
-    public String getTextMatchingAnalysis() {
-        return textMatchingAnalysis;
-    }
-
-    public void setTextMatchingAnalysis(String textMatchingAnalysis) {
-        this.textMatchingAnalysis = textMatchingAnalysis;
-    }
-
-    public String getRejectionComment() {
-        return rejectionComment;
-    }
-
-    public void setRejectionComment(String rejectionComment) {
-        this.rejectionComment = rejectionComment;
-    }
-
-    @Override
-    public String toString() {
-        return "FinalThesis(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", textMatchingDocument=" + this.getTextMatchingDocument() + ", project=" + this.getProject() + ", status=" + this.getStatus() + ", dateApproved=" + this.getDateApproved() + ", dateRejected=" + this.getDateRejected() + ", englishTitle=" + this.getEnglishTitle() + ", swedishTitle=" + this.getSwedishTitle() + ")";
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof FinalThesis)) return false;
-        final FinalThesis other = (FinalThesis) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getDocument(), other.getDocument())
-                && Objects.equals(this.getProject(), other.getProject());
-    }
-
     protected boolean canEqual(final Object other) {
         return other instanceof FinalThesis;
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(this.getDocument(), this.getProject());
-    }
-
-    public boolean isRejected() {
-        return getStatus() == Status.REJECTED;
-    }
-
-    public Date getDateRejected() {
-        return dateRejected;
-    }
-
-    public Date getDateApproved() {
-        return dateApproved;
-    }
-
     public LocalDate getUploadDate() {
         Instant instant = document.getFileDescription().getDateCreated().toInstant();
         return instant.atZone(ZoneId.systemDefault()).toLocalDate();
     }
+
+    public boolean isRejected() {
+        return getStatus() == Status.REJECTED;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Nested types
+    // ----------------------------------------------------------------------------------
+    public enum Status {
+        APPROVED, REJECTED, NO_DECISION
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java
index 98b775c07b..f505a3d189 100644
--- a/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/finalthesis/FinalThesisServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.finalthesis;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.Predicate;
 import jakarta.persistence.EntityManager;
@@ -56,6 +56,7 @@ public class FinalThesisServiceImpl extends AbstractServiceImpl<FinalThesis, Lon
     }
 
     @Override
+    @Transactional
     public FinalThesis upload(ProjectFileUpload fileUpload, String englishTitle, String swedishTitle) {
         ProjectFile fileDescription = storeFinalThesisFile(fileUpload);
         final FileReference reference = fileService.createReference(fileDescription.getFileDescription());
@@ -133,6 +134,7 @@ public class FinalThesisServiceImpl extends AbstractServiceImpl<FinalThesis, Lon
     }
 
     @Override
+    @Transactional
     public void removeApproval(Project project) {
         setStatus(project, FinalThesis.Status.NO_DECISION);
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java
deleted file mode 100644
index e567605a8d..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingModule.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package se.su.dsv.scipro.firstmeeting;
-
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.firstmeeting.FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule;
-
-public class FirstMeetingModule extends AbstractModule {
-    @Override
-    public void configure() {
-        bind(FirstMeetingReminderWorkerSchedule.class).asEagerSingleton();
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java
index 23d1832201..1ab1e575a8 100644
--- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/firstmeeting/FirstMeetingServiceImpl.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.firstmeeting;
 
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.activityplan.Activity;
 import se.su.dsv.scipro.activityplan.ActivityPlanFacade;
 import se.su.dsv.scipro.project.Project;
@@ -26,6 +27,7 @@ public class FirstMeetingServiceImpl extends AbstractServiceImpl<ProjectFirstMee
     }
 
     @Override
+    @Transactional
     public ProjectFirstMeeting schedule(final Project project, final Date date, final String room, final String description) {
         final Optional<ProjectFirstMeeting> optFirstMeeting = findByProject(project);
         final ProjectFirstMeeting firstMeeting = optFirstMeeting
diff --git a/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java b/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java
index acfaa134eb..759f63f781 100644
--- a/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java
+++ b/core/src/main/java/se/su/dsv/scipro/firstmeeting/ProjectFirstMeeting.java
@@ -1,37 +1,58 @@
 package se.su.dsv.scipro.firstmeeting;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.activityplan.Activity;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Date;
 
 @Entity
 @Table(name = "project_first_meeting")
 public final class ProjectFirstMeeting extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @QueryInit("activityPlan.project")
-    @OneToOne(optional = false, cascade = CascadeType.ALL)
-    private Activity activity;
-
     @Basic(optional = false)
+    @Column(name = "room")
     private String room;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_first_meeting) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = false, cascade = CascadeType.ALL)
+    @JoinColumn(name = "activity_id", referencedColumnName = "id")
+    @QueryInit("activityPlan.project")
+    private Activity activity;
+
+    // ----------------------------------------------------------------------------------
+    // constructor
+    // ----------------------------------------------------------------------------------
     protected ProjectFirstMeeting() {}
 
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return id;
     }
 
-    public Date getDate() {
-        return activity.getDate();
-    }
-
     public String getRoom() {
         return room;
     }
@@ -40,10 +61,6 @@ public final class ProjectFirstMeeting extends DomainObject {
         this.room = room;
     }
 
-    public String getDescription() {
-        return activity.getDescription();
-    }
-
     Activity getActivity() {
         return activity;
     }
@@ -51,4 +68,15 @@ public final class ProjectFirstMeeting extends DomainObject {
     void setActivity(Activity activity) {
         this.activity = activity;
     }
+
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
+    public Date getDate() {
+        return activity.getDate();
+    }
+
+    public String getDescription() {
+        return activity.getDescription();
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java
index 05642970d2..0dae3383bb 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.forum;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java
deleted file mode 100644
index 7346fd1166..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/forum/ForumModule.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package se.su.dsv.scipro.forum;
-
-import com.google.inject.PrivateModule;
-
-public class ForumModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        bind(AbstractThreadRepository.class).to(AbstractThreadRepositoryImpl.class);
-        bind(ForumPostReadStateRepository.class).to(ForumPostReadStateRepositoryImpl.class);
-        bind(ForumPostRepository.class).to(ForumPostRepositoryImpl.class);
-        bind(ProjectThreadRepository.class).to(ProjectThreadRepositoryImpl.class);
-        bind(GroupThreadRepository.class).to(GroupThreadRepositoryImpl.class);
-
-        expose(ProjectThreadRepository.class);
-        expose(GroupThreadRepository.class);
-
-        bind(ProjectForumService.class).to(ProjectForumServiceImpl.class);
-        bind(GroupForumService.class).to(GroupForumServiceImpl.class);
-
-        expose(ProjectForumService.class);
-        expose(GroupForumService.class);
-
-        bind(BasicForumService.class).to(BasicForumServiceImpl.class);
-        expose(BasicForumService.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java
index 4d385c0255..00dd52bb7c 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java
index 909c57693f..862884445c 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostReadStateRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.LockModeType;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java
index 0b39495268..92e3afb1c8 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/ForumPostRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java
index bed0169c09..0ba81e0b92 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/GroupForumServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.forum;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.forum.dataobjects.ForumThread;
 import se.su.dsv.scipro.forum.dataobjects.GroupThread;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java
index 37e0a30d31..2c254d5bd2 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/GroupThreadRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.forum.dataobjects.GroupThread;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java
index 7ed3e1715c..1825a16197 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/ProjectForumServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.forum;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileSource;
 import se.su.dsv.scipro.file.ProjectFileService;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java b/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java
index b50913b764..cbe28506a1 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/ProjectThreadRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java
index 7740741863..aff80a655f 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPost.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.Basic;
 import jakarta.persistence.GenerationType;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.system.LazyDeletableDomainObject;
@@ -15,54 +16,51 @@ import jakarta.persistence.Lob;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.Table;
-import java.util.*;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
 
 @Entity
 @Table(name = "forum_post")
 public class ForumPost extends LazyDeletableDomainObject {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Lob
+    @Basic
     @Column(name = "content", nullable = false)
+    @Lob
     private String content;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (forum_post) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
-    @JoinColumn(name = "user", nullable = true)
-    private User postedBy;
-
-    @ManyToOne
-    @JoinColumn(name = "thread", nullable = false)
+    @JoinColumn(name = "thread_id", nullable = false)
     private ForumThread forumThread;
 
+    @ManyToOne
+    @JoinColumn(name = "user_id", nullable = true)
+    private User postedBy;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "forum_post"
+    // ----------------------------------------------------------------------------------
     @OneToMany(orphanRemoval = true)
-    @JoinTable(name = "forum_post_file_description",
-            joinColumns = {@JoinColumn(name = "forum_post_id")},
+    @JoinTable(name = "forum_post_file_reference",
+            joinColumns = {@JoinColumn(name = "forum_post_id", referencedColumnName = "id")},
             inverseJoinColumns = {@JoinColumn(name = "file_reference_id")})
     private Set<FileReference> attachments = new HashSet<>();
 
-    public String getSubject() {
-        return forumThread.getSubject();
-    }
-
-    public Set<FileReference> getAttachments() {
-        return attachments;
-    }
-
-    public User getPostedBy() {
-        return postedBy;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public ForumThread getForumThread() {
-        return forumThread;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
@@ -72,27 +70,41 @@ public class ForumPost extends LazyDeletableDomainObject {
         this.id = id;
     }
 
+    public String getContent() {
+        return content;
+    }
+
     public void setContent(String content) {
         this.content = content;
     }
 
-    public void setPostedBy(User postedBy) {
-        this.postedBy = postedBy;
+    public ForumThread getForumThread() {
+        return forumThread;
     }
 
     public void setForumThread(ForumThread forumThread) {
         this.forumThread = forumThread;
     }
 
+    public User getPostedBy() {
+        return postedBy;
+    }
+
+    public void setPostedBy(User postedBy) {
+        this.postedBy = postedBy;
+    }
+
+    public Set<FileReference> getAttachments() {
+        return attachments;
+    }
+
     public void setAttachments(Set<FileReference> attachments) {
         this.attachments = attachments;
     }
 
-    @Override
-    public String toString() {
-        return "ForumPost(id=" + this.getId() + ", content=" + this.getContent() + ", postedBy=" + this.getPostedBy() + ", forumThread=" + this.getForumThread() + ", attachments=" + this.getAttachments() + ")";
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -106,10 +118,6 @@ public class ForumPost extends LazyDeletableDomainObject {
                 && Objects.equals(this.getAttachments(), other.getAttachments());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ForumPost;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(
@@ -119,4 +127,22 @@ public class ForumPost extends LazyDeletableDomainObject {
                 this.getForumThread(),
                 this.getAttachments());
     }
+
+    @Override
+    public String toString() {
+        return "ForumPost(id=" + this.getId() + ", content=" + this.getContent() +
+                ", postedBy=" + this.getPostedBy() + ", forumThread=" + this.getForumThread() +
+                ", attachments=" + this.getAttachments() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ForumPost;
+    }
+
+    public String getSubject() {
+        return forumThread.getSubject();
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java
index 655a3baf41..eff11f8578 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadState.java
@@ -1,14 +1,21 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 
 @Entity
-@Table(name = "forum_post_read")
+@Table(name = "forum_post_read_state")
 public class ForumPostReadState implements Serializable {
 
+    // ----------------------------------------------------------------------------------
+    // Basic and embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @EmbeddedId
     private ForumPostReadStateId id;
 
@@ -16,6 +23,9 @@ public class ForumPostReadState implements Serializable {
     @Column(name = "`read`", nullable = false)
     private boolean read = false;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public ForumPostReadState() {
     }
 
@@ -23,6 +33,9 @@ public class ForumPostReadState implements Serializable {
         id = new ForumPostReadStateId(user, post);
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public ForumPostReadStateId getId() {
         return id;
     }
@@ -39,4 +52,3 @@ public class ForumPostReadState implements Serializable {
         this.read = read;
     }
 }
-
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java
index c596d98513..818fd9ca86 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumPostReadStateId.java
@@ -11,11 +11,11 @@ import java.util.Objects;
 @Embeddable
 public class ForumPostReadStateId implements Serializable {
     @ManyToOne
-    @JoinColumn(name = "user", nullable = false)
+    @JoinColumn(name = "user_id", nullable = false)
     private User user;
 
     @ManyToOne
-    @JoinColumn(name = "post", nullable = false)
+    @JoinColumn(name = "forum_post_id", nullable = false)
     private ForumPost post;
 
     public ForumPostReadStateId() {
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java
index 3068a8fa62..aaeaf4849e 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ForumThread.java
@@ -1,9 +1,21 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.PostLoad;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.LazyDeletableDomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -13,17 +25,88 @@ import java.util.Objects;
 @Inheritance(strategy = InheritanceType.JOINED)
 public class ForumThread extends LazyDeletableDomainObject {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
-    private List<ForumPost> posts = new ArrayList<>();
-
     @Basic
     @Column(name = "subject", nullable = false)
     private String subject;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "thread"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "forumThread", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
+    private List<ForumPost> posts = new ArrayList<>();
+
+    // ----------------------------------------------------------------------------------
+    // JPA-lifecycle method
+    // ----------------------------------------------------------------------------------
+    @PostLoad
+    void lazyDeletion() {
+        posts.removeIf(LazyDeletableDomainObject::isDeleted);
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public List<ForumPost> getPosts() {
+        return this.posts;
+    }
+
+    public void setPosts(List<ForumPost> posts) {
+        this.posts = posts;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof ForumThread)) return false;
+        final ForumThread other = (ForumThread) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
+    }
+
+    @Override
+    public String toString() {
+        return "ForumThread(id=" + this.getId() + ", subject=" + this.getSubject() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ForumThread;
+    }
+
     public void addPost(ForumPost post) {
         posts.add(post);
     }
@@ -32,15 +115,6 @@ public class ForumThread extends LazyDeletableDomainObject {
         return posts.size();
     }
 
-    @PostLoad
-    void lazyDeletion() {
-        posts.removeIf(LazyDeletableDomainObject::isDeleted);
-    }
-
-    public String getSubject() {
-        return subject;
-    }
-
     public User getCreatedBy(){
         return getPosts().get(0).getPostedBy();
     }
@@ -53,48 +127,4 @@ public class ForumThread extends LazyDeletableDomainObject {
         }
         return false;
     }
-
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public List<ForumPost> getPosts() {
-        return this.posts;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setPosts(List<ForumPost> posts) {
-        this.posts = posts;
-    }
-
-    public void setSubject(String subject) {
-        this.subject = subject;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof ForumThread)) return false;
-        final ForumThread other = (ForumThread) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof ForumThread;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getId());
-    }
-
-    @Override
-    public String toString() {
-        return "ForumThread(id=" + this.getId() + ", subject=" + this.getSubject() + ")";
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java
index 5956a4d6de..ed7d45f410 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/GroupThread.java
@@ -1,49 +1,70 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.group.Group;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
-@Table(name = "group_thread")
+@Table(name = "project_group_thread")
 public class GroupThread implements Serializable {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_group_thread) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
-    @JoinColumn(name = "group_id", nullable = false)
+    @JoinColumn(name = "project_group_id", referencedColumnName = "id", nullable = false)
     private Group group;
 
     @OneToOne(cascade = CascadeType.ALL, optional = false)
-    @JoinColumn(name = "thread_id")
+    @JoinColumn(name = "thread_id", referencedColumnName = "id")
     private ForumThread forumThread;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() { return id; }
 
-    public Group getGroup() {
-        return group;
-    }
-
-    public ForumThread getForumThread() {
-        return forumThread;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
+    public Group getGroup() {
+        return group;
+    }
+
     public void setGroup(Group group) {
         this.group = group;
     }
 
+    public ForumThread getForumThread() {
+        return forumThread;
+    }
+
     public void setForumThread(ForumThread forumThread) {
         this.forumThread = forumThread;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -55,10 +76,6 @@ public class GroupThread implements Serializable {
                 && Objects.equals(this.getForumThread(), other.getForumThread());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof GroupThread;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getGroup(), this.getForumThread());
@@ -66,6 +83,14 @@ public class GroupThread implements Serializable {
 
     @Override
     public String toString() {
-        return "GroupThread(id=" + this.getId() + ", group=" + this.getGroup() + ", forumThread=" + this.getForumThread() + ")";
+        return "GroupThread(id=" + this.getId() + ", group=" + this.getGroup() + ", forumThread=" +
+                this.getForumThread() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof GroupThread;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java
index 32b99a8a84..ba32a9f14f 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ProjectThread.java
@@ -1,50 +1,70 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
 @Table(name = "project_thread")
 public class ProjectThread implements Serializable {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToOne(optional = false)
-    @JoinColumn(name = "thread_id")
-    private ForumThread forumThread;
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_thread) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
-    @JoinColumn(name = "project_id")
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
     private Project project;
 
+    @OneToOne(optional = false)
+    @JoinColumn(name = "thread_id", referencedColumnName = "id")
+    private ForumThread forumThread;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public ForumThread getForumThread() {
-        return forumThread;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setForumThread(ForumThread forumThread) {
-        this.forumThread = forumThread;
+    public Project getProject() {
+        return project;
     }
 
     public void setProject(Project project) {
         this.project = project;
     }
 
+    public ForumThread getForumThread() {
+        return forumThread;
+    }
+
+    public void setForumThread(ForumThread forumThread) {
+        this.forumThread = forumThread;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -56,10 +76,6 @@ public class ProjectThread implements Serializable {
                 && Objects.equals(this.getProject(), other.getProject());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ProjectThread;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getForumThread(), this.getProject());
@@ -67,6 +83,14 @@ public class ProjectThread implements Serializable {
 
     @Override
     public String toString() {
-        return "ProjectThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + ", project=" + this.getProject() + ")";
+        return "ProjectThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() +
+                ", project=" + this.getProject() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ProjectThread;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java
index 010a5686d6..5cce25c1ca 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/dataobjects/ReviewerThread.java
@@ -1,50 +1,69 @@
 package se.su.dsv.scipro.forum.dataobjects;
 
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name = "reviewer_thread")
 public class ReviewerThread {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mapping
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToOne(optional = false)
-    @JoinColumn(name = "thread_id")
-    private ForumThread forumThread;
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (mail_event) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @OneToOne
-    @JoinColumn(name = "project_id", unique = true)
+    @JoinColumn(name = "project_id", referencedColumnName = "id", unique = true)
     private Project project;
 
+    @OneToOne(optional = false)
+    @JoinColumn(name = "thread_id", referencedColumnName = "id")
+    private ForumThread forumThread;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return this.id;
     }
 
-    public ForumThread getForumThread() {
-        return this.forumThread;
-    }
-
-    public Project getProject() {
-        return this.project;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setForumThread(ForumThread forumThread) {
-        this.forumThread = forumThread;
+    public Project getProject() {
+        return this.project;
     }
 
     public void setProject(Project project) {
         this.project = project;
     }
 
+    public ForumThread getForumThread() {
+        return this.forumThread;
+    }
+
+    public void setForumThread(ForumThread forumThread) {
+        this.forumThread = forumThread;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -56,10 +75,6 @@ public class ReviewerThread {
                 && Objects.equals(this.getProject(), other.getProject());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ReviewerThread;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getForumThread(), this.getProject());
@@ -67,6 +82,14 @@ public class ReviewerThread {
 
     @Override
     public String toString() {
-        return "ReviewerThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() + ", project=" + this.getProject() + ")";
+        return "ReviewerThread(id=" + this.getId() + ", forumThread=" + this.getForumThread() +
+                ", project=" + this.getProject() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ReviewerThread;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java
index 3bc39f38ab..fe2bc877e4 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotification.java
@@ -1,26 +1,44 @@
 package se.su.dsv.scipro.forum.notifications;
 
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapsId;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.notifications.dataobject.NotificationEvent;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
 @Table(name = "forum_notification")
 class ForumNotification {
+    // ----------------------------------------------------------------------------------
+    // Embedded JPA-mapping
+    // ----------------------------------------------------------------------------------
     @EmbeddedId
     private Id id = new Id();
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (forum_notification) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
+    @JoinColumn(name = "forum_post_id", referencedColumnName = "id")
     @MapsId("forumPostId")
     private ForumPost forumPost;
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "notification_data_id")
     @MapsId("notificationEventId")
     private NotificationEvent notificationEvent;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected ForumNotification() { } // JPA
 
     ForumNotification(final ForumPost forumPost, final NotificationEvent notificationEvent) {
@@ -28,6 +46,9 @@ class ForumNotification {
         this.notificationEvent = notificationEvent;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters)
+    // ----------------------------------------------------------------------------------
     public ForumPost getForumPost() {
         return forumPost;
     }
@@ -36,6 +57,9 @@ class ForumNotification {
         return notificationEvent;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -47,10 +71,6 @@ class ForumNotification {
                 && Objects.equals(this.getNotificationEvent(), other.getNotificationEvent());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ForumNotification;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.id, this.getForumPost(), this.getNotificationEvent());
@@ -58,9 +78,20 @@ class ForumNotification {
 
     @Override
     public String toString() {
-        return "ForumNotification(id=" + this.id + ", forumPost=" + this.getForumPost() + ", notificationEvent=" + this.getNotificationEvent() + ")";
+        return "ForumNotification(id=" + this.id + ", forumPost=" + this.getForumPost() +
+                ", notificationEvent=" + this.getNotificationEvent() + ")";
     }
 
+    // ----------------------------------------------------------------------------------
+    // Other method
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ForumNotification;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Nested type
+    // ----------------------------------------------------------------------------------
     @Embeddable
     static class Id implements Serializable {
         private Long forumPostId;
@@ -103,7 +134,8 @@ class ForumNotification {
 
         @Override
         public String toString() {
-            return "ForumNotification.Id(forumPostId=" + this.getForumPostId() + ", notificationEventId=" + this.getNotificationEventId() + ")";
+            return "ForumNotification.Id(forumPostId=" + this.getForumPostId() + ", notificationEventId=" +
+                    this.getNotificationEventId() + ")";
         }
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java
index b294608351..5b1ff17920 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotifications.java
@@ -2,7 +2,7 @@ package se.su.dsv.scipro.forum.notifications;
 
 import com.google.common.eventbus.EventBus;
 import com.google.common.eventbus.Subscribe;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.forum.ForumPostReadEvent;
 import se.su.dsv.scipro.forum.NewGroupForumReplyEvent;
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java b/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java
deleted file mode 100644
index 2a77013615..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/forum/notifications/ForumNotificationsModule.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package se.su.dsv.scipro.forum.notifications;
-
-import com.google.inject.AbstractModule;
-
-public class ForumNotificationsModule extends AbstractModule {
-    @Override
-    public void configure() {
-        bind(ForumNotificationRepository.class).to(ForumNotificationRepositoryImpl.class);
-        bind(ForumNotifications.class).asEagerSingleton();
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java b/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java
deleted file mode 100644
index 65a3f3ae8f..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/gdpr/GDPRModule.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package se.su.dsv.scipro.gdpr;
-
-import com.google.inject.PrivateModule;
-
-public class GDPRModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        bind(Reporter.class).to(ZipReporter.class);
-
-        expose(Reporter.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java
index b7f7bc0b0b..511fd841b4 100755
--- a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettings.java
@@ -14,81 +14,86 @@ public class GeneralSystemSettings extends DomainObject {
     @Id
     private Long id = null;
 
-    @Basic
+    @Column(name = "daisy_profile_link_base_url")
     private String daisyProfileLinkBaseURL;
 
-    @Basic
+    @Column(name = "daisy_select_research_area_url")
     private String daisySelectResearchAreaURL;
 
     @ElementCollection
-    @CollectionTable(name = "general_system_settings_alarm_recipients")
+    @CollectionTable(name = "general_system_settings_alarm_recipient",
+            joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id"))
     @Column(name = "mail")
     private List<String> alarmMails = new ArrayList<>();
 
     @ElementCollection
-    @CollectionTable(name = "general_system_settings_supervisor_change_recipients")
+    @CollectionTable(name = "general_system_settings_supervisor_change_recipient",
+            joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id"))
     @Column(name = "mail")
     private List<String> supervisorChangeMails = new ArrayList<>();
 
-    @Basic(optional = true)
+    @Column(name = "project_partner_days_to_live", nullable = true)
     private int projectPartnerDaysToLive;
 
-    @Basic(optional = false)
+    @Column(name = "mail_notifications", nullable = false)
     private boolean mailNotifications = true;
 
-    @Basic(optional = false)
+    @Column(name = "mail_from_name", nullable = false)
     private String mailFromName = "SciPro";
 
-    @Basic(optional = false)
+    @Column(name = "system_from_mail", nullable = false)
     private String systemFromMail = "noreply-scipro@dsv.su.se";
 
-    @Basic(optional = false)
+    @Column(name = "smtp_server", nullable = false)
     private String smtpServer = "localhost";
 
+    @Column(name = "peer_display_latest_reviews")
     private boolean peerDisplayLatestReviews = true;
 
-    @Basic(optional = false)
+    @Column(name = "number_of_latest_reviews_displayed", nullable = false)
     private int numberOfLatestReviewsDisplayed = DEFAULT_NUMER_OF_LATEST_REVIEWS_DISPLAYED;
 
-    @Basic(optional = false)
+    @Column(name = "public_reviews_activated", nullable = false)
     private boolean publicReviewsActivated = true;
 
-    @Basic(optional = false)
+    @Column(name = "peer_download_enabled", nullable = false)
     private boolean peerDownloadEnabled = true;
 
-    @Basic(optional = false)
+    @Column(name = "scipro_url", nullable = false)
     private String sciproURL = "http://localhost:8080/";
 
-    @Basic(optional = false)
+    @Column(name = "show_single_sign_on", nullable = false)
     private boolean showSingleSignOn = true;
 
     @ElementCollection
     @Enumerated(EnumType.STRING)
-    @JoinTable(name = "general_system_settings_system_modules")
+    @CollectionTable(name = "general_system_settings_system_module",
+            joinColumns = @JoinColumn(name = "general_system_settings_id", referencedColumnName = "id"))
+    @Column(name = "system_module")
     private Set<SystemModule> systemModules = EnumSet.allOf(SystemModule.class);
 
-    @Basic(optional = true)
+    @Column(name = "match_responsible_mail", nullable = true)
     private String matchResponsibleMail = "";
 
-    @Basic(optional = true)
+    @Column(name = "reviewer_support_mail", nullable = true)
     private String reviewerSupportMail;
 
-    @Basic(optional = true)
+    @Column(name = "thesis_support_mail", nullable = true)
     private String thesisSupportMail;
 
-    @Basic(optional = true)
+    @Column(name = "external_room_booking_url", nullable = true)
     private String externalRoomBookingURL;
 
-    @Basic(optional = true)
+    @Column(name = "external_getting_started_with_idea_url", nullable = true)
     private String externalGettingStartedWithIdeaURL;
 
-    @Basic(optional = true)
+    @Column(name = "external_grading_url", nullable = true)
     private String externalGradingURL;
 
-    @Basic(optional = false)
+    @Column(name = "final_survey_available", nullable = false)
     private boolean finalSurveyAvailable = false;
 
-    @Basic
+    @Column(name = "active_project_idea_support_mail")
     private String activeProjectIdeaSupportMail;
 
     public GeneralSystemSettings() {
diff --git a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java
index 1550844b4e..5450f5b837 100755
--- a/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/generalsystemsettings/GeneralSystemSettingsServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.generalsystemsettings;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractServiceImpl;
 
 import jakarta.inject.Inject;
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java
index dfe7e5b08b..88160eb8a9 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/ApprovedEvent.java
@@ -16,20 +16,31 @@ import java.time.Instant;
 import java.util.Objects;
 
 @Entity
-@Table(name = "grading_history_approvals")
+@Table(name = "grading_history_approval")
 public class ApprovedEvent {
+
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    @JoinColumn(name = "project_id")
-    private Project project;
-
     @Temporal(TemporalType.TIMESTAMP)
     @Column(name = "`when`")
     private Instant when;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_history_rejections) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "project_id")
+    private Project project;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -38,14 +49,6 @@ public class ApprovedEvent {
         this.id = id;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
     public Instant getWhen() {
         return when;
     }
@@ -54,6 +57,17 @@ public class ApprovedEvent {
         this.when = when;
     }
 
+    public Project getProject() {
+        return project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -70,10 +84,7 @@ public class ApprovedEvent {
 
     @Override
     public String toString() {
-        return "ApprovedEvent{" +
-                "id=" + id +
-                ", project=" + project +
-                ", when=" + when +
-                '}';
+        return "ApprovedEvent{" + "id=" + id + ", project=" + project +
+                ", when=" + when + '}';
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java
index 68b25d1cd0..de3f36ac13 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/GradingHistoryEventRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.grading;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.EntityManager;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.AbstractRepository;
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java b/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java
deleted file mode 100644
index e67d559b77..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/grading/GradingModule.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package se.su.dsv.scipro.grading;
-
-import com.google.inject.Key;
-import com.google.inject.PrivateModule;
-import com.google.inject.name.Names;
-import se.su.dsv.scipro.report.GradingReportServiceImpl;
-
-public class GradingModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        requireBinding(Key.get(String.class, Names.named("service.grading.url")));
-        bind(GradingService.class).to(GradingServiceImpl.class);
-
-        expose(GradingService.class);
-
-        bind(PublicationMetadataRepository.class).to(PublicationMetadataRepositoryImpl.class);
-        bind(PublicationMetadataService.class).to(PublicationMetadataServiceImpl.class);
-        expose(PublicationMetadataService.class);
-
-        bind(ExaminerTimelineService.class).to(GradingHistory.class);
-        expose(ExaminerTimelineService.class);
-        bind(GradingHistoryEventRepository.class).to(GradingHistoryEventRepositoryImpl.class);
-        bind(ThesisRejectionHistoryService.class).to(GradingHistory.class);
-        expose(ThesisRejectionHistoryService.class);
-        bind(ThesisApprovedHistoryService.class).to(GradingHistory.class);
-        expose(ThesisApprovedHistoryService.class);
-        bind(ThesisSubmissionHistoryService.class).to(GradingHistory.class);
-        expose(ThesisSubmissionHistoryService.class);
-
-        bind(NationalSubjectCategoryRepository.class).to(NationalSubjectCategoryRepositoryImpl.class);
-        bind(NationalSubjectCategoryService.class).to(NationalSubjectCategoryServiceImpl.class);
-        expose(NationalSubjectCategoryService.class);
-
-        bind(GradingReportTemplateService.class).to(GradingReportServiceImpl.class);
-        expose(GradingReportTemplateService.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java
index 26323389d8..c2ec2aa67e 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategory.java
@@ -12,21 +12,20 @@ import java.util.Objects;
 @Entity
 @Table(name = "national_subject_category")
 public class NationalSubjectCategory {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY)
     @Column(name = "id")
     private Long id;
 
     @Basic
-    @Column(name = "external_id")
-    private Integer externalId;
-
-    @Basic
-    @Column(name = "swedish_name")
+    @Column(name = "name_sv")
     private String swedishName;
 
     @Basic
-    @Column(name = "english_name")
+    @Column(name = "name_en")
     private String englishName;
 
     @Basic
@@ -37,9 +36,19 @@ public class NationalSubjectCategory {
     @Column(name = "preselected")
     private boolean preselected;
 
+    @Basic
+    @Column(name = "external_id")
+    private Integer externalId;
+
+    // ----------------------------------------------------------------------------------
+    // Constructor
+    // ----------------------------------------------------------------------------------
     public NationalSubjectCategory() {
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -48,14 +57,6 @@ public class NationalSubjectCategory {
         this.id = id;
     }
 
-    public Integer getExternalId() {
-        return externalId;
-    }
-
-    public void setExternalId(Integer externalId) {
-        this.externalId = externalId;
-    }
-
     public String getSwedishName() {
         return swedishName;
     }
@@ -88,6 +89,17 @@ public class NationalSubjectCategory {
         this.preselected = preselected;
     }
 
+    public Integer getExternalId() {
+        return externalId;
+    }
+
+    public void setExternalId(Integer externalId) {
+        this.externalId = externalId;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(Object o) {
         if (this == o) {
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java
index 2a6d009a47..90c2723739 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/NationalSubjectCategoryRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.grading;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.EntityManager;
 import se.su.dsv.scipro.system.AbstractRepository;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java
index 87b0a82f6c..2fe7236e6c 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadata.java
@@ -17,34 +17,44 @@ import java.util.Objects;
 @Entity
 @Table(name = "publication_metadata")
 public class PublicationMetadata {
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToOne(optional = false)
-    private Project project;
-
     @Basic
-    @Column(name = "abstract_swedish")
+    @Column(name = "abstract_sv")
     private String abstractSwedish;
 
     @Basic
-    @Column(name = "abstract_english")
+    @Column(name = "abstract_en")
     private String abstractEnglish;
 
     @Basic
-    @Column(name = "keywords_swedish")
+    @Column(name = "keywords_sv")
     private String keywordsSwedish;
 
     @Basic
-    @Column(name = "keywords_english")
+    @Column(name = "keywords_en")
     private String keywordsEnglish;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (publication_metadata) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
     @JoinColumn(name = "national_subject_category_id")
     private NationalSubjectCategory nationalSubjectCategory;;
 
+    @OneToOne(optional = false)
+    @JoinColumn(name = "project_id")
+    private Project project;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -53,14 +63,6 @@ public class PublicationMetadata {
         this.id = id;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
     public String getAbstractSwedish() {
         return abstractSwedish;
     }
@@ -101,19 +103,17 @@ public class PublicationMetadata {
         this.nationalSubjectCategory = nationalSubjectCategory;
     }
 
-    @Override
-    public String toString() {
-        return "PublicationMetadata{" +
-                "id=" + id +
-                ", project=" + project +
-                ", abstractSwedish='" + abstractSwedish + '\'' +
-                ", abstractEnglish='" + abstractEnglish + '\'' +
-                ", keywordsSwedish='" + keywordsSwedish + '\'' +
-                ", keywordsEnglish='" + keywordsEnglish + '\'' +
-                ", nationalSubjectCategory=" + nationalSubjectCategory + '\'' +
-                '}';
+    public Project getProject() {
+        return project;
     }
 
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(Object o) {
         return o instanceof PublicationMetadata that &&
@@ -124,4 +124,15 @@ public class PublicationMetadata {
     public int hashCode() {
         return Objects.hashCode(id);
     }
+
+    @Override
+    public String toString() {
+        return "PublicationMetadata{" + "id=" + id + ", project=" + project +
+                ", abstractSwedish='" + abstractSwedish + '\'' +
+                ", abstractEnglish='" + abstractEnglish + '\'' +
+                ", keywordsSwedish='" + keywordsSwedish + '\'' +
+                ", keywordsEnglish='" + keywordsEnglish + '\'' +
+                ", nationalSubjectCategory=" + nationalSubjectCategory + '\'' +
+                '}';
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java
index 05702c1d93..10c37dab9e 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepository.java
@@ -2,7 +2,7 @@ package se.su.dsv.scipro.grading;
 
 import se.su.dsv.scipro.project.Project;
 
-interface PublicationMetadataRepository {
+public interface PublicationMetadataRepository {
     void save(PublicationMetadata publicationMetadata);
 
     PublicationMetadata findByProject(Project project);
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java
index f1b2ac5a38..503b62f6ec 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.grading;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.EntityManager;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.AbstractRepository;
@@ -8,9 +8,9 @@ import se.su.dsv.scipro.system.AbstractRepository;
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 
-class PublicationMetadataRepositoryImpl extends AbstractRepository implements PublicationMetadataRepository {
+public class PublicationMetadataRepositoryImpl extends AbstractRepository implements PublicationMetadataRepository {
     @Inject
-    PublicationMetadataRepositoryImpl(Provider<EntityManager> em) {
+    public PublicationMetadataRepositoryImpl(Provider<EntityManager> em) {
         super(em);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java
index 26f0e1801b..684e24ae7b 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/PublicationMetadataServiceImpl.java
@@ -6,11 +6,11 @@ import se.su.dsv.scipro.system.Language;
 import jakarta.inject.Inject;
 import java.util.Objects;
 
-class PublicationMetadataServiceImpl implements PublicationMetadataService {
+public class PublicationMetadataServiceImpl implements PublicationMetadataService {
     private final PublicationMetadataRepository publicationMetadataRepository;
 
     @Inject
-    PublicationMetadataServiceImpl(PublicationMetadataRepository publicationMetadataRepository) {
+    public PublicationMetadataServiceImpl(PublicationMetadataRepository publicationMetadataRepository) {
         this.publicationMetadataRepository = publicationMetadataRepository;
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java
index 745eaf14a8..d7a24907e3 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/RejectionEvent.java
@@ -17,23 +17,35 @@ import java.time.Instant;
 import java.util.Objects;
 
 @Entity
-@Table(name = "grading_history_rejections")
+@Table(name = "grading_history_rejection")
 public class RejectionEvent {
+
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    @JoinColumn(name = "project_id")
-    private Project project;
+    @Basic
+    @Column(name = "reason")
+    private String reason;
 
     @Temporal(TemporalType.TIMESTAMP)
     @Column(name = "`when`")
     private Instant when;
 
-    @Basic
-    private String reason;
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_history_rejections) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "project_id")
+    private Project project;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -42,22 +54,6 @@ public class RejectionEvent {
         this.id = id;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public Instant getWhen() {
-        return when;
-    }
-
-    public void setWhen(Instant when) {
-        this.when = when;
-    }
-
     public String getReason() {
         return reason;
     }
@@ -66,6 +62,25 @@ public class RejectionEvent {
         this.reason = reason;
     }
 
+    public Instant getWhen() {
+        return when;
+    }
+
+    public void setWhen(Instant when) {
+        this.when = when;
+    }
+
+    public Project getProject() {
+        return project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java b/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java
index 664c1e6bcf..fd88070c36 100644
--- a/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/grading/SubmissionEvent.java
@@ -18,27 +18,38 @@ import java.time.Instant;
 import java.util.Objects;
 
 @Entity
-@Table(name = "grading_history_submissions")
+@Table(name = "grading_history_submission")
 public class SubmissionEvent {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    @JoinColumn(name = "project_id")
-    private Project project;
-
-    @ManyToOne
-    @JoinColumn(name = "author_id")
-    private User author;
-
     @Temporal(TemporalType.TIMESTAMP)
     @Column(name = "`when`")
     private Instant when;
 
     @Basic
+    @Column(name = "corrections")
     private String corrections;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_history_submission) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
+    @ManyToOne
+    @JoinColumn(name = "author_user_id", referencedColumnName = "id")
+    private User author;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -47,22 +58,6 @@ public class SubmissionEvent {
         this.id = id;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public User getAuthor() {
-        return author;
-    }
-
-    public void setAuthor(User user) {
-        this.author = user;
-    }
-
     public Instant getWhen() {
         return when;
     }
@@ -79,6 +74,25 @@ public class SubmissionEvent {
         this.corrections = corrections;
     }
 
+    public Project getProject() {
+        return project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public User getAuthor() {
+        return author;
+    }
+
+    public void setAuthor(User user) {
+        this.author = user;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -97,11 +111,8 @@ public class SubmissionEvent {
 
     @Override
     public String toString() {
-        return "RejectionEvent{" +
-                "id=" + id +
-                ", project=" + project +
-                ", author=" + author +
-                ", when=" + when +
+        return "RejectionEvent{" + "id=" + id + ", project=" + project +
+                ", author=" + author + ", when=" + when +
                 ", corrections='" + corrections + '\'' +
                 '}';
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/group/Group.java b/core/src/main/java/se/su/dsv/scipro/group/Group.java
index c85082e740..11aecf59e8 100644
--- a/core/src/main/java/se/su/dsv/scipro/group/Group.java
+++ b/core/src/main/java/se/su/dsv/scipro/group/Group.java
@@ -18,30 +18,124 @@ public class Group extends DomainObject {
 
     public static final int STRING_MAX_LENGTH = 255;
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Column(length = STRING_MAX_LENGTH)
     @Basic(optional = false)
+    @Column(name = "title", length = STRING_MAX_LENGTH)
     private String title;
 
     @Basic(optional = true)
+    @Column(name = "description")
     private String description;
 
+    @Basic
+    @Column(name = "active")
+    private boolean active = true;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_group) referencing other tables.
+    // ----------------------------------------------------------------------------------
     //Creator, should be a supervisor
     @ManyToOne(optional = false)
-    @JoinColumn(name = "user_id")
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
     private User user;
 
+    // ----------------------------------------------------------------------------------
+    // @ManyToMany JPA-mappings
+    // ----------------------------------------------------------------------------------
     @ManyToMany
-    @JoinTable(
-            name = "project_group_project",
-            joinColumns =  @JoinColumn(name = "project_group_id"),
-            inverseJoinColumns = @JoinColumn(name = "project_id"))
+    @JoinTable(name = "project_group_project",
+            joinColumns =  @JoinColumn(name = "project_group_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"))
     private Set<Project> projects = new HashSet<>();
 
-    private boolean active = true;
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public boolean isActive() {
+        return this.active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    public User getUser() {
+        return this.user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public Set<Project> getProjects() {
+        return projects;
+    }
+
+    public void setProjects(Set<Project> projects) {
+        this.projects = projects;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof Group)) return false;
+        final Group other = (Group) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
+    }
+
+    @Override
+    public String toString() {
+        return "Group(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" +
+                this.getDescription() + ", user=" + this.getUser() + ", projects=" +
+                this.getProjects() + ", active=" + this.isActive() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof Group;
+    }
 
     public boolean isAuthor(final User user) {
         for (Project project : projects) {
@@ -58,76 +152,4 @@ public class Group extends DomainObject {
                 .filter(member -> member.getType() != Member.Type.REVIEWER)
                 .toList();
     }
-
-    public Set<Project> getProjects() {
-        return projects;
-    }
-
-    public String getTitle() {
-        return title;
-    }
-
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public User getUser() {
-        return this.user;
-    }
-
-    public boolean isActive() {
-        return this.active;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    public void setUser(User user) {
-        this.user = user;
-    }
-
-    public void setProjects(Set<Project> projects) {
-        this.projects = projects;
-    }
-
-    public void setActive(boolean active) {
-        this.active = active;
-    }
-
-    @Override
-    public String toString() {
-        return "Group(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", user=" + this.getUser() + ", projects=" + this.getProjects() + ", active=" + this.isActive() + ")";
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof Group)) return false;
-        final Group other = (Group) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof Group;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getId());
-    }
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java
index f5bd35bd82..7a34082b32 100644
--- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java
+++ b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminar.java
@@ -1,30 +1,49 @@
 package se.su.dsv.scipro.integration.activityfinalseminar;
 
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.Column;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapsId;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.activityplan.Activity;
 import se.su.dsv.scipro.finalseminar.FinalSeminar;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
 @Table(name = "activity_final_seminar")
 class ActivityFinalSeminar {
+    // ----------------------------------------------------------------------------------
+    // embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @EmbeddedId
     @AttributeOverride(name = "activityId", column = @Column(name = "activity_id"))
     @AttributeOverride(name = "finalSeminarId", column = @Column(name = "final_seminar_id"))
     private Id id = new Id();
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (activity_final_seminiar) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
     @MapsId("activityId")
-    @JoinColumn(name = "activity_id")
+    @JoinColumn(name = "activity_id", referencedColumnName = "id")
     private Activity activity;
 
     @ManyToOne
     @MapsId("finalSeminarId")
-    @JoinColumn(name = "final_seminar_id")
+    @JoinColumn(name = "final_seminar_id", referencedColumnName = "id")
     private FinalSeminar finalSeminar;
 
+    // ----------------------------------------------------------------------------------
+    // constructor
+    // ----------------------------------------------------------------------------------
     protected ActivityFinalSeminar() {
         // JPA
     }
@@ -34,6 +53,9 @@ class ActivityFinalSeminar {
         this.finalSeminar = finalSeminar;
     }
 
+    // ----------------------------------------------------------------------------------
+    // getters
+    // ----------------------------------------------------------------------------------
     public Id getId() {
         return this.id;
     }
@@ -46,6 +68,9 @@ class ActivityFinalSeminar {
         return this.finalSeminar;
     }
 
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -57,10 +82,6 @@ class ActivityFinalSeminar {
                 && Objects.equals(this.getFinalSeminar(), other.getFinalSeminar());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ActivityFinalSeminar;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getActivity(), this.getFinalSeminar());
@@ -71,6 +92,13 @@ class ActivityFinalSeminar {
         return "ActivityFinalSeminar(id=" + this.getId() + ", activity=" + this.getActivity() + ", finalSeminar=" + this.getFinalSeminar() + ")";
     }
 
+    protected boolean canEqual(final Object other) {
+        return other instanceof ActivityFinalSeminar;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // nested class
+    // ----------------------------------------------------------------------------------
     @Embeddable
     static class Id implements Serializable {
         private Long activityId;
diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java
deleted file mode 100644
index 0d5d8bf9a4..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarModule.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package se.su.dsv.scipro.integration.activityfinalseminar;
-
-import com.google.inject.AbstractModule;
-
-public class ActivityFinalSeminarModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(FinalSeminarActivityHandler.class).asEagerSingleton();
-        bind(ActivityFinalSeminarRepository.class).to(ActivityFinalSeminarRepositoryImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java
index 87191121e6..6f1af4098c 100644
--- a/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/integration/activityfinalseminar/ActivityFinalSeminarRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.integration.activityfinalseminar;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.finalseminar.FinalSeminar;
diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java
deleted file mode 100644
index c14a655f13..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityForumModule.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package se.su.dsv.scipro.integration.activityforum;
-
-import com.google.inject.AbstractModule;
-
-public class ActivityForumModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(PostActivityUploadToForum.class).asEagerSingleton();
-        bind(ActivityThreadRepository.class).to(ActivityThreadRepositoryImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java
index 89d7f0ee43..a890466fc5 100644
--- a/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/integration/activityforum/ActivityThread.java
@@ -1,27 +1,44 @@
 package se.su.dsv.scipro.integration.activityforum;
 
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapsId;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.activityplan.Activity;
 import se.su.dsv.scipro.forum.dataobjects.ProjectThread;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
 @Table(name = "activity_thread")
 class ActivityThread {
+    // ----------------------------------------------------------------------------------
+    // basic and embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @EmbeddedId
     private Id id = new Id();
 
-    @ManyToOne
-    @MapsId("threadId")
-    @JoinColumn(name = "project_thread_id")
-    private ProjectThread thread;
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (activity_thread) referencing other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
     @MapsId("activityId")
+    @JoinColumn(name = "activity_id", referencedColumnName = "id")
     private Activity activity;
 
+    @ManyToOne
+    @MapsId("threadId")
+    @JoinColumn(name = "project_thread_id", referencedColumnName = "id")
+    private ProjectThread thread;
+
+    // ----------------------------------------------------------------------------------
+    // constructor
+    // ----------------------------------------------------------------------------------
     protected ActivityThread() {
         // JPA
     }
@@ -31,6 +48,9 @@ class ActivityThread {
         this.activity = activity;
     }
 
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
     public Id getId() {
         return this.id;
     }
@@ -43,6 +63,9 @@ class ActivityThread {
         return this.activity;
     }
 
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -54,10 +77,6 @@ class ActivityThread {
                 && Objects.equals(this.getActivity(), other.getActivity());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ActivityThread;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getThread(), this.getActivity());
@@ -68,6 +87,13 @@ class ActivityThread {
         return "ActivityThread(id=" + this.getId() + ", thread=" + this.getThread() + ", activity=" + this.getActivity() + ")";
     }
 
+    protected boolean canEqual(final Object other) {
+        return other instanceof ActivityThread;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // nested class
+    // ----------------------------------------------------------------------------------
     @Embeddable
     static class Id implements Serializable {
         private Long threadId;
diff --git a/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java b/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java
index 200d362663..a8b99efd4d 100755
--- a/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/mail/MailEvent.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.mail;
 
+import jakarta.persistence.CollectionTable;
 import jakarta.persistence.GenerationType;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.system.DomainObject;
@@ -19,61 +20,80 @@ import jakarta.persistence.Lob;
 import jakarta.persistence.ManyToMany;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.Table;
-import java.util.*;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
 
 @Entity
 @Table(name = "mail_event")
 @Cacheable(false)
 public class MailEvent extends DomainObject {
     public static final int STRING_MAX_LENGTH = 255;
+
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @JoinTable(
-            name = "mail_event_recipients",
-            joinColumns = @JoinColumn(name = "mail_event_id"),
-            inverseJoinColumns = @JoinColumn(name = "recipients_id"))
-    @ManyToMany(fetch = FetchType.EAGER)
-    private Set<User> recipients = new HashSet<>();
-
-    @ElementCollection
-    private Set<String> nonUserRecipients = new HashSet<>();
-
-    @Column(length = STRING_MAX_LENGTH)
     @Basic(optional = false)
+    @Column(name = "subject", length = STRING_MAX_LENGTH)
     private String subject;
 
-    @Column(length = STRING_MAX_LENGTH)
     @Basic(optional = true)
+    @Column(name = "from_name", length = STRING_MAX_LENGTH)
     private String fromName;
 
-    @Column(length = STRING_MAX_LENGTH)
     @Basic(optional = true)
+    @Column(name = "from_email", length = STRING_MAX_LENGTH)
     private String fromEmail;
 
-    @Lob
     @Basic(optional = false)
+    @Column(name = "message_body")
+    @Lob
     private String messageBody;
 
     @Basic(optional = false)
+    @Column(name = "sent")
     private boolean sent = false;
 
     @Basic(optional = true)
+    @Column(name = "message_id")
     private String messageID;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (mail_event) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = true)
-    @JoinColumn(name = "attachment_reference_id")
+    @JoinColumn(name = "attachment_file_reference_id", referencedColumnName = "id")
     private FileReference attachment;
 
+    // ----------------------------------------------------------------------------------
+    // @ManyToMany JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @ManyToMany(fetch = FetchType.EAGER)
+    @JoinTable(name = "mail_event_recipient",
+            joinColumns = @JoinColumn(name = "mail_event_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "recipient_id", referencedColumnName = "id"))
+    private Set<User> recipients = new HashSet<>();
+
+    @ElementCollection
+    @CollectionTable(name = "mail_event_non_user_recipient",
+            joinColumns = @JoinColumn(name = "mail_event_id", referencedColumnName = "id"))
+    @Column(name = "non_user_recipient")
+    private Set<String> nonUserRecipients = new HashSet<>();
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public MailEvent() {
     }
 
-    public MailEvent(
-            final String subject,
-            final String messageBody,
-            final User recipient,
-            final String fromName,
+    public MailEvent(final String subject, final String messageBody, final User recipient, final String fromName,
             final String fromEmail) {
         this.subject = subject;
         this.messageBody = messageBody;
@@ -82,13 +102,8 @@ public class MailEvent extends DomainObject {
         this.fromEmail = fromEmail;
     }
 
-    public MailEvent(
-            final String subject,
-            final String messageBody,
-            final Collection<User> recipients,
-            final String fromName,
-            final String fromEmail
-    ) {
+    public MailEvent(final String subject, final String messageBody, final Collection<User> recipients,
+                     final String fromName, final String fromEmail) {
         this.subject = subject;
         this.messageBody = messageBody;
         this.recipients.addAll(recipients);
@@ -96,35 +111,124 @@ public class MailEvent extends DomainObject {
         this.fromEmail = fromEmail;
     }
 
-    public boolean isSent() {
-        return sent;
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
     }
 
-    public void markSent(final String messageID) {
-        this.messageID = messageID;
-        this.sent = true;
+    public void setId(Long id) {
+        this.id = id;
     }
 
-    public Set<User> getRecipients() {
-        return recipients;
-    }
-
-    public void setMessageBody(String messageBody) {
-        this.messageBody = messageBody;
+    public String getSubject() {
+        return this.subject;
     }
 
     public void setSubject(String subject) {
         this.subject = subject;
     }
 
+    public String getFromName() {
+        return this.fromName;
+    }
+
     public void setFromName(String fromName) {
         this.fromName = fromName;
     }
 
+    public String getFromEmail() {
+        return this.fromEmail;
+    }
+
     public void setFromEmail(String fromEmail) {
         this.fromEmail = fromEmail;
     }
 
+    public String getMessageBody() {
+        return this.messageBody;
+    }
+
+    public void setMessageBody(String messageBody) {
+        this.messageBody = messageBody;
+    }
+
+    public boolean isSent() {
+        return sent;
+    }
+
+    public void setSent(boolean sent) {
+        this.sent = sent;
+    }
+
+    public String getMessageID() {
+        return this.messageID;
+    }
+
+    public void setMessageID(String messageID) {
+        this.messageID = messageID;
+    }
+
+    public FileReference getAttachment() {
+        return this.attachment;
+    }
+
+    public void setAttachment(FileReference attachment) {
+        this.attachment = attachment;
+    }
+
+    public Set<User> getRecipients() {
+        return recipients;
+    }
+
+    public void setRecipients(Set<User> recipients) {
+        this.recipients = recipients;
+    }
+
+    public Set<String> getNonUserRecipients() {
+        return this.nonUserRecipients;
+    }
+
+    public void setNonUserRecipients(Set<String> nonUserRecipients) {
+        this.nonUserRecipients = nonUserRecipients;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof MailEvent)) return false;
+        final MailEvent other = (MailEvent) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
+    }
+
+    @Override
+    public String toString() {
+        return "MailEvent(id=" + this.getId() + ", recipients=" + this.getRecipients() +
+                ", nonUserRecipients=" + this.getNonUserRecipients() + ", subject=" +
+                this.getSubject() + ", fromName=" + this.getFromName() +
+                ", fromEmail=" + this.getFromEmail() + ", messageBody=" + this.getMessageBody() +
+                ", sent=" + this.isSent() + ", messageID=" + this.getMessageID() +
+                ", attachment=" + this.getAttachment() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof MailEvent;
+    }
+
     public void addRecipients(final Iterable<Recipient> recipients) {
         for (Recipient recipient : recipients) {
             recipient.accept(new RecipientVisitor<Boolean>() {
@@ -141,83 +245,8 @@ public class MailEvent extends DomainObject {
         }
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public Set<String> getNonUserRecipients() {
-        return this.nonUserRecipients;
-    }
-
-    public String getSubject() {
-        return this.subject;
-    }
-
-    public String getFromName() {
-        return this.fromName;
-    }
-
-    public String getFromEmail() {
-        return this.fromEmail;
-    }
-
-    public String getMessageBody() {
-        return this.messageBody;
-    }
-
-    public String getMessageID() {
-        return this.messageID;
-    }
-
-    public FileReference getAttachment() {
-        return this.attachment;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setRecipients(Set<User> recipients) {
-        this.recipients = recipients;
-    }
-
-    public void setNonUserRecipients(Set<String> nonUserRecipients) {
-        this.nonUserRecipients = nonUserRecipients;
-    }
-
-    public void setSent(boolean sent) {
-        this.sent = sent;
-    }
-
-    public void setMessageID(String messageID) {
+    public void markSent(final String messageID) {
         this.messageID = messageID;
-    }
-
-    public void setAttachment(FileReference attachment) {
-        this.attachment = attachment;
-    }
-
-    @Override
-    public String toString() {
-        return "MailEvent(id=" + this.getId() + ", recipients=" + this.getRecipients() + ", nonUserRecipients=" + this.getNonUserRecipients() + ", subject=" + this.getSubject() + ", fromName=" + this.getFromName() + ", fromEmail=" + this.getFromEmail() + ", messageBody=" + this.getMessageBody() + ", sent=" + this.isSent() + ", messageID=" + this.getMessageID() + ", attachment=" + this.getAttachment() + ")";
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof MailEvent)) return false;
-        final MailEvent other = (MailEvent) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof MailEvent;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getId());
+        this.sent = true;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java b/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java
index a5c7f597be..179bffc02c 100644
--- a/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java
+++ b/core/src/main/java/se/su/dsv/scipro/mail/PrintingMailer.java
@@ -6,7 +6,7 @@ import se.su.dsv.scipro.file.FileDescription;
 import java.util.Arrays;
 import java.util.UUID;
 
-class PrintingMailer implements Mailer {
+public class PrintingMailer implements Mailer {
     @Override
     public MailResult mail(final String fromName, final String fromEmail, final String[] recipients, final String subject, final String message, final FileDescription attachment) {
         return new MailResult() {
diff --git a/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java b/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java
index f5e0035fa5..6a91588ff1 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/AllowAllIdeaCreationJudge.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-class AllowAllIdeaCreationJudge implements IdeaCreationJudge {
+public class AllowAllIdeaCreationJudge implements IdeaCreationJudge {
     @Override
     public Decision ruling(Idea idea) {
         return Decision.allowed();
diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java
index 6955d28d2d..d3c7a21e50 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriod.java
@@ -1,17 +1,30 @@
 package se.su.dsv.scipro.match;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 
-import jakarta.persistence.*;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.*;
-
 @Entity
 @Cacheable(true)
-@Table(name="ApplicationPeriod")
+@Table(name="application_period")
 public class ApplicationPeriod extends DomainObject {
 
     @Id
@@ -23,17 +36,16 @@ public class ApplicationPeriod extends DomainObject {
 
     private String name;
 
-    @Basic
+    @Column(name = "start_date")
     private LocalDate startDate = LocalDate.now();
 
-    @Basic
+    @Column(name = "end_date")
     private LocalDate endDate = LocalDate.now();
 
-    @Basic
-    @Column(name = "courseStartDate")
+    @Column(name = "course_start_date")
     private LocalDateTime courseStartDateTime = LocalDate.now().atTime(8, 0);
 
-    @Basic
+    @Column(name = "course_end_date")
     private LocalDate courseEndDate;
 
     @OneToMany(fetch = FetchType.LAZY, mappedBy = "applicationPeriod", cascade=CascadeType.ALL, orphanRemoval=true)
diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java
index 717d71f294..82197dc73d 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodExemption.java
@@ -1,15 +1,23 @@
 package se.su.dsv.scipro.match;
 
-import se.su.dsv.scipro.system.User;
-
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.Objects;
 
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.Column;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapsId;
+import jakarta.persistence.Table;
+
+import se.su.dsv.scipro.system.User;
+
 @Entity
-@Table(name = "applicationperiodexemption")
+@Table(name = "application_period_exemption")
 public class ApplicationPeriodExemption implements Serializable {
     public enum Type {
         SUBMIT_STUDENT_IDEA(true),
@@ -39,16 +47,19 @@ public class ApplicationPeriodExemption implements Serializable {
 
     @MapsId("applicationPeriodId")
     @ManyToOne(optional = false)
-    @JoinColumn(name = "applicationPeriodId")
+    @JoinColumn(name = "application_period_id")
     private ApplicationPeriod applicationPeriod;
 
+    @Column(name = "end_date")
     private LocalDate endDate;
 
     private String comment;
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "granted_by_id")
     private User grantedBy;
 
+    @Column(name = "granted_on")
     private LocalDateTime grantedOn;
 
     public ApplicationPeriodExemptionId getApplicationperiodexemptionId() {
diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java
index 0d9a6f0b91..eac5ccfbc2 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodProjectType.java
@@ -1,5 +1,7 @@
 package se.su.dsv.scipro.match;
 
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.activityplan.ActivityPlanTemplate;
 import se.su.dsv.scipro.system.ProjectType;
 
@@ -10,19 +12,23 @@ import jakarta.persistence.MapsId;
 import java.io.Serializable;
 
 @Entity
+@Table(name = "application_period_project_type")
 public class ApplicationPeriodProjectType implements Serializable {
     @EmbeddedId
     private ApplicationPeriodProjectTypeId applicationPeriodProjectTypeId = new ApplicationPeriodProjectTypeId();
 
     @MapsId("applicationPeriodId")
     @ManyToOne
+    @JoinColumn(name = "application_period_id")
     private ApplicationPeriod applicationPeriod;
 
     @MapsId("projectTypeId")
     @ManyToOne
+    @JoinColumn(name = "project_type_id")
     private ProjectType projectType;
 
     @ManyToOne(optional = true)
+    @JoinColumn(name = "activity_plan_template_id")
     private ActivityPlanTemplate activityPlanTemplate;
 
     protected ApplicationPeriodProjectType() {}
diff --git a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java
index 0156c88bd8..29499c6f0c 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/ApplicationPeriodServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import com.querydsl.core.types.dsl.Expressions;
 import se.su.dsv.scipro.system.PageRequest;
diff --git a/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java b/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java
index 2df0e579c7..4367c24d73 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/FirstMeeting.java
@@ -1,6 +1,16 @@
 package se.su.dsv.scipro.match;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 import java.io.Serializable;
 import java.util.Date;
 import java.util.Objects;
@@ -9,72 +19,92 @@ import java.util.Objects;
 @Table(name = "idea_first_meeting")
 @Cacheable(true)
 public class FirstMeeting implements Serializable {
-    public static final int LENGTH = 1024;
+    private static final int LENGTH = 1024;
+
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Basic(optional = false)
-    private Date firstMeetingDate;
-
-    @Column(nullable = false, length = LENGTH)
-    private String room;
-
-    @Column(nullable = true, length = LENGTH)
+    @Basic
+    @Column(name = "description", nullable = true, length = LENGTH)
     private String description;
 
+    @Basic(optional = false)
+    @Column(name = "first_meeting_date")
+    private Date firstMeetingDate;
+
+    @Basic
+    @Column(name = "room", nullable = false, length = LENGTH)
+    private String room;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea_first_meeting) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @OneToOne(optional = false)
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
     private Idea idea;
 
-    public FirstMeeting() {
-
-    }
+    // ----------------------------------------------------------------------------------
+    // constructors
+    // ----------------------------------------------------------------------------------
+    public FirstMeeting() { }
 
     public FirstMeeting(Date firstMeetingDate, Idea idea) {
         this.firstMeetingDate = firstMeetingDate;
         this.idea = idea;
     }
 
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
+
     public Long getId() {
         return this.id;
     }
 
-    public Date getFirstMeetingDate() {
-        return this.firstMeetingDate;
-    }
-
-    public String getRoom() {
-        return this.room;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public Idea getIdea() {
-        return this.idea;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setFirstMeetingDate(Date firstMeetingDate) {
-        this.firstMeetingDate = firstMeetingDate;
-    }
-
-    public void setRoom(String room) {
-        this.room = room;
+    public String getDescription() {
+        return this.description;
     }
 
     public void setDescription(String description) {
         this.description = description;
     }
 
+    public Date getFirstMeetingDate() {
+        return this.firstMeetingDate;
+    }
+
+    public void setFirstMeetingDate(Date firstMeetingDate) {
+        this.firstMeetingDate = firstMeetingDate;
+    }
+
+    public String getRoom() {
+        return this.room;
+    }
+
+    public void setRoom(String room) {
+        this.room = room;
+    }
+
+    public Idea getIdea() {
+        return this.idea;
+    }
+
     public void setIdea(Idea idea) {
         this.idea = idea;
     }
 
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -94,11 +124,13 @@ public class FirstMeeting implements Serializable {
 
     @Override
     public int hashCode() {
-        return Objects.hash(this.getId(), this.getFirstMeetingDate(), this.getRoom(), this.getDescription(), this.getIdea());
+        return Objects.hash(this.getId(), this.getFirstMeetingDate(), this.getRoom(), this.getDescription(),
+                this.getIdea());
     }
 
     @Override
     public String toString() {
-        return "FirstMeeting(id=" + this.getId() + ", firstMeetingDate=" + this.getFirstMeetingDate() + ", room=" + this.getRoom() + ", description=" + this.getDescription() + ", idea=" + this.getIdea() + ")";
+        return "FirstMeeting(id=" + this.getId() + ", firstMeetingDate=" + this.getFirstMeetingDate() + ", room=" +
+                this.getRoom() + ", description=" + this.getDescription() + ", idea=" + this.getIdea() + ")";
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java b/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java
index 7714a267a9..caa4bab050 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/FirstMeetingRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/match/Idea.java b/core/src/main/java/se/su/dsv/scipro/match/Idea.java
index 15b457b17b..e2772b539b 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/Idea.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/Idea.java
@@ -1,103 +1,190 @@
 package se.su.dsv.scipro.match;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.AttributeOverrides;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.OrderBy;
+import jakarta.persistence.PostLoad;
+import jakarta.persistence.PostPersist;
+import jakarta.persistence.PostUpdate;
+import jakarta.persistence.PrePersist;
+import jakarta.persistence.PreUpdate;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.project.Project;
-import se.su.dsv.scipro.system.*;
+import se.su.dsv.scipro.system.DomainObject;
+import se.su.dsv.scipro.system.Language;
+import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.ResearchArea;
+import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.time.LocalDate;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 @Entity
 @Table(name = "idea")
 @Cacheable(true)
 public class Idea extends DomainObject {
+    private static final int DESCRIPTION_LENGTH = 4000;
+    private static final int PREREQUISITES_LENGTH = 4000;
+    private static final int TITLE_LENGTH = 1024;
 
-    public static final int DESCRIPTION_LENGTH = 4000;
-    public static final int PREREQUISITES_LENGTH = 4000;
-    public static final int TITLE_LENGTH = 1024;
+    // ----------------------------------------------------------------------------------
+    // basic and embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne(optional = false)
-    private ProjectType projectType;
-
-    @Enumerated(EnumType.STRING)
-    private Type type;
-
-    @ManyToOne(optional = false)
-    private User creator;
-
+    @Basic
     @Column(nullable = true, length = DESCRIPTION_LENGTH)
     private String description;
 
+    @Basic
     @Column(nullable = true, length = PREREQUISITES_LENGTH)
     private String prerequisites;
 
-    @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL, orphanRemoval = true)
-    @QueryInit({"user", "program"})
-    private Set<IdeaParticipation> ideaParticipations = new HashSet<>();
-
-    @ManyToOne(optional = true)
-    private ApplicationPeriod applicationPeriod;
-
+    @Basic
     @Column(nullable = false, length = TITLE_LENGTH)
     private String title;
 
-    @ManyToOne(optional = true)
-    private ResearchArea researchArea;
-
-    @ElementCollection
-    @CollectionTable(name = "idea_language")
-    @Column(name = "language")
+    @Basic
     @Enumerated(EnumType.STRING)
-    private Set<Language> languages = EnumSet.noneOf(Language.class);
+    private Type type;
+
+    @Basic
+    @Column(name = "published")
+    private boolean published = true;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "cached_status")
+    private Status cachedStatus;
+
+    @Basic
+    @Column(name = "inactive")
+    private boolean inactive = false;
 
     @Embedded
     @AttributeOverrides({
-            @AttributeOverride(name = "practicalHow", column = @Column(insertable = false, updatable = false)),
-            @AttributeOverride(name = "literature", column = @Column(insertable = false, updatable = false)),
-            @AttributeOverride(name = "theoryHow", column = @Column(insertable = false, updatable = false)),
-            @AttributeOverride(name = "why", column = @Column(insertable = false, updatable = false)),
-            @AttributeOverride(name = "what", column = @Column(insertable = false, updatable = false))
+            @AttributeOverride(name = "practicalHow", column = @Column(name = "practical_how", insertable = false, updatable = false)),
+            @AttributeOverride(name = "theoryHow", column = @Column(name = "theory_how", insertable = false, updatable = false)),
+            @AttributeOverride(name = "what", column = @Column(name = "what", insertable = false, updatable = false)),
+            @AttributeOverride(name = "why", column = @Column(name = "why", insertable = false, updatable = false)),
+            @AttributeOverride(name = "literature", column = @Column(name  = "literature", insertable = false, updatable = false))
     })
     private Watson watson;
 
     @Embedded
+    @AttributeOverrides({
+            @AttributeOverride(name = "literature", column = @Column(name  = "literature", insertable = false, updatable = false)),
+            @AttributeOverride(name = "background", column = @Column(name  = "background", insertable = false, updatable = false)),
+            @AttributeOverride(name = "problem", column = @Column(name  = "problem", insertable = false, updatable = false)),
+            @AttributeOverride(name = "method", column = @Column(name  = "method", insertable = false, updatable = false)),
+            @AttributeOverride(name = "interests", column = @Column(name  = "interests", insertable = false, updatable = false))
+    })
     private TholanderBox tholanderBox = new TholanderBox();
 
-    @ManyToMany
-    private Set<Keyword> keywords = new HashSet<>();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "application_period_id", referencedColumnName = "id")
+    private ApplicationPeriod applicationPeriod;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "creator_user_id", referencedColumnName = "id")
+    private User creator;
+
+    @OneToOne(optional = true, cascade = CascadeType.ALL)
+    @JoinColumn(name = "latest_match_id", referencedColumnName = "id")
+    @QueryInit({"supervisor.user", "supervisor.unit"})
+    private Match match;
 
     @OneToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
     private Project project;
 
-    @OneToOne(mappedBy = "idea", orphanRemoval = true, optional = true)
-    private FirstMeeting firstMeeting;
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_type_id", referencedColumnName = "id")
+    private ProjectType projectType;
 
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "research_area_id", referencedColumnName = "id")
+    private ResearchArea researchArea;
+
+    // ----------------------------------------------------------------------------------
+    // @ManyToMany JPA-mappings
+    // ----------------------------------------------------------------------------------
+
+    // many-to-many from table "keyword" through table "idea_keyword"
+    @ManyToMany
+    @JoinTable(name="idea_keyword",
+            joinColumns = @JoinColumn(name = "idea_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "keyword_id", referencedColumnName = "id"))
+    private Set<Keyword> keywords = new HashSet<>();
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "idea"
+    // ----------------------------------------------------------------------------------
+
+    // from table idea_language
+    @ElementCollection
+    @CollectionTable(name = "idea_language",
+            joinColumns = @JoinColumn(name = "idea_id", referencedColumnName = "id"))
+    @Column(name = "language")
+    @Enumerated(EnumType.STRING)
+    private Set<Language> languages = EnumSet.noneOf(Language.class);
+
+    // from table idea_export
+    @OneToMany(mappedBy = "idea", cascade = CascadeType.ALL)
+    private List<IdeaExport> exports = new ArrayList<>();
+
+    // from table idea_student
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL, orphanRemoval = true)
+    @QueryInit({"user", "program"})
+    private Set<IdeaParticipation> ideaParticipations = new HashSet<>();
+
+    // from table "idea_match"
     @OneToMany(fetch = FetchType.LAZY, mappedBy = "idea", cascade = CascadeType.ALL)
     @OrderBy("dateCreated DESC")
     private List<Match> matchHistory = new ArrayList<>();
 
-    @OneToOne(optional = true, cascade = CascadeType.ALL)
-    @QueryInit({"supervisor.user", "supervisor.unit"})
-    private Match match;
-
-    @Column(name = "published")
-    private boolean published = true;
-
-    @OneToMany(mappedBy = "idea", cascade = CascadeType.ALL)
-    private List<IdeaExport> exports = new ArrayList<>();
-
-    @Enumerated(EnumType.STRING)
-    private Status cachedStatus;
-
-    @Basic
-    private boolean inactive = false;
+    // from table "idea_first_meeting"
+    @OneToOne(mappedBy = "idea", orphanRemoval = true, optional = true)
+    private FirstMeeting firstMeeting;
 
+    // ----------------------------------------------------------------------------------
+    // methods...
+    // ----------------------------------------------------------------------------------
     public Idea copy(User supervisor) {
         Idea copy = new Idea();
         copy.projectType = this.projectType;
@@ -448,7 +535,9 @@ public class Idea extends DomainObject {
             public String toString() {
                 return "Student idea";
             }
-        }, SUPERVISOR {
+        },
+
+        SUPERVISOR {
             @Override
             public String toString() {
                 return "Supervisor idea";
@@ -463,18 +552,21 @@ public class Idea extends DomainObject {
                 return "Unmatched";
             }
         },
+
         MATCHED {
             @Override
             public String toString() {
                 return "Matched, no project";
             }
         },
+
         COMPLETED {
             @Override
             public String toString() {
                 return "Matched, has project";
             }
         },
+
         INACTIVE {
             @Override
             public String toString() {
diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java
index 39b00e453a..321ccda22b 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaExport.java
@@ -1,8 +1,18 @@
 package se.su.dsv.scipro.match;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
@@ -11,56 +21,69 @@ public class IdeaExport extends DomainObject {
 
     public enum Result { FAIL, SUCCESS }
 
+    // ----------------------------------------------------------------------------------
+    // basic and embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Enumerated(EnumType.STRING)
-    private Result result;
-
     @Basic
     private String reason;
 
+    @Enumerated(EnumType.STRING)
+    private Result result;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea_export) referencing other tables
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
     private Idea idea;
 
-    public boolean wasSuccessful() {
-        return result == Result.SUCCESS;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public Result getResult() {
-        return this.result;
-    }
-
-    public String getReason() {
-        return this.reason;
-    }
-
-    public Idea getIdea() {
-        return this.idea;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setResult(Result result) {
-        this.result = result;
+    public String getReason() {
+        return this.reason;
     }
 
     public void setReason(String reason) {
         this.reason = reason;
     }
 
+    public Result getResult() {
+        return this.result;
+    }
+
+    public void setResult(Result result) {
+        this.result = result;
+    }
+
+    public Idea getIdea() {
+        return this.idea;
+    }
+
     public void setIdea(Idea idea) {
         this.idea = idea;
     }
 
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
+    public boolean wasSuccessful() {
+        return result == Result.SUCCESS;
+    }
+
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java
index 625e38cf8f..7bf357d62f 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaParticipation.java
@@ -1,83 +1,114 @@
 package se.su.dsv.scipro.match;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.Program;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Date;
 import java.util.Objects;
 
 @Entity
 @Table(name = "idea_student")
-@AssociationOverrides({
-		@AssociationOverride(name = "idea",
-			joinColumns = @JoinColumn(name = "idea_id")) })
 public class IdeaParticipation implements Serializable {
-	protected IdeaParticipation() {
-		
-	}
-	
-	public IdeaParticipation(User student, Idea idea) {
-		this.user = student;
-		this.idea = idea;
-	}
 
+    // ----------------------------------------------------------------------------------
+    // basic and embedded JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    private User user;
-
-    @ManyToOne
-    private Idea idea;
-
+    @Basic
+    @Column(name = "date_created")
     private Date dateCreated = new Date();
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea_student) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
+    private Idea idea;
+
     @ManyToOne(optional = true)
+    @JoinColumn(name = "program_id", referencedColumnName = "id")
     private Program program;
 
+    @ManyToOne
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
+
+    // JPA/Hibernate works by create a child class of your entity class with all database
+    // tricks in it, it therefore requires no-arg constructor to be able to instantiate
+    // a new instance.
+    // By creating a protected constructor, JPA/Hibernate still works as expected, but it
+    // declares the intention that parameters need to be provided when new instances are
+    // created.
+    protected IdeaParticipation() { }
+
+    public IdeaParticipation(User student, Idea idea) {
+        this.user = student;
+        this.idea = idea;
+    }
+
+    // ----------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------
     public Long getId() {
         return this.id;
     }
 
-    public User getUser() {
-        return this.user;
-    }
-
-    public Idea getIdea() {
-        return this.idea;
-    }
-
-    public Date getDateCreated() {
-        return this.dateCreated;
-    }
-
-    public Program getProgram() {
-        return this.program;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setUser(User user) {
-        this.user = user;
-    }
-
-    public void setIdea(Idea idea) {
-        this.idea = idea;
+    public Date getDateCreated() {
+        return this.dateCreated;
     }
 
     public void setDateCreated(Date dateCreated) {
         this.dateCreated = dateCreated;
     }
 
+    public Idea getIdea() {
+        return this.idea;
+    }
+
+    public void setIdea(Idea idea) {
+        this.idea = idea;
+    }
+
+    public Program getProgram() {
+        return this.program;
+    }
+
     public void setProgram(Program program) {
         this.program = program;
     }
 
+    public User getUser() {
+        return this.user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    // ----------------------------------------------------------------------------
+    // methods
+    // ----------------------------------------------------------------------------
     @Override
     public String toString() {
         return "IdeaParticipation(id=" + this.getId() + ", user=" + this.getUser() + ", idea=" + this.getIdea() + ", dateCreated=" + this.getDateCreated() + ", program=" + this.getProgram() + ")";
diff --git a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
index 07a468f894..e6be18e1c3 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/IdeaServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.BooleanExpression;
@@ -358,7 +358,6 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
         }
     }
 
-    @Transactional
     private Idea acceptIdea0(Idea idea, User creator, Program accepteeProgram, User coAuthor, final ApplicationPeriod applicationPeriod) {
 
         Idea localIdea = idea;
@@ -442,6 +441,7 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
     }
 
     @Override
+    @Transactional
     public void studentUnselect(final Idea idea, final User student) {
         unmatch(idea, student, new NotificationSource());
     }
@@ -490,7 +490,6 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
         return returnValue;
     }
 
-    @Transactional
     private Idea addMatch(User creator, User supervisor, Idea idea, NotificationSource notificationSource) {
         Match match = new Match();
         match.setIdea(idea);
diff --git a/core/src/main/java/se/su/dsv/scipro/match/Keyword.java b/core/src/main/java/se/su/dsv/scipro/match/Keyword.java
index 320c278981..060efc46b7 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/Keyword.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/Keyword.java
@@ -1,15 +1,25 @@
 package se.su.dsv.scipro.match;
 
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.LazyDeletableDomainObject;
 import se.su.dsv.scipro.system.ResearchArea;
 
-import jakarta.persistence.*;
-
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
 
 @Entity
+@Table(name = "keyword")
 @Cacheable(true)
 public class Keyword extends LazyDeletableDomainObject {
 
@@ -19,8 +29,10 @@ public class Keyword extends LazyDeletableDomainObject {
 
     private String keyword;
 
-    @ManyToMany(fetch = FetchType.EAGER,targetEntity=ResearchArea.class)
-	@JoinTable(name="Keyword_researcharea")
+    @ManyToMany(fetch = FetchType.EAGER, targetEntity = ResearchArea.class)
+	@JoinTable(name="keyword_research_area",
+            joinColumns = @JoinColumn(name = "keyword_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "research_area_id", referencedColumnName = "id"))
     private Set<ResearchArea> researchAreas = new HashSet<>();
 
     public Keyword() {
diff --git a/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java
index 44c702b1aa..9eb0a58232 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/KeywordServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/core/src/main/java/se/su/dsv/scipro/match/Match.java b/core/src/main/java/se/su/dsv/scipro/match/Match.java
index ec4bb68099..2408e5058f 100755
--- a/core/src/main/java/se/su/dsv/scipro/match/Match.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/Match.java
@@ -1,56 +1,85 @@
 package se.su.dsv.scipro.match;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
-@Cacheable(true)
 @Table(name = "idea_match")
+@Cacheable(true)
 public class Match extends DomainObject {
+
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne(optional = false)
-    private Idea idea;
-
-    @ManyToOne
-    @QueryInit({"unit"})
-    private User supervisor;
-
+    @Basic
     @Enumerated(EnumType.STRING)
     private Idea.Status status;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea_match) referencing other tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = true)
+    @JoinColumn(name = "changed_by_user_id", referencedColumnName = "id")
     private User changedBy;
 
-    public User getSupervisor() {
-        return supervisor;
-    }
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
+    private Idea idea;
 
+    @ManyToOne
+    @JoinColumn(name = "supervisor_user_id", referencedColumnName = "id")
+    @QueryInit({"unit"})
+    private User supervisor;
+
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public Idea getIdea() {
-        return this.idea;
+    public void setId(Long id) {
+        this.id = id;
     }
 
     public Idea.Status getStatus() {
         return this.status;
     }
 
+    public void setStatus(Idea.Status status) {
+        this.status = status;
+    }
+
     public User getChangedBy() {
         return this.changedBy;
     }
 
-    public void setId(Long id) {
-        this.id = id;
+    public void setChangedBy(User changedBy) {
+        this.changedBy = changedBy;
+    }
+
+    public Idea getIdea() {
+        return this.idea;
     }
 
     public void setIdea(Idea idea) {
@@ -61,14 +90,13 @@ public class Match extends DomainObject {
         this.supervisor = supervisor;
     }
 
-    public void setStatus(Idea.Status status) {
-        this.status = status;
-    }
-
-    public void setChangedBy(User changedBy) {
-        this.changedBy = changedBy;
+    public User getSupervisor() {
+        return supervisor;
     }
 
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -93,6 +121,7 @@ public class Match extends DomainObject {
 
     @Override
     public String toString() {
-        return "Match(id=" + this.getId() + ", supervisor=" + this.getSupervisor() + ", status=" + this.getStatus() + ", changedBy=" + this.getChangedBy() + ")";
+        return "Match(id=" + this.getId() + ", supervisor=" + this.getSupervisor() + ", status=" + this.getStatus() +
+                ", changedBy=" + this.getChangedBy() + ")";
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java b/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java
deleted file mode 100644
index 28e19d2295..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/match/MatchModule.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package se.su.dsv.scipro.match;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.multibindings.OptionalBinder;
-
-public class MatchModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        OptionalBinder.newOptionalBinder(binder(), IdeaCreationJudge.class)
-                .setDefault().to(AllowAllIdeaCreationJudge.class);
-        bind(ProjectStartNotifier.class).asEagerSingleton();
-        bind(AddActivityPlanOnProjectStart.class).asEagerSingleton();
-        bind(ApplicationPeriodService.class).to(ApplicationPeriodServiceImpl.class);
-        bind(IdeaService.class).to(IdeaServiceImpl.class);
-        bind(FirstMeetingRepository.class).to(FirstMeetingRepositoryImpl.class);
-        bind(KeywordService.class).to(KeywordServiceImpl.class);
-        bind(MatchService.class).to(MatchServiceImpl.class);
-        bind(ProgramService.class).to(ProgramServiceImpl.class);
-        bind(MatchFollowUpService.class).to(MatchFollowUpServiceImpl.class);
-        bind(TargetService.class).to(TargetServiceImpl.class);
-        bind(ApplicationPeriodProjectTypeService.class).to(ApplicationPeriodProjectTypeServiceImpl.class);
-        bind(PreliminaryMatchService.class).to(PreliminaryMatchServiceImpl.class);
-        bind(IdeaRepository.class).to(IdeaRepositoryImpl.class);
-        bind(TargetRepository.class).to(TargetRepositoryImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java b/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java
index 5845f8f479..4a2b0229ba 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/PreliminaryMatch.java
@@ -1,70 +1,98 @@
 package se.su.dsv.scipro.match;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name = "preliminary_match")
 public class PreliminaryMatch extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
+    @Column(name = "comment")
+    private String comment;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (idea_first_meeting) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
     private Idea idea;
 
     @ManyToOne
+    @JoinColumn(name = "supervisor_user_id", referencedColumnName = "id")
     private User supervisor;
 
-    private String comment;
-
-    // JPA
-    public PreliminaryMatch() {
-    }
+    // ----------------------------------------------------------------------------------
+    // constructors
+    // ----------------------------------------------------------------------------------
+    public PreliminaryMatch() { }
 
     public PreliminaryMatch(final Idea idea) {
         this.idea = idea;
     }
 
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public Idea getIdea() {
-        return this.idea;
-    }
-
-    public User getSupervisor() {
-        return this.supervisor;
-    }
-
-    public String getComment() {
-        return this.comment;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setIdea(Idea idea) {
-        this.idea = idea;
-    }
-
-    public void setSupervisor(User supervisor) {
-        this.supervisor = supervisor;
+    public String getComment() {
+        return this.comment;
     }
 
     public void setComment(String comment) {
         this.comment = comment;
     }
 
+    public Idea getIdea() {
+        return this.idea;
+    }
+
+    public void setIdea(Idea idea) {
+        this.idea = idea;
+    }
+
+    public User getSupervisor() {
+        return this.supervisor;
+    }
+
+    public void setSupervisor(User supervisor) {
+        this.supervisor = supervisor;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     @Override
     public String toString() {
-        return "PreliminaryMatch(id=" + this.getId() + ", idea=" + this.getIdea() + ", supervisor=" + this.getSupervisor() + ", comment=" + this.getComment() + ")";
+        return "PreliminaryMatch(id=" + this.getId() + ", idea=" + this.getIdea() + ", supervisor=" +
+                this.getSupervisor() + ", comment=" + this.getComment() + ")";
     }
 
     @Override
diff --git a/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java
index e759f53f93..925831af46 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/ProgramServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import se.su.dsv.scipro.system.PageRequest;
 import se.su.dsv.scipro.system.Sort;
diff --git a/core/src/main/java/se/su/dsv/scipro/match/Target.java b/core/src/main/java/se/su/dsv/scipro/match/Target.java
index 2be7fac981..79d88f4514 100644
--- a/core/src/main/java/se/su/dsv/scipro/match/Target.java
+++ b/core/src/main/java/se/su/dsv/scipro/match/Target.java
@@ -20,12 +20,12 @@ public class Target implements Serializable {
 
     @MapsId("applicationPeriodId")
     @ManyToOne
-    @JoinColumn(name = "applicationPeriodId")
+    @JoinColumn(name = "application_period_id")
     private ApplicationPeriod applicationPeriod;
 
     @MapsId("projectTypeId")
     @ManyToOne
-    @JoinColumn(name = "projectTypeId")
+    @JoinColumn(name = "project_type_id")
     private ProjectType projectType;
 
     private int target;
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java b/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java
index e43bb892e8..8d8aaaeb33 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/MilestoneActivityTemplateRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.milestones;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java
index 45bbd74bfb..f72cf1954f 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/Milestone.java
@@ -1,39 +1,54 @@
 package se.su.dsv.scipro.milestones.dataobjects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Collections;
 import java.util.List;
 
 @Entity
 @Table(name = "milestone")
 public class Milestone extends DomainObject {
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     protected long id;
 
-    @ManyToOne
-    private Project project;
-
-    @ManyToOne(optional = true)
-    private User user;
-
-    @ManyToOne(optional = false)
-    private MilestoneActivityTemplate activity;
-
+    @Basic
     @Column(name = "confirmed", nullable = false)
     private boolean confirmed = false;
 
-    @Override
-    public Long getId() {
-        return id;
-    }
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (milestone) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "milestone_activity_template_id", referencedColumnName = "id")
+    private MilestoneActivityTemplate activity;
 
+    @ManyToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected Milestone() {
 
     }
@@ -49,6 +64,15 @@ public class Milestone extends DomainObject {
         this.activity = activity;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+
+    @Override
+    public Long getId() {
+        return id;
+    }
+
     public void setId(Long id) {
         this.id = id;
     }
@@ -61,14 +85,6 @@ public class Milestone extends DomainObject {
         this.confirmed = confirmed;
     }
 
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
     public MilestoneActivityTemplate getActivity() {
         return activity;
     }
@@ -77,11 +93,22 @@ public class Milestone extends DomainObject {
         this.activity = activity;
     }
 
-    public List<Member> getMembers() {
-        return Collections.singletonList(new Member(user, Member.Type.MILESTONE_INDIVIDUAL));
+    public Project getProject() {
+        return project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
     }
 
     public User getUser() {
         return this.user;
     }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    public List<Member> getMembers() {
+        return Collections.singletonList(new Member(user, Member.Type.MILESTONE_INDIVIDUAL));
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java
index f86421e861..583c558278 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestoneActivityTemplate.java
@@ -1,10 +1,23 @@
 package se.su.dsv.scipro.milestones.dataobjects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.Event;
 import se.su.dsv.scipro.system.LazyDeletableDomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -18,42 +31,66 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject {
     public static final String PEER_REVIEW_ONE = "PEER_REVIEW_ONE";
     public static final String PEER_REVIEW_TWO = "PEER_REVIEW_TWO";
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
     @Basic(optional = false)
+    @Column(name = "title")
     private String title;
 
     @Basic(optional = true)
+    @Column(name = "description")
     private String description;
 
     @Enumerated(EnumType.STRING)
+    @Column(name = "type")
     private Type type;
 
-    @Column(unique = true)
+    @Basic
+    @Column(name = "code", unique = true)
     private String code;
 
+    @Basic
+    @Column(name = "sort_order")
+    private int sortOrder;
+
+    @Basic
+    @Column(name = "editable_by_students")
+    private boolean editableByStudents = false;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (milestone_activity_template)
+    // referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "milestone_phase_template_id", referencedColumnName = "id", nullable = false)
+    private MilestonePhaseTemplate milestonePhaseTemplate;
+
+    @OneToOne
+    @JoinColumn(name = "activated_by_event_name", referencedColumnName = "name")
+    private Event activatedBy;
+
+    // ----------------------------------------------------------------------------------
+    // @ManyToMany JPA-mappings
+    // ----------------------------------------------------------------------------------
+
+    // Many-to-Many between table milestone_activity_template and project_type through
+    // table "milestone_activity_template_project_type".
     @ManyToMany
     @JoinTable(
-            joinColumns = @JoinColumn(name = "milestone_activity_template_id")
+            name = "milestone_activity_template_project_type",
+            joinColumns = @JoinColumn(name = "milestone_activity_template_id"),
+            inverseJoinColumns = @JoinColumn(name = "project_type_id")
     )
     private Set<ProjectType> projectTypes = new HashSet<>();
 
-    @ManyToOne
-    @JoinColumn(name = "phase", nullable = false)
-    private MilestonePhaseTemplate milestonePhaseTemplate;
-
-    @Column
-    private int sortOrder;
-
-    @Column
-    private boolean editableByStudents = false;
-
-    @OneToOne
-    @JoinColumn(name = "activatedBy")
-    private Event activatedBy;
-
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public MilestoneActivityTemplate() {
     }
 
@@ -67,10 +104,9 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject {
         this.description = description;
     }
 
-    public void addProjectType(ProjectType projectType) {
-        projectTypes.add(projectType);
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
@@ -80,79 +116,95 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject {
         return this.title;
     }
 
-    public String getDescription() {
-        return this.description;
-    }
-
-    public Type getType() {
-        return this.type;
-    }
-
-    public String getCode() {
-        return this.code;
-    }
-
-    public Set<ProjectType> getProjectTypes() {
-        return this.projectTypes;
-    }
-
-    public MilestonePhaseTemplate getMilestonePhaseTemplate() {
-        return this.milestonePhaseTemplate;
-    }
-
-    public int getSortOrder() {
-        return this.sortOrder;
-    }
-
-    public boolean isEditableByStudents() {
-        return this.editableByStudents;
-    }
-
-    public Event getActivatedBy() {
-        return this.activatedBy;
-    }
-
     public void setTitle(String title) {
         this.title = title;
     }
 
+    public String getDescription() {
+        return this.description;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
 
+    public Type getType() {
+        return this.type;
+    }
+
     public void setType(Type type) {
         this.type = type;
     }
 
+    public String getCode() {
+        return this.code;
+    }
+
     public void setCode(String code) {
         this.code = code;
     }
 
-    public void setMilestonePhaseTemplate(MilestonePhaseTemplate milestonePhaseTemplate) {
-        this.milestonePhaseTemplate = milestonePhaseTemplate;
+    public int getSortOrder() {
+        return this.sortOrder;
     }
 
     public void setSortOrder(int sortOrder) {
         this.sortOrder = sortOrder;
     }
 
+    public boolean isEditableByStudents() {
+        return this.editableByStudents;
+    }
+
     public void setEditableByStudents(boolean editableByStudents) {
         this.editableByStudents = editableByStudents;
     }
 
+    public MilestonePhaseTemplate getMilestonePhaseTemplate() {
+        return this.milestonePhaseTemplate;
+    }
+
+    public void setMilestonePhaseTemplate(MilestonePhaseTemplate milestonePhaseTemplate) {
+        this.milestonePhaseTemplate = milestonePhaseTemplate;
+    }
+
+    public Event getActivatedBy() {
+        return this.activatedBy;
+    }
+
     public void setActivatedBy(Event activatedBy) {
         this.activatedBy = activatedBy;
     }
 
+    public Set<ProjectType> getProjectTypes() {
+        return this.projectTypes;
+    }
+
     public void setProjectTypes(Set<ProjectType> projectTypes) {
         this.projectTypes = projectTypes;
     }
 
-    public static class BySortOrderComparator implements Comparator<MilestoneActivityTemplate>, Serializable {
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    public void addProjectType(ProjectType projectType) {
+        projectTypes.add(projectType);
+    }
+
+    public boolean isAutomatic() {
+        return code != null || activatedBy != null;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Nested classes and types
+    // ----------------------------------------------------------------------------------
+    public static class BySortOrderComparator implements Comparator<MilestoneActivityTemplate>,
+            Serializable {
         @Override
         public int compare(MilestoneActivityTemplate o1, MilestoneActivityTemplate o2) {
             int sortOrderResult = o1.sortOrder - o2.sortOrder;
-            int phaseSortOrderResult = o1.milestonePhaseTemplate.getSortOrder() - o2.getMilestonePhaseTemplate().getSortOrder();
+            int phaseSortOrderResult = o1.milestonePhaseTemplate.getSortOrder() -
+                    o2.getMilestonePhaseTemplate().getSortOrder();
 
             if (phaseSortOrderResult == 0) {
                 return sortOrderResult;
@@ -175,8 +227,4 @@ public class MilestoneActivityTemplate extends LazyDeletableDomainObject {
             return asString;
         }
     }
-
-    public boolean isAutomatic() {
-        return code != null || activatedBy != null;
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java
index 3078dd4d24..34b29d2fe4 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/dataobjects/MilestonePhaseTemplate.java
@@ -1,31 +1,41 @@
 package se.su.dsv.scipro.milestones.dataobjects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.LazyDeletableDomainObject;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name = "milestone_phase_template")
 public class MilestonePhaseTemplate extends LazyDeletableDomainObject {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     protected long id;
 
-    @Override
-    public Long getId() {
-        return id;
-    }
-
     @Basic(optional = false)
+    @Column(name = "title")
     private String title;
 
     @Basic(optional = true)
+    @Column(name = "description")
     private String description;
 
-    @Column(name = "sortOrder")
+    @Basic
+    @Column(name = "sort_order")
     private int sortOrder;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public MilestonePhaseTemplate() {
 
     }
@@ -41,37 +51,47 @@ public class MilestonePhaseTemplate extends LazyDeletableDomainObject {
         this.sortOrder = sortOrder;
     }
 
-    public String getTitle() {
-        return this.title;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public int getSortOrder() {
-        return this.sortOrder;
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return id;
     }
 
     public void setId(long id) {
         this.id = id;
     }
 
+    public String getTitle() {
+        return this.title;
+    }
+
     public void setTitle(String title) {
         this.title = title;
     }
 
+    public String getDescription() {
+        return this.description;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
 
+    public int getSortOrder() {
+        return this.sortOrder;
+    }
+
     public void setSortOrder(int sortOrder) {
         this.sortOrder = sortOrder;
     }
 
-    @Override
-    public String toString() {
-        return "MilestonePhaseTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", sortOrder=" + this.getSortOrder() + ")";
+    // ----------------------------------------------------------------------------------
+    // Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof MilestonePhaseTemplate;
     }
 
     @Override
@@ -86,12 +106,13 @@ public class MilestonePhaseTemplate extends LazyDeletableDomainObject {
                 && this.getSortOrder() == other.getSortOrder();
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof MilestonePhaseTemplate;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getTitle(), this.getDescription(), this.getSortOrder());
     }
+
+    @Override
+    public String toString() {
+        return "MilestonePhaseTemplate(id=" + this.getId() + ", title=" + this.getTitle() + ", description=" + this.getDescription() + ", sortOrder=" + this.getSortOrder() + ")";
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java
index d19f65687a..e70062e7b1 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/MilestoneActivator.java
@@ -61,7 +61,7 @@ public class MilestoneActivator {
         int minimumActiveParticipationsToBeGraded = event.getProject()
                 .getProjectType()
                 .getProjectTypeSettings()
-                .getMinimumActiveParticipationsToBeGraded();
+                .getMinActiveParticipationsToBeGraded();
         if (completedParticipations >= minimumActiveParticipationsToBeGraded) {
             activateIndividualMilestone(Set.of("ParticipationGradingEvent"), event.getProject(), event.getStudent());
         } else {
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java
index f5bd91a316..197e947bda 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestonePhaseTemplateServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.milestones.service.impl;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.Sort;
 import se.su.dsv.scipro.milestones.dataobjects.MilestonePhaseTemplate;
 import se.su.dsv.scipro.milestones.dataobjects.QMilestonePhaseTemplate;
diff --git a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java
index 70c69ddef2..f7b5b8c447 100644
--- a/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/milestones/service/impl/MilestoneServiceImpl.java
@@ -4,6 +4,7 @@ import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import com.querydsl.jpa.impl.JPAQuery;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.Pageable;
 import se.su.dsv.scipro.milestones.dataobjects.Milestone;
 import se.su.dsv.scipro.milestones.dataobjects.MilestoneActivityTemplate;
@@ -54,6 +55,7 @@ public class MilestoneServiceImpl extends AbstractServiceImpl<Milestone, Long> i
     }
 
     @Override
+    @Transactional
     public void setConfirmed(Project project, MilestoneActivityTemplate activity, boolean confirmed) {
         if (confirmed) {
             for (MilestoneActivityTemplate earlierActivity : getEarlierIncompleteProjectMilestoneActivities(project, activity)) {
@@ -84,6 +86,7 @@ public class MilestoneServiceImpl extends AbstractServiceImpl<Milestone, Long> i
     }
 
     @Override
+    @Transactional
     public void setConfirmed(Project project, User student, MilestoneActivityTemplate activity, boolean confirmed) {
 
         if (!project.hasModule(ProjectModule.MILESTONES)) {
diff --git a/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java b/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java
index b12335ead6..639da2f1f5 100755
--- a/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java
+++ b/core/src/main/java/se/su/dsv/scipro/nonworkperiod/NonWorkDayPeriod.java
@@ -1,24 +1,29 @@
 package se.su.dsv.scipro.nonworkperiod;
 
-import jakarta.persistence.GenerationType;
-import se.su.dsv.scipro.system.DomainObject;
-
 import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
 import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import se.su.dsv.scipro.system.DomainObject;
+
 import java.time.LocalDate;
 import java.util.Objects;
 
 @Entity
 @Cacheable(true)
+@Table(name = "non_work_day_period")
 public class NonWorkDayPeriod extends DomainObject {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Column(name = "start_date")
     private LocalDate startDate;
 
+    @Column(name = "end_date")
     private LocalDate endDate;
 
     private String comment;
diff --git a/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java
index 126470035e..58cb33dbc1 100755
--- a/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notes/NoteServiceImpl.java
@@ -1,6 +1,7 @@
 package se.su.dsv.scipro.notes;
 
 import com.querydsl.core.types.dsl.BooleanExpression;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractServiceImpl;
 import se.su.dsv.scipro.system.User;
 
@@ -20,6 +21,7 @@ public class NoteServiceImpl extends AbstractServiceImpl<Note, Long> implements
     }
 
     @Override
+    @Transactional
     public Note getNote(User user) {
         Note note = findOne(hasUser(user));
         if (note == null){
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java
index 8bd1a88a13..0a4a6e08f4 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationControllerImpl.java
@@ -1,6 +1,5 @@
 package se.su.dsv.scipro.notifications;
 
-import com.google.inject.ProvisionException;
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.group.Group;
@@ -94,7 +93,7 @@ public class NotificationControllerImpl implements NotificationController {
         try {
             return currentUserProvider.get().get();
         }
-        catch (ProvisionException ignored) {
+        catch (RuntimeException ignored) {
             return null;
         }
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java
deleted file mode 100644
index 507ca4bcab..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationModule.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package se.su.dsv.scipro.notifications;
-
-import com.google.inject.PrivateModule;
-import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter;
-import se.su.dsv.scipro.notifications.interfaces.impl.NotificationMailFormatterImpl;
-
-public class NotificationModule extends PrivateModule {
-
-    public static final String NOTIFICATION_RELATIVE_PAGE_URL = "notification";
-
-    @Override
-    protected void configure() {
-        bind(Notifications.class).asEagerSingleton();
-
-        bind(NotificationService.class).to(NotificationServiceImpl.class);
-        expose(NotificationService.class);
-
-        bind(NotificationEventRepository.class).to(NotificationEventRepositoryImpl.class);
-        bind(NotificationEventService.class).to(NotificationEventServiceImpl.class);
-        expose(NotificationEventService.class);
-
-        bind(NotificationMailFormatter.class).to(NotificationMailFormatterImpl.class);
-        expose(NotificationMailFormatter.class);
-        bind(NotificationController.class).to(NotificationControllerImpl.class);
-        expose(NotificationController.class);
-    }
-
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java
index 826991801f..5bbe68093e 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/NotificationServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.notifications;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.Predicate;
 import se.su.dsv.scipro.system.Pageable;
@@ -50,6 +50,7 @@ public class NotificationServiceImpl extends AbstractServiceImpl<Notification,Lo
     }
 
     @Override
+    @Transactional
     public void setRead(User user, NotificationEvent notificationEvent, boolean read) {
         Iterable<Notification> notifications = findAll(
                 QNotification.notification.notificationEvent.eq(notificationEvent)
@@ -62,6 +63,7 @@ public class NotificationServiceImpl extends AbstractServiceImpl<Notification,Lo
     }
 
     @Override
+    @Transactional
     @SuppressWarnings("unchecked")
     // This looks so wrong but a List<Notification> is what we actually get
     // during runtime, see SCIPRO-167935. Reflection so awesome...
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java
index 3fd7e4a0ac..f738fbf6c8 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/CustomEvent.java
@@ -1,5 +1,7 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
 import se.su.dsv.scipro.system.DomainObject;
 
 import jakarta.persistence.Entity;
@@ -13,6 +15,8 @@ public class CustomEvent extends NotificationEvent {
         IDEA_DELETED
     }
 
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private CustomEvent.Event event;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java
index fa25851094..079c0cb09a 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/GroupEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.group.Group;
 import se.su.dsv.scipro.system.DomainObject;
 
@@ -11,37 +14,40 @@ import jakarta.persistence.ManyToOne;
 @Entity
 public class GroupEvent extends NotificationEvent {
 
-    public void setEvent(Event event) {
-        this.event = event;
-    }
-
     public enum Event {
         MESSAGE_THREAD_CREATED, MESSAGE_THREAD_REPLY
     }
 
+    @Basic
+    @Column(name = "event")
+    @Enumerated(EnumType.STRING)
+    private Event event;
+
+    @ManyToOne
+    @JoinColumn(name = "project_group_id", referencedColumnName = "id")
+    private Group group;
+
+    public GroupEvent() {
+        super(Notification.Type.GROUP);
+    }
+
+    @Override
+    public Enum getEvent() {
+        return event;
+    }
+
+    public void setEvent(Event event) {
+        this.event = event;
+    }
+
     public Group getGroup() {
         return group;
     }
 
-    @ManyToOne
-    private Group group;
-
-    @Enumerated(EnumType.STRING)
-    private Event event;
-
-    public GroupEvent() {
-        super(Notification.Type.GROUP);
-    }
-
     public void setGroup(Group group) {
         this.group = group;
     }
 
-    @Override
-    public Enum getEvent() {
-        return event;
-    }
-
     @Override
     protected String getEntityTitle() {
         return group.getTitle();
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java
index 8ef2b2d070..54df3b315e 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/IdeaEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.match.Idea;
 import se.su.dsv.scipro.system.DomainObject;
 
@@ -11,18 +14,29 @@ import jakarta.persistence.ManyToOne;
 @Entity
 public class IdeaEvent extends NotificationEvent {
 
-
     public enum Event {
         STATUS_CHANGE, PARTNER_ACCEPT,
         ADDED_AS_PARTNER, FIRST_MEETING, REMOVED_AS_PARTNER, EXPORTED_FAIL
     }
 
-    @ManyToOne
-    private Idea idea;
-
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private Event event;
 
+    @ManyToOne
+    @JoinColumn(name = "idea_id", referencedColumnName = "id")
+    private Idea idea;
+
+    @Override
+    public Event getEvent() {
+        return event;
+    }
+
+    public void setEvent(Event event) {
+        this.event = event;
+    }
+
     public IdeaEvent() {
         super(Notification.Type.IDEA);
     }
@@ -35,15 +49,6 @@ public class IdeaEvent extends NotificationEvent {
         this.idea = idea;
     }
 
-    @Override
-    public Event getEvent() {
-        return event;
-    }
-
-    public void setEvent(Event event) {
-        this.event = event;
-    }
-
     @Override
     public String getEntityTitle() {
         return idea.getTitle();
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java
index 9e4c1bf5a9..f84a47be57 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/MileStoneEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.milestones.dataobjects.Milestone;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -17,24 +20,64 @@ public class MileStoneEvent extends NotificationEvent {
         MILESTONE_CONFIRMED, MILESTONE_REVOKED
     }
 
-    @ManyToOne
-    private Milestone milestone;
-
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private Event event;
 
+    @ManyToOne
+    @JoinColumn(name = "milestone_id", referencedColumnName = "id")
+    private Milestone milestone;
+
     public MileStoneEvent() {
         super(Notification.Type.MILESTONE);
     }
 
     @Override
-    public Project getProject() {
-        return milestone.getProject();
+    public Enum getEvent() {
+        return event;
+    }
+
+    public void setEvent(Event event) {
+        this.event = event;
+    }
+
+    public Milestone getMilestone() {
+        return this.milestone;
+    }
+
+    public void setMilestone(Milestone milestone) {
+        this.milestone = milestone;
     }
 
     @Override
-    public Enum getEvent() {
-        return event;
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof MileStoneEvent)) return false;
+        final MileStoneEvent other = (MileStoneEvent) o;
+        return other.canEqual(this)
+                && super.equals(o)
+                && Objects.equals(this.getMilestone(), other.getMilestone())
+                && Objects.equals(this.getEvent(), other.getEvent());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.getMilestone(), this.getEvent());
+    }
+
+    @Override
+    public String toString() {
+        return "MileStoneEvent(milestone=" + this.getMilestone() + ", event=" + this.getEvent() + ")";
+    }
+
+    protected boolean canEqual(final Object other) {
+        return other instanceof MileStoneEvent;
+    }
+
+    @Override
+    public Project getProject() {
+        return milestone.getProject();
     }
 
     @Override
@@ -51,41 +94,4 @@ public class MileStoneEvent extends NotificationEvent {
     public DomainObject getEntity() {
         return milestone;
     }
-
-    public Milestone getMilestone() {
-        return this.milestone;
-    }
-
-    public void setMilestone(Milestone milestone) {
-        this.milestone = milestone;
-    }
-
-    public void setEvent(Event event) {
-        this.event = event;
-    }
-
-    @Override
-    public String toString() {
-        return "MileStoneEvent(milestone=" + this.getMilestone() + ", event=" + this.getEvent() + ")";
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof MileStoneEvent)) return false;
-        final MileStoneEvent other = (MileStoneEvent) o;
-        return other.canEqual(this)
-                && super.equals(o)
-                && Objects.equals(this.getMilestone(), other.getMilestone())
-                && Objects.equals(this.getEvent(), other.getEvent());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof MileStoneEvent;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(this.getMilestone(), this.getEvent());
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java
index 073be08b40..5102db88cd 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/Notification.java
@@ -1,41 +1,59 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-
 @Entity
+@Table(name = "notification")
 public class Notification extends DomainObject {
 
-
-    public enum Type {
-        PROJECT, IDEA, FINAL_SEMINAR, PEER, MILESTONE,
-        GROUP, FORUM, CUSTOM
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
     @Basic(optional = false)
-    private boolean unread = true;
-
-    @Basic(optional = false)
+    @Column(name = "mailed")
     private boolean mailed = false;
 
+    @Basic(optional = false)
+    @Column(name = "unread")
+    private boolean unread = true;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (notification) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(cascade = CascadeType.ALL)
-    @JoinColumn(name = "notificationData_id")
+    @JoinColumn(name = "notification_data_id", referencedColumnName = "id")
     private NotificationEvent notificationEvent;
 
     @ManyToOne
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
     private User user;
 
+    // ----------------------------------------------------------------------------------
+    // Constructor
+    // ----------------------------------------------------------------------------------
     public Notification() {
-
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return id;
@@ -45,6 +63,14 @@ public class Notification extends DomainObject {
         this.id = id;
     }
 
+    public boolean isMailed() {
+        return mailed;
+    }
+
+    public void setMailed(boolean mailed) {
+        this.mailed = mailed;
+    }
+
     public boolean isUnread() {
         return unread;
     }
@@ -69,14 +95,9 @@ public class Notification extends DomainObject {
         this.user = user;
     }
 
-    public boolean isMailed() {
-        return mailed;
-    }
-
-    public void setMailed(boolean mailed) {
-        this.mailed = mailed;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
     public String getTitle() {
         return getNotificationEvent().getTitle();
     }
@@ -108,4 +129,12 @@ public class Notification extends DomainObject {
     public User getCausedBy() {
         return getNotificationEvent().getCausedBy();
     }
+
+    // ----------------------------------------------------------------------------------
+    // Nested type
+    // ----------------------------------------------------------------------------------
+    public enum Type {
+        PROJECT, IDEA, FINAL_SEMINAR, PEER, MILESTONE,
+        GROUP, FORUM, CUSTOM
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java
index 1aac89eca6..6eb2f15ef4 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/NotificationEvent.java
@@ -1,55 +1,70 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Collection;
 
 @Entity
+@Table(name = "notification_data")
 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
-@Table(name = "NotificationData")
+@DiscriminatorColumn(name = "subclass")
 public abstract class NotificationEvent extends DomainObject {
 
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     protected long id;
 
+    @Basic
+    @Column(name = "type")
     @Enumerated(EnumType.STRING)
     protected Notification.Type type;
 
-    @OneToMany(mappedBy = "notificationEvent", cascade = CascadeType.ALL, orphanRemoval = true)
-    private Collection<Notification> notifications;
-
     @Basic(optional = true)
+    @Column(name = "source")
     private String source;
 
     @Basic(optional = true)
+    @Column(name = "additional_source")
     private String additionalSource;
 
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (notification_data) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = true)
+    @JoinColumn(name = "caused_by_user_id", referencedColumnName = "id")
     private User causedBy;
 
-    public abstract Enum getEvent();
-
-    /**
-     * The title of the entity this event is about.
-     *
-     * @return a human readable title
-     */
-    protected abstract String getEntityTitle();
-
-    /**
-     * Return true if there is an entity backing this event.
-     * Used to determine if this event was about a deletion, or has since been deleted.
-     */
-    public abstract boolean hasEntity();
-
-    public abstract DomainObject getEntity();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "notification_data"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "notificationEvent", cascade = CascadeType.ALL, orphanRemoval = true)
+    private Collection<Notification> notifications;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected NotificationEvent() {
 
     }
@@ -58,6 +73,9 @@ public abstract class NotificationEvent extends DomainObject {
         this.type = type;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return id;
@@ -75,14 +93,6 @@ public abstract class NotificationEvent extends DomainObject {
         this.type = type;
     }
 
-    public Collection<Notification> getNotifications() {
-        return notifications;
-    }
-
-    public void setNotifications(Collection<Notification> notifications) {
-        this.notifications = notifications;
-    }
-
     public String getSource() {
         return source;
     }
@@ -91,8 +101,12 @@ public abstract class NotificationEvent extends DomainObject {
         this.source = source;
     }
 
-    public String getTitle() {
-        return hasEntity() ? getEntityTitle() : "[Deleted entity]";
+    public String getAdditionalSource() {
+        return additionalSource;
+    }
+
+    public void setAdditionalSource(String additionalSource) {
+        this.additionalSource = additionalSource;
     }
 
     public User getCausedBy() {
@@ -103,6 +117,41 @@ public abstract class NotificationEvent extends DomainObject {
         this.causedBy = user;
     }
 
+    public Collection<Notification> getNotifications() {
+        return notifications;
+    }
+
+    public void setNotifications(Collection<Notification> notifications) {
+        this.notifications = notifications;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Abstract methods to be implemented by subclasses
+    // ----------------------------------------------------------------------------------
+    /**
+     * The title of the entity this event is about.
+     *
+     * @return a human readable title
+     */
+    protected abstract String getEntityTitle();
+
+    /**
+     * Return true if there is an entity backing this event.
+     * Used to determine if this event was about a deletion, or has since been deleted.
+     */
+    public abstract boolean hasEntity();
+
+    public abstract DomainObject getEntity();
+
+    public abstract Enum getEvent();
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    public String getTitle() {
+        return hasEntity() ? getEntityTitle() : "[Deleted entity]";
+    }
+
     /**
      * Override this method if the event has an association with a {@link Project}.
      *
@@ -111,12 +160,4 @@ public abstract class NotificationEvent extends DomainObject {
     public Project getProject() {
         return null;
     }
-
-    public String getAdditionalSource() {
-        return additionalSource;
-    }
-
-    public void setAdditionalSource(String additionalSource) {
-        this.additionalSource = additionalSource;
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java
index 17272c9768..8ca7f15e9e 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.peer.PeerReview;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -12,22 +15,31 @@ import jakarta.persistence.ManyToOne;
 @Entity
 public class PeerEvent extends NotificationEvent {
 
-    public enum Event { REVIEW_COMPLETED, REVIEW_COMMENT, REVIEW_ACCEPTED, REQUEST_DELETED,
-        REQUEST_EXPIRED }
-
-    @ManyToOne
-    private PeerReview review;
+    public enum Event {
+        REVIEW_COMPLETED, REVIEW_COMMENT, REVIEW_ACCEPTED, REQUEST_DELETED,
+        REQUEST_EXPIRED
+    }
 
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private Event event;
 
+    @ManyToOne
+    @JoinColumn(name = "peer_review_id", referencedColumnName = "id")
+    private PeerReview review;
+
     public PeerEvent() {
         super(Notification.Type.PEER);
     }
 
     @Override
-    public Project getProject() {
-        return review.getProject();
+    public Event getEvent() {
+        return event;
+    }
+
+    public void setEvent(Event event) {
+        this.event = event;
     }
 
     public PeerReview getReview() {
@@ -39,12 +51,8 @@ public class PeerEvent extends NotificationEvent {
     }
 
     @Override
-    public Event getEvent() {
-        return event;
-    }
-
-    public void setEvent(Event event) {
-        this.event = event;
+    public Project getProject() {
+        return review.getProject();
     }
 
     @Override
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java
index 37355d4d44..72f6dac062 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/PeerRequestEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.peer.PeerRequest;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -12,10 +15,13 @@ import jakarta.persistence.ManyToOne;
 @Entity
 public class PeerRequestEvent extends NotificationEvent {
 
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private PeerEvent.Event event;
 
     @ManyToOne
+    @JoinColumn(name = "peer_request_id", referencedColumnName = "id")
     private PeerRequest request;
 
     public PeerRequestEvent() {
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
index c8c3e51032..ae72d48f16 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 
@@ -19,29 +22,24 @@ public class ProjectEvent extends NotificationEvent {
         FINAL_SEMINAR_APPROVAL_APPROVED, FINAL_SEMINAR_APPROVAL_REJECTED, ROUGH_DRAFT_APPROVAL_REQUESTED,
         ROUGH_DRAFT_APPROVAL_APPROVED, ROUGH_DRAFT_APPROVAL_REJECTED, REVIEWER_GRADING_REPORT_SUBMITTED,
         ONE_YEAR_PASSED_FROM_LATEST_ANNUAL_REVIEW, SUPERVISOR_GRADING_INITIAL_ASSESSMENT_DONE,
-        EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED, PARTICIPATION_APPROVED, COMPLETED,
-        PARTICIPATION_FAILED
+        EXPORTED_SUCCESS, REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, FIRST_MEETING, OPPOSITION_FAILED,
+        PARTICIPATION_APPROVED, COMPLETED, PARTICIPATION_FAILED, REFLECTION_IMPROVEMENTS_REQUESTED,
+        REFLECTION_IMPROVEMENTS_SUBMITTED
     }
 
-    @ManyToOne
-    private Project project;
-
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private Event event;
 
+    @ManyToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
     public ProjectEvent() {
         super(Notification.Type.PROJECT);
     }
 
-    @Override
-    public Project getProject() {
-        return project;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
     @Override
     public Event getEvent() {
         return event;
@@ -51,6 +49,15 @@ public class ProjectEvent extends NotificationEvent {
         this.event = event;
     }
 
+    @Override
+    public Project getProject() {
+        return project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
     @Override
     public String getEntityTitle() {
         return project.getTitle();
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java
index a5b2989c19..c95ec8bf05 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/ProjectForumEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 
@@ -10,29 +13,24 @@ import jakarta.persistence.ManyToOne;
 
 @Entity
 public class ProjectForumEvent extends NotificationEvent {
-    @ManyToOne
-    private Project project;
-
-    @Enumerated(EnumType.STRING)
-    private Event event;
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
 
     public enum Event {
         NEW_FORUM_POST, NEW_FORUM_POST_COMMENT, NEW_REVIEWER_INTERACTION
     }
 
+    @Basic
+    @Column(name = "event")
+    @Enumerated(EnumType.STRING)
+    private Event event;
+
+    @ManyToOne
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
     public ProjectForumEvent() {
         super(Notification.Type.FORUM);
     }
 
-    @Override
-    public Project getProject() {
-        return this.project;
-    }
-
     @Override
     public Event getEvent() {
         return event;
@@ -42,6 +40,15 @@ public class ProjectForumEvent extends NotificationEvent {
         this.event = event;
     }
 
+    @Override
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
     @Override
     protected String getEntityTitle() {
         return project.getTitle();
@@ -56,5 +63,4 @@ public class ProjectForumEvent extends NotificationEvent {
     public DomainObject getEntity() {
         return project;
     }
-
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java
index 46951edcc3..dedad4ca0a 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/dataobject/SeminarEvent.java
@@ -1,5 +1,8 @@
 package se.su.dsv.scipro.notifications.dataobject;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.JoinColumn;
 import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -12,27 +15,24 @@ import jakarta.persistence.ManyToOne;
 @Entity
 public class SeminarEvent extends NotificationEvent {
 
-    public enum Event { CREATED, ROOM_CHANGED, DATE_CHANGED, OPPOSITION_CHANGED, PARTICIPATION_CHANGED, THESIS_UPLOADED, THESIS_UPLOADED_OPPONENT,
-                        OPPOSITION_REPORT_UPLOADED, THESIS_DELETED, THESIS_UPLOAD_REMIND, CANCELLED}
-
-    @ManyToOne
-    private FinalSeminar seminar;
+    public enum Event { CREATED, ROOM_CHANGED, DATE_CHANGED, OPPOSITION_CHANGED,
+        PARTICIPATION_CHANGED, THESIS_UPLOADED, THESIS_UPLOADED_OPPONENT,
+        OPPOSITION_REPORT_UPLOADED, THESIS_DELETED, THESIS_UPLOAD_REMIND, CANCELLED
+    }
 
+    @Basic
+    @Column(name = "event")
     @Enumerated(EnumType.STRING)
     private Event event;
 
+    @ManyToOne
+    @JoinColumn(name = "final_seminar_id", referencedColumnName = "id")
+    private FinalSeminar seminar;
+
     public SeminarEvent() {
         super(Notification.Type.FINAL_SEMINAR);
     }
 
-    public FinalSeminar getSeminar() {
-        return seminar;
-    }
-
-    public void setSeminar(FinalSeminar seminar) {
-        this.seminar = seminar;
-    }
-
     @Override
     public Event getEvent() {
         return event;
@@ -42,6 +42,14 @@ public class SeminarEvent extends NotificationEvent {
         this.event = event;
     }
 
+    public FinalSeminar getSeminar() {
+        return seminar;
+    }
+
+    public void setSeminar(FinalSeminar seminar) {
+        this.seminar = seminar;
+    }
+
     @Override
     public String getEntityTitle() {
         return seminar.getProject().getTitle();
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java
index cdf67a52d4..b8aeadcb99 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/interfaces/impl/NotificationMailFormatterImpl.java
@@ -8,7 +8,6 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.finalseminar.FinalSeminarService;
 import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettings;
 import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
-import se.su.dsv.scipro.notifications.NotificationModule;
 import se.su.dsv.scipro.notifications.dataobject.*;
 import se.su.dsv.scipro.notifications.interfaces.NotificationMailFormatter;
 import se.su.dsv.scipro.project.Project;
@@ -158,7 +157,7 @@ public class NotificationMailFormatterImpl implements NotificationMailFormatter
     private String getAbsoluteURL(final Notification notification) {
         final String baseUrl = systemSettingsService.getGeneralSystemSettingsInstance().getSciproURL();
         long id = notification.getNotificationEvent().getId();
-        return baseUrl + "/" + NotificationModule.NOTIFICATION_RELATIVE_PAGE_URL + "?id=" + id;
+        return baseUrl + "/" + "notification" + "?id=" + id;
     }
 
     String makeProperty(Object... parts) {
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
index a972eac30e..c5cb11b76a 100755
--- a/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/notifications.properties
@@ -85,6 +85,13 @@ PROJECT.PARTICIPATION_APPROVED.body = Your active participation on {0} has been
 PROJECT.PARTICIPATION_FAILED.title = Your active participation on {1} did not meet the minimum requirements.
 PROJECT.PARTICIPATION_FAILED.body = Your active participation did not meet the minimum requirements set, and you will \
   have to be an active participant on a different final seminar to pass this step.
+PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.title = Reflection improvements requested
+PROJECT.REFLECTION_IMPROVEMENTS_REQUESTED.body = The supervisor has deemed that the reflection submitted does not meet \
+  the minimum requirements and has requested improvements. Please log into SciPro and submit a new reflection. \
+  Their comments can be seen below:\n\n{0}
+PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.title = Reflection improvements submitted
+PROJECT.REFLECTION_IMPROVEMENTS_SUBMITTED.body = The reflection improvements have been submitted. \
+  \n\n{0}
 
 FORUM.NEW_FORUM_POST.title = Forum post: {2}
 FORUM.NEW_FORUM_POST.body = New forum post submitted:<br /><br />{0}
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java
index 65af5aaa5c..7e20fa7ffb 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/entities/DeliveryConfiguration.java
@@ -1,14 +1,21 @@
 package se.su.dsv.scipro.notifications.settings.entities;
 
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import jakarta.persistence.UniqueConstraint;
+
 import se.su.dsv.scipro.notifications.dataobject.Notification;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-
 @Entity
 @Table(name = "notification_delivery_configuration",
        uniqueConstraints = {
-               @UniqueConstraint(name = "one_setting_per_user", columnNames = {"type", "event", "method", "user_id"})
+               @UniqueConstraint(name = "uk_one_setting_per_user", columnNames = {"type", "event", "method", "user_id"})
        })
 public class DeliveryConfiguration extends Configuration {
 
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java
index 285b9f6c0a..75f7624ac6 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/DeliveryConfigurationServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.notifications.settings.service;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.notifications.dataobject.Notification;
 import se.su.dsv.scipro.notifications.dataobject.Notification.Type;
 import se.su.dsv.scipro.notifications.settings.entities.DeliveryConfiguration;
diff --git a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java
index 37befe6c34..596c2e3821 100644
--- a/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/notifications/settings/service/ReceiverConfigurationServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.notifications.settings.service;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.notifications.dataobject.Notification;
 import se.su.dsv.scipro.notifications.settings.entities.QReceiverConfiguration;
diff --git a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java
deleted file mode 100644
index bce825afe1..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthModule.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package se.su.dsv.scipro.oauth;
-
-import com.google.inject.PrivateModule;
-import com.google.inject.Provides;
-
-import jakarta.inject.Named;
-
-public class OAuthModule extends PrivateModule {
-    @Override
-    protected void configure() {
-        bind(OAuthService.class).to(OAuthServiceImpl.class);
-
-        expose(OAuthService.class);
-    }
-
-    @Provides
-    OAuthSettings settings(
-        @Named("oauth.uri") String uri,
-        @Named("oauth.redirectUri") String redirectUri,
-        @Named("oauth.clientId") String clientId,
-        @Named("oauth.clientSecret") String clientSecret)
-    {
-        return new OAuthSettings(uri, redirectUri, clientId, clientSecret);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java
index a8b41b8648..2a20bcf204 100644
--- a/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/oauth/OAuthSettings.java
@@ -1,4 +1,4 @@
 package se.su.dsv.scipro.oauth;
 
-record OAuthSettings(String uri, String redirectUri, String clientId, String clientSecret) {
+public record OAuthSettings(String uri, String redirectUri, String clientId, String clientSecret) {
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/Answer.java b/core/src/main/java/se/su/dsv/scipro/peer/Answer.java
index fd7b4b0ca4..bf40f7d72e 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/Answer.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/Answer.java
@@ -1,80 +1,115 @@
 package se.su.dsv.scipro.peer;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.checklist.ChecklistAnswerEnum;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name="answer")
 @Cacheable(true)
 public class Answer extends DomainObject {
+	// ----------------------------------------------------------------------------------
+	// basic JPA-mappings
+	// ----------------------------------------------------------------------------------
     @Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
-	
+
+	@Basic(optional = false)
+	@Column(name = "question")
+	private String question;
+
+	@Enumerated(EnumType.STRING)
+	@Column(name = "answer", nullable=false)
+	private ChecklistAnswerEnum answer = ChecklistAnswerEnum.NO_ANSWER;
+
+	@Basic(optional=true)
+	@Lob
+	@Column(name = "motivation")
+	private String motivation;
+
+	// ----------------------------------------------------------------------------------
+	// JPA-mappings of foreign keys in this table (answer) referencing other tables.
+	// ----------------------------------------------------------------------------------
 	@ManyToOne(optional=false)
+	@JoinColumn(name = "peer_review_id", referencedColumnName = "id")
 	private PeerReview peerReview;
 
-    @Basic(optional = false)
-	private String question;
-	
-	@Lob
-	@Basic(optional=true)
-	private String motivation;
-	
-	@Enumerated(EnumType.STRING)
-	@Column(nullable=false)
-	private ChecklistAnswerEnum answer = ChecklistAnswerEnum.NO_ANSWER;
-	
+	// ----------------------------------------------------------------------------------
+	// constructors
+	// ----------------------------------------------------------------------------------
 	public Answer() {}
+
 	public Answer(PeerReview peerReview, String question){
 		this.peerReview = peerReview;
 		this.question = question;
 	}
 
+	// ----------------------------------------------------------------------------------
+	// getters and setters
+	// ----------------------------------------------------------------------------------
 	@Override
 	public Long getId() {
 		return this.id;
 	}
 
-	public PeerReview getPeerReview() {
-		return this.peerReview;
-	}
-
-	public String getQuestion() {
-		return this.question;
-	}
-
-	public String getMotivation() {
-		return this.motivation;
-	}
-
-	public ChecklistAnswerEnum getAnswer() {
-		return this.answer;
-	}
-
 	public void setId(Long id) {
 		this.id = id;
 	}
 
-	public void setPeerReview(PeerReview peerReview) {
-		this.peerReview = peerReview;
+	public String getQuestion() {
+		return this.question;
 	}
 
 	public void setQuestion(String question) {
 		this.question = question;
 	}
 
-	public void setMotivation(String motivation) {
-		this.motivation = motivation;
+	public ChecklistAnswerEnum getAnswer() {
+		return this.answer;
 	}
 
 	public void setAnswer(ChecklistAnswerEnum answer) {
 		this.answer = answer;
 	}
 
+	public String getMotivation() {
+		return this.motivation;
+	}
+
+	public void setMotivation(String motivation) {
+		this.motivation = motivation;
+	}
+
+	public PeerReview getPeerReview() {
+		return this.peerReview;
+	}
+
+	public void setPeerReview(PeerReview peerReview) {
+		this.peerReview = peerReview;
+	}
+
+	// ----------------------------------------------------------------------------------
+	// other methods
+	// ----------------------------------------------------------------------------------
+	protected boolean canEqual(final Object other) {
+		return other instanceof Answer;
+	}
+
 	@Override
 	public boolean equals(final Object o) {
 		if (o == this) return true;
@@ -84,10 +119,6 @@ public class Answer extends DomainObject {
 				&& Objects.equals(this.getId(), other.getId());
 	}
 
-	protected boolean canEqual(final Object other) {
-		return other instanceof Answer;
-	}
-
 	@Override
 	public int hashCode() {
 		return Objects.hashCode(this.getId());
@@ -95,6 +126,7 @@ public class Answer extends DomainObject {
 
 	@Override
 	public String toString() {
-		return "Answer(id=" + this.getId() + ", question=" + this.getQuestion() + ", motivation=" + this.getMotivation() + ", answer=" + this.getAnswer() + ")";
+		return "Answer(id=" + this.getId() + ", question=" + this.getQuestion() + ", motivation=" +
+				this.getMotivation() + ", answer=" + this.getAnswer() + ")";
 	}
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/Comment.java b/core/src/main/java/se/su/dsv/scipro/peer/Comment.java
index 32d3fe771d..bb5c68db96 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/Comment.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/Comment.java
@@ -1,9 +1,19 @@
 package se.su.dsv.scipro.peer;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Comparator;
 
@@ -16,12 +26,16 @@ public class Comment extends DomainObject {
     private Long id;
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "creator_user_id", referencedColumnName = "id")
     private User creator;
 
+    @Basic
+    @Column(name = "comment")
     @Lob
     private String comment;
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "comment_thread_id", referencedColumnName = "id")
     private CommentThread commentThread;
 
     protected Comment() {
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java
index db26096621..63723ecf16 100644
--- a/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentServiceImpl.java
@@ -10,7 +10,7 @@ import java.util.List;
 public class CommentServiceImpl extends AbstractServiceImpl<Comment, Long> implements CommentService {
 
     @Inject
-    protected CommentServiceImpl(Provider<EntityManager> em) {
+    public CommentServiceImpl(Provider<EntityManager> em) {
         super(em, Comment.class, QComment.comment1);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java
index d90511945c..803fb375af 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThread.java
@@ -8,7 +8,9 @@ import java.util.Set;
 import java.util.TreeSet;
 
 @Entity
-@Table(name = "comment_thread", uniqueConstraints = {@UniqueConstraint(columnNames = {"commentableKey", "commentableId"})})
+@Table(name = "comment_thread",
+        uniqueConstraints = {@UniqueConstraint(name = "uk_comment_thread_id_key",
+                                               columnNames = {"commentable_key", "commentable_id"})})
 @Cacheable(true)
 public class CommentThread extends DomainObject {
 
@@ -16,11 +18,10 @@ public class CommentThread extends DomainObject {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Basic(optional = false)
-    @Column(length = 191)
+    @Column(name = "commentable_key", length = 191, nullable = false)
     private String commentableKey;
 
-    @Basic(optional = false)
+    @Column(name = "commentable_id", nullable = false)
     private Long commentableId;
 
     @OneToMany(mappedBy = "commentThread", orphanRemoval = true, cascade = CascadeType.ALL, targetEntity = Comment.class)
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java
index 025bb02da1..8210abd3c5 100644
--- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.peer;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java
index 82d1e68e53..604e36b9a5 100644
--- a/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/CommentThreadServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.peer;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 import jakarta.inject.Inject;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java
deleted file mode 100644
index 0fdd05980c..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerModule.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package se.su.dsv.scipro.peer;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.multibindings.Multibinder;
-import se.su.dsv.scipro.system.Lifecycle;
-
-public class PeerModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        Multibinder.newSetBinder(binder(), Lifecycle.class)
-                .addBinding().to(PeerWorkerSchedules.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java
index 5582001f6a..aa6b178072 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerPortalImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.peer;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import se.su.dsv.scipro.file.FileReference;
@@ -152,7 +152,7 @@ public class PeerPortalImpl implements PeerPortal, PerformReviewService {
     }
 
     @Override
-    @Transactional(ignore = {TooShortCommentException.class, MissingAnswerException.class})
+    @Transactional(dontRollbackOn = {TooShortCommentException.class, MissingAnswerException.class})
     public void submit(PeerReview review, Optional<FileUpload> upload) {
         review.submit();
         final Optional<FileReference> fileDescription = storePeerReviewFileUpload(upload);
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java
index 8bf04b8d37..addf9fff54 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequest.java
@@ -1,7 +1,20 @@
 package se.su.dsv.scipro.peer;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
 import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.checklist.ChecklistTemplate;
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.file.FileReference;
@@ -10,57 +23,138 @@ import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.Language;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.Basic;
-import jakarta.persistence.Cacheable;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.EnumType;
-import jakarta.persistence.Enumerated;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.Lob;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.OneToMany;
-import jakarta.persistence.Table;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 
 @Entity
 @Table(name = "peer_request")
 @Cacheable(true)
 public class PeerRequest extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Lob
     @Basic(optional = true)
+    @Lob
+    @Column(name = "comment")
     private String comment;
 
-    @ManyToOne(optional = false)
-    @QueryInit({"headSupervisor", "projectType"})
-    private Project project;
-
-    @ManyToOne(optional = false)
-    private User requester;
-
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "file_reference_id")
-    private FileReference file;
-
-    @ManyToOne(optional = true)
-    private ChecklistTemplate checklistTemplate;
+    @Enumerated(EnumType.STRING)
+    @Column(name = "status", nullable = false)
+    private RequestStatus status = RequestStatus.WAITING;
 
     @Enumerated(EnumType.STRING)
     private Language language;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (peer_request) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = true)
+    @JoinColumn(name = "checklist_template_id", referencedColumnName = "id")
+    private ChecklistTemplate checklistTemplate;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "file_reference_id", referencedColumnName = "id")
+    private FileReference file;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    @QueryInit({"headSupervisor", "projectType"})
+    private Project project;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "requester_user_id", referencedColumnName = "id")
+    private User requester;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "peer_request"
+    // ----------------------------------------------------------------------------------
     @OneToMany(mappedBy = "peerRequest")
     private List<PeerReview> peerReviews = new ArrayList<>(1);
 
-    @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
-    private RequestStatus status = RequestStatus.WAITING;
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
 
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getComment() {
+        return this.comment;
+    }
+
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    public RequestStatus getStatus() {
+        return this.status;
+    }
+
+    public void setStatus(RequestStatus status) {
+        this.status = status;
+    }
+
+    public Language getLanguage() {
+        return this.language;
+    }
+
+    public void setLanguage(Language language) {
+        this.language = language;
+    }
+
+    public ChecklistTemplate getChecklistTemplate() {
+        return this.checklistTemplate;
+    }
+
+    public void setChecklistTemplate(ChecklistTemplate checklistTemplate) {
+        this.checklistTemplate = checklistTemplate;
+    }
+
+    public FileReference getFile() {
+        return this.file;
+    }
+
+    public void setFile(FileReference file) {
+        this.file = file;
+    }
+
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public User getRequester() {
+        return this.requester;
+    }
+
+    public void setRequester(User requester) {
+        this.requester = requester;
+    }
+
+    public List<PeerReview> getPeerReviews() {
+        return this.peerReviews;
+    }
+
+    public void setPeerReviews(List<PeerReview> peerReviews) {
+        this.peerReviews = peerReviews;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
     public List<Member> getMembers() {
         List<Member> members = project.getMembers();
 
@@ -80,77 +174,8 @@ public class PeerRequest extends DomainObject {
         return null;
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public String getComment() {
-        return this.comment;
-    }
-
-    public Project getProject() {
-        return this.project;
-    }
-
-    public User getRequester() {
-        return this.requester;
-    }
-
-    public FileReference getFile() {
-        return this.file;
-    }
-
-    public ChecklistTemplate getChecklistTemplate() {
-        return this.checklistTemplate;
-    }
-
-    public Language getLanguage() {
-        return this.language;
-    }
-
-    public List<PeerReview> getPeerReviews() {
-        return this.peerReviews;
-    }
-
-    public RequestStatus getStatus() {
-        return this.status;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setComment(String comment) {
-        this.comment = comment;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public void setRequester(User requester) {
-        this.requester = requester;
-    }
-
-    public void setFile(FileReference file) {
-        this.file = file;
-    }
-
-    public void setChecklistTemplate(ChecklistTemplate checklistTemplate) {
-        this.checklistTemplate = checklistTemplate;
-    }
-
-    public void setLanguage(Language language) {
-        this.language = language;
-    }
-
-    public void setPeerReviews(List<PeerReview> peerReviews) {
-        this.peerReviews = peerReviews;
-    }
-
-    public void setStatus(RequestStatus status) {
-        this.status = status;
+    protected boolean canEqual(final Object other) {
+        return other instanceof PeerRequest;
     }
 
     @Override
@@ -162,10 +187,6 @@ public class PeerRequest extends DomainObject {
                 && Objects.equals(this.getId(), other.getId());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof PeerRequest;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hashCode(this.getId());
@@ -173,6 +194,9 @@ public class PeerRequest extends DomainObject {
 
     @Override
     public String toString() {
-        return "PeerRequest(id=" + this.getId() + ", comment=" + this.getComment() + ", project=" + this.getProject() + ", requester=" + this.getRequester() + ", file=" + this.getFile() + ", checklistTemplate=" + this.getChecklistTemplate() + ", language=" + this.getLanguage() + ", status=" + this.getStatus() + ")";
+        return "PeerRequest(id=" + this.getId() + ", comment=" + this.getComment() + ", project=" +
+                this.getProject() + ", requester=" + this.getRequester() + ", file=" + this.getFile() +
+                ", checklistTemplate=" + this.getChecklistTemplate() + ", language=" + this.getLanguage() +
+                ", status=" + this.getStatus() + ")";
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java
index d6ca147c68..1a5c7439ff 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.peer;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java
index b79394efd6..ad77dcfe22 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerRequestServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.peer;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import se.su.dsv.scipro.system.Pageable;
diff --git a/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java b/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java
index e721778e38..7ce7378d1d 100755
--- a/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java
+++ b/core/src/main/java/se/su/dsv/scipro/peer/PeerReview.java
@@ -1,6 +1,24 @@
 package se.su.dsv.scipro.peer;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.OrderBy;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.checklist.ChecklistAnswerEnum;
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.file.FileReference;
@@ -8,7 +26,6 @@ import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -23,41 +40,140 @@ public class PeerReview extends DomainObject implements Commentable {
     public enum ReviewStatus {
 		IN_PROGRESS, COMPLETED, EXPIRED
 	}
-	
+
+    // ----------------------------------------------------------------------------------
+    // basic JPA-mappings
+    // ----------------------------------------------------------------------------------
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
-	
+
+    @Basic
+    @Lob
+    @Column(name = "comment")
+    private String comment;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "status")
+    private ReviewStatus status = ReviewStatus.IN_PROGRESS;
+
+    @Basic(optional = false)
+    @Column(name = "deadline")
+    private Date deadline;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (peer_review) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional=true, orphanRemoval = true, cascade = CascadeType.ALL)
+    @JoinColumn(name = "file_reference_id", referencedColumnName = "id")
+    private FileReference file;
+
+    @ManyToOne(optional=false)
+    @JoinColumn(name = "peer_request_id", referencedColumnName = "id")
+    @QueryInit({"project.headSupervisor", "requester.user", "language", "checklistTemplate"})
+    private PeerRequest peerRequest;
+
+    @ManyToOne(optional=false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    @QueryInit({"headSupervisor", "projectType"})
+    private Project project;
+
 	@ManyToOne(optional=false)
+    @JoinColumn(name = "reviewer_user_id", referencedColumnName = "id")
 	@QueryInit("*.*")
 	private User reviewer;
-	
-	@ManyToOne(optional=false)
-	@QueryInit({"headSupervisor", "projectType"})
-	private Project project;
-	
-	@ManyToOne(optional=false)
-	@QueryInit({"project.headSupervisor","requester.user", "language", "checklistTemplate"})
-	private PeerRequest peerRequest;	
-	
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "peer_review"
+    // ----------------------------------------------------------------------------------
 	@OneToMany(mappedBy="peerReview", orphanRemoval=true, cascade=CascadeType.ALL)
 	@OrderBy("id")
 	private List<Answer> answers = new ArrayList<>();
 
-	@OneToOne(optional=true, orphanRemoval = true, cascade = CascadeType.ALL)
-    @JoinColumn(name = "file_reference_id")
-	private FileReference file;
-	
-	@Lob
-	private String comment;
+    // ----------------------------------------------------------------------------------
+    // getters and setters
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
+    }
 
-    @Enumerated(EnumType.STRING)
-    private ReviewStatus status = ReviewStatus.IN_PROGRESS;
+    public void setId(Long id) {
+        this.id = id;
+    }
 
-    @Basic(optional = false)
-    private Date deadline;
+    public String getComment() {
+        return this.comment;
+    }
 
-	@Override
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    public ReviewStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(ReviewStatus status) {
+        this.status = status;
+    }
+
+    public Date getDeadline() {
+        return this.deadline;
+    }
+
+    public void setDeadline(Date deadline) {
+        this.deadline = deadline;
+    }
+
+    public FileReference getFile() {
+        return this.file;
+    }
+
+    public void setFile(FileReference file) {
+        this.file = file;
+    }
+
+    public PeerRequest getPeerRequest() {
+        return this.peerRequest;
+    }
+
+    public void setPeerRequest(PeerRequest peerRequest) {
+        this.peerRequest = peerRequest;
+    }
+
+    public Project getProject() {
+        return this.project;
+    }
+
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public User getReviewer() {
+        return this.reviewer;
+    }
+
+    public void setReviewer(User reviewer) {
+        this.reviewer = reviewer;
+    }
+
+    public List<Answer> getAnswers() {
+        return this.answers;
+    }
+
+    public void setAnswers(List<Answer> answers) {
+        this.answers = answers;
+    }
+
+    public void addAnswer(String question) {
+        this.answers.add(new Answer(this, question));
+    }
+
+    // ----------------------------------------------------------------------------------
+    // other methods
+    // ----------------------------------------------------------------------------------
+    @Override
 	public final String getCommentKey() {
 		return PeerReview.class.getCanonicalName();
 	}
@@ -73,10 +189,6 @@ public class PeerReview extends DomainObject implements Commentable {
         return new Date().after(getDeadline());
     }
 
-    public ReviewStatus getStatus() {
-        return status;
-    }
-
     public boolean isExpired() {
         return status == ReviewStatus.EXPIRED;
     }
@@ -97,90 +209,12 @@ public class PeerReview extends DomainObject implements Commentable {
         setStatus(isLate() ? ReviewStatus.EXPIRED : ReviewStatus.COMPLETED);
     }
 
-    private static boolean isEmpty(String s) {
-        return s == null || s.isBlank();
-    }
-
     public void expire() {
         status = ReviewStatus.EXPIRED;
     }
 
-    public void addAnswer(String question) {
-        this.answers.add(new Answer(this, question));
-    }
-
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public User getReviewer() {
-        return this.reviewer;
-    }
-
-    public Project getProject() {
-        return this.project;
-    }
-
-    public PeerRequest getPeerRequest() {
-        return this.peerRequest;
-    }
-
-    public List<Answer> getAnswers() {
-        return this.answers;
-    }
-
-    public FileReference getFile() {
-        return this.file;
-    }
-
-    public String getComment() {
-        return this.comment;
-    }
-
-    public Date getDeadline() {
-        return this.deadline;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setReviewer(User reviewer) {
-        this.reviewer = reviewer;
-    }
-
-    public void setProject(Project project) {
-        this.project = project;
-    }
-
-    public void setPeerRequest(PeerRequest peerRequest) {
-        this.peerRequest = peerRequest;
-    }
-
-    public void setAnswers(List<Answer> answers) {
-        this.answers = answers;
-    }
-
-    public void setFile(FileReference file) {
-        this.file = file;
-    }
-
-    public void setComment(String comment) {
-        this.comment = comment;
-    }
-
-    public void setStatus(ReviewStatus status) {
-        this.status = status;
-    }
-
-    public void setDeadline(Date deadline) {
-        this.deadline = deadline;
-    }
-
-    @Override
-    public String toString() {
-        return "PeerReview(id=" + this.getId() + ", reviewer=" + this.getReviewer() + ", project=" + this.getProject() + ", peerRequest=" + this.getPeerRequest() + ", answers=" + this.getAnswers() + ", file=" + this.getFile() + ", comment=" + this.getComment() + ", status=" + this.getStatus() + ", deadline=" + this.getDeadline() + ")";
+    protected boolean canEqual(final Object other) {
+        return other instanceof PeerReview;
     }
 
     @Override
@@ -192,12 +226,23 @@ public class PeerReview extends DomainObject implements Commentable {
                 && Objects.equals(this.getId(), other.getId());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof PeerReview;
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
     }
 
     @Override
-    public int hashCode() {
-	    return Objects.hashCode(this.getId());
+    public String toString() {
+        return "PeerReview(id=" + this.getId() + ", reviewer=" + this.getReviewer() + ", project=" +
+                this.getProject() + ", peerRequest=" + this.getPeerRequest() + ", answers=" + this.getAnswers() +
+                ", file=" + this.getFile() + ", comment=" + this.getComment() + ", status=" + this.getStatus() +
+                ", deadline=" + this.getDeadline() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Static helper methods
+    // ----------------------------------------------------------------------------------
+    private static boolean isEmpty(String s) {
+        return s == null || s.isBlank();
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java
index b21bd32fe9..d72913163d 100755
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismControlImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.plagiarism;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileDescription;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java
deleted file mode 100644
index 3f862ea21c..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismModule.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package se.su.dsv.scipro.plagiarism;
-
-import com.google.inject.AbstractModule;
-
-public class PlagiarismModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(PlagiarismControl.class).to(PlagiarismControlImpl.class);
-        bind(PlagiarismRequestRepository.class).to(PlagiarismRequestRepositoryImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java
index 3356526223..1aece5bd51 100644
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/PlagiarismRequest.java
@@ -11,46 +11,61 @@ import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.Table;
-import java.util.*;
+
+import java.util.Objects;
 
 @Entity
 @Table(name = "plagiarism_request")
 class PlagiarismRequest {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (plagiarism_request) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @OneToOne(optional = false)
-    @JoinColumn(name = "document_reference_id")
+    @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id")
     private FileReference document;
 
     @ManyToOne
+    @JoinColumn(name = "receiver_user_id", referencedColumnName = "id")
     private User receiver;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return this.id;
     }
 
-    public FileReference getDocument() {
-        return this.document;
-    }
-
-    public User getReceiver() {
-        return this.receiver;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
+    public FileReference getDocument() {
+        return this.document;
+    }
+
     public void setDocument(FileReference fileDescription) {
         this.document = fileDescription;
     }
 
+    public User getReceiver() {
+        return this.receiver;
+    }
+
     public void setReceiver(User receiver) {
         this.receiver = receiver;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -62,10 +77,6 @@ class PlagiarismRequest {
                 && Objects.equals(this.getReceiver(), other.getReceiver());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof PlagiarismRequest;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getDocument(), this.getReceiver());
@@ -73,6 +84,14 @@ class PlagiarismRequest {
 
     @Override
     public String toString() {
-        return "PlagiarismRequest(id=" + this.getId() + ", fileDescription=" + this.getDocument() + ", receiver=" + this.getReceiver() + ")";
+        return "PlagiarismRequest(id=" + this.getId() + ", fileDescription=" + this.getDocument() +
+                ", receiver=" + this.getReceiver() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other method
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof PlagiarismRequest;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java
index 774dfdda3a..5a5f58f929 100644
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundApiImpl.java
@@ -36,7 +36,7 @@ public class UrkundApiImpl implements UrkundApi {
     private final FileService fileService;
 
     @Inject
-    UrkundApiImpl(final UrkundSettingsRepository urkundSettingsRepository, FileService fileService) {
+    public UrkundApiImpl(final UrkundSettingsRepository urkundSettingsRepository, FileService fileService) {
         this.urkundSettingsRepository = urkundSettingsRepository;
         this.fileService = fileService;
         objectMapper = new ObjectMapper();
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java
deleted file mode 100644
index 573a3a5559..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundModule.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package se.su.dsv.scipro.plagiarism.urkund;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-import com.google.inject.Scopes;
-import se.su.dsv.scipro.sukat.Sukat;
-
-import jakarta.persistence.EntityManager;
-
-public class UrkundModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(UrkundService.class).to(UrkundServiceImpl.class);
-        bind(UrkundSubmissionRepository.class).to(UrkundSubmissionRepositoryImpl.class);
-        bind(UrkundApi.class).to(UrkundApiImpl.class).in(Scopes.SINGLETON);
-        bind(UrkundSettingsRepository.class).to(UrkundSettingsRepositoryImpl.class);
-
-        requireBinding(EntityManager.class);
-        requireBinding(Sukat.class);
-    }
-
-    @Provides
-    public UrkundSettings urkundSettings(UrkundSettingsRepository urkundSettingsRepository) {
-        return urkundSettingsRepository.getSettings();
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java
index 8eac423c9b..e83125690b 100644
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.plagiarism.urkund;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileDescription;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java
index 74716b4e56..fa97b51a46 100644
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettings.java
@@ -1,9 +1,11 @@
 package se.su.dsv.scipro.plagiarism.urkund;
 
 import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.Id;
 import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
@@ -15,12 +17,15 @@ public class UrkundSettings {
     private long id = ID;
 
     @Basic
+    @Column(name = "enabled")
     private boolean enabled = false;
 
     @Basic
+    @Column(name = "username")
     private String username;
 
     @Basic
+    @Column(name = "password")
     private String password;
 
     public boolean isEnabled() {
@@ -70,6 +75,7 @@ public class UrkundSettings {
 
     @Override
     public String toString() {
-        return "UrkundSettings(id=" + this.id + ", enabled=" + this.isEnabled() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")";
+        return "UrkundSettings(id=" + this.id + ", enabled=" + this.isEnabled() + ", username=" +
+                this.getUsername() + ", password=" + this.getPassword() + ")";
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java
index 594dd691fc..87580259a7 100644
--- a/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java
+++ b/core/src/main/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmission.java
@@ -17,139 +17,159 @@ import jakarta.persistence.ManyToOne;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.Table;
 import java.time.Instant;
-import java.util.*;
+import java.util.Objects;
 
 @Entity
 @Table(name = "urkund_submission")
 public class UrkundSubmission extends DomainObject {
-
-    public enum State {
-        SUBMISSION_FAILED, SUBMITTED, REJECTED, ACCEPTED, ANALYZED, ERROR;
-
-        public boolean isFinal() {
-            return !(this == SUBMITTED || this == ACCEPTED);
-        }
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne
-    private User receiver;
+    @Basic
+    @Column(name = "submitted_date", nullable = false)
+    private Instant submitted;
 
     @Basic
-    private String analysisAddress;
-
-    @Column(nullable = false)
+    @Column(name = "state", nullable = false)
     @Enumerated(EnumType.STRING)
     private State state;
 
-    @Column(nullable = false)
-    private Instant submitted;
-
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "next_poll_date", nullable = false)
     private Instant nextPoll;
 
-    @Column(nullable = false)
+    @Basic
+    @Column(name = "polling_delay", nullable = false)
     @Enumerated(EnumType.STRING)
     private PollingDelay pollingDelay = PollingDelay.FIRST;
 
-    @OneToOne(optional = false)
-    @JoinColumn(name = "document_reference_id")
-    private FileReference document;
-
     @Basic(optional = false)
+    @Column(name = "message")
     private String message;
 
     @Basic
+    @Column(name = "report_url")
     private String reportUrl;
 
     @Basic
+    @Column(name = "significance")
     private Float significance;
 
+    @Basic
+    @Column(name = "analysis_address")
+    private String analysisAddress;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (urkund_submission) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = false)
+    @JoinColumn(name = "document_file_reference_id", referencedColumnName = "id")
+    private FileReference document;
+
+    @ManyToOne
+    @JoinColumn(name = "receiver_user_id", referencedColumnName = "id")
+    private User receiver;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public String getAnalysisAddress() {
-        return this.analysisAddress;
-    }
-
-    public State getState() {
-        return this.state;
-    }
-
-    public Instant getSubmitted() {
-        return this.submitted;
-    }
-
-    public FileReference getDocument() {
-        return this.document;
-    }
-
-    public String getMessage() {
-        return this.message;
-    }
-
-    public String getReportUrl() {
-        return this.reportUrl;
-    }
-
-    public Float getSignificance() {
-        return this.significance;
-    }
-
-    @Override
-    public String toString() {
-        return "UrkundSubmission(id=" + this.getId() + ", receiver=" + this.getReceiver() + ", analysisAddress=" + this.getAnalysisAddress() + ", state=" + this.getState() + ", submitted=" + this.getSubmitted() + ", nextPoll=" + this.getNextPoll() + ", pollingDelay=" + this.getPollingDelay() + ", fileDescription=" + this.getDocument() + ", message=" + this.getMessage() + ", reportUrl=" + this.getReportUrl() + ", significance=" + this.getSignificance() + ")";
-    }
-
     void setId(Long id) {
         this.id = id;
     }
 
-    void setReceiver(User receiver) {
-        this.receiver = receiver;
-    }
-
-    void setAnalysisAddress(String analysisAddress) {
-        this.analysisAddress = analysisAddress;
-    }
-
-    void setState(State state) {
-        this.state = state;
+    public Instant getSubmitted() {
+        return this.submitted;
     }
 
     void setSubmitted(Instant submitted) {
         this.submitted = submitted;
     }
 
+    public State getState() {
+        return this.state;
+    }
+
+    void setState(State state) {
+        this.state = state;
+    }
+
+    Instant getNextPoll() {
+        return this.nextPoll;
+    }
+
     void setNextPoll(Instant nextPoll) {
         this.nextPoll = nextPoll;
     }
 
+    PollingDelay getPollingDelay() {
+        return this.pollingDelay;
+    }
+
     void setPollingDelay(PollingDelay pollingDelay) {
         this.pollingDelay = pollingDelay;
     }
 
-    void setDocument(FileReference fileDescription) {
-        this.document = fileDescription;
+    public String getMessage() {
+        return this.message;
     }
 
     void setMessage(String message) {
         this.message = message;
     }
 
+    public String getReportUrl() {
+        return this.reportUrl;
+    }
+
     void setReportUrl(String reportUrl) {
         this.reportUrl = reportUrl;
     }
 
+    public Float getSignificance() {
+        return this.significance;
+    }
+
     void setSignificance(Float significance) {
         this.significance = significance;
     }
 
+    public String getAnalysisAddress() {
+        return this.analysisAddress;
+    }
+
+    void setAnalysisAddress(String analysisAddress) {
+        this.analysisAddress = analysisAddress;
+    }
+
+    public FileReference getDocument() {
+        return this.document;
+    }
+
+    void setDocument(FileReference fileDescription) {
+        this.document = fileDescription;
+    }
+
+    User getReceiver() {
+        return this.receiver;
+    }
+
+    void setReceiver(User receiver) {
+        this.receiver = receiver;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -170,10 +190,6 @@ public class UrkundSubmission extends DomainObject {
                 && Objects.equals(this.getSignificance(), other.getSignificance());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof UrkundSubmission;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(
@@ -190,15 +206,31 @@ public class UrkundSubmission extends DomainObject {
                 this.getSignificance());
     }
 
-    User getReceiver() {
-        return this.receiver;
+    @Override
+    public String toString() {
+        return "UrkundSubmission(id=" + this.getId() + ", receiver=" + this.getReceiver() +
+                ", analysisAddress=" + this.getAnalysisAddress() + ", state=" +
+                this.getState() + ", submitted=" + this.getSubmitted() +
+                ", nextPoll=" + this.getNextPoll() + ", pollingDelay=" + this.getPollingDelay() +
+                ", fileDescription=" + this.getDocument() + ", message=" + this.getMessage() +
+                ", reportUrl=" + this.getReportUrl() + ", significance=" + this.getSignificance() + ")";
     }
 
-    Instant getNextPoll() {
-        return this.nextPoll;
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof UrkundSubmission;
     }
 
-    PollingDelay getPollingDelay() {
-        return this.pollingDelay;
+    // ----------------------------------------------------------------------------------
+    // Nested type
+    // ----------------------------------------------------------------------------------
+    public enum State {
+        SUBMISSION_FAILED, SUBMITTED, REJECTED, ACCEPTED, ANALYZED, ERROR;
+
+        public boolean isFinal() {
+            return !(this == SUBMITTED || this == ACCEPTED);
+        }
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java b/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java
index 679ba53157..6bf6f2bd19 100755
--- a/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java
+++ b/core/src/main/java/se/su/dsv/scipro/profiles/CurrentProfile.java
@@ -1,14 +1,10 @@
 package se.su.dsv.scipro.profiles;
 
-import jakarta.inject.Inject;
-import jakarta.inject.Named;
-
 public class CurrentProfile {
 
     private String currentProfileString;
 
-    @Inject
-    public void setCurrentProfileString(@Named("profile") String currentProfileString) {
+    public void setCurrentProfileString(String currentProfileString) {
         this.currentProfileString = currentProfileString;
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/project/Author.java b/core/src/main/java/se/su/dsv/scipro/project/Author.java
index c3094e697c..96ec7ce284 100644
--- a/core/src/main/java/se/su/dsv/scipro/project/Author.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/Author.java
@@ -1,26 +1,45 @@
 package se.su.dsv.scipro.project;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.EmbeddedId;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapsId;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
 @Table(name = "project_user")
 public class Author {
+    // ----------------------------------------------------------------------------------
+    // Embedded JPA-mapping
+    // ----------------------------------------------------------------------------------
     @EmbeddedId
     private AuthorPK authorPK;
 
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "project_id", nullable = false)
-    @MapsId("projectId")
-    private Project project;
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @Basic(optional = true)
+    @Column(name = "reflection")
+    private String reflection;
 
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "user_id", nullable = false)
-    @MapsId("userId")
-    private User user;
+    @Basic
+    @Enumerated(EnumType.STRING)
+    @Column(name = "reflection_status")
+    private ReflectionStatus reflectionStatus = ReflectionStatus.NOT_SUBMITTED;
+
+    @Basic
+    @Column(name = "reflection_comment_by_supervisor")
+    private String reflectionSupervisorComment;
 
     /**
      * If this author wants to be notified when a final seminar created
@@ -36,15 +55,29 @@ public class Author {
     @Column(name = "subscribed_to_final_seminar_notifications", nullable = false, columnDefinition = "BOOLEAN DEFAULT FALSE")
     private boolean subscribedToFinalSeminarNotifications;
 
-    @Basic(optional = true)
-    private String reflection;
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (project_user) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", nullable = false)
+    @MapsId("projectId")
+    private Project project;
 
-    public Project getProject() {
-        return project;
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "user_id", nullable = false)
+    @MapsId("userId")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public String getReflection() {
+        return reflection;
     }
 
-    public User getUser() {
-        return user;
+    public void setReflection(String reflection) {
+        this.reflection = reflection;
     }
 
     public boolean isSubscribedToFinalSeminarNotifications() {
@@ -55,14 +88,33 @@ public class Author {
         this.subscribedToFinalSeminarNotifications = subscribedToFinalSeminarNotifications;
     }
 
-    public String getReflection() {
-        return reflection;
+    public Project getProject() {
+        return project;
     }
 
-    public void setReflection(String reflection) {
-        this.reflection = reflection;
+    public User getUser() {
+        return user;
     }
 
+    public ReflectionStatus getReflectionStatus() {
+        return reflectionStatus;
+    }
+
+    public void setReflectionStatus(ReflectionStatus reflectionStatus) {
+        this.reflectionStatus = reflectionStatus;
+    }
+
+    public void setReflectionSupervisorComment(String reflectionSupervisorComment) {
+        this.reflectionSupervisorComment = reflectionSupervisorComment;
+    }
+
+    public String getReflectionSupervisorComment() {
+        return reflectionSupervisorComment;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Nested class
+    // ----------------------------------------------------------------------------------
     @Embeddable
     public static class AuthorPK implements Serializable {
         private Long projectId;
diff --git a/core/src/main/java/se/su/dsv/scipro/project/Project.java b/core/src/main/java/se/su/dsv/scipro/project/Project.java
index 9429d2cbfc..569d1da4a7 100755
--- a/core/src/main/java/se/su/dsv/scipro/project/Project.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/Project.java
@@ -1,13 +1,51 @@
 package se.su.dsv.scipro.project;
 
 import com.querydsl.core.annotations.QueryInit;
+import jakarta.persistence.AttributeOverride;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.MapKeyJoinColumn;
+import jakarta.persistence.PrePersist;
+import jakarta.persistence.PreUpdate;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.data.dataobjects.Member;
 import se.su.dsv.scipro.reusable.SciProUtilities;
-import se.su.dsv.scipro.system.*;
+import se.su.dsv.scipro.system.DegreeType;
+import se.su.dsv.scipro.system.DomainObject;
+import se.su.dsv.scipro.system.Language;
+import se.su.dsv.scipro.system.ProjectModule;
+import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.ResearchArea;
+import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.time.LocalDate;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.stream.Collectors;
 
 @Entity
@@ -18,17 +56,30 @@ public class Project extends DomainObject {
     public static final String NO_CO_SUPERVISOR = "No co-supervisor";
     public static final int TITLE_MAX_LENGTH = 255;
 
+    public static ITitle builder() {
+        return new Builder();
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Column(unique = true)
-    private Integer identifier;
-
-    @Column(length = TITLE_MAX_LENGTH)
     @Basic(optional = false)
+    @Column(name = "title", length = TITLE_MAX_LENGTH)
     private String title;
 
+    @Basic
+    @Column(name = "credits")
+    private int credits;
+
+    @Basic
+    @Column(name = "language")
+    @Enumerated(EnumType.STRING)
+    private Language language;
+
     @Basic(optional = false)
     @Column(name = "start_date", nullable = false)
     private LocalDate startDate;
@@ -37,61 +88,91 @@ public class Project extends DomainObject {
     @Column(name = "expected_end_date")
     private LocalDate expectedEndDate;
 
-    @ManyToMany
-    @JoinTable(name = "project_user", inverseJoinColumns = @JoinColumn(name = "user_id"))
-    private Set<User> projectParticipants = new TreeSet<>(new User.ByNameComparator());
-
-    @ManyToMany
-    @JoinTable(name = "project_reviewer", inverseJoinColumns = @JoinColumn(name = "user_id"))
-    private Set<User> reviewers = new TreeSet<>(new User.ByNameComparator());
-
-    @ManyToMany
-    @JoinTable(name = "project_cosupervisor", inverseJoinColumns = @JoinColumn(name = "user_id"))
-    private Set<User> coSupervisors = new TreeSet<>(new User.ByNameComparator());
-
-    @ManyToOne(optional = false)
-    @QueryInit({"unit"})
-    @JoinColumn(name = "supervisor_id")
-    private User headSupervisor;
-
+    @Basic
+    @Column(name = "project_status")
     @Enumerated(EnumType.STRING)
     private ProjectStatus projectStatus = ProjectStatus.ACTIVE;
 
+    @Basic
+    @Column(name = "final_seminar_rule_exmpt")
+    private boolean finalSeminarRuleExempted = false;
+
+    @Basic
+    @Column(name = "state_of_mind")
     @Enumerated(EnumType.STRING)
     private StateOfMind stateOfMind = StateOfMind.FINE;
 
     @Basic(optional = true)
-    private Date stateOfMindDate;
-
-    @Basic(optional = true)
+    @Column(name = "state_of_mind_reason")
     private String stateOfMindReason;
 
-    @ManyToOne(optional = false)
-    private ProjectType projectType;
-
-    @Embedded
-    @AttributeOverride(name = "name", column = @Column(name = "externalOrganization"))
-    private ExternalOrganization externalOrganization;
-
-    @Column(name = "fs_rule_exmpt")
-    private boolean finalSeminarRuleExempted = false;
+    @Basic(optional = true)
+    @Column(name = "state_of_mind_date")
+    private Date stateOfMindDate;
 
     @Basic
-    private int credits;
+    @Column(name = "daisy_identifier", unique = true)
+    private Integer identifier;
+
+    // ----------------------------------------------------------------------------------
+    // Embedded JPA-mapping
+    // ----------------------------------------------------------------------------------
+    @Embedded
+    @AttributeOverride(name = "name", column = @Column(name = "external_organization"))
+    private ExternalOrganization externalOrganization;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (opposition_report) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_type_id", referencedColumnName = "id")
+    private ProjectType projectType;
 
     @ManyToOne(optional = true)
+    @JoinColumn(name = "research_area_id", referencedColumnName = "id")
     private ResearchArea researchArea;
 
-    @Enumerated(EnumType.STRING)
-    private Language language;
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "supervisor_id", referencedColumnName = "id")
+    @QueryInit({"unit"})
+    private User headSupervisor;
 
+    // ----------------------------------------------------------------------------------
+    // @ManyToMany JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @ManyToMany
+    @JoinTable(name = "project_user",
+            joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
+    private Set<User> projectParticipants = new TreeSet<>(new User.ByNameComparator());
+
+    @ManyToMany
+    @JoinTable(name = "project_reviewer",
+            joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
+    private Set<User> reviewers = new TreeSet<>(new User.ByNameComparator());
+
+    @ManyToMany
+    @JoinTable(name = "project_cosupervisor",
+            joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
+    private Set<User> coSupervisors = new TreeSet<>(new User.ByNameComparator());
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "project"
+    // ----------------------------------------------------------------------------------
     @ElementCollection(fetch = FetchType.LAZY)
-    @CollectionTable(name = "project_user_note", joinColumns = @JoinColumn(name = "project_id"))
+    @CollectionTable(name = "project_user_note",
+            joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"))
     @Column(name = "note")
     @SuppressWarnings("JpaDataSourceORMInspection")  // false warning from IntelliJ for the @MapKeyJoinColumn
     @MapKeyJoinColumn(name = "user_id")
     private Map<User, String> userNotes = new HashMap<>();
 
+    // ----------------------------------------------------------------------------------
+    // JPA Lifecycle Methods
+    // ----------------------------------------------------------------------------------
     @PrePersist
     @PreUpdate
     void cleanTitle() {
@@ -101,12 +182,67 @@ public class Project extends DomainObject {
         title = title.trim();
     }
 
-    public Map<User, String> getUserNotes() {
-        return userNotes;
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
     }
 
-    public void setUserNotes(Map<User, String> userNotes) {
-        this.userNotes = userNotes;
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return SciProUtilities.cleanString(title);
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public int getCredits() {
+        return this.credits;
+    }
+
+    public void setCredits(int credits) {
+        this.credits = credits;
+    }
+
+    public Language getLanguage() {
+        return this.language;
+    }
+
+    public void setLanguage(Language language) {
+        this.language = language;
+    }
+
+    public LocalDate getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(LocalDate startDate) {
+        this.startDate = startDate;
+    }
+
+    public LocalDate getExpectedEndDate() {
+        return this.expectedEndDate;
+    }
+
+    public void setExpectedEndDate(LocalDate expectedEndDate) {
+        this.expectedEndDate = expectedEndDate;
+    }
+
+    public ProjectStatus getProjectStatus() {
+        return this.projectStatus;
+    }
+
+    public void setProjectStatus(ProjectStatus projectStatus) {
+        this.projectStatus = projectStatus;
+        if (projectStatus == ProjectStatus.COMPLETED) {
+            this.stateOfMind = StateOfMind.FINE;
+        }
     }
 
     public boolean isFinalSeminarRuleExempted() {
@@ -117,53 +253,20 @@ public class Project extends DomainObject {
         this.finalSeminarRuleExempted = finalSeminarRuleExempted;
     }
 
-    public User getHeadSupervisor() {
-        return headSupervisor;
+    public StateOfMind getStateOfMind() {
+        return this.stateOfMind;
     }
 
-    public ProjectType getProjectType() {
-        return projectType;
+    public void setStateOfMind(StateOfMind stateOfMind) {
+        this.stateOfMind = stateOfMind;
     }
 
-    public SortedSet<User> getCoSupervisors() {
-        TreeSet<User> s = new TreeSet<>(new User.ByNameComparator());
-        s.addAll(coSupervisors);
-        return Collections.unmodifiableSortedSet(s);
+    public String getStateOfMindReason() {
+        return this.stateOfMindReason;
     }
 
-    public void setCoSupervisors(Collection<User> coSupervisors) {
-        this.coSupervisors.clear();
-        this.coSupervisors.addAll(coSupervisors);
-    }
-
-    public void addCoSupervisor(User coSupervisor) {
-        coSupervisors.add(coSupervisor);
-    }
-
-    public SortedSet<User> getReviewers() {
-        TreeSet<User> s = new TreeSet<>(new User.ByNameComparator());
-        s.addAll(reviewers);
-        return Collections.unmodifiableSortedSet(s);
-    }
-
-    public void setReviewers(Collection<User> reviewers) {
-        this.reviewers.clear();
-        this.reviewers.addAll(reviewers);
-    }
-
-    public void addReviewer(User reviewer) {
-        reviewers.add(reviewer);
-    }
-
-    public void removeReviewer(User reviewer) {
-        reviewers.remove(reviewer);
-    }
-
-    public void setProjectStatus(ProjectStatus projectStatus) {
-        this.projectStatus = projectStatus;
-        if (projectStatus == ProjectStatus.COMPLETED) {
-            this.stateOfMind = StateOfMind.FINE;
-        }
+    public void setStateOfMindReason(String stateOfMindReason) {
+        this.stateOfMindReason = stateOfMindReason;
     }
 
     public Date getStateOfMindDate() {
@@ -176,8 +279,44 @@ public class Project extends DomainObject {
                 : new Date(stateOfMindDate.getTime());
     }
 
-    public String getTitle() {
-        return SciProUtilities.cleanString(title);
+    public Integer getIdentifier() {
+        return this.identifier;
+    }
+
+    public void setIdentifier(Integer identifier) {
+        this.identifier = identifier;
+    }
+
+    public ExternalOrganization getExternalOrganization() {
+        return this.externalOrganization;
+    }
+
+    public void setExternalOrganization(ExternalOrganization externalOrganization) {
+        this.externalOrganization = externalOrganization;
+    }
+
+    public ProjectType getProjectType() {
+        return projectType;
+    }
+
+    public void setProjectType(ProjectType projectType) {
+        this.projectType = projectType;
+    }
+
+    public ResearchArea getResearchArea() {
+        return this.researchArea;
+    }
+
+    public void setResearchArea(ResearchArea researchArea) {
+        this.researchArea = researchArea;
+    }
+
+    public User getHeadSupervisor() {
+        return headSupervisor;
+    }
+
+    public void setHeadSupervisor(User headSupervisor) {
+        this.headSupervisor = headSupervisor;
     }
 
     public SortedSet<User> getProjectParticipants() {
@@ -191,11 +330,91 @@ public class Project extends DomainObject {
         this.projectParticipants.addAll(projectParticipants);
     }
 
+    public SortedSet<User> getReviewers() {
+        TreeSet<User> s = new TreeSet<>(new User.ByNameComparator());
+        s.addAll(reviewers);
+        return Collections.unmodifiableSortedSet(s);
+    }
+
+    public void setReviewers(Collection<User> reviewers) {
+        this.reviewers.clear();
+        this.reviewers.addAll(reviewers);
+    }
+
+    public SortedSet<User> getCoSupervisors() {
+        TreeSet<User> s = new TreeSet<>(new User.ByNameComparator());
+        s.addAll(coSupervisors);
+        return Collections.unmodifiableSortedSet(s);
+    }
+
+    public void setCoSupervisors(Collection<User> coSupervisors) {
+        this.coSupervisors.clear();
+        this.coSupervisors.addAll(coSupervisors);
+    }
+
+    public Map<User, String> getUserNotes() {
+        return userNotes;
+    }
+
+    public void setUserNotes(Map<User, String> userNotes) {
+        this.userNotes = userNotes;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof Project)) return false;
+        final Project other = (Project) o;
+        return other.canEqual(this)
+                && Objects.equals(this.getId(), other.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getId());
+    }
+
+    @Override
+    public String toString() {
+        return "Project(id=" + this.getId() + ", identifier=" + this.getIdentifier() +
+                ", title=" + this.getTitle() + ", projectParticipants=" + this.getProjectParticipants() +
+                ", headSupervisor=" + this.getHeadSupervisor() + ", projectType=" +
+                this.getProjectType() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+
+    protected boolean canEqual(final Object other) {
+        return other instanceof Project;
+    }
+
     public void addProjectParticipant(User s) {
         projectParticipants.add(s);
     }
 
-    //TODO remove this method
+    public boolean isParticipant(User user) {
+        for (User s : projectParticipants) {
+            if (s.equals(user)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void addReviewer(User reviewer) {
+        reviewers.add(reviewer);
+    }
+
+    public void removeReviewer(User reviewer) {
+        reviewers.remove(reviewer);
+    }
+
+    // TODO remove this method
     public User getReviewer() {
         if (reviewers.isEmpty()) {
             return null;
@@ -204,6 +423,14 @@ public class Project extends DomainObject {
         }
     }
 
+    public String getReviewerName() {
+        return getReviewer() != null ? getReviewer().getFullName() : NO_REVIEWER;
+    }
+
+    public void addCoSupervisor(User coSupervisor) {
+        coSupervisors.add(coSupervisor);
+    }
+
     public List<Member> getMembers() {
         List<Member> members = new ArrayList<>();
 
@@ -240,23 +467,10 @@ public class Project extends DomainObject {
         return externalOrganization != null;
     }
 
-    public boolean isParticipant(User user) {
-        for (User s : projectParticipants) {
-            if (s.equals(user)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     public String getSupervisorName() {
         return getHeadSupervisor().getFullName();
     }
 
-    public String getReviewerName() {
-        return getReviewer() != null ? getReviewer().getFullName() : NO_REVIEWER;
-    }
-
     public DegreeType getProjectTypeDegreeType() {
         return getProjectType().getDegreeType();
     }
@@ -289,10 +503,6 @@ public class Project extends DomainObject {
         return getProjectType().hasModule(projectModule);
     }
 
-    public static ITitle builder() {
-        return new Builder();
-    }
-
     public boolean isSupervisor(User user) {
         return headSupervisor != null && headSupervisor.equals(user);
     }
@@ -319,125 +529,9 @@ public class Project extends DomainObject {
         return Objects.requireNonNullElse(language, getProjectType().getDefaultLanguage());
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
-    }
-
-    public Integer getIdentifier() {
-        return this.identifier;
-    }
-
-    public LocalDate getExpectedEndDate() {
-        return this.expectedEndDate;
-    }
-
-    public ProjectStatus getProjectStatus() {
-        return this.projectStatus;
-    }
-
-    public StateOfMind getStateOfMind() {
-        return this.stateOfMind;
-    }
-
-    public String getStateOfMindReason() {
-        return this.stateOfMindReason;
-    }
-
-    public ExternalOrganization getExternalOrganization() {
-        return this.externalOrganization;
-    }
-
-    public int getCredits() {
-        return this.credits;
-    }
-
-    public ResearchArea getResearchArea() {
-        return this.researchArea;
-    }
-
-    public Language getLanguage() {
-        return this.language;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
-    }
-
-    public void setIdentifier(Integer identifier) {
-        this.identifier = identifier;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
-    public void setExpectedEndDate(LocalDate expectedEndDate) {
-        this.expectedEndDate = expectedEndDate;
-    }
-
-    public void setHeadSupervisor(User headSupervisor) {
-        this.headSupervisor = headSupervisor;
-    }
-
-    public void setStateOfMind(StateOfMind stateOfMind) {
-        this.stateOfMind = stateOfMind;
-    }
-
-    public void setStateOfMindReason(String stateOfMindReason) {
-        this.stateOfMindReason = stateOfMindReason;
-    }
-
-    public void setProjectType(ProjectType projectType) {
-        this.projectType = projectType;
-    }
-
-    public void setExternalOrganization(ExternalOrganization externalOrganization) {
-        this.externalOrganization = externalOrganization;
-    }
-
-    public void setCredits(int credits) {
-        this.credits = credits;
-    }
-
-    public void setResearchArea(ResearchArea researchArea) {
-        this.researchArea = researchArea;
-    }
-
-    public void setLanguage(Language language) {
-        this.language = language;
-    }
-
-    public LocalDate getStartDate() {
-        return startDate;
-    }
-
-    public void setStartDate(LocalDate startDate) {
-        this.startDate = startDate;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof Project)) return false;
-        final Project other = (Project) o;
-        return other.canEqual(this)
-                && Objects.equals(this.getId(), other.getId());
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof Project;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getId());
-    }
-
-    @Override
-    public String toString() {
-        return "Project(id=" + this.getId() + ", identifier=" + this.getIdentifier() + ", title=" + this.getTitle() + ", projectParticipants=" + this.getProjectParticipants() + ", headSupervisor=" + this.getHeadSupervisor() + ", projectType=" + this.getProjectType() + ")";
-    }
+    // ----------------------------------------------------------------------------------
+    // Nested classes and interfaces
+    // ----------------------------------------------------------------------------------
 
     private static class Builder implements ITitle, IProjectType, IStartDate, IBuild {
         private final Project instance = new Project();
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java
index 9a2862ae63..ada1db066b 100644
--- a/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectPeopleStatisticsServiceImpl.java
@@ -10,7 +10,7 @@ import jakarta.persistence.EntityManager;
 public class ProjectPeopleStatisticsServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectPeopleStatisticsService {
 
     @Inject
-    protected ProjectPeopleStatisticsServiceImpl(Provider<EntityManager> em) {
+    public ProjectPeopleStatisticsServiceImpl(Provider<EntityManager> em) {
         super(em, Project.class, QProject.project);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java
index 43892156ca..a1c985044f 100755
--- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.project;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.JpaRepository;
 import se.su.dsv.scipro.system.QueryDslPredicateExecutor;
 import se.su.dsv.scipro.system.User;
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java
index f8dfb462bd..8211412568 100644
--- a/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectRepoImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.project;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.GenericRepo;
 import se.su.dsv.scipro.system.User;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java
index 617f39e795..e52cae2397 100755
--- a/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/project/ProjectServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.project;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.BooleanBuilder;
 import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.BooleanExpression;
diff --git a/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java
new file mode 100644
index 0000000000..92b94cd7b6
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/project/ReflectionStatus.java
@@ -0,0 +1,7 @@
+package se.su.dsv.scipro.project;
+
+public enum ReflectionStatus {
+    NOT_SUBMITTED,
+    SUBMITTED,
+    IMPROVEMENTS_NEEDED
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java
index 0afe97861e..643956fe8e 100755
--- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java
+++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartner.java
@@ -1,15 +1,26 @@
 package se.su.dsv.scipro.projectpartner;
 
+import java.util.Objects;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.match.ApplicationPeriod;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.Objects;
-
 @Entity
-@Table(name="projectPartner")
+@Table(name="project_partner")
 @Cacheable(true)
 public class ProjectPartner extends DomainObject {
 	@Id
@@ -20,17 +31,19 @@ public class ProjectPartner extends DomainObject {
 	private User user;
 
 	@ManyToOne(optional = false)
+	@JoinColumn(name = "project_type_id")
 	private ProjectType projectType;
 
 	@ManyToOne(optional = false)
+	@JoinColumn(name = "application_period_id")
 	private ApplicationPeriod applicationPeriod;
 
 	@Lob
-	@Basic(optional=false)
+	@Column(name = "info_text", nullable=false)
 	private String infotext;
 
 	@Basic(optional = false)
-	@Column(nullable = false, name = "active")
+	@Column(name = "active", nullable = false)
 	private boolean active = true;
 
 	public ProjectPartner(User user){
diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java
index 63dada7bf6..a437f162d5 100644
--- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.projectpartner;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.system.AbstractRepository;
 
 import jakarta.inject.Inject;
diff --git a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java
index 3b39364a33..5af5e3a0a7 100644
--- a/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/projectpartner/ProjectPartnerServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.projectpartner;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.dsl.Expressions;
 import com.querydsl.jpa.JPAExpressions;
 import se.su.dsv.scipro.system.Pageable;
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java
new file mode 100644
index 0000000000..898d961a2c
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/Reflection.java
@@ -0,0 +1,22 @@
+package se.su.dsv.scipro.reflection;
+
+public sealed interface Reflection {
+    boolean isSubmittable();
+
+    record NotSubmitted() implements Reflection {
+        @Override
+        public boolean isSubmittable() { return true; }
+    }
+
+    record Submitted(String reflection) implements Reflection {
+        @Override
+        public boolean isSubmittable() {
+            return false;
+        }
+    }
+
+    record ImprovementsNeeded(String oldReflection, String commentBySupervisor) implements Reflection {
+        @Override
+        public boolean isSubmittable() { return true; }
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java
new file mode 100644
index 0000000000..07d8811f99
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsRequestedEvent.java
@@ -0,0 +1,7 @@
+package se.su.dsv.scipro.reflection;
+
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.User;
+
+public record ReflectionImprovementsRequestedEvent(Project project, User author, String supervisorComment) {
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java
new file mode 100644
index 0000000000..ce43d5eed4
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionImprovementsSubmittedEvent.java
@@ -0,0 +1,10 @@
+package se.su.dsv.scipro.reflection;
+
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.User;
+
+/**
+ * This event may be triggered by the supervisor if they edit the reflection after requesting improvements.
+ */
+public record ReflectionImprovementsSubmittedEvent(Project project, User author, String reflection) {
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java
deleted file mode 100644
index 872fd7d8dd..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionModule.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package se.su.dsv.scipro.reflection;
-
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.finalseminar.AuthorRepository;
-
-public class ReflectionModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        requireBinding(AuthorRepository.class);
-
-        bind(ReflectionService.class).to(ReflectionServiceImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
index b4a206bf76..139dc9a6d9 100644
--- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionService.java
@@ -14,4 +14,15 @@ public interface ReflectionService {
      * @return the reflection, or {@code null} if none has been submitted
      */
     String getSubmittedReflection(Project project, User author);
+
+    /**
+     * Used by the supervisor when the currently submitted reflection does not meet the minimum requirements.
+     * This is done individually by author.
+     *
+     * @param author the author whose reflection does not meet the minimum requirements.
+     * @param supervisorComment feedback provided by the supervisor so the author knows what to improve.
+     */
+    void requestNewReflection(Project project, User author, String supervisorComment);
+
+    Reflection getReflection(Project project, User author);
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
index ccd23a6244..73d934ca32 100644
--- a/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reflection/ReflectionServiceImpl.java
@@ -1,22 +1,32 @@
 package se.su.dsv.scipro.reflection;
 
-import com.google.inject.persist.Transactional;
+import com.google.common.eventbus.EventBus;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.finalseminar.AuthorRepository;
 import se.su.dsv.scipro.finalseminar.FinalSeminarService;
 import se.su.dsv.scipro.project.Author;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.project.ReflectionStatus;
 import se.su.dsv.scipro.system.User;
 
 import jakarta.inject.Inject;
 
-class ReflectionServiceImpl implements ReflectionService {
+import java.util.Optional;
+
+public class ReflectionServiceImpl implements ReflectionService {
     private final AuthorRepository authorRepository;
     private final FinalSeminarService finalSeminarService;
+    private final EventBus eventBus;
 
     @Inject
-    ReflectionServiceImpl(AuthorRepository authorRepository, FinalSeminarService finalSeminarService) {
+    public ReflectionServiceImpl(
+            AuthorRepository authorRepository,
+            FinalSeminarService finalSeminarService,
+            EventBus eventBus)
+    {
         this.authorRepository = authorRepository;
         this.finalSeminarService = finalSeminarService;
+        this.eventBus = eventBus;
     }
 
     @Override
@@ -25,10 +35,13 @@ class ReflectionServiceImpl implements ReflectionService {
     }
 
     @Override
-    public boolean hasToFillInReflection(Project project, User author) {
-        boolean noReflectionSubmitted = authorRepository.findByProjectAndUser(project, author)
-                .map(Author::getReflection)
-                .isEmpty();
+    public boolean hasToFillInReflection(Project project, User user) {
+        Optional<Author> optionalAuthor = authorRepository.findByProjectAndUser(project, user);
+        if (optionalAuthor.isEmpty()) {
+            return false;
+        }
+        Author author = optionalAuthor.get();
+        boolean noReflectionSubmitted = author.getReflectionStatus() != ReflectionStatus.SUBMITTED;
         return hasReachedReflectionProcess(project) && noReflectionSubmitted;
     }
 
@@ -36,7 +49,13 @@ class ReflectionServiceImpl implements ReflectionService {
     @Transactional
     public void submitReflection(Project project, User user, String reflection) {
         authorRepository.findByProjectAndUser(project, user)
-                .ifPresent(author -> author.setReflection(reflection));
+                .ifPresent(author -> {
+                    if (author.getReflectionStatus() == ReflectionStatus.IMPROVEMENTS_NEEDED) {
+                        eventBus.post(new ReflectionImprovementsSubmittedEvent(project, user, reflection));
+                    }
+                    author.setReflection(reflection);
+                    author.setReflectionStatus(ReflectionStatus.SUBMITTED);
+                });
     }
 
     @Override
@@ -45,4 +64,32 @@ class ReflectionServiceImpl implements ReflectionService {
                 .map(Author::getReflection)
                 .orElse(null);
     }
+
+    @Override
+    @Transactional
+    public void requestNewReflection(Project project, User user, String supervisorComment) {
+        authorRepository.findByProjectAndUser(project, user)
+                .ifPresent(author -> {
+                    author.setReflectionStatus(ReflectionStatus.IMPROVEMENTS_NEEDED);
+                    author.setReflectionSupervisorComment(supervisorComment);
+                });
+        eventBus.post(new ReflectionImprovementsRequestedEvent(project, user, supervisorComment));
+    }
+
+    @Override
+    public Reflection getReflection(Project project, User author) {
+        return authorRepository.findByProjectAndUser(project, author)
+                .map(this::toReflection)
+                .orElseGet(Reflection.NotSubmitted::new);
+    }
+
+    private Reflection toReflection(Author author) {
+        return switch (author.getReflectionStatus()) {
+            case SUBMITTED -> new Reflection.Submitted(author.getReflection());
+            case IMPROVEMENTS_NEEDED -> new Reflection.ImprovementsNeeded(
+                    author.getReflection(),
+                    author.getReflectionSupervisorComment());
+            default -> new Reflection.NotSubmitted();
+        };
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java
index 7fd640236b..e9d80f2699 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractCriterion.java
@@ -1,12 +1,12 @@
 package se.su.dsv.scipro.report;
 
-import jakarta.persistence.GenerationType;
-import se.su.dsv.scipro.system.DomainObject;
-
 import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
 import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
 import jakarta.persistence.Id;
 import jakarta.persistence.MappedSuperclass;
+import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.Language;
 
 import java.io.Serializable;
@@ -15,19 +15,28 @@ import java.util.Objects;
 
 @MappedSuperclass
 public abstract class AbstractCriterion extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @Basic(optional = false)
+    @Basic
+    @Column(name = "title_sv", nullable = false)
     private String title;
 
-    @Basic(optional = false)
+    @Basic
+    @Column(name = "title_en", nullable = false)
     private String titleEn;
 
-    @Basic(optional = false)
+    @Basic
+    @Column(name = "sort_order", nullable = false)
     private Integer sortOrder;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected AbstractCriterion() {
     }
 
@@ -37,6 +46,9 @@ public abstract class AbstractCriterion extends DomainObject {
         this.sortOrder = sortOrder;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
@@ -50,14 +62,13 @@ public abstract class AbstractCriterion extends DomainObject {
         return titleEn;
     }
 
-    public String getTitle(Language language) {
-        return language == Language.ENGLISH ? getTitleEn() : getTitle();
-    }
-
     public Integer getSortOrder() {
         return this.sortOrder;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -71,10 +82,6 @@ public abstract class AbstractCriterion extends DomainObject {
                 && Objects.equals(this.getSortOrder(), other.getSortOrder());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof AbstractCriterion;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getTitle(), this.getTitleEn(), this.getSortOrder());
@@ -85,6 +92,20 @@ public abstract class AbstractCriterion extends DomainObject {
         return "AbstractCriterion(id=" + this.getId() + ", title=" + this.getTitle()  + ", titleEn=" + this.getTitleEn() + ", sortOrder=" + this.getSortOrder() + ")";
     }
 
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof AbstractCriterion;
+    }
+
+    public String getTitle(Language language) {
+        return language == Language.ENGLISH ? getTitleEn() : getTitle();
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Embedded class
+    // ----------------------------------------------------------------------------------
     public static class BySortOrderComparator implements Comparator<AbstractCriterion>, Serializable {
         @Override
         public int compare(AbstractCriterion o1, AbstractCriterion o2) {
diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java
index 64d2f0433b..81b55d0982 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterion.java
@@ -8,7 +8,109 @@ import jakarta.persistence.MappedSuperclass;
 
 @MappedSuperclass
 public abstract class AbstractGradingCriterion extends AbstractCriterion {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @Basic(optional = false)
+    @Column(name = "points_required_to_pass", nullable = false)
+    protected int pointsRequiredToPass;
 
+    @Basic
+    @Column(name = "fx")
+    private boolean fx = true;
+
+    @Basic
+    @Column(name = "flag")
+    @Enumerated(EnumType.STRING)
+    private Flag flag;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
+    protected AbstractGradingCriterion() {
+
+    }
+
+    protected AbstractGradingCriterion(String title, String titleEn, int sortOrder, int pointsRequiredToPass) {
+        super(title, titleEn, sortOrder);
+        this.pointsRequiredToPass = pointsRequiredToPass;
+    }
+
+    protected AbstractGradingCriterion(String title, String titleEn, Integer sortOrder, int pointsRequiredToPass,
+            Flag flag) {
+        this(title, titleEn, sortOrder, pointsRequiredToPass);
+        this.flag = flag;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public int getPointsRequiredToPass() {
+        return this.pointsRequiredToPass;
+    }
+
+    public boolean isFx() {
+        return this.fx;
+    }
+
+    public void setFx(boolean fx) {
+        this.fx = fx;
+    }
+
+    public Flag getFlag() {
+        return flag;
+    }
+
+    public void setFlag(Flag flag) {
+        this.flag = flag;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof AbstractGradingCriterion)) return false;
+        final AbstractGradingCriterion other = (AbstractGradingCriterion) o;
+        return other.canEqual(this)
+                && super.equals(o)
+                && this.getPointsRequiredToPass() == other.getPointsRequiredToPass()
+                && this.isFx() == other.isFx();
+    }
+
+    @Override
+    public int hashCode() {
+        final int PRIME = 59;
+        int result = super.hashCode();
+        result = result * PRIME + this.getPointsRequiredToPass();
+        result = result * PRIME + (this.isFx() ? 79 : 97);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "AbstractGradingCriterion(pointsRequiredToPass=" + this.getPointsRequiredToPass() +
+                ", fx=" + this.isFx() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    @Override
+    protected boolean canEqual(final Object other) {
+        return other instanceof AbstractGradingCriterion;
+    }
+
+    public abstract boolean isProjectCriterion();
+
+    public abstract boolean isIndividualCriterion();
+
+    public abstract int getMaxPoints();
+
+    // ----------------------------------------------------------------------------------
+    // Nested type
+    // ----------------------------------------------------------------------------------
     public enum Flag {
         /**
          * Criterion marked with this flag will add extra functionality related
@@ -25,91 +127,4 @@ public abstract class AbstractGradingCriterion extends AbstractCriterion {
          */
         OPPOSITION
     }
-
-    @Basic(optional = false)
-    protected int pointsRequiredToPass;
-
-    @Basic
-    private boolean fx = true;
-
-    @Basic
-    @Column(name = "flag")
-    @Enumerated(EnumType.STRING)
-    private Flag flag;
-
-    protected AbstractGradingCriterion() {
-
-    }
-
-    protected AbstractGradingCriterion(String title, String titleEn, int sortOrder, int pointsRequiredToPass) {
-        super(title, titleEn, sortOrder);
-        this.pointsRequiredToPass = pointsRequiredToPass;
-    }
-
-    protected AbstractGradingCriterion(
-            String title,
-            String titleEn,
-            Integer sortOrder,
-            int pointsRequiredToPass,
-            Flag flag)
-    {
-        this(title, titleEn, sortOrder, pointsRequiredToPass);
-        this.flag = flag;
-    }
-
-    public abstract boolean isProjectCriterion();
-
-    public abstract boolean isIndividualCriterion();
-
-    public abstract int getMaxPoints();
-
-    public int getPointsRequiredToPass() {
-        return this.pointsRequiredToPass;
-    }
-
-    public boolean isFx() {
-        return this.fx;
-    }
-
-    public Flag getFlag() {
-        return flag;
-    }
-
-    public void setFlag(Flag flag) {
-        this.flag = flag;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof AbstractGradingCriterion)) return false;
-        final AbstractGradingCriterion other = (AbstractGradingCriterion) o;
-        return other.canEqual(this)
-                && super.equals(o)
-                && this.getPointsRequiredToPass() == other.getPointsRequiredToPass()
-                && this.isFx() == other.isFx();
-    }
-
-    @Override
-    protected boolean canEqual(final Object other) {
-        return other instanceof AbstractGradingCriterion;
-    }
-
-    @Override
-    public int hashCode() {
-        final int PRIME = 59;
-        int result = super.hashCode();
-        result = result * PRIME + this.getPointsRequiredToPass();
-        result = result * PRIME + (this.isFx() ? 79 : 97);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "AbstractGradingCriterion(pointsRequiredToPass=" + this.getPointsRequiredToPass() + ", fx=" + this.isFx() + ")";
-    }
-
-    public void setFx(boolean fx) {
-        this.fx = fx;
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java
index ae653266ac..29e423d0f2 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/AbstractGradingCriterionPoint.java
@@ -1,70 +1,86 @@
 package se.su.dsv.scipro.report;
 
-import se.su.dsv.scipro.system.DomainObject;
-
-import jakarta.persistence.*;
-import se.su.dsv.scipro.system.Language;
-
 import java.util.Objects;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.MappedSuperclass;
+import se.su.dsv.scipro.system.DomainObject;
+
+import se.su.dsv.scipro.system.Language;
+
 @MappedSuperclass
-public abstract class AbstractGradingCriterionPoint extends DomainObject implements Comparable<AbstractGradingCriterionPoint> {
+public abstract class AbstractGradingCriterionPoint extends DomainObject
+        implements Comparable<AbstractGradingCriterionPoint> {
     public static final int DESCRIPTION_LENGTH = 600;
+
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
     @Basic(optional = false)
+    @Column(name = "point")
     private Integer point;
 
     @Basic
-    @Column(length = DESCRIPTION_LENGTH)
+    @Column(name = "description_sv", length = DESCRIPTION_LENGTH)
     private String description;
 
     @Basic
-    @Column(length = DESCRIPTION_LENGTH)
+    @Column(name = "description_en", length = DESCRIPTION_LENGTH)
     private String descriptionEn;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public AbstractGradingCriterionPoint() {
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return id;
     }
 
-    public Integer getPoint() {
-        return this.point;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
-    public String getDescriptionEn() {
-        return descriptionEn;
-    }
-
-    public String getDescription(Language language) {
-        return language == Language.ENGLISH ? getDescriptionEn() : getDescription();
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
+    public Integer getPoint() {
+        return this.point;
+    }
+
     public void setPoint(Integer point) {
         this.point = point;
     }
 
+    public String getDescription() {
+        return this.description;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
 
+    public String getDescriptionEn() {
+        return descriptionEn;
+    }
+
     public void setDescriptionEn(String descriptionEn) {
         this.descriptionEn = descriptionEn;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects and Comparable
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -78,10 +94,6 @@ public abstract class AbstractGradingCriterionPoint extends DomainObject impleme
                 && Objects.equals(this.getDescriptionEn(), other.getDescriptionEn());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof AbstractGradingCriterionPoint;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(), this.getId(), this.getPoint(), this.getDescription(), this.getDescriptionEn());
@@ -91,4 +103,15 @@ public abstract class AbstractGradingCriterionPoint extends DomainObject impleme
     public String toString() {
         return "AbstractGradingCriterionPoint(id=" + this.getId() + ", point=" + this.getPoint() + ", description=" + this.getDescription() + ", descriptionEn=" + this.getDescriptionEn() + ")";
     }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof AbstractGradingCriterionPoint;
+    }
+
+    public String getDescription(Language language) {
+        return language == Language.ENGLISH ? getDescriptionEn() : getDescription();
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java b/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java
index 3ec5ea0ac4..53c135a971 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/AttachmentReport.java
@@ -6,16 +6,23 @@ import jakarta.persistence.CascadeType;
 import jakarta.persistence.JoinColumn;
 import jakarta.persistence.MappedSuperclass;
 import jakarta.persistence.OneToOne;
-import java.util.*;
 
+import java.util.Objects;
 
 @MappedSuperclass
 public abstract class AttachmentReport extends Report {
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in table of children class (OppositionReport)
+    // referencing other tables.
+    // ----------------------------------------------------------------------------------
     @OneToOne(optional = true, cascade = CascadeType.ALL)
-    @JoinColumn(name = "attachment_reference_id")
+    @JoinColumn(name = "attachment_file_reference_id", referencedColumnName = "id")
     private FileReference attachment;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public FileReference getAttachment() {
         return this.attachment;
     }
@@ -24,6 +31,9 @@ public abstract class AttachmentReport extends Report {
         this.attachment = attachment;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -34,14 +44,16 @@ public abstract class AttachmentReport extends Report {
                 && Objects.equals(this.attachment, other.attachment);
     }
 
-    @Override
-    protected boolean canEqual(final Object other) {
-        return other instanceof AttachmentReport;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(super.hashCode(), this.attachment);
     }
 
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    @Override
+    protected boolean canEqual(final Object other) {
+        return other instanceof AttachmentReport;
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/Criterion.java b/core/src/main/java/se/su/dsv/scipro/report/Criterion.java
index de823bdb5c..63978c9170 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/Criterion.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/Criterion.java
@@ -1,6 +1,11 @@
 package se.su.dsv.scipro.report;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.Language;
 
 import java.util.Objects;
@@ -8,26 +13,34 @@ import java.util.Objects;
 @Entity
 @Table(name = "criterion")
 public class Criterion extends AbstractCriterion {
-
     public static final int DESCRIPTION_LENGTH = 2000;
 
-    @ManyToOne(optional = false)
-    private Report report;
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Basic
-    @Column
-    private String feedback;
-
-    @Basic
-    @Column(length = DESCRIPTION_LENGTH)
+    @Column(name = "description_sv", length = DESCRIPTION_LENGTH)
     private String description;
 
     @Basic
-    @Column(length = DESCRIPTION_LENGTH)
+    @Column(name = "description_en", length = DESCRIPTION_LENGTH)
     private String descriptionEn;
 
-    protected Criterion() {
+    @Basic
+    @Column(name = "feedback")
+    private String feedback;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (criterion) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name ="report_id", referencedColumnName = "id")
+    private Report report;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
+    protected Criterion() {
     }
 
     Criterion(Report report, String title, String titleEn, String description, String descriptionEn, int sortOrder) {
@@ -41,22 +54,9 @@ public class Criterion extends AbstractCriterion {
         this(report, gradingCriterionTemplate.getTitle(), gradingCriterionTemplate.getTitleEn(), gradingCriterionTemplate.getDescription(), gradingCriterionTemplate.getDescriptionEn(), gradingCriterionTemplate.getSortOrder());
     }
 
-    public void setFeedback(final String feedback) {
-        this.feedback = feedback;
-    }
-
-    public boolean isFilledOut() {
-        return feedback != null && !feedback.isEmpty();
-    }
-
-    public Report getReport() {
-        return this.report;
-    }
-
-    public String getFeedback() {
-        return this.feedback;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public String getDescription() {
         return this.description;
     }
@@ -65,10 +65,21 @@ public class Criterion extends AbstractCriterion {
         return this.descriptionEn;
     }
 
-    public String getDescription(Language language) {
-        return language == Language.ENGLISH ? getDescriptionEn() : getDescription();
+    public String getFeedback() {
+        return this.feedback;
     }
 
+    public void setFeedback(final String feedback) {
+        this.feedback = feedback;
+    }
+
+    public Report getReport() {
+        return this.report;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -82,11 +93,6 @@ public class Criterion extends AbstractCriterion {
                 && Objects.equals(this.getDescriptionEn(), other.getDescriptionEn());
     }
 
-    @Override
-    protected boolean canEqual(final Object other) {
-        return other instanceof Criterion;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getReport(), this.getFeedback(), this.getDescription(), this.getDescriptionEn());
@@ -94,6 +100,24 @@ public class Criterion extends AbstractCriterion {
 
     @Override
     public String toString() {
-        return "Criterion(report=" + this.getReport() + ", feedback=" + this.getFeedback() + ", description=" + this.getDescription() + ", descriptionEn=" + this.getDescriptionEn() + ")";
+        return "Criterion(report=" + this.getReport() + ", feedback=" + this.getFeedback() +
+                ", description=" + this.getDescription() + ", descriptionEn=" +
+                this.getDescriptionEn() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    @Override
+    protected boolean canEqual(final Object other) {
+        return other instanceof Criterion;
+    }
+
+    public String getDescription(Language language) {
+        return language == Language.ENGLISH ? getDescriptionEn() : getDescription();
+    }
+
+    public boolean isFilledOut() {
+        return feedback != null && !feedback.isEmpty();
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java b/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java
index 49d6b60097..385d4941f3 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradeLimit.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.report;
 
+import jakarta.persistence.Basic;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.GeneratedValue;
@@ -8,18 +9,26 @@ import jakarta.persistence.Id;
 import jakarta.persistence.Table;
 
 @Entity
-@Table(name = "grading_report_template_grade_limits")
+@Table(name = "grading_report_template_grade_limit")
 public class GradeLimit {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
     @Column(name = "grade")
     private String grade;
 
+    @Basic
     @Column(name = "lower_limit")
     private int lowerLimit;
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java
index aad898db4c..10ea7059b0 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterion.java
@@ -1,30 +1,57 @@
 package se.su.dsv.scipro.report;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
 @Entity
-@DiscriminatorColumn(name = "type")
+@Table(name = "grading_criterion")
 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(name = "type")
 public abstract class GradingCriterion extends AbstractGradingCriterion {
     public static final int FEEDBACK_LENGTH = 2000;
 
-    @ManyToOne(optional = false)
-    private GradingReport gradingReport;
-
-    @OneToMany(mappedBy = "gradingCriterion", orphanRemoval = true, cascade = CascadeType.PERSIST)
-    private List<GradingCriterionPoint> gradingCriterionPoints = new ArrayList<>();
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Basic
+    @Column(name = "points")
     private Integer points;
 
     @Basic
-    @Column(length = FEEDBACK_LENGTH)
+    @Column(name = "feedback", length = FEEDBACK_LENGTH)
     private String feedback;
+    
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_criterion) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "grading_report_id", referencedColumnName = "id")
+    private GradingReport gradingReport;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "grading_criterion"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "gradingCriterion", orphanRemoval = true, cascade = CascadeType.PERSIST)
+    private List<GradingCriterionPoint> gradingCriterionPoints = new ArrayList<>();
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected GradingCriterion() {
         // JPA
     }
@@ -41,6 +68,71 @@ public abstract class GradingCriterion extends AbstractGradingCriterion {
         }
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public Integer getPoints() {
+        return this.points;
+    }
+
+    public void setPoints(Integer points) {
+        this.points = points;
+    }
+
+    public String getFeedback() {
+        return this.feedback;
+    }
+
+    public void setFeedback(String feedback) {
+        this.feedback = feedback;
+    }
+
+    public List<GradingCriterionPoint> getGradingCriterionPoints() {
+        return this.gradingCriterionPoints;
+    }
+
+    public GradingReport getGradingReport() {
+        return this.gradingReport;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof GradingCriterion)) return false;
+        final GradingCriterion other = (GradingCriterion) o;
+        return other.canEqual(this)
+                && super.equals(o)
+                && Objects.equals(this.getGradingReport(), other.getGradingReport())
+                && Objects.equals(this.getPoints(), other.getPoints())
+                && Objects.equals(this.getFeedback(), other.getFeedback());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), this.getGradingReport(), this.getPoints(), this.getFeedback());
+    }
+
+    @Override
+    public String toString() {
+        return "GradingCriterion(gradingReport=" + this.getGradingReport() + ", points=" + this.getPoints() +
+                ", feedback=" + this.getFeedback() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    @Override
+    protected boolean canEqual(final Object other) {
+        return other instanceof GradingCriterion;
+    }
+
+    public boolean isPassFail() {
+        return getMaxPoints() == 1 && getPointsRequiredToPass() == 1;
+    }
+
     public boolean meetsMinimumPointRequirement() {
         return Objects.requireNonNullElse(getPoints(), 0) >= getPointsRequiredToPass();
     }
@@ -57,59 +149,4 @@ public abstract class GradingCriterion extends AbstractGradingCriterion {
     public int getMaxPoints() {
         return Collections.max(gradingCriterionPoints).getPoint();
     }
-
-    public GradingReport getGradingReport() {
-        return this.gradingReport;
-    }
-
-    public Integer getPoints() {
-        return this.points;
-    }
-
-    public String getFeedback() {
-        return this.feedback;
-    }
-
-    public List<GradingCriterionPoint> getGradingCriterionPoints() {
-        return this.gradingCriterionPoints;
-    }
-
-    public void setPoints(Integer points) {
-        this.points = points;
-    }
-
-    public void setFeedback(String feedback) {
-        this.feedback = feedback;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof GradingCriterion)) return false;
-        final GradingCriterion other = (GradingCriterion) o;
-        return other.canEqual(this)
-                && super.equals(o)
-                && Objects.equals(this.getGradingReport(), other.getGradingReport())
-                && Objects.equals(this.getPoints(), other.getPoints())
-                && Objects.equals(this.getFeedback(), other.getFeedback());
-    }
-
-    @Override
-    protected boolean canEqual(final Object other) {
-        return other instanceof GradingCriterion;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), this.getGradingReport(), this.getPoints(), this.getFeedback());
-    }
-
-    @Override
-    public String toString() {
-        return "GradingCriterion(gradingReport=" + this.getGradingReport() + ", points=" + this.getPoints() + ", feedback=" + this.getFeedback() + ")";
-    }
-
-    public boolean isPassFail() {
-        return getMaxPoints() == 1 && getPointsRequiredToPass() == 1;
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java
index 5c8734af9b..6c516f95b4 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPoint.java
@@ -1,37 +1,39 @@
 package se.su.dsv.scipro.report;
 
 import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.Table;
 import java.util.Objects;
 
 @Entity
-@Table(name = "GradingCriterionPoint")
+@Table(name = "grading_criterion_point")
 public class GradingCriterionPoint extends AbstractGradingCriterionPoint {
-
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_criterion_point) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @ManyToOne(optional = false)
+    @JoinColumn(name = "grading_criterion_id", referencedColumnName = "id")
     private GradingCriterion gradingCriterion;
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     public GradingCriterionPoint() {
     }
 
-    public GradingCriterionPoint(
-            final Integer point,
-            final String description,
-            final String descriptionEn,
-            final GradingCriterion gradingCriterion)
-    {
+    public GradingCriterionPoint(final Integer point, final String description,
+            final String descriptionEn, final GradingCriterion gradingCriterion) {
         setPoint(point);
         setDescription(description);
         setDescriptionEn(descriptionEn);
         this.gradingCriterion = gradingCriterion;
     }
 
-    @Override
-    public int compareTo(AbstractGradingCriterionPoint abstractGradingCriterionPoint) {
-        return this.getPoint().compareTo(abstractGradingCriterionPoint.getPoint());
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public GradingCriterion getGradingCriterion() {
         return this.gradingCriterion;
     }
@@ -40,9 +42,12 @@ public class GradingCriterionPoint extends AbstractGradingCriterionPoint {
         this.gradingCriterion = gradingCriterion;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects and Comparable
+    // ----------------------------------------------------------------------------------
     @Override
-    public String toString() {
-        return "GradingCriterionPoint(gradingCriterion=" + this.getGradingCriterion() + ")";
+    public int compareTo(AbstractGradingCriterionPoint abstractGradingCriterionPoint) {
+        return this.getPoint().compareTo(abstractGradingCriterionPoint.getPoint());
     }
 
     @Override
@@ -55,13 +60,22 @@ public class GradingCriterionPoint extends AbstractGradingCriterionPoint {
                 && Objects.equals(this.getGradingCriterion(), other.getGradingCriterion());
     }
 
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.getGradingCriterion());
+    }
+
+    @Override
+    public String toString() {
+        return "GradingCriterionPoint(gradingCriterion=" + this.getGradingCriterion() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
     @Override
     protected boolean canEqual(final Object other) {
         return other instanceof GradingCriterionPoint;
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.getGradingCriterion());
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java
index 88708ddf1d..a41785948a 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionPointTemplate.java
@@ -1,8 +1,10 @@
 package se.su.dsv.scipro.report;
 
 import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
 import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
@@ -10,6 +12,7 @@ import java.util.Objects;
 public class GradingCriterionPointTemplate extends AbstractGradingCriterionPoint {
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "grading_criterion_template_id", nullable = false)
     private GradingCriterionTemplate gradingCriterionTemplate;
 
     @Override
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java
index 6feaee5bd8..92ab7539dc 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingCriterionTemplate.java
@@ -1,18 +1,29 @@
 package se.su.dsv.scipro.report;
 
-import jakarta.persistence.*;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.DiscriminatorColumn;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
+
 @Entity
-@DiscriminatorColumn(name = "type", length = GradingCriterionTemplate.LENGTH)
-@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 @Table(name = "grading_criterion_template")
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(name = "type", length = GradingCriterionTemplate.LENGTH)
 public abstract class GradingCriterionTemplate extends AbstractGradingCriterion {
     public static final int LENGTH = 64;
+
     @ManyToOne(optional = false)
+    @JoinColumn(name = "grading_report_template_id")
     private GradingReportTemplate gradingReportTemplate;
 
     @OneToMany(mappedBy = "gradingCriterionTemplate", orphanRemoval = true, cascade = CascadeType.ALL)
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java
index 0c036ede48..6957cae4d5 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReport.java
@@ -1,11 +1,19 @@
 package se.su.dsv.scipro.report;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.Language;
 import se.su.dsv.scipro.system.ProjectType;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -13,6 +21,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 @Entity
+@Table(name = "grading_report")
 public abstract class GradingReport extends Report {
 
     public record Grade(String name) {
@@ -27,40 +36,51 @@ public abstract class GradingReport extends Report {
 
     public enum State { INITIAL, REVIEWING, FINALIZED }
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @Basic
+    @Column(name = "state")
     @Enumerated(EnumType.STRING)
     private State state = State.INITIAL;
 
-    @ManyToOne(optional = false)
-    private Project project;
-
-    @OneToMany(mappedBy = "gradingReport", cascade = {CascadeType.ALL})
-    private List<GradingCriterion> gradingCriteria = new ArrayList<>();
-
     @Basic
     @Column(name = "date_submitted_to_examiner")
     private Instant dateSubmittedToExaminer;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_report) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    private Project project;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "grading_report"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "gradingReport", cascade = {CascadeType.ALL})
+    private List<GradingCriterion> gradingCriteria = new ArrayList<>();
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected GradingReport() {
         // JPA
     }
 
-    @Override
-    public void submit() {
-        super.submit();
-        setState(State.FINALIZED);
-        setDateSubmittedToExaminer(Instant.now());
-    }
-
-    public Project getProject() {
-        return project;
-    }
-
     GradingReport(Project project) {
         this.project = project;
     }
 
-    void addCriterion(GradingCriterion criterion) {
-        gradingCriteria.add(criterion);
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public State getState() {
+        return state;
+    }
+
+    public void setState(final State state) {
+        this.state = state;
     }
 
     public Instant getDateSubmittedToExaminer(){
@@ -71,12 +91,8 @@ public abstract class GradingReport extends Report {
         this.dateSubmittedToExaminer = dateSubmittedToExaminer;
     }
 
-    public State getState() {
-        return state;
-    }
-
-    public void setState(final State state) {
-        this.state = state;
+    public Project getProject() {
+        return project;
     }
 
     public List<GradingCriterion> getGradingCriteria() {
@@ -84,6 +100,21 @@ public abstract class GradingReport extends Report {
         return Collections.unmodifiableList(gradingCriteria);
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return "GradingReport(state=" + this.getState() + ", project=" + this.getProject() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    void addCriterion(GradingCriterion criterion) {
+        gradingCriteria.add(criterion);
+    }
+
     public String getProjectTitle() {
         return project.getTitle();
     }
@@ -112,7 +143,9 @@ public abstract class GradingReport extends Report {
     }
 
     @Override
-    public String toString() {
-        return "GradingReport(state=" + this.getState() + ", project=" + this.getProject() + ")";
+    public void submit() {
+        super.submit();
+        setState(State.FINALIZED);
+        setDateSubmittedToExaminer(Instant.now());
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java
index 6f9b1a9824..876d3a4010 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.report;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.grading.GradingBasis;
 import se.su.dsv.scipro.grading.GradingReportTemplateService;
@@ -48,6 +48,7 @@ public class GradingReportServiceImpl implements GradingReportTemplateService, G
     }
 
     @Override
+    @Transactional
     public boolean updateOppositionCriteria(SupervisorGradingReport report, FinalSeminarOpposition opposition) {
         for (GradingCriterion gradingCriterion : report.getIndividualCriteria()) {
             boolean isOppositionCriterion = gradingCriterion.getFlag() == GradingCriterion.Flag.OPPOSITION;
@@ -133,6 +134,7 @@ public class GradingReportServiceImpl implements GradingReportTemplateService, G
     }
 
     @Override
+    @Transactional
     public List<SupervisorGradingReport> getSupervisorGradingReports(Project project) {
         List<SupervisorGradingReport> gradingReports = new ArrayList<>();
         for (User user : project.getProjectParticipants()) {
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java
index cc106b6c95..55fe04823b 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplate.java
@@ -1,17 +1,28 @@
 package se.su.dsv.scipro.report;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.OrderBy;
+import jakarta.persistence.Table;
+import jakarta.persistence.Temporal;
+import jakarta.persistence.TemporalType;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-
 import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 
@@ -19,18 +30,16 @@ import java.util.Objects;
 @Table(name = "grading_report_template")
 public class GradingReportTemplate extends DomainObject {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    @OneToOne(optional = false)
-    private ProjectType projectType;
-
-    @OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL}, orphanRemoval = true)
-    private Collection<GradingCriterionTemplate> criteria = new HashSet<>();
-
-    @Temporal(TemporalType.DATE)
+    @Basic
     @Column(name = "valid_from")
+    @Temporal(TemporalType.DATE)
     private LocalDate validFrom;
 
     @Basic
@@ -41,10 +50,28 @@ public class GradingReportTemplate extends DomainObject {
     @Column(name = "failing_grade")
     private String failingGrade;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_report_template) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = false)
+    @JoinColumn(name = "project_type_id", referencedColumnName = "id")
+    private ProjectType projectType;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "grading_report_template"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "gradingReportTemplate", cascade = {CascadeType.ALL}, orphanRemoval = true)
+    @OrderBy("sortOrder ASC")
+    private List<GradingCriterionTemplate> criteria = new ArrayList<>();
+
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
-    @JoinColumn(name = "grading_report_template_id")
+    @JoinColumn(name = "grading_report_template_id", referencedColumnName = "id")
     private Collection<GradeLimit> gradeLimits = new ArrayList<>();
 
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected GradingReportTemplate() {
 
     }
@@ -57,43 +84,9 @@ public class GradingReportTemplate extends DomainObject {
         this.validFrom = validFrom;
     }
 
-    public SupervisorGradingReport createSupervisorReport(Project project, User student) {
-        if (!this.projectType.equals(project.getProjectType())) {
-            throw new IllegalArgumentException("Project has a different project class than this template");
-        }
-        return new SupervisorGradingReportFactory().using(criteria).create(project, student);
-    }
-
-    public OppositionReport createOppositionReport(FinalSeminarOpposition finalSeminarOpposition) {
-        return new OppositionReport(this, finalSeminarOpposition);
-    }
-
-    public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) {
-        return addProjectCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null);
-    }
-
-    public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, AbstractGradingCriterion.Flag flag) {
-        GradingCriterionTemplate gradingCriterionTemplate = new ProjectGradingCriterionTemplate(this, criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates);
-        gradingCriterionTemplate.setFlag(flag);
-        criteria.add(gradingCriterionTemplate);
-        return gradingCriterionTemplate;
-    }
-
-    public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) {
-        return addIndividualCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null);
-    }
-
-    public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass, List<GradingCriterionPointTemplate> gradingCriterionPointTemplates, AbstractGradingCriterion.Flag flag) {
-        GradingCriterionTemplate gradingCriterionTemplate = new IndividualGradingCriterionTemplate(this, criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates);
-        gradingCriterionTemplate.setFlag(flag);
-        criteria.add(gradingCriterionTemplate);
-        return gradingCriterionTemplate;
-    }
-
-    public Collection<GradingCriterionTemplate> getCriteria() {
-        return criteria;
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
@@ -107,14 +100,6 @@ public class GradingReportTemplate extends DomainObject {
         this.validFrom = validFrom;
     }
 
-    public ProjectType getProjectType() {
-        return projectType;
-    }
-
-    public void setProjectType(ProjectType projectType) {
-        this.projectType = projectType;
-    }
-
     public String getNote() {
         return note;
     }
@@ -131,6 +116,18 @@ public class GradingReportTemplate extends DomainObject {
         this.failingGrade = failingGrade;
     }
 
+    public ProjectType getProjectType() {
+        return projectType;
+    }
+
+    public void setProjectType(ProjectType projectType) {
+        this.projectType = projectType;
+    }
+
+    public Collection<GradingCriterionTemplate> getCriteria() {
+        return criteria;
+    }
+
     public Collection<GradeLimit> getGradeLimits() {
         return gradeLimits;
     }
@@ -139,6 +136,9 @@ public class GradingReportTemplate extends DomainObject {
         this.gradeLimits = gradeLimits;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -148,10 +148,6 @@ public class GradingReportTemplate extends DomainObject {
                 && Objects.equals(this.id, other.id);
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof GradingReportTemplate;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hashCode(this.id);
@@ -159,6 +155,56 @@ public class GradingReportTemplate extends DomainObject {
 
     @Override
     public String toString() {
-        return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", validFrom=" + this.validFrom + ")";
+        return "GradingReportTemplate(id=" + this.id + ", projectType=" + this.projectType + ", validFrom=" +
+                this.validFrom + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    public SupervisorGradingReport createSupervisorReport(Project project, User student) {
+        if (!this.projectType.equals(project.getProjectType())) {
+            throw new IllegalArgumentException("Project has a different project class than this template");
+        }
+        return new SupervisorGradingReportFactory().using(criteria).create(project, student);
+    }
+
+    public OppositionReport createOppositionReport(FinalSeminarOpposition finalSeminarOpposition) {
+        return new OppositionReport(this, finalSeminarOpposition);
+    }
+
+    public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass,
+                                                        List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) {
+        return addProjectCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null);
+    }
+
+    public GradingCriterionTemplate addProjectCriterion(String title, String titleEn, int pointsRequiredToPass,
+                                                        List<GradingCriterionPointTemplate> gradingCriterionPointTemplates,
+                                                        AbstractGradingCriterion.Flag flag) {
+        GradingCriterionTemplate gradingCriterionTemplate = new ProjectGradingCriterionTemplate(this,
+                criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates);
+        gradingCriterionTemplate.setFlag(flag);
+        criteria.add(gradingCriterionTemplate);
+        return gradingCriterionTemplate;
+    }
+
+    public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass,
+                                                           List<GradingCriterionPointTemplate> gradingCriterionPointTemplates) {
+        return addIndividualCriterion(title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates, null);
+    }
+
+    public GradingCriterionTemplate addIndividualCriterion(String title, String titleEn, int pointsRequiredToPass,
+                                                           List<GradingCriterionPointTemplate> gradingCriterionPointTemplates,
+                                                           AbstractGradingCriterion.Flag flag) {
+        GradingCriterionTemplate gradingCriterionTemplate = new IndividualGradingCriterionTemplate(this,
+                criteria.size(), title, titleEn, pointsRequiredToPass, gradingCriterionPointTemplates);
+        gradingCriterionTemplate.setFlag(flag);
+        criteria.add(gradingCriterionTemplate);
+        return gradingCriterionTemplate;
+    }
+
+
+    protected boolean canEqual(final Object other) {
+        return other instanceof GradingReportTemplate;
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java
index 8cf96941a1..7eec180ce5 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/GradingReportTemplateRepoImpl.java
@@ -1,8 +1,8 @@
 package se.su.dsv.scipro.report;
 
-import com.google.inject.persist.Transactional;
 import com.querydsl.jpa.JPAExpressions;
 import com.querydsl.jpa.JPQLQuery;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.grading.GradingReportTemplateUpdate;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.GenericRepo;
diff --git a/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java b/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java
index 5775a6db0b..426e393399 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/OppositionReport.java
@@ -1,10 +1,17 @@
 package se.su.dsv.scipro.report;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.system.Language;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -15,56 +22,57 @@ import java.util.stream.Collectors;
 @Table(name = "opposition_report")
 public class OppositionReport extends AttachmentReport {
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @Basic
+    @Column(name = "thesis_summary")
+    private String thesisSummary;
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (opposition_report) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
     @OneToOne(optional = false)
+    @JoinColumn(name = "final_seminar_opposition_id", referencedColumnName = "id")
     private FinalSeminarOpposition finalSeminarOpposition;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "opposition_report"
+    // ----------------------------------------------------------------------------------
     @OneToMany(mappedBy = "report", cascade = {CascadeType.ALL})
     private List<Criterion> oppositionCriteria = new ArrayList<>();
 
-    @Basic
-    @Column
-    private String thesisSummary;
-
-
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected OppositionReport() {
-
     }
 
-    public OppositionReport(GradingReportTemplate gradingReportTemplate, FinalSeminarOpposition finalSeminarOpposition) {
+    public OppositionReport(GradingReportTemplate gradingReportTemplate,
+                            FinalSeminarOpposition finalSeminarOpposition) {
         this.finalSeminarOpposition = finalSeminarOpposition;
         createCriteriaFromTemplate(gradingReportTemplate);
     }
 
-    private void createCriteriaFromTemplate(GradingReportTemplate gradingReportTemplate) {
-        for (GradingCriterionTemplate template : gradingReportTemplate.getCriteria()) {
-            if (template.isProjectCriterion()) {
-                oppositionCriteria.add(new Criterion(this, template));
-            }
-        }
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public String getThesisSummary() {
+        return this.thesisSummary;
     }
 
-    public List<Criterion> getCriteria() {
-        oppositionCriteria.sort(new AbstractCriterion.BySortOrderComparator());
-        return Collections.unmodifiableList(oppositionCriteria);
+    public void setThesisSummary(String thesisSummary) {
+        this.thesisSummary = thesisSummary;
     }
 
-    @Override
-    public boolean isFinished() {
-        if (thesisSummaryIsEmpty()) {
-            return false;
-        }
-        for (Criterion criterion : oppositionCriteria) {
-            if (!criterion.isFilledOut()) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean thesisSummaryIsEmpty() {
-        return thesisSummary == null || thesisSummary.isEmpty();
+    public FinalSeminarOpposition getFinalSeminarOpposition() {
+        return this.finalSeminarOpposition;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
     public User getUser() {
         return finalSeminarOpposition.getUser();
     }
@@ -110,15 +118,33 @@ public class OppositionReport extends AttachmentReport {
         return finalSeminarOpposition.getUser().getLastName();
     }
 
-    public FinalSeminarOpposition getFinalSeminarOpposition() {
-        return this.finalSeminarOpposition;
+    private void createCriteriaFromTemplate(GradingReportTemplate gradingReportTemplate) {
+        for (GradingCriterionTemplate template : gradingReportTemplate.getCriteria()) {
+            if (template.isProjectCriterion()) {
+                oppositionCriteria.add(new Criterion(this, template));
+            }
+        }
     }
 
-    public String getThesisSummary() {
-        return this.thesisSummary;
+    public List<Criterion> getCriteria() {
+        oppositionCriteria.sort(new AbstractCriterion.BySortOrderComparator());
+        return Collections.unmodifiableList(oppositionCriteria);
     }
 
-    public void setThesisSummary(String thesisSummary) {
-        this.thesisSummary = thesisSummary;
+    @Override
+    public boolean isFinished() {
+        if (thesisSummaryIsEmpty()) {
+            return false;
+        }
+        for (Criterion criterion : oppositionCriteria) {
+            if (!criterion.isFilledOut()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean thesisSummaryIsEmpty() {
+        return thesisSummary == null || thesisSummary.isEmpty();
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java
index 417e7a15bf..231fe6f692 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/OppositionReportServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.report;
 
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
diff --git a/core/src/main/java/se/su/dsv/scipro/report/Report.java b/core/src/main/java/se/su/dsv/scipro/report/Report.java
index dd1437fc18..da88711b3b 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/Report.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/Report.java
@@ -1,48 +1,36 @@
 package se.su.dsv.scipro.report;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Inheritance;
+import jakarta.persistence.InheritanceType;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.DomainObject;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
 @Table(name = "report")
 @Inheritance(strategy = InheritanceType.JOINED)
 public abstract class Report extends DomainObject {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
     @Basic(optional = false)
+    @Column(name = "submitted")
     private boolean submitted = false;
 
-    public abstract boolean isFinished();
-
-    public void submit() {
-        if (!isFinished()) {
-            throw new IllegalStateException("Report is not finished: you need to score and give feedback to every criteria");
-        }
-        submitted = true;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (o == this) return true;
-        if (!(o instanceof Report)) return false;
-        final Report other = (Report) o;
-        return other.canEqual(this)
-                && Objects.equals(this.id, other.id);
-    }
-
-    protected boolean canEqual(final Object other) {
-        return other instanceof Report;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(this.id);
-    }
-
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
@@ -55,4 +43,37 @@ public abstract class Report extends DomainObject {
     public void setSubmitted(boolean submitted) {
         this.submitted = submitted;
     }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        if (!(o instanceof Report)) return false;
+        final Report other = (Report) o;
+        return other.canEqual(this)
+                && Objects.equals(this.id, other.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.id);
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof Report;
+    }
+
+    public abstract boolean isFinished();
+
+    public void submit() {
+        if (!isFinished()) {
+            throw new IllegalStateException("Report is not finished: you need to score and give feedback to every criteria");
+        }
+        submitted = true;
+    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java
index f8ba6bd969..a0f324029f 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/ReportServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.report;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.file.FileUpload;
@@ -22,12 +22,14 @@ public class ReportServiceImpl extends AbstractServiceImpl<Report, Long> impleme
     }
 
     @Override
+    @Transactional
     public AttachmentReport submit(AttachmentReport report) {
         report.submit();
         return save(report);
     }
 
     @Override
+    @Transactional
     public void save(AttachmentReport report, Optional<FileUpload> fileUpload) {
         storeReportFile(report, fileUpload);
         save(report);
diff --git a/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java b/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java
index b3e682dfba..59b4bca6b8 100644
--- a/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java
+++ b/core/src/main/java/se/su/dsv/scipro/report/SupervisorGradingReport.java
@@ -1,26 +1,24 @@
 package se.su.dsv.scipro.report;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import se.su.dsv.scipro.project.Project;
-import se.su.dsv.scipro.system.User;
-
 import jakarta.persistence.Basic;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
+import jakarta.persistence.JoinColumn;
 import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.User;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 @Entity
+@Table(name = "supervisor_grading_report")
 public class SupervisorGradingReport extends GradingReport {
-
-    private static final Logger LOG = LoggerFactory.getLogger(SupervisorGradingReport.class);
-
-    @ManyToOne(optional = false)
-    private User user;
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Basic
     @Column(name = "rejection_comment")
     private String rejectionComment;
@@ -33,6 +31,17 @@ public class SupervisorGradingReport extends GradingReport {
     @Column(name = "motivation")
     private String motivation;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (grading_criterion) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected SupervisorGradingReport() {
         // JPA
     }
@@ -42,6 +51,40 @@ public class SupervisorGradingReport extends GradingReport {
         this.user = user;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    public User getUser() {
+        return this.user;
+    }
+
+    public String getRejectionComment() {
+        return rejectionComment;
+    }
+
+    public void setRejectionComment(String rejectionComment) {
+        this.rejectionComment = rejectionComment;
+    }
+
+    public String getRejectionCommentFeedback() {
+        return rejectionCommentFeedback;
+    }
+
+    public void setRejectionCommentFeedback(String rejectionCommentFeedback) {
+        this.rejectionCommentFeedback = rejectionCommentFeedback;
+    }
+
+    public String getMotivation() {
+        return motivation;
+    }
+
+    public void setMotivation(String motivation) {
+        this.motivation = motivation;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
     public List<GradingCriterion> getProjectCriteria() {
         List<GradingCriterion> result = new ArrayList<>();
         for (GradingCriterion criterion : getGradingCriteria()) {
@@ -82,34 +125,6 @@ public class SupervisorGradingReport extends GradingReport {
         return true;
     }
 
-    public User getUser() {
-        return this.user;
-    }
-
-    public String getRejectionComment() {
-        return rejectionComment;
-    }
-
-    public void setRejectionComment(String rejectionComment) {
-        this.rejectionComment = rejectionComment;
-    }
-
-    public String getRejectionCommentFeedback() {
-        return rejectionCommentFeedback;
-    }
-
-    public void setRejectionCommentFeedback(String rejectionCommentFeedback) {
-        this.rejectionCommentFeedback = rejectionCommentFeedback;
-    }
-
-    public String getMotivation() {
-        return motivation;
-    }
-
-    public void setMotivation(String motivation) {
-        this.motivation = motivation;
-    }
-
     public boolean hasProvidedOverallMotivation() {
         return getMotivation() != null && !getMotivation().isBlank();
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
index cc255a893e..6d3fb25f16 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/Decision.java
@@ -20,51 +20,73 @@ import se.su.dsv.scipro.system.User;
 
 import java.time.Instant;
 import java.time.LocalDate;
-import java.util.*;
+import java.util.Date;
+import java.util.Optional;
 
 @Entity
-@Table(name = "Decision")
+@Table(name = "decision")
 public class Decision {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
+    @Basic
+    @Column(name = "status")
     @Enumerated(EnumType.STRING)
     private Status status = Status.UNDECIDED;
 
-    @OneToOne(optional = false)
-    @JoinColumn(name = "thesis_reference_id")
-    private FileReference thesis;
-
     @Basic
+    @Column(name = "reason")
     private String reason;
 
     @Basic
+    @Column(name = "comment")
     private String comment;
 
-    @OneToOne(optional = true)
-    @JoinColumn(name = "attachment_reference_id")
-    private FileReference attachment;
-
+    @Basic
+    @Column(name = "requested_date")
     @Temporal(TemporalType.TIMESTAMP)
     private Date requested;
 
-    @Temporal(TemporalType.TIMESTAMP)
-    private Date deadline;
-
+    @Basic
+    @Column(name = "decision_date")
     @Temporal(TemporalType.TIMESTAMP)
     private Date decisionDate;
 
-    @ManyToOne(optional = false)
-    private ReviewerApproval reviewerApproval;
-
-    @ManyToOne
-    @JoinColumn(name = "assigned_reviewer_id")
-    private User assignedReviewer;
+    @Basic
+    @Column(name = "deadline")
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date deadline;
 
+    @Basic
     @Column(name = "assigned_reviewer_date")
     private LocalDate reviewerAssignedAt;
 
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (decision) referencing other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne
+    @JoinColumn(name = "assigned_reviewer_id", referencedColumnName = "id")
+    private User assignedReviewer;
+
+    @OneToOne(optional = true)
+    @JoinColumn(name = "attachment_reference_id", referencedColumnName = "id")
+    private FileReference attachment;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "reviewer_approval_id", referencedColumnName = "id")
+    private ReviewerApproval reviewerApproval;
+
+    @OneToOne(optional = false)
+    @JoinColumn(name = "thesis_reference_id", referencedColumnName = "id")
+    private FileReference thesis;
+
+    // ----------------------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------------------
     protected Decision() {} // JPA
 
     Decision(ReviewerApproval reviewerApproval, final FileReference thesis, final String comment, final Date deadline) {
@@ -79,6 +101,9 @@ public class Decision {
         this.comment = comment;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     public Long getId() {
         return id;
     }
@@ -87,14 +112,6 @@ public class Decision {
         this.id = id;
     }
 
-    public FileReference getThesis() {
-        return thesis;
-    }
-
-    public ReviewerApproval getReviewerApproval() {
-        return reviewerApproval;
-    }
-
     public Status getStatus() {
         return status;
     }
@@ -107,10 +124,6 @@ public class Decision {
         return comment;
     }
 
-    public Optional<FileReference> getAttachment() {
-        return Optional.ofNullable(attachment);
-    }
-
     public Date getRequested() {
         return requested;
     }
@@ -127,14 +140,6 @@ public class Decision {
         this.deadline = deadline;
     }
 
-    public User getAssignedReviewer() {
-        return assignedReviewer;
-    }
-
-    public void setAssignedReviewer(User assignedReviewer) {
-        this.assignedReviewer = assignedReviewer;
-    }
-
     public LocalDate getReviewerAssignedAt() {
         return reviewerAssignedAt;
     }
@@ -143,6 +148,29 @@ public class Decision {
         this.reviewerAssignedAt = reviewerAssignedAt;
     }
 
+    public User getAssignedReviewer() {
+        return assignedReviewer;
+    }
+
+    public void setAssignedReviewer(User assignedReviewer) {
+        this.assignedReviewer = assignedReviewer;
+    }
+
+    public Optional<FileReference> getAttachment() {
+        return Optional.ofNullable(attachment);
+    }
+
+    public ReviewerApproval getReviewerApproval() {
+        return reviewerApproval;
+    }
+
+    public FileReference getThesis() {
+        return thesis;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
     void approve(final String reason, final Optional<FileReference> attachment) {
         decide(Status.APPROVED, reason, attachment);
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java
index 5d8e123342..fec755260c 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/FinalSeminarApprovalServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.reviewing;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.file.FileUpload;
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java
index 736c9d4120..9a5239e570 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ProjectFinalSeminarStatisticsServiceImpl.java
@@ -27,7 +27,7 @@ import static com.querydsl.core.types.dsl.Expressions.anyOf;
 public class ProjectFinalSeminarStatisticsServiceImpl extends AbstractServiceImpl<Project, Long> implements ProjectFinalSeminarStatisticsService {
 
     @Inject
-    protected ProjectFinalSeminarStatisticsServiceImpl(Provider<EntityManager> em) {
+    public ProjectFinalSeminarStatisticsServiceImpl(Provider<EntityManager> em) {
         super(em, Project.class, QProject.project);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
index 25c63338aa..cdad680797 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerApproval.java
@@ -1,6 +1,8 @@
 package se.su.dsv.scipro.reviewing;
 
 import jakarta.persistence.GenerationType;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
@@ -13,31 +15,61 @@ import jakarta.persistence.Id;
 import jakarta.persistence.OneToMany;
 import jakarta.persistence.OneToOne;
 import jakarta.persistence.OrderBy;
-import java.util.*;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
 
 @Entity
+@Table(name = "reviewer_approval")
 @DiscriminatorColumn(name = "type", length = 64)
 public abstract class ReviewerApproval extends DomainObject {
-    @OneToOne(optional = false)
-    protected Project project;
-
-    @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL)
-    @OrderBy("requested desc")
-    protected List<Decision> decisions = new LinkedList<>();
-
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
 
-    public abstract Step getStep();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (reviewer_approval) referencing other
+    // tables.
+    // ----------------------------------------------------------------------------------
+    @OneToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    protected Project project;
 
-    public FileReference getCurrentThesis() {
-        return getCurrentDecision().getThesis();
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of other tables referencing to this table "reviewer_approval"
+    // ----------------------------------------------------------------------------------
+    @OneToMany(mappedBy = "reviewerApproval", cascade = CascadeType.ALL)
+    @OrderBy("requested desc")
+    protected List<Decision> decisions = new LinkedList<>();
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
+    @Override
+    public Long getId() {
+        return this.id;
     }
 
     public Project getProject(){return this.project;}
 
+    // ----------------------------------------------------------------------------------
+    // Other methods
+    // ----------------------------------------------------------------------------------
+    public abstract Step getStep();
 
+    public Decision getCurrentDecision() {
+        return decisions.get(0);
+    }
+
+    public FileReference getCurrentThesis() {
+        return getCurrentDecision().getThesis();
+    }
 
     public Status getCurrentStatus() {
         return getCurrentDecision().getStatus();
@@ -63,10 +95,6 @@ public abstract class ReviewerApproval extends DomainObject {
         getCurrentDecision().reject(reason, attachment);
     }
 
-    public Decision getCurrentDecision() {
-        return decisions.get(0);
-    }
-
     public void addNewThesis(final FileReference thesis, final String comment, final Date deadline) {
         if (getCurrentStatus() != Status.REJECTED) {
             throw new IllegalStateException();
@@ -86,17 +114,15 @@ public abstract class ReviewerApproval extends DomainObject {
         return getCurrentStatus() == Status.APPROVED;
     }
 
-    @Override
-    public Long getId() {
-        return this.id;
+    public Date getCurrentDeadline() {
+        return getCurrentDecision().getDeadline();
     }
 
+    // ----------------------------------------------------------------------------------
+    // Nested types.
+    // ----------------------------------------------------------------------------------
     public enum Step {
         ROUGH_DRAFT_APPROVAL,
         FINAL_SEMINAR_APPROVAL
     }
-
-    public Date getCurrentDeadline() {
-        return getCurrentDecision().getDeadline();
-    }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java
index c758523db5..08e67aa38b 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerCapacityServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.reviewing;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.project.ProjectService;
 import se.su.dsv.scipro.project.ReviewerAssignedEvent;
@@ -25,7 +25,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Stream;
 
-class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService {
+public class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAssignmentService {
     private final ReviewerTargetRepository reviewerTargetRepository;
     private final DecisionRepository decisionRepository;
     private final UserService userService;
@@ -33,7 +33,7 @@ class ReviewerCapacityServiceImpl implements ReviewerCapacityService, ReviewerAs
     private final EventBus eventBus;
 
     @Inject
-    ReviewerCapacityServiceImpl(
+    public ReviewerCapacityServiceImpl(
             ReviewerTargetRepository reviewerTargetRepository,
             DecisionRepository decisionRepository,
             UserService userService,
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java
index 3b200eac44..044ada8fb5 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettings.java
@@ -13,13 +13,13 @@ public class ReviewerDeadlineSettings extends DomainObject {
     @Id
     private Long id = null;
 
-    @Basic(optional = false)
+    @Column(name = "rough_draft_approval", nullable = false)
     private int roughDraftApproval = 5;
 
-    @Basic(optional = false)
+    @Column(name = "final_seminar_approval", nullable = false)
     private int finalSeminarApproval = 2;
 
-    @Basic(optional = false)
+    @Column(name = "final_grading", nullable = false)
     private int finalGrading = 5;
 
     public ReviewerDeadlineSettings() {
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java
index 0094b9e7dc..e95b191bb8 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepository.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.reviewing;
 
-interface ReviewerDeadlineSettingsRepository {
+public interface ReviewerDeadlineSettingsRepository {
     ReviewerDeadlineSettings findOne(long instanceId);
 
     ReviewerDeadlineSettings save(ReviewerDeadlineSettings entity);
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java
index bcaf1e434e..6839c0cac5 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsRepositoryImpl.java
@@ -6,12 +6,12 @@ import se.su.dsv.scipro.system.AbstractRepository;
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 
-class ReviewerDeadlineSettingsRepositoryImpl
+public class ReviewerDeadlineSettingsRepositoryImpl
         extends AbstractRepository
         implements ReviewerDeadlineSettingsRepository
 {
     @Inject
-    ReviewerDeadlineSettingsRepositoryImpl(Provider<EntityManager> em) {
+    public ReviewerDeadlineSettingsRepositoryImpl(Provider<EntityManager> em) {
         super(em);
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java
index e52d28d078..3f0db387dd 100755
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerDeadlineSettingsServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.reviewing;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 import jakarta.inject.Inject;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java
index 0079e40a2b..f0e62aacc6 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerInteractionServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.reviewing;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.forum.Attachment;
 import se.su.dsv.scipro.forum.BasicForumService;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
@@ -49,6 +49,7 @@ public class ReviewerInteractionServiceImpl implements ReviewerInteractionServic
     }
 
     @Override
+    @Transactional
     public ForumPost reply(final Project project, final User user, final String content, final Set<Attachment> attachments) {
         ReviewerThread reviewerThread = getReviewerThread(project);
         ForumPost reply = forumService.createReply(reviewerThread.getForumThread(), user, content, attachments);
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java
index 4a8b145f2e..29803d920f 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTarget.java
@@ -1,5 +1,6 @@
 package se.su.dsv.scipro.reviewing;
 
+import jakarta.persistence.Basic;
 import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.GeneratedValue;
@@ -10,7 +11,6 @@ import jakarta.persistence.Table;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import java.time.LocalDate;
 import java.util.Objects;
 
 @Entity
@@ -20,22 +20,26 @@ public class ReviewerTarget extends DomainObject {
     @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY)
     private Long id;
 
-    @ManyToOne(optional = false)
-    @JoinColumn(name = "reviewer_id", nullable = false)
-    private User reviewer;
-
+    @Basic
     @Column(name = "year", nullable = false)
     private int year;
 
+    @Basic
     @Column(name = "spring", nullable = false)
     private int spring;
 
+    @Basic
     @Column(name = "autumn", nullable = false)
     private int autumn;
 
+    @Basic
     @Column(name = "note")
     private String note;
 
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "reviewer_user_id", referencedColumnName = "id", nullable = false)
+    private User reviewer;
+
     @Override
     public Long getId() {
         return id;
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java
index 985ae1934b..ba1b9b961c 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerTargetRepositoryImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.reviewing;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.persistence.EntityManager;
 import se.su.dsv.scipro.system.AbstractRepository;
 import se.su.dsv.scipro.system.User;
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java
deleted file mode 100644
index 9a0d1d53f7..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingModule.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package se.su.dsv.scipro.reviewing;
-
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.file.FileService;
-
-import jakarta.persistence.EntityManager;
-
-public class ReviewingModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        requireBinding(FileService.class);
-        requireBinding(EntityManager.class);
-        bind(ReviewerThreadRepository.class).to(ReviewerThreadRepositoryImpl.class);
-        bind(ReviewerInteractionService.class).to(ReviewerInteractionServiceImpl.class);
-        bind(FinalSeminarApprovalService.class).to(FinalSeminarApprovalServiceImpl.class);
-        bind(MyReviewService.class).to(ReviewingServiceImpl.class);
-        bind(ReviewerDecisionService.class).to(ReviewingServiceImpl.class);
-        bind(RoughDraftApprovalService.class).to(RoughDraftApprovalServiceImpl.class);
-        bind(ReviewerDeadlineSettingsService.class).to(ReviewerDeadlineSettingsServiceImpl.class);
-        bind(ReviewerDeadlineSettingsRepository.class).to(ReviewerDeadlineSettingsRepositoryImpl.class);
-        bind(ReviewerDeadlineFollowupService.class).to(ReviewerDeadlineFollowupServiceImpl.class);
-        bind(ReviewerCapacityService.class).to(ReviewerCapacityServiceImpl.class);
-        bind(ReviewerAssignmentService.class).to(ReviewerCapacityServiceImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java
index 9087510e37..b56e733c68 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewingServiceImpl.java
@@ -7,6 +7,7 @@ import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import com.querydsl.core.types.dsl.LiteralExpression;
 import com.querydsl.jpa.impl.JPAQuery;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.file.FileUpload;
@@ -92,6 +93,7 @@ public class ReviewingServiceImpl extends AbstractServiceImpl<ReviewerApproval,
     }
 
     @Override
+    @Transactional
     public void reject(final ReviewerApproval reviewerApproval, final String reason, final Optional<FileUpload> feedback) {
         Optional<FileReference> feedbackFile = store(feedback);
         reviewerApproval.reject(reason, feedbackFile);
@@ -106,6 +108,7 @@ public class ReviewingServiceImpl extends AbstractServiceImpl<ReviewerApproval,
     }
 
     @Override
+    @Transactional
     public void approve(final ReviewerApproval process, final String reason, final Optional<FileUpload> feedback) {
         Optional<FileReference> feedbackFile = store(feedback);
         process.approve(reason, feedbackFile);
diff --git a/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java
index fea26c83d6..f7a4365b24 100644
--- a/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/reviewing/RoughDraftApprovalServiceImpl.java
@@ -1,7 +1,7 @@
 package se.su.dsv.scipro.reviewing;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.file.FileReference;
 import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.file.FileUpload;
diff --git a/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java b/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java
deleted file mode 100644
index 3598358043..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/security/auth/AuthenticationModule.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package se.su.dsv.scipro.security.auth;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.multibindings.Multibinder;
-
-public class AuthenticationModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(AuthenticationService.class).to(AuthenticationServiceImpl.class);
-
-        Multibinder<AuthenticationProvider> authenticationProviders
-                = Multibinder.newSetBinder(binder(), AuthenticationProvider.class);
-        authenticationProviders.addBinding().to(LocalAuthentication.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java
index ac863a2afa..e88c4b289b 100644
--- a/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java
+++ b/core/src/main/java/se/su/dsv/scipro/settings/dataobjects/UserProfile.java
@@ -1,5 +1,26 @@
 package se.su.dsv.scipro.settings.dataobjects;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Objects;
+
+import jakarta.persistence.Basic;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 import se.su.dsv.scipro.project.ProjectStatus;
 import se.su.dsv.scipro.project.ProjectTeamMemberRoles;
 import se.su.dsv.scipro.security.auth.roles.Roles;
@@ -7,12 +28,6 @@ import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.ProjectType;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Objects;
-
 @Entity
 @Table(name = "user_profile")
 public class UserProfile extends DomainObject {
@@ -24,40 +39,46 @@ public class UserProfile extends DomainObject {
     @OneToOne(optional = false)
     private User user;
 
-    @Basic(optional = true)
-    private String skypeId;
-
-    @Basic(optional = true)
-    private String phoneNumber;
-
-    @Basic(optional = true)
+    @Column(name = "other_info", nullable = true)
     private String otherInfo;
 
-    @Basic(optional = false)
+    @Column(name = "phone_number", nullable = true)
+    private String phoneNumber;
+
+    @Column(name = "skype_id", nullable = true)
+    private String skypeId;
+
+    @Column(name = "mail_compilation", nullable = false)
     private boolean mailCompilation = false;
 
+    @Column(name = "default_supervisor_filter", nullable = false)
+    private boolean defaultSupervisorFilter = true;
+
+    @Enumerated(EnumType.STRING)
+    @Column(name = "selected_role")
+    private Roles selectedRole;
+
     @ElementCollection
     @Enumerated(EnumType.STRING)
+    @CollectionTable(name = "user_profile_default_project_status_filter",
+            joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id"))
+    @Column(name = "default_project_status_filter")
     private Collection<ProjectStatus> defaultProjectStatusFilter = EnumSet.of(ProjectStatus.ACTIVE);
 
     @ElementCollection
     @Enumerated(EnumType.STRING)
+    @CollectionTable(name = "user_profile_default_project_team_member_roles_filter",
+            joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id"))
+    @Column(name = "default_project_team_member_roles_filter")
     private Collection<ProjectTeamMemberRoles> defaultProjectTeamMemberRolesFilter = EnumSet.of(ProjectTeamMemberRoles.CO_SUPERVISOR);
 
-    @Basic(optional = false)
-    private boolean defaultSupervisorFilter = true;
-
     @ManyToMany
-    @JoinTable(
-            name = "user_profile_ProjectType",
-            joinColumns = {@JoinColumn(name = "user_profile_id")}
+    @JoinTable(name = "user_profile_project_type",
+            joinColumns = @JoinColumn(name = "user_profile_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "project_type_id", referencedColumnName = "id")
     )
     private Collection<ProjectType> defaultProjectTypeFilter = new ArrayList<>();
 
-    @Basic
-    @Enumerated(EnumType.STRING)
-    private Roles selectedRole;
-
     @Basic
     @Enumerated(EnumType.STRING)
     @Column(name = "supervisor_project_note_display")
diff --git a/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java
index a89512dab1..992aa54888 100644
--- a/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/springdata/serviceimpls/UserProfileServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.springdata.serviceimpls;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.security.auth.roles.Roles;
 import se.su.dsv.scipro.settings.dataobjects.QUserProfile;
 import se.su.dsv.scipro.settings.dataobjects.UserProfile;
@@ -38,11 +38,13 @@ public class UserProfileServiceImpl extends AbstractServiceImpl<UserProfile, Lon
     }
 
     @Override
+    @Transactional
     public Roles findSelectedRole(User user) {
         return findByUser(user).getSelectedRole();
     }
 
     @Override
+    @Transactional
     public void setSelectedRole(User user, Roles role) {
         UserProfile profile = findByUser(user);
         profile.setSelectedRole(role);
diff --git a/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java b/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java
deleted file mode 100644
index 544a17ec39..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/sukat/SukatModule.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package se.su.dsv.scipro.sukat;
-
-import com.google.inject.AbstractModule;
-
-public class SukatModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        bind(Sukat.class).to(LDAP.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/survey/Question.java b/core/src/main/java/se/su/dsv/scipro/survey/Question.java
index 4097ad1283..4c2d6e4a73 100644
--- a/core/src/main/java/se/su/dsv/scipro/survey/Question.java
+++ b/core/src/main/java/se/su/dsv/scipro/survey/Question.java
@@ -1,11 +1,23 @@
 package se.su.dsv.scipro.survey;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Table;
+
 import java.io.Serializable;
 import java.util.LinkedList;
 import java.util.List;
 
 @Entity
+@Table(name = "question")
 public class Question implements Serializable {
     public enum Type { TEXT, SINGLE_CHOICE, MULTIPLE_CHOICE, GROUP_HEADING }
 
@@ -20,6 +32,9 @@ public class Question implements Serializable {
     private String text;
 
     @ElementCollection(fetch = FetchType.EAGER)
+    @CollectionTable(name = "question_choices",
+            joinColumns = @JoinColumn(name = "question_id", referencedColumnName = "id"))
+    @Column(name = "choices")
     private List<String> choices = new LinkedList<>();
 
     private Type type = Type.TEXT;
diff --git a/core/src/main/java/se/su/dsv/scipro/survey/Survey.java b/core/src/main/java/se/su/dsv/scipro/survey/Survey.java
index 01b44b7e1d..9c9621ec02 100644
--- a/core/src/main/java/se/su/dsv/scipro/survey/Survey.java
+++ b/core/src/main/java/se/su/dsv/scipro/survey/Survey.java
@@ -1,14 +1,23 @@
 package se.su.dsv.scipro.survey;
 
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
 import java.util.LinkedList;
 import java.util.List;
 
 @Entity
+@Table(name = "survey")
 public class Survey implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java
index 0deab2b69b..f8d94e7ab9 100644
--- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java
+++ b/core/src/main/java/se/su/dsv/scipro/survey/SurveyAnswer.java
@@ -6,7 +6,7 @@ import java.util.Set;
 import java.util.TreeSet;
 
 @Entity
-@Table
+@Table(name = "survey_answer")
 public class SurveyAnswer implements Serializable {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -21,6 +21,9 @@ public class SurveyAnswer implements Serializable {
     private String answer;
 
     @ElementCollection(fetch = FetchType.EAGER)
+    @CollectionTable(name = "survey_answer_multiple_answers",
+            joinColumns = @JoinColumn(name = "survey_answer_id", referencedColumnName = "id"))
+    @Column(name = "multiple_answers")
     private Set<String> multipleAnswers = new TreeSet<>();
 
     public Survey getSurvey() {
diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java
deleted file mode 100644
index 54a6c83c92..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyModule.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package se.su.dsv.scipro.survey;
-
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.finalthesis.FinalThesisService;
-
-import jakarta.persistence.EntityManager;
-
-public class SurveyModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        requireBinding(EntityManager.class);
-        requireBinding(FinalThesisService.class);
-        bind(SurveyRepository.class).to(SurveyRepositoryImpl.class);
-        bind(QuestionRepository.class).to(QuestionRepositoryImpl.class);
-        bind(SurveyService.class).to(SurveyServiceImpl.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java
index ecb7c22070..386c771880 100644
--- a/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/survey/SurveyServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.survey;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.finalthesis.FinalThesisService;
 import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettings;
 import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java
index 748940900e..f6d52a414b 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/AbstractServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.EntityPathBase;
 import com.querydsl.core.types.dsl.Expressions;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java b/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java
index bb414d678c..ebcdbb5627 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/DomainObject.java
@@ -8,10 +8,10 @@ import java.util.Objects;
 @MappedSuperclass
 public abstract class DomainObject implements Serializable {
 
-    @Basic(optional=false)
+    @Column(name = "date_created", nullable = false)
     private Date dateCreated = new Date();
 
-    @Basic(optional = false)
+    @Column(name = "last_modified", nullable = false)
     private Date lastModified = new Date();
 
     @Version
diff --git a/core/src/main/java/se/su/dsv/scipro/system/Event.java b/core/src/main/java/se/su/dsv/scipro/system/Event.java
index 76abc8f2bb..be417ccb9a 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/Event.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/Event.java
@@ -1,22 +1,36 @@
 package se.su.dsv.scipro.system;
 
 import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+
 import java.io.Serializable;
 import java.util.Objects;
 
 @Entity
+@Table(name = "event")
 public class Event implements Serializable {
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
     @Id
     private String name;
 
     @Basic
+    @Column(name = "description")
     private String description;
 
+    // ----------------------------------------------------------------------------------
+    // Constructor
+    // ----------------------------------------------------------------------------------
     protected Event() {
     }
 
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters)
+    // ----------------------------------------------------------------------------------
     public String getName() {
         return this.name;
     }
@@ -25,6 +39,13 @@ public class Event implements Serializable {
         return this.description;
     }
 
+    // ----------------------------------------------------------------------------------
+    // Other Methods
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof Event;
+    }
+
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -34,10 +55,6 @@ public class Event implements Serializable {
                 && Objects.equals(this.getName(), other.getName());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof Event;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hashCode(this.getName());
@@ -45,6 +62,7 @@ public class Event implements Serializable {
 
     @Override
     public String toString() {
-        return "Event(name=" + this.getName() + ", description=" + this.getDescription() + ")";
+        return "Event(name=" + this.getName() + ", description=" +
+                this.getDescription() + ")";
     }
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java b/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java
index 852eac7bbb..008e47babe 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/ExternalResource.java
@@ -1,9 +1,18 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
+@Table(name = "external_resource")
 public class ExternalResource {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -16,6 +25,7 @@ public class ExternalResource {
     private String url;
 
     @ManyToOne(optional = false)
+    @JoinColumn(name = "project_type_id")
     private ProjectType relevantFor;
 
     public ExternalResource() {} // JPA
diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java b/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java
index ad0f13494d..b326a9c967 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/FooterAddressRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 @Transactional
 public interface FooterAddressRepo extends JpaRepository<FooterAddress, Long>, QueryDslPredicateExecutor<FooterAddress> {
diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java
index 7676611142..68a84f622f 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLink.java
@@ -13,6 +13,7 @@ public class FooterLink extends DomainObject {
     private Long id;
 
     @Enumerated(EnumType.STRING)
+    @Column(name = "footer_column")
     private FooterColumn footerColumn;
 
     @Basic(optional = false)
diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java
index bd0c349289..8994ba19ae 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 import java.util.List;
 import java.util.Optional;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java
index 327b83accc..901a487f84 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/FooterLinkServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 import jakarta.inject.Inject;
 import java.util.List;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java b/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java
index 2a42a60a0e..07ae33135f 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/GenericRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.EntityPathBase;
 import com.querydsl.core.types.dsl.Expressions;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java
index 0c58d7f4d5..e14516ffb9 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/MergeServiceImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 import jakarta.inject.Inject;
 
diff --git a/core/src/main/java/se/su/dsv/scipro/system/Password.java b/core/src/main/java/se/su/dsv/scipro/system/Password.java
index 32dd434660..8cc600ed24 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/Password.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/Password.java
@@ -1,11 +1,18 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 import java.util.Arrays;
 import java.util.Objects;
 
 @Entity
-@Table
+@Table(name = "password")
 public class Password extends LazyDeletableDomainObject {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
diff --git a/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java b/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java
index 32d5c4c4f9..53dfe5d7a8 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/PasswordRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 
 
 @Transactional
diff --git a/core/src/main/java/se/su/dsv/scipro/system/Program.java b/core/src/main/java/se/su/dsv/scipro/system/Program.java
index 2c23655ccc..f2aba4587d 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/Program.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/Program.java
@@ -1,10 +1,16 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+
 @Entity
-@Table(name = "Program")
+@Table(name = "program")
 public class Program extends DomainObject {
 
     @Id
@@ -12,13 +18,13 @@ public class Program extends DomainObject {
     @Column(name = "id")
     private Long id;
 
-    @Column(name = "externalId")
+    @Column(name = "external_id")
     private Integer externalId;
 
-    @Column(name = "name")
+    @Column(name = "name_sv")
     private String name;
 
-    @Column(name = "nameEn", nullable = true)
+    @Column(name = "name_en", nullable = true)
     private String nameEn;
 
     @Column(name = "code")
diff --git a/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java b/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java
index 0d3bd00f2c..b3f8849870 100644
--- a/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/ProjectType.java
@@ -1,12 +1,29 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
 import java.util.EnumSet;
 import java.util.Objects;
 import java.util.Set;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.Lob;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 @Entity
 @Cacheable(true)
+@Table(name = "project_type")
 public class ProjectType extends LazyDeletableDomainObject {
 	public static final DegreeType MASTER = DegreeType.MASTER;
 	public static final DegreeType BACHELOR = DegreeType.BACHELOR;
@@ -26,7 +43,7 @@ public class ProjectType extends LazyDeletableDomainObject {
 	private ProjectTypeSettings projectTypeSettings = new ProjectTypeSettings(this);
 
     @Enumerated(EnumType.STRING)
-    @Column(nullable = false)
+    @Column(name = "degree_type", nullable = false)
     private DegreeType degreeType = DegreeType.NONE;
 	
 	@Lob
@@ -34,7 +51,9 @@ public class ProjectType extends LazyDeletableDomainObject {
 
     @ElementCollection
     @Enumerated(EnumType.STRING)
-    @JoinTable(name = "project_type_project_modules")
+    @CollectionTable(name = "project_type_project_module",
+            joinColumns = @JoinColumn(name = "project_type_id", referencedColumnName = "id"))
+    @Column(name = "project_module")
     private Set<ProjectModule> projectModules = EnumSet.allOf(ProjectModule.class);
 
     @Basic(optional = false)
diff --git a/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java b/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java
index f83d626f1b..2c64d6629d 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/ProjectTypeSettings.java
@@ -1,68 +1,84 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
-@Table(name="project_type_settings")
 @Cacheable(true)
+@Table(name="project_type_settings")
 public class ProjectTypeSettings extends DomainObject {
-	public ProjectTypeSettings(){}
-	
-	public ProjectTypeSettings(ProjectType projectType){
-		this.projectType = projectType;
-	}
+	public static final int DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT = 7;
+	public static final int DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW = 3;
+	public static final int DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS = 90;
 
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 
 	@OneToOne(optional = false)
+	@JoinColumn(name = "project_type_id")
 	private ProjectType projectType;
 
-	@Basic(optional=false)
-	private int minAuthors = 1;
-	@Basic(optional=false)
-	private int maxAuthors = 2;
-
-	@Basic(optional=false)
-	private int maxFinalSeminarActiveParticipation;
-	@Basic(optional=false)
-	private int maxOpponentsOnFinalSeminar;
-	@Basic(optional=false)
-	private int minFinalSeminarActiveParticipation;
-	@Basic(optional=false)
-	private int minOpponentsOnFinalSeminar;
-
-	private int minimumOppositionsToBeGraded = 0;
-	private int minimumActiveParticipationsToBeGraded = 0;
-
-	public static final int DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT = 7;
-	public static final int DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW = 3;
-	public static final int DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS = 90;
-	
 	/*
 	 * Defines the time span between reviews on the same project
 	 */
-	@Basic(optional = false)
+	@Column(name = "num_days_between_peer_reviews_on_same_project", nullable = false)
 	private int numDaysBetweenPeerReviewsOnSameProject = DEFAULT_NUM_DAYS_BETWEEN_REVIEWS_ON_SAME_PROJECT;
-	
+
 	/*
 	 * Defines the number of days between accepting a review and the deadline for review submission
 	 */
-	@Basic(optional = false)
+	@Column(name = "num_days_to_submit_peer_review", nullable = false)
 	private int numDaysToSubmitPeerReview = DEFAULT_NUM_DAYS_TO_SUBMIT_PEER_REVIEW;
 
 	/*
 	 * Defines the number of days between accepting a review and the deadline for review submission
 	 */
-	@Basic(optional = false)
+	@Column(name = "num_days_before_peer_gets_cancelled", nullable = false)
 	private int numDaysBeforePeerGetsCancelled = DEFAULT_NUM_DAYS_BEFORE_CANCELLED_PEERS;
 
-	@Basic
+	@Column(name = "min_authors", nullable = false)
+	private int minAuthors = 1;
+
+	@Column(name = "max_authors", nullable = false)
+	private int maxAuthors = 2;
+
+	@Column(name = "max_final_seminar_active_participation", nullable = false)
+	private int maxFinalSeminarActiveParticipation;
+
+	@Column(name = "max_opponents_on_final_seminar", nullable = false)
+	private int maxOpponentsOnFinalSeminar;
+
+	@Column(name = "min_final_seminar_active_participation", nullable = false)
+	private int minFinalSeminarActiveParticipation;
+
+	@Column(name = "min_opponents_on_final_seminar", nullable = false)
+	private int minOpponentsOnFinalSeminar;
+
+	@Column(name = "min_oppositions_to_be_graded")
+	private int minOppositionsToBeGraded = 0;
+
+	@Column(name = "min_active_participations_to_be_graded")
+	private int minActiveParticipationsToBeGraded = 0;
+
 	@Column(name = "review_process_information_url_for_supervisor")
 	private String reviewProcessInformationUrl;
 
+	public ProjectTypeSettings(){}
+
+	public ProjectTypeSettings(ProjectType projectType){
+		this.projectType = projectType;
+	}
+
 	@Override
 	public Long getId() {
 		return this.id;
@@ -152,20 +168,20 @@ public class ProjectTypeSettings extends DomainObject {
 		this.numDaysBeforePeerGetsCancelled = numDaysBeforePeerGetsCancelled;
 	}
 
-	public int getMinimumOppositionsToBeGraded() {
-		return minimumOppositionsToBeGraded;
+	public int getMinOppositionsToBeGraded() {
+		return minOppositionsToBeGraded;
 	}
 
-	public void setMinimumOppositionsToBeGraded(int minimumOppositionsToBeGraded) {
-		this.minimumOppositionsToBeGraded = minimumOppositionsToBeGraded;
+	public void setMinOppositionsToBeGraded(int minimumOppositionsToBeGraded) {
+		this.minOppositionsToBeGraded = minimumOppositionsToBeGraded;
 	}
 
-	public int getMinimumActiveParticipationsToBeGraded() {
-		return minimumActiveParticipationsToBeGraded;
+	public int getMinActiveParticipationsToBeGraded() {
+		return minActiveParticipationsToBeGraded;
 	}
 
-	public void setMinimumActiveParticipationsToBeGraded(int minimumActiveParticipationsToBeGraded) {
-		this.minimumActiveParticipationsToBeGraded = minimumActiveParticipationsToBeGraded;
+	public void setMinActiveParticipationsToBeGraded(int minimumActiveParticipationsToBeGraded) {
+		this.minActiveParticipationsToBeGraded = minimumActiveParticipationsToBeGraded;
 	}
 
 	public String getReviewProcessInformationUrl() {
diff --git a/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java b/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java
index 11a8bb041f..01e994645b 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/ResearchArea.java
@@ -1,14 +1,22 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
-@Table(name = "researcharea")
+@Table(name = "research_area")
 @Cacheable(true)
 public class ResearchArea extends LazyDeletableDomainObject {
-
     public static final int STRING_MAX_LENGTH = 255;
+
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Long id;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java b/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java
index 76dc29c854..3c75c66915 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/ResearchAreaServiceImpl.java
@@ -3,6 +3,8 @@ package se.su.dsv.scipro.system;
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 import jakarta.persistence.EntityManager;
+import jakarta.transaction.Transactional;
+
 import java.util.Comparator;
 import java.util.List;
 
@@ -13,6 +15,7 @@ public class ResearchAreaServiceImpl extends AbstractServiceImpl<ResearchArea,Lo
     }
 
     @Override
+    @Transactional
     public ResearchArea updateExternalResearchArea(Long identifier, String name, final boolean active) {
         ResearchArea ra = new ResearchArea();
         if (identifier != null) {
diff --git a/core/src/main/java/se/su/dsv/scipro/system/Unit.java b/core/src/main/java/se/su/dsv/scipro/system/Unit.java
index acc2b2793c..404baee063 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/Unit.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/Unit.java
@@ -1,6 +1,13 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+
 import java.util.Objects;
 
 @Entity
@@ -17,11 +24,10 @@ public class Unit extends DomainObject {
     @Column(unique = true)
     private Integer identifier;
 
-    @Column(length = STRING_MAX_LENGTH)
-    @Basic(optional = false)
+    @Column(nullable = false, length = STRING_MAX_LENGTH)
     private String title;
 
-    @Basic(optional = true)
+    @Column(name = "match_responsible", nullable = true)
     private String matchResponsible;
 
     public String getMatchResponsible() {
diff --git a/core/src/main/java/se/su/dsv/scipro/system/User.java b/core/src/main/java/se/su/dsv/scipro/system/User.java
index 1ee2da3877..9addbde052 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/User.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/User.java
@@ -1,10 +1,32 @@
 package se.su.dsv.scipro.system;
 
-import se.su.dsv.scipro.security.auth.roles.Roles;
+import jakarta.persistence.Basic;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.CascadeType;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.OneToMany;
+import jakarta.persistence.OneToOne;
+import jakarta.persistence.Table;
 
-import jakarta.persistence.*;
 import java.io.Serializable;
-import java.util.*;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+import se.su.dsv.scipro.security.auth.roles.Roles;
 
 @Entity
 @Table(name = "user")
@@ -18,9 +40,10 @@ public class User extends LazyDeletableDomainObject {
     @Column(unique = true)
     private Integer identifier;
 
-    @Basic(optional = false)
+    @Column(name = "first_name", nullable = false)
     private String firstName;
-    @Basic(optional = false)
+
+    @Column(name = "last_name", nullable = false)
     private String lastName;
 
     // Mapped to a generated column to allow sorting UserColumn in DataTables
@@ -35,14 +58,15 @@ public class User extends LazyDeletableDomainObject {
     // If you wish to test specific sort orders then add specific methods that sort
     // by firstName, lastName instead.
     @SuppressWarnings("unused")
-    @Basic
-    @Column(insertable = false, updatable = false)
+    @Column(name = "full_name", insertable = false, updatable = false)
     private String fullName;
 
-    @Basic(optional = false)
+    @Column(name = "email_address", nullable = false)
     private String emailAddress;
+
     @Basic(optional = false)
     private boolean deceased = false;
+
     @Basic(optional = false)
     @Column(name = "active_as_supervisor")
     private boolean activeAsSupervisor = false;
@@ -64,20 +88,22 @@ public class User extends LazyDeletableDomainObject {
     private Set<Program> programs = new HashSet<>();
 
     @ElementCollection
-    @CollectionTable(name = "user_languages")
+    @CollectionTable(name = "user_language")
     @Column(name = "language")
     @Enumerated(EnumType.STRING)
     private Set<Language> languages = EnumSet.noneOf(Language.class);
 
     @ManyToMany
-    @JoinTable(name = "user_research_area", inverseJoinColumns = @JoinColumn(name = "research_area_id"))
+    @JoinTable(name = "user_research_area",
+            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
+            inverseJoinColumns = @JoinColumn(name = "research_area_id", referencedColumnName = "id"))
     private Set<ResearchArea> researchAreas = new HashSet<>();
 
     @OneToOne(optional = true)
     private Unit unit;
 
-    @Basic
     @Enumerated(EnumType.STRING)
+    @Column(name = "degree_type")
     private DegreeType degreeType = ProjectType.UNKNOWN;
 
     public Unit getUnit() {
diff --git a/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java b/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java
index 1a227078e1..9831c44da1 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/UserRepo.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.system;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.security.auth.roles.Roles;
 
 import java.util.Collection;
diff --git a/core/src/main/java/se/su/dsv/scipro/system/Username.java b/core/src/main/java/se/su/dsv/scipro/system/Username.java
index e4836b5070..5da461d2b6 100755
--- a/core/src/main/java/se/su/dsv/scipro/system/Username.java
+++ b/core/src/main/java/se/su/dsv/scipro/system/Username.java
@@ -1,17 +1,26 @@
 package se.su.dsv.scipro.system;
 
-import jakarta.persistence.*;
+import jakarta.persistence.Cacheable;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import jakarta.persistence.UniqueConstraint;
+
 import java.util.Objects;
 
 @Entity
+@Table(name="username", uniqueConstraints={@UniqueConstraint(name = "uk_username", columnNames={"username"})})
 @Cacheable(true)
-@Table(name="username", uniqueConstraints={@UniqueConstraint(columnNames={"username"})})
 public class Username extends DomainObject {
 	@Id
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 	
-	@Basic(optional=false)
+	@Column(name = "username", nullable = false)
 	private String username;
 	
 	@ManyToOne(optional=false)
diff --git a/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java b/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java
index aeeff1631a..ee96eb8884 100644
--- a/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java
+++ b/core/src/main/java/se/su/dsv/scipro/thesislink/ExternalLink.java
@@ -1,84 +1,103 @@
 package se.su.dsv.scipro.thesislink;
 
+import jakarta.persistence.Basic;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.system.DomainObject;
 import se.su.dsv.scipro.system.User;
 
-import jakarta.persistence.*;
 import java.util.Objects;
 
 @Entity
-@Table(name = "externallink")
+@Table(name = "external_link")
 public class ExternalLink extends DomainObject {
 
     public static final int MAX_CHARS = 255;
 
-    @Id
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Long id;
-
-    @ManyToOne(optional = false)
-    private Project project;
-
-    @Column(nullable = false, length = MAX_CHARS)
-    private String url = "";
-
-    @ManyToOne(optional = false)
-    private User user;
-
-    @Column(nullable = true, length = MAX_CHARS)
-    private String description = "";
-
     public static IProject builder() {
         return new Builder();
     }
 
+    // ----------------------------------------------------------------------------------
+    // Basic JPA-mappings
+    // ----------------------------------------------------------------------------------
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Basic
+    @Column(name = "url", nullable = false, length = MAX_CHARS)
+    private String url = "";
+
+    @Column(name = "description", nullable = true, length = MAX_CHARS)
+    private String description = "";
+
+    // ----------------------------------------------------------------------------------
+    // JPA-mappings of foreign keys in this table (external_link) referencing
+    // other tables.
+    // ----------------------------------------------------------------------------------
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "project_id", referencedColumnName = "id")
+    private Project project;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "user_id", referencedColumnName = "id")
+    private User user;
+
+    // ----------------------------------------------------------------------------------
+    // Properties (Getters and Setters)
+    // ----------------------------------------------------------------------------------
     @Override
     public Long getId() {
         return this.id;
     }
 
-    public Project getProject() {
-        return this.project;
-    }
-
-    public String getUrl() {
-        return this.url;
-    }
-
-    public User getUser() {
-        return this.user;
-    }
-
-    public String getDescription() {
-        return this.description;
-    }
-
     public void setId(Long id) {
         this.id = id;
     }
 
-    public void setProject(Project project) {
-        this.project = project;
+    public String getUrl() {
+        return this.url;
     }
 
     public void setUrl(String url) {
         this.url = url;
     }
 
-    public void setUser(User user) {
-        this.user = user;
+    public String getDescription() {
+        return this.description;
     }
 
     public void setDescription(String description) {
         this.description = description;
     }
 
-    @Override
-    public String toString() {
-        return "ExternalLink(id=" + this.getId() + ", project=" + this.getProject() + ", url=" + this.getUrl() + ", user=" + this.getUser() + ", description=" + this.getDescription() + ")";
+    public Project getProject() {
+        return this.project;
     }
 
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    public User getUser() {
+        return this.user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Methods Common To All Objects
+    // ----------------------------------------------------------------------------------
     @Override
     public boolean equals(final Object o) {
         if (o == this) return true;
@@ -92,15 +111,28 @@ public class ExternalLink extends DomainObject {
                 && Objects.equals(this.getDescription(), other.getDescription());
     }
 
-    protected boolean canEqual(final Object other) {
-        return other instanceof ExternalLink;
-    }
-
     @Override
     public int hashCode() {
         return Objects.hash(this.getId(), this.getProject(), this.getUrl(), this.getUser(), this.getDescription());
     }
 
+    @Override
+    public String toString() {
+        return "ExternalLink(id=" + this.getId() + ", project=" + this.getProject() +
+                ", url=" + this.getUrl() + ", user=" + this.getUser() + ", description=" +
+                this.getDescription() + ")";
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Other method
+    // ----------------------------------------------------------------------------------
+    protected boolean canEqual(final Object other) {
+        return other instanceof ExternalLink;
+    }
+
+    // ----------------------------------------------------------------------------------
+    // Nested types
+    // ----------------------------------------------------------------------------------
     private static class Builder implements IProject, IURL, IUser, IBuild {
         private ExternalLink instance = new ExternalLink();
 
diff --git a/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java b/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java
new file mode 100644
index 0000000000..a111714130
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/war/PluginConfiguration.java
@@ -0,0 +1,4 @@
+package se.su.dsv.scipro.war;
+
+public interface PluginConfiguration {
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java
index 751b6c8831..5c721b2ffe 100755
--- a/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java
+++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/AbstractWorker.java
@@ -1,6 +1,5 @@
 package se.su.dsv.scipro.workerthreads;
 
-import com.google.inject.persist.UnitOfWork;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -23,9 +22,7 @@ public abstract class AbstractWorker implements Worker {
     private WorkerData wd = null;
     private Date lastSuccessfulRun = new Date(0);
     private boolean successfulWorker = true;
-    private Provider<EntityManager> emProvider;
-    private EntityTransaction transaction;
-    private UnitOfWork unitOfWork;
+    private WorkerTransactionManager txManager;
 
     /**
      * Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work
@@ -39,22 +36,13 @@ public abstract class AbstractWorker implements Worker {
     }
 
     @Inject
-    public void setTxManager(Provider<EntityManager> em) {
-        this.emProvider = em;
-    }
-
-    @Inject
-    public void setUnitOfWork(UnitOfWork unitOfWork) {
-        this.unitOfWork = unitOfWork;
+    public void setTxManager(WorkerTransactionManager txManager) {
+        this.txManager = txManager;
     }
 
     @Override
     public void run() {
-        unitOfWork.begin();
-        EntityManager em = emProvider.get();
         try {
-            transaction = em.getTransaction();
-
             wd = workerDataService.getWorkerDataByName(getName());
             if (wd != null) {
                 lastSuccessfulRun = wd.getLastSuccessfulRun();
@@ -80,9 +68,7 @@ public abstract class AbstractWorker implements Worker {
                 setSuccessfulWorker(false);
             }
             finally {
-                if (transaction.isActive() && em.isOpen()) {
-                    transaction.rollback();
-                }
+                txManager.rollbackIfActive();
             }
 
             // in case a job crashes or clears the cache (so the entity is detached)
@@ -95,10 +81,7 @@ public abstract class AbstractWorker implements Worker {
             saveWorkerData();
 
         } finally {
-            if (transaction.isActive() && em.isOpen()) {
-                transaction.rollback();
-            }
-            unitOfWork.end();
+            txManager.rollbackIfActive();
         }
     }
 
@@ -148,15 +131,15 @@ public abstract class AbstractWorker implements Worker {
     protected abstract void doWork();
 
     protected void beginTransaction() {
-        transaction.begin();
+        txManager.begin();
     }
 
     protected void commitTransaction() {
-        transaction.commit();
+        txManager.commit();
     }
 
     protected void rollbackTransaction() {
-        transaction.rollback();
+        txManager.rollback();
     }
 
 }
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java
index 4827139331..59fefc8d63 100755
--- a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java
+++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerData.java
@@ -7,7 +7,7 @@ import java.util.Date;
 import java.util.Objects;
 
 @Entity
-@Table(name="worker_data")
+@Table(name = "worker_data")
 @Cacheable(true)
 public class WorkerData extends DomainObject {
 	public WorkerData() {
@@ -18,13 +18,13 @@ public class WorkerData extends DomainObject {
 	@GeneratedValue(strategy = GenerationType.IDENTITY)
 	private Long id;
 	
-	@Column(unique=true, nullable=false)
+	@Column(unique = true, nullable = false)
 	private String name;
 	
-	@Column(nullable=false)
-	private Date lastRun=new Date();
+	@Column(nullable = false, name = "last_run")
+	private Date lastRun = new Date();
 	
-	@Column(nullable=false)
+	@Column(nullable = false, name = "last_successful_run")
 	private Date lastSuccessfulRun;
 	
 	@PreUpdate
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java
deleted file mode 100644
index 370d486d83..0000000000
--- a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerModule.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package se.su.dsv.scipro.workerthreads;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Scopes;
-import com.google.inject.multibindings.Multibinder;
-import se.su.dsv.scipro.mail.MailEventWorker;
-import se.su.dsv.scipro.projectpartner.RemoveFulfilledPartnerAdsWorker;
-import se.su.dsv.scipro.system.Lifecycle;
-
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class WorkerModule extends AbstractModule {
-    private static final int NUMBER_OF_WORKER_THREADS = 4;
-
-    @Override
-    protected void configure() {
-        Multibinder.newSetBinder(binder(), Lifecycle.class).addBinding().to(SchedulerImpl.class);
-        bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS));
-        bind(Scheduler.class).to(SchedulerImpl.class).in(Scopes.SINGLETON);
-        bind(TemporaryWorkerScheduler.class).asEagerSingleton();
-        bind(WorkerDataService.class).to(WorkerDataServiceImpl.class);
-        bind(ThesisUploadDeadlineWorker.class);
-        bind(ManualMatchRemindWorker.class);
-        bind(MailEventWorker.class);
-        bind(NotificationCompilationWorker.class);
-        bind(ThesisUploadReminderWorker.class);
-        bind(IdeaExportWorker.class);
-        bind(RemoveFulfilledPartnerAdsWorker.class);
-    }
-}
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java
new file mode 100644
index 0000000000..1ff2b458d4
--- /dev/null
+++ b/core/src/main/java/se/su/dsv/scipro/workerthreads/WorkerTransactionManager.java
@@ -0,0 +1,20 @@
+package se.su.dsv.scipro.workerthreads;
+
+public interface WorkerTransactionManager {
+    void rollbackIfActive();
+
+    /**
+     * @throws IllegalStateException if a transaction is already active
+     */
+    void begin();
+
+    /**
+     * @throws IllegalStateException if a transaction is not active
+     */
+    void commit();
+
+    /**
+     * @throws IllegalStateException if a transaction is not active
+     */
+    void rollback();
+}
diff --git a/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql b/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql
new file mode 100644
index 0000000000..3edeeb923b
--- /dev/null
+++ b/core/src/main/resources/db/migration/V390__longer_titles_in_final_thesis.sql
@@ -0,0 +1,3 @@
+-- Match what project.title allows
+ALTER TABLE `FinalThesis` MODIFY `englishTitle` LONGTEXT NULL;
+ALTER TABLE `FinalThesis` MODIFY `swedishTitle` LONGTEXT NULL;
diff --git a/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql b/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql
new file mode 100644
index 0000000000..15c116c0ff
--- /dev/null
+++ b/core/src/main/resources/db/migration/V391__harmonize_table_attribute_name.sql
@@ -0,0 +1,3222 @@
+/*
+ * Step 1: Remove obsolete tables
+ */
+
+drop table plugin_settings;
+drop table turnitincheck;
+
+alter table TurnitinSettings_expirationMails drop foreign key FK_lji32bekgobx76otvw7syu4hb;
+drop table TurnitinSettings_expirationMails;
+
+drop table TurnitinSettings;
+
+/*
+ * Step 2: DomainObject related classes and tables.
+ *
+ * Many entity classes inherit directly or indirectly from abstract super class DomainObject. Two attributes
+ * dateCreated and lastModified, have changed mapping to column name with snake case, date_created and last_modified.
+ * This change affects many, many tables, which are to be managed at first.
+ */
+
+-- table: ActivityPlan
+
+alter table `ActivityPlan` rename column `dateCreated` to `date_created`;
+alter table `ActivityPlan` rename column `lastModified` to `last_modified`;
+
+-- table: ActivityPlanTemplate
+
+alter table `ActivityPlanTemplate` rename column `dateCreated` to `date_created`;
+alter table `ActivityPlanTemplate` rename column `lastModified` to `last_modified`;
+
+-- table: ActivityTemplate
+
+alter table `ActivityTemplate` rename column `dateCreated` to `date_created`;
+alter table `ActivityTemplate` rename column `lastModified` to `last_modified`;
+
+-- table: file_description
+
+alter table `file_description` rename column `dateCreated` to `date_created`;
+alter table `file_description` rename column `lastModified` to `last_modified`;
+
+-- table: answer
+
+alter table `answer` rename column `dateCreated` to `date_created`;
+alter table `answer` rename column `lastModified` to `last_modified`;
+
+-- table: ApplicationPeriod
+
+alter table `ApplicationPeriod` rename column `dateCreated` to `date_created`;
+alter table `ApplicationPeriod` rename column `lastModified` to `last_modified`;
+
+-- table: checklist
+
+alter table `checklist` rename column `dateCreated` to `date_created`;
+alter table `checklist` rename column `lastModified` to `last_modified`;
+
+-- table: checklist_answer
+
+alter table `checklist_answer` rename column `dateCreated` to `date_created`;
+alter table `checklist_answer` rename column `lastModified` to `last_modified`;
+
+-- table: checklist_category
+
+alter table `checklist_category` rename column `dateCreated` to `date_created`;
+alter table `checklist_category` rename column `lastModified` to `last_modified`;
+
+-- table: checklist_question
+
+alter table `checklist_question` rename column `dateCreated` to `date_created`;
+alter table `checklist_question` rename column `lastModified` to `last_modified`;
+
+-- table: checklist_template
+
+alter table `checklist_template` rename column `dateCreated` to `date_created`;
+alter table `checklist_template` rename column `lastModified` to `last_modified`;
+
+-- table: comment
+
+alter table `comment` rename column `dateCreated` to `date_created`;
+alter table `comment` rename column `lastModified` to `last_modified`;
+
+-- table: externallink
+
+alter table `externallink` rename column `dateCreated` to `date_created`;
+alter table `externallink` rename column `lastModified` to `last_modified`;
+
+-- table: comment_thread
+
+alter table `comment_thread` rename column `dateCreated` to `date_created`;
+alter table `comment_thread` rename column `lastModified` to `last_modified`;
+
+-- table: FinalSeminarSettings
+
+alter table `FinalSeminarSettings` rename column `dateCreated` to `date_created`;
+alter table `FinalSeminarSettings` rename column `lastModified` to `last_modified`;
+
+-- table: FinalThesis
+
+alter table `FinalThesis` rename column `dateCreated` to `date_created`;
+alter table `FinalThesis` rename column `lastModified` to `last_modified`;
+
+-- table: footer_address
+
+alter table `footer_address` rename column `dateCreated` to `date_created`;
+alter table `footer_address` rename column `lastModified` to `last_modified`;
+
+-- table: footer_link
+
+alter table `footer_link` rename column `dateCreated` to `date_created`;
+alter table `footer_link` rename column `lastModified` to `last_modified`;
+
+-- table: general_system_settings
+
+alter table `general_system_settings` rename column `dateCreated` to `date_created`;
+alter table `general_system_settings` rename column `lastModified` to `last_modified`;
+
+-- table: grading_report_template
+
+alter table `grading_report_template` rename column `dateCreated` to `date_created`;
+alter table `grading_report_template` rename column `lastModified` to `last_modified`;
+
+-- table: project_group
+
+alter table `project_group` rename column `dateCreated` to `date_created`;
+alter table `project_group` rename column `lastModified` to `last_modified`;
+
+-- table: idea
+
+alter table `idea` rename column `dateCreated` to `date_created`;
+alter table `idea` rename column `lastModified` to `last_modified`;
+
+-- table: idea_export
+
+alter table `idea_export` rename column `dateCreated` to `date_created`;
+alter table `idea_export` rename column `lastModified` to `last_modified`;
+
+-- table: mail_event
+
+alter table `mail_event` rename column `dateCreated` to `date_created`;
+alter table `mail_event` rename column `lastModified` to `last_modified`;
+
+-- table: idea_match
+
+alter table `idea_match` rename column `dateCreated` to `date_created`;
+alter table `idea_match` rename column `lastModified` to `last_modified`;
+
+-- table: milestone
+
+alter table `milestone` rename column `dateCreated` to `date_created`;
+alter table `milestone` rename column `lastModified` to `last_modified`;
+
+-- table: NonWorkDayPeriod
+
+alter table `NonWorkDayPeriod` rename column `dateCreated` to `date_created`;
+alter table `NonWorkDayPeriod` rename column `lastModified` to `last_modified`;
+
+-- table: note
+
+alter table `note` rename column `dateCreated` to `date_created`;
+alter table `note` rename column `lastModified` to `last_modified`;
+
+-- table: Notification
+
+alter table `Notification` rename column `dateCreated` to `date_created`;
+alter table `Notification` rename column `lastModified` to `last_modified`;
+
+-- table: NotificationData
+
+alter table `NotificationData` rename column `dateCreated` to `date_created`;
+alter table `NotificationData` rename column `lastModified` to `last_modified`;
+
+-- table: peer_request
+
+alter table `peer_request` rename column `dateCreated` to `date_created`;
+alter table `peer_request` rename column `lastModified` to `last_modified`;
+
+-- table: peer_review
+
+alter table `peer_review` rename column `dateCreated` to `date_created`;
+alter table `peer_review` rename column `lastModified` to `last_modified`;
+
+-- table: preliminary_match
+
+alter table `preliminary_match` rename column `dateCreated` to `date_created`;
+alter table `preliminary_match` rename column `lastModified` to `last_modified`;
+
+-- table: Program
+
+alter table `Program` rename column `dateCreated` to `date_created`;
+alter table `Program` rename column `lastModified` to `last_modified`;
+
+-- table: project
+
+alter table `project` rename column `dateCreated` to `date_created`;
+alter table `project` rename column `lastModified` to `last_modified`;
+
+-- table: project_file
+
+alter table `project_file` rename column `dateCreated` to `date_created`;
+alter table `project_file` rename column `lastModified` to `last_modified`;
+
+-- table: project_first_meeting
+
+alter table `project_first_meeting` rename column `dateCreated` to `date_created`;
+alter table `project_first_meeting` rename column `lastModified` to `last_modified`;
+
+-- table: projectPartner
+
+alter table `projectPartner` rename column `dateCreated` to `date_created`;
+alter table `projectPartner` rename column `lastModified` to `last_modified`;
+
+-- table: project_type_settings
+
+alter table `project_type_settings` rename column `dateCreated` to `date_created`;
+alter table `project_type_settings` rename column `lastModified` to `last_modified`;
+
+-- table: reviewer_deadline_settings
+
+alter table `reviewer_deadline_settings` rename column `dateCreated` to `date_created`;
+alter table `reviewer_deadline_settings` rename column `lastModified` to `last_modified`;
+
+-- table: reviewer_target
+
+alter table `reviewer_target` rename column `dateCreated` to `date_created`;
+alter table `reviewer_target` rename column `lastModified` to `last_modified`;
+
+-- table: unit
+
+alter table `unit` rename column `dateCreated` to `date_created`;
+alter table `unit` rename column `lastModified` to `last_modified`;
+
+-- table: urkund_submission
+
+alter table `urkund_submission` rename column `dateCreated` to `date_created`;
+alter table `urkund_submission` rename column `lastModified` to `last_modified`;
+
+-- table: username
+
+alter table `username` rename column `dateCreated` to `date_created`;
+alter table `username` rename column `lastModified` to `last_modified`;
+
+-- table: user_profile
+
+alter table `user_profile` rename column `dateCreated` to `date_created`;
+alter table `user_profile` rename column `lastModified` to `last_modified`;
+
+-- table: worker_data
+
+alter table `worker_data` rename column `dateCreated` to `date_created`;
+alter table `worker_data` rename column `lastModified` to `last_modified`;
+
+-- table: criterion
+
+alter table `criterion` rename column `dateCreated` to `date_created`;
+alter table `criterion` rename column `lastModified` to `last_modified`;
+
+-- table: grading_criterion_template
+
+alter table `grading_criterion_template` rename column `dateCreated` to `date_created`;
+alter table `grading_criterion_template` rename column `lastModified` to `last_modified`;
+
+-- table: GradingCriterion
+
+alter table `GradingCriterion` rename column `dateCreated` to `date_created`;
+alter table `GradingCriterion` rename column `lastModified` to `last_modified`;
+
+-- table: GradingCriterionPoint
+
+alter table `GradingCriterionPoint` rename column `dateCreated` to `date_created`;
+alter table `GradingCriterionPoint` rename column `lastModified` to `last_modified`;
+
+-- table: grading_criterion_point_template
+
+alter table `grading_criterion_point_template` rename column `dateCreated` to `date_created`;
+alter table `grading_criterion_point_template` rename column `lastModified` to `last_modified`;
+
+-- table: ReviewerApproval
+
+alter table `ReviewerApproval` rename column `dateCreated` to `date_created`;
+alter table `ReviewerApproval` rename column `lastModified` to `last_modified`;
+
+-- table: final_seminar_active_participation
+
+alter table `final_seminar_active_participation` rename column `dateCreated` to `date_created`;
+alter table `final_seminar_active_participation` rename column `lastModified` to `last_modified`;
+
+-- table: final_seminar_opposition
+
+alter table `final_seminar_opposition` rename column `dateCreated` to `date_created`;
+alter table `final_seminar_opposition` rename column `lastModified` to `last_modified`;
+
+-- table: final_seminar_respondent
+
+alter table `final_seminar_respondent` rename column `dateCreated` to `date_created`;
+alter table `final_seminar_respondent` rename column `lastModified` to `last_modified`;
+
+-- table: report
+
+alter table `report` rename column `dateCreated` to `date_created`;
+alter table `report` rename column `lastModified` to `last_modified`;
+
+-- table: notification_delivery_configuration
+
+alter table `notification_delivery_configuration` rename column `dateCreated` to `date_created`;
+alter table `notification_delivery_configuration` rename column `lastModified` to `last_modified`;
+
+-- table: notification_receiver_configuration
+
+alter table `notification_receiver_configuration` rename column `dateCreated` to `date_created`;
+alter table `notification_receiver_configuration` rename column `lastModified` to `last_modified`;
+
+-- table: Activity
+
+alter table `Activity` rename column `dateCreated` to `date_created`;
+alter table `Activity` rename column `lastModified` to `last_modified`;
+
+-- table: final_seminar
+
+alter table `final_seminar` rename column `dateCreated` to `date_created`;
+alter table `final_seminar` rename column `lastModified` to `last_modified`;
+
+-- table: forum_post
+
+alter table `forum_post` rename column `dateCreated` to `date_created`;
+alter table `forum_post` rename column `lastModified` to `last_modified`;
+
+-- table: thread
+
+alter table `thread` rename column `dateCreated` to `date_created`;
+alter table `thread` rename column `lastModified` to `last_modified`;
+
+-- table: Keyword
+
+alter table `Keyword` rename column `dateCreated` to `date_created`;
+alter table `Keyword` rename column `lastModified` to `last_modified`;
+
+-- table: milestone_activity_template
+
+alter table `milestone_activity_template` rename column `dateCreated` to `date_created`;
+alter table `milestone_activity_template` rename column `lastModified` to `last_modified`;
+
+-- table: milestone_phase_template
+
+alter table `milestone_phase_template` rename column `dateCreated` to `date_created`;
+alter table `milestone_phase_template` rename column `lastModified` to `last_modified`;
+
+-- table: Password
+
+alter table `Password` rename column `dateCreated` to `date_created`;
+alter table `Password` rename column `lastModified` to `last_modified`;
+
+-- table: ProjectType
+
+alter table `ProjectType` rename column `dateCreated` to `date_created`;
+alter table `ProjectType` rename column `lastModified` to `last_modified`;
+
+-- table: researcharea
+
+alter table `researcharea` rename column `dateCreated` to `date_created`;
+alter table `researcharea` rename column `lastModified` to `last_modified`;
+
+-- table: user
+
+alter table `user` rename column `dateCreated` to `date_created`;
+alter table `user` rename column `lastModified` to `last_modified`;
+
+/*
+ * Step 3: standalone tables
+ */
+
+-- table: worker_data
+
+alter table `worker_data` rename column `lastRun` to `last_run`;
+alter table `worker_data` rename column `lastSuccessfulRun` to `last_successful_run`;
+
+-- table: footer_link
+
+alter table `footer_link` rename column `footerColumn` to `footer_column`;
+
+-- table: NonWorkDayPeriod
+
+alter table `NonWorkDayPeriod` rename column `endDate` to `end_date`;
+alter table `NonWorkDayPeriod` rename column `startDate` to `start_date`;
+
+rename table `NonWorkDayPeriod` to `non_work_day_period`;
+
+-- table: reviewer_deadline_settings
+
+alter table `reviewer_deadline_settings` rename column `roughDraftApproval` to `rough_draft_approval`;
+alter table `reviewer_deadline_settings` rename column `finalSeminarApproval` to `final_seminar_approval`;
+alter table `reviewer_deadline_settings` rename column `finalGrading` to `final_grading`;
+
+-- table: final_seminar_settings
+
+alter table `FinalSeminarSettings` rename column `daysAheadToCreate` to `days_ahead_to_create`;
+alter table `FinalSeminarSettings` rename column `daysAheadToRegisterParticipation` to `days_ahead_to_register_participation`;
+alter table `FinalSeminarSettings` rename column `daysAheadToRegisterOpposition` to `days_ahead_to_register_opposition`;
+alter table `FinalSeminarSettings` rename column `daysAheadToUploadThesis` to `days_ahead_to_upload_thesis`;
+alter table `FinalSeminarSettings` rename column `thesisMustBePDF` to `thesis_must_be_pdf`;
+alter table `FinalSeminarSettings` rename column `evaluationURL` to `evaluation_url`;
+alter table `FinalSeminarSettings` rename column `oppositionPriorityDays` to `opposition_priority_days`;
+
+rename table `FinalSeminarSettings` to `final_seminar_settings`;
+
+/*
+ * Step 4: general_system_settings and three related tables.
+ */
+
+-- table: general_system_settings_system_module
+
+alter table `general_system_settings_system_modules` drop foreign key `general_system_settings_system_modules_ibfk_1`;
+alter table `general_system_settings_system_modules` drop key `GeneralSystemSettings_id`;
+alter table `general_system_settings_system_modules` drop primary key;
+
+alter table `general_system_settings_system_modules` rename column `GeneralSystemSettings_id` to `general_system_settings_id`;
+alter table `general_system_settings_system_modules` rename column `systemModules` to `system_module`;
+
+rename table `general_system_settings_system_modules` to `general_system_settings_system_module`;
+
+alter table `general_system_settings_system_module` add primary key (general_system_settings_id, system_module);
+
+alter table `general_system_settings_system_module`
+    add constraint fk_general_system_settings_system_module_id
+        foreign key (general_system_settings_id) references general_system_settings (id)
+            on delete cascade on update cascade;
+
+-- table: general_system_settings_supervisor_change_recipient
+
+alter table `general_system_settings_supervisor_change_recipients` drop foreign key `FK7DA712D52AC37675`;
+alter table `general_system_settings_supervisor_change_recipients` drop key `FK7DA712D52AC37675`;
+
+alter table `general_system_settings_supervisor_change_recipients` rename column `GeneralSystemSettings_id` to `general_system_settings_id`;
+
+rename table `general_system_settings_supervisor_change_recipients` to `general_system_settings_supervisor_change_recipient`;
+
+alter table `general_system_settings_supervisor_change_recipient` add primary key (general_system_settings_id, mail);
+
+alter table `general_system_settings_supervisor_change_recipient`
+    add constraint fk_general_system_settings_supervisor_change_recipient_id
+        foreign key (general_system_settings_id) references general_system_settings (id)
+            on delete cascade on update cascade;
+
+-- table: general_system_settings_alarm_recipient
+
+alter table `general_system_settings_alarm_recipients` drop foreign key `FK3C9272B2AC37675`;
+alter table `general_system_settings_alarm_recipients` drop key `FK3C9272B2AC37675`;
+
+alter table `general_system_settings_alarm_recipients` rename column `GeneralSystemSettings_id` to `general_system_settings_id`;
+
+rename table `general_system_settings_alarm_recipients` to `general_system_settings_alarm_recipient`;
+
+alter table `general_system_settings_alarm_recipient` add primary key (general_system_settings_id, mail);
+
+alter table `general_system_settings_alarm_recipient`
+    add constraint fk_general_system_settings_alarm_recipient_id
+        foreign key (general_system_settings_id) references general_system_settings (id)
+            on delete cascade on update cascade;
+
+-- table: general_system_settings
+
+alter table `general_system_settings` rename column `daisyProfileLinkBaseURL` to `daisy_profile_link_base_url`;
+alter table `general_system_settings` rename column `daisySelectResearchAreaURL` to `daisy_select_research_area_url`;
+alter table `general_system_settings` rename column `projectPartnerDaysToLive` to `project_partner_days_to_live`;
+alter table `general_system_settings` rename column `mailNotifications` to `mail_notifications`;
+alter table `general_system_settings` rename column `mailFromName` to `mail_from_name`;
+alter table `general_system_settings` rename column `systemFromMail` to `system_from_mail`;
+alter table `general_system_settings` rename column `smtpServer` to `smtp_server`;
+alter table `general_system_settings` rename column `peerDisplayLatestReviews` to `peer_display_latest_reviews`;
+alter table `general_system_settings` rename column `numberOfLatestReviewsDisplayed` to `number_of_latest_reviews_displayed`;
+alter table `general_system_settings` rename column `publicReviewsActivated` to `public_reviews_activated`;
+alter table `general_system_settings` rename column `peerDownloadEnabled` to `peer_download_enabled`;
+alter table `general_system_settings` rename column `sciproURL` to `scipro_url`;
+alter table `general_system_settings` rename column `showSingleSignOn` to `show_single_sign_on`;
+alter table `general_system_settings` rename column `matchResponsibleMail` to `match_responsible_mail`;
+alter table `general_system_settings` rename column `reviewerSupportMail` to `reviewer_support_mail`;
+alter table `general_system_settings` rename column `thesisSupportMail` to `thesis_support_mail`;
+alter table `general_system_settings` rename column `externalRoomBookingURL` to `external_room_booking_url`;
+alter table `general_system_settings` rename column `externalGettingStartedWithIdeaURL` to `external_getting_started_with_idea_url`;
+alter table `general_system_settings` rename column `externalGradingURL` to `external_grading_url`;
+alter table `general_system_settings` rename column `finalSurveyAvailable` to `final_survey_available`;
+alter table `general_system_settings` rename column `activeProjectIdeaSupportMail` to `active_project_idea_support_mail`;
+
+/*
+ * Step 5: table user and related tables.
+ *
+ * Table user is one of four fundamental tables (other three: project, file_reference, ProjectType). All four
+ * tables have many foreign keys referenced to them.
+ *
+ * Related tables of table user are the tables which have no relationship with other three fundamental tables. Their
+ * foreign key references end at table user.
+ */
+
+-- table: Program and user_program
+
+alter table `user_program` drop foreign key `user_program_program_id`;
+alter table `user_program` drop key `user_program_program_id`;
+
+alter table `user_program` drop foreign key `user_program_user_id`;
+
+rename table `Program` to `program`;
+
+alter table `program` rename column `externalId` to `external_id`;
+alter table `program` rename column `name` to `name_sv`;
+alter table `program` rename column `nameEn` to `name_en`;
+
+alter table `user_program`
+    add constraint fk_user_program_program_id
+        foreign key (program_id) references program (id)
+            on delete cascade on update cascade;
+
+alter table `user_program`
+    add constraint fk_user_program_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: note
+
+alter table `note` drop foreign key `note_ibfk_1`;
+alter table `note` drop key `user_id`;
+
+alter table `note`
+    add constraint fk_note_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: comment and comment_thread
+
+alter table `comment` drop foreign key `FK38A5EE5FE44F4DBE`;
+alter table `comment` drop foreign key `FK38A5EE5F45F802F5`;
+alter table `comment` drop key `FK38A5EE5FE44F4DBE`;
+alter table `comment` drop key `FK38A5EE5F45F802F5`;
+
+alter table `comment_thread` drop key `UK_s0ve8ppa3snl8i1wocqwiuwn2`;
+alter table `comment_thread` drop key `commentableKey`;
+
+alter table comment_thread rename column `commentableId` to `commentable_id`;
+alter table comment_thread rename column `commentableKey` to `commentable_key`;
+
+alter table `comment_thread` add constraint uk_comment_thread_id_key unique(commentable_id, commentable_key);
+
+alter table comment rename column `commentThread_id` to `comment_thread_id`;
+alter table comment rename column `creator_id` to `creator_user_id`;
+
+alter table `comment`
+    add constraint fk_comment_creator_user_id
+        foreign key (creator_user_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `comment`
+    add constraint fk_comment_comment_thread_id
+        foreign key (comment_thread_id) references comment_thread (id)
+            on delete cascade on update cascade;
+
+-- table: reviewer_target
+
+alter table `reviewer_target` drop foreign key `FK_ReviewerTarget_ReviewerId`;
+alter table `reviewer_target` drop key `UK_ReviewerTarget_ReviewerId_Year`;
+
+alter table `reviewer_target` rename column `reviewer_id` to `reviewer_user_id`;
+
+alter table `reviewer_target` add constraint uk_reviewer_target_reviewer_user_id_year unique(reviewer_user_id, year);
+
+alter table `reviewer_target`
+    add constraint fk_reviewer_target_reviewer_user_id
+        foreign key (reviewer_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: notification_delivery_configuration
+
+alter table `notification_delivery_configuration` drop foreign key `FK7B2EE5BF895349BF`;
+alter table `notification_delivery_configuration` drop key `FK7B2EE5BF895349BF`;
+alter table `notification_delivery_configuration` drop key `one_setting_per_user`;
+
+alter table `notification_delivery_configuration` add constraint uk_one_setting_per_user unique(type, event, method, user_id);
+
+alter table `notification_delivery_configuration`
+    add constraint fk_notification_delivery_configuration_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: username
+
+alter table `username` drop foreign key `FK_17moq4bksxe30ihucce3jovdc`;
+alter table `username` drop key `FK_17moq4bksxe30ihucce3jovdc`;
+alter table `username` drop key `username_must_be_unique`;
+
+alter table `username` add constraint uk_username unique(username);
+
+alter table `username`
+    add constraint fk_username_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: user_role
+
+alter table `user_role` drop foreign key `user_role_user_id`;
+
+alter table `user_role`
+    add constraint fk_user_role_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: user_languages
+
+alter table `user_languages` drop foreign key `user_languages_user_id`;
+alter table `user_languages` drop key `user_languages_user_id`;
+
+rename table `user_languages` to `user_language`;
+
+alter table `user_language`
+    add constraint fk_user_language_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * table: user, unit and Password
+ */
+
+alter table `user` drop foreign key `FK_hpmviec1b7vdg23xtxsalwxw8`;
+alter table `user` drop key `FK_hpmviec1b7vdg23xtxsalwxw8`;
+
+alter table `user` drop foreign key `user_unit_id`;
+alter table `user` drop key `user_unit_id`;
+
+alter table `user` drop key `identifier`;
+alter table `user` drop key `deleted_index`;
+
+-- rename columns in table user
+
+alter table `user` rename column `emailAddress` to `email_address`;
+alter table `user` rename column `firstName` to `first_name`;
+alter table `user` rename column `lastName` to `last_name`;
+alter table `user` rename column `fullName` to `full_name`;
+alter table `user` rename column `degreeType` to `degree_type`;
+
+alter table `user` add constraint uk_user_identifier unique(identifier);
+create index idx_user_deleted on user(deleted);
+
+-- table: unit
+
+alter table `unit` drop key `identifier`;
+
+alter table `unit` rename column `matchResponsible` to `match_responsible`;
+
+alter table `unit` add constraint uk_unit_identifier unique(identifier);
+
+-- add FK from user to unit
+
+alter table `user`
+    add constraint fk_user_unit_id
+        foreign key (unit_id) references unit (id)
+            on delete cascade on update cascade;
+
+-- table: Password
+
+alter table `Password` drop foreign key `FK_43erxladp39q03wrco68hi9iq`;
+alter table `Password` drop key `FK_43erxladp39q03wrco68hi9iq`;
+alter table `Password` drop key `FK4C641EBB895349BF`;
+alter table `Password` drop key `deleted_index`;
+alter table `Password` drop key `UK_43erxladp39q03wrco68hi9iq`;
+alter table `Password` drop key `user_id`;
+
+rename table `Password` to `password`;
+
+alter table `password` add constraint uk_password_user_id unique(user_id);
+create index idx_password_deleted on password(deleted);
+
+alter table `password`
+    add constraint fk_password_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- add FK from user till password
+
+alter table `user`
+    add constraint fk_user_password_id
+        foreign key (password_id) references password (id)
+            on delete cascade on update cascade;
+
+-- table: user_profile
+
+alter table `user_profile` drop foreign key `FK_user_profile_user`;
+alter table `user_profile` drop key `FK487E2135895349BF`;
+alter table `user_profile` drop key `UK_ebc21hy5j7scdvcjt0jy6xxrv`;
+alter table `user_profile` drop key `user_id`;
+
+alter table `user_profile` rename column `otherInfo` to `other_info`;
+alter table `user_profile` rename column `phoneNumber` to `phone_number`;
+alter table `user_profile` rename column `skypeId` to `skype_id`;
+alter table `user_profile` rename column `mailCompilation` to `mail_compilation`;
+alter table `user_profile` drop column `threadedForum`;
+alter table `user_profile` rename column `defaultSupervisorFilter` to `default_supervisor_filter`;
+alter table `user_profile` rename column `selectedRole` to `selected_role`;
+
+alter table `user_profile` add constraint uk_user_profile_user_id unique(user_id);
+
+alter table `user_profile`
+    add constraint fk_user_profile_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: user_profile_default_project_status_filter
+
+alter table `UserProfile_defaultProjectStatusFilter` drop foreign key `FK_user_profile_project_status_user_profile`;
+alter table `UserProfile_defaultProjectStatusFilter` drop key `FK_icub74l6htav89sx85ar4qcqg`;
+
+rename table `UserProfile_defaultProjectStatusFilter` to `user_profile_default_project_status_filter`;
+
+alter table `user_profile_default_project_status_filter` rename column `UserProfile_id` to `user_profile_id`;
+alter table `user_profile_default_project_status_filter` rename column `defaultProjectStatusFilter` to `default_project_status_filter`;
+
+alter table `user_profile_default_project_status_filter`
+    add constraint fk_user_profile_default_project_status_filter_user_profile_id
+        foreign key (user_profile_id) references user_profile (id)
+            on delete cascade on update cascade;
+
+-- table: user_profile_default_project_team_member_roles_filter
+
+alter table `UserProfile_defaultProjectTeamMemberRolesFilter` drop foreign key `FK_user_profile_role_user_profile`;
+alter table `UserProfile_defaultProjectTeamMemberRolesFilter` drop key `FK_ibub74l6htav89sx85ar4qcqg`;
+
+rename table `UserProfile_defaultProjectTeamMemberRolesFilter` to `user_profile_default_project_team_member_roles_filter`;
+
+alter table `user_profile_default_project_team_member_roles_filter` rename column `UserProfile_id` to `user_profile_id`;
+alter table `user_profile_default_project_team_member_roles_filter` rename column `defaultProjectTeamMemberRolesFilter` to `default_project_team_member_roles_filter`;
+
+alter table `user_profile_default_project_team_member_roles_filter`
+    add constraint fk_up_dp_tm_roles_filter_user_profile_id
+        foreign key (user_profile_id) references user_profile (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 6: table ProjectType and related tables.
+ *
+ * Table ProjectType is one of four fundamental tables (other three: project, file_reference, user). All four
+ * tables have many foreign keys referenced to them.
+ *
+ * Table ProjectType has 12 foreign keys referenced to it, this part is the most complex part of this refactoring.
+ */
+
+-- table: user_profile_ProjectType, except foreign key to coming table project_type
+
+alter table `user_profile_ProjectType` drop foreign key `FK_user_profile_project_type_user_profile`;
+alter table `user_profile_ProjectType` drop foreign key `FK_76s8320kw3w7bxp6lw7pmawfh`;
+alter table `user_profile_ProjectType` drop key `FK_2blea2vk0b5cvgxjo1fy4p2j0`;
+alter table `user_profile_ProjectType` drop key `FK_76s8320kw3w7bxp6lw7pmawfh`;
+
+rename table `user_profile_ProjectType` to `user_profile_project_type`;
+
+alter table `user_profile_project_type` rename column `defaultProjectTypeFilter_id` to `project_type_id`;
+
+alter table `user_profile_project_type`
+    add constraint fk_user_profile_project_type_user_profile_id
+        foreign key (user_profile_id) references user_profile (id)
+            on delete cascade on update cascade;
+
+-- table: ExternalResource, except foreign key to coming table project_type
+
+alter table `ExternalResource` drop foreign key `ExternalResource_ProjectType_relevantFor`;
+alter table `ExternalResource` drop key `ExternalResource_ProjectType_relevantFor`;
+
+rename table `ExternalResource` to `external_resource`;
+
+alter table `external_resource` rename column `relevantFor_id` to `project_type_id`;
+
+-- table: project_type_project_modules, except foreign key to coming table project_type
+
+alter table `project_type_project_modules` drop foreign key `FK_4attsf1e22qpveesgl6o9b7lg`;
+alter table `project_type_project_modules` drop key `FK_4attsf1e22qpveesgl6o9b7lg`;
+alter table `project_type_project_modules` drop primary key;
+
+rename table `project_type_project_modules` to `project_type_project_module`;
+
+alter table `project_type_project_module` rename column `ProjectType_id` to `project_type_id`;
+alter table `project_type_project_module` rename column `projectModules` to `project_module`;
+
+alter table `project_type_project_module` add primary key (project_type_id, project_module);
+
+-- table: project_type_settings, except foreign key to coming table project_type
+
+alter table `project_type_settings` drop foreign key `FK_project_class_settings_projectType`;
+alter table `project_type_settings` drop key `FK_oxqyb1t8jo7cq2fx8j9slvloa`;
+alter table `project_type_settings` drop key `UK_project_class_settings_projectType`;
+
+alter table `project_type_settings` rename column `numDaysBetweenPeerReviewsOnSameProject` to `num_days_between_peer_reviews_on_same_project`;
+alter table `project_type_settings` rename column `numDaysToSubmitPeerReview` to `num_days_to_submit_peer_review`;
+alter table `project_type_settings` rename column `projectType_id` to `project_type_id`;
+alter table `project_type_settings` rename column `numDaysBeforePeerGetsCancelled` to `num_days_before_peer_gets_cancelled`;
+alter table `project_type_settings` rename column `minAuthors` to `min_authors`;
+alter table `project_type_settings` rename column `maxAuthors` to `max_authors`;
+alter table `project_type_settings` rename column `maxFinalSeminarActiveParticipation` to `max_final_seminar_active_participation`;
+alter table `project_type_settings` rename column `maxOpponentsOnFinalSeminar` to `max_opponents_on_final_seminar`;
+alter table `project_type_settings` rename column `minFinalSeminarActiveParticipation` to `min_final_seminar_active_participation`;
+alter table `project_type_settings` rename column `minOpponentsOnFinalSeminar` to `min_opponents_on_final_seminar`;
+alter table `project_type_settings` rename column `minimumOppositionsToBeGraded` to `min_oppositions_to_be_graded`;
+alter table `project_type_settings` rename column `minimumActiveParticipationsToBeGraded` to `min_active_participations_to_be_graded`;
+
+alter table `project_type_settings` add constraint uk_project_type_settings_project_type_id unique(project_type_id);
+
+-- table: grading_report_template, except foreign key to coming table project_type
+
+alter table `grading_report_template` drop foreign key `FK_grading_report_template_projectType`;
+alter table `grading_report_template` drop key `FK_qovbb9ql33oaxprfr01w7ss9u`;
+alter table `grading_report_template` drop key `UK_only_one_template_per_date_and_type`;
+
+alter table `grading_report_template` change `projectType_id` `project_type_id` bigint(20) not null after `failing_grade`;
+
+alter table `grading_report_template` add constraint uk_grading_report_template_project_type_id_valid_from unique(project_type_id, valid_from);
+
+-- table: grading_report_template_grade_limits
+
+alter table `grading_report_template_grade_limits` drop foreign key `FK_grade_limit_grading_report_template `;
+alter table `grading_report_template_grade_limits` drop key `UK_one_grade_per_template`;
+
+rename table `grading_report_template_grade_limits` to `grading_report_template_grade_limit`;
+
+alter table `grading_report_template_grade_limit` change `grading_report_template_id` `grading_report_template_id` bigint(20) default null after `lower_limit`;
+
+alter table `grading_report_template_grade_limit` add constraint uk_grt_gl_grading_report_template_id_grade unique (grading_report_template_id, grade);
+
+alter table `grading_report_template_grade_limit`
+    add constraint fk_grt_gl_grading_report_template_id
+        foreign key (grading_report_template_id) references grading_report_template (id)
+            on delete cascade on update cascade;
+
+/* >>> START: table grading_criterion_template, GradingCriterion and criterion share same JPA MappedSuperclass, must be handled together. */
+
+-- table: criterion (partially, only rename three columns, since this table criterion shares same
+-- JPA MappedSuperclass AbstractCriterion with grading_criterion_template, and GradingCriterion
+
+alter table `criterion` rename column `title` to `title_sv`;
+alter table `criterion` rename column `titleEn` to `title_en`;
+alter table `criterion` rename column `sortOrder` to `sort_order`;
+
+-- table: GradingCriterion (partially, only rename four columns, since this table GradingCriterion shares same
+-- JPA MappedSuperclass AbstractCriterion and AbstractGradingCriterion with grading_criterion_template.
+
+alter table `GradingCriterion` rename column `title` to `title_sv`;
+alter table `GradingCriterion` rename column `titleEn` to `title_en`;
+alter table `GradingCriterion` rename column `sortOrder` to `sort_order`;
+alter table `GradingCriterion` rename column `pointsRequiredToPass` to `points_required_to_pass`;
+
+-- table: grading_criterion_template
+
+alter table `grading_criterion_template` drop foreign key `FK_b37xw6uyfj98ff2tsn5t8x5q`;
+alter table `grading_criterion_template` drop key `FK_b37xw6uyfj98ff2tsn5t8x5q`;
+
+alter table `grading_criterion_template` rename column `title` to `title_sv`;
+alter table `grading_criterion_template` rename column `titleEn` to `title_en`;
+alter table `grading_criterion_template` rename column `sortOrder` to `sort_order`;
+alter table `grading_criterion_template` rename column `pointsRequiredToPass` to `points_required_to_pass`;
+alter table `grading_criterion_template` rename column `gradingReportTemplate_id` to `grading_report_template_id`;
+
+alter table `grading_criterion_template`
+    add constraint fk_gct_grading_report_template_id
+        foreign key (grading_report_template_id) references grading_report_template (id)
+            on delete cascade on update cascade;
+
+/* >>> END: */
+
+/* >>> START: table grading_criterion_point_template and GradingCriterionPoint share same JPA MappedSuperclass, must be handled together. */
+
+-- table: GradingCriterionPoint (partially, only rename two columns since this table and grading_criterion_pint_template
+-- shares same MappedSuperclass AbstractGradingCriterionPoint.
+
+alter table `GradingCriterionPoint` rename column `description` to `description_sv`;
+alter table `GradingCriterionPoint` rename column `descriptionEn` to `description_en`;
+
+-- table: grading_criterion_point_template
+
+alter table `grading_criterion_point_template` drop foreign key `FK_gradingCriterionTemplate_id`;
+alter table `grading_criterion_point_template` drop key `FK_gradingCriterionTemplate_id`;
+
+alter table `grading_criterion_point_template` rename column `description` to `description_sv`;
+alter table `grading_criterion_point_template` rename column `descriptionEn` to `description_en`;
+alter table `grading_criterion_point_template` rename column `gradingCriterionTemplate_id` to `grading_criterion_template_id`;
+
+alter table `grading_criterion_point_template`
+    add constraint fk_gc_pt_grading_criterion_template_id
+        foreign key (grading_criterion_template_id) references grading_criterion_template (id)
+            on delete cascade on update cascade;
+
+/* >>> END: */
+
+-- table: checklist_template_ProjectType, except foreign key to coming table project_type
+
+alter table `checklist_template_ProjectType` drop foreign key `FK_checklist_template_projectType_id`;
+alter table `checklist_template_ProjectType` drop foreign key `FK_checklist_template_degree_level_checklist_template_id`;
+alter table `checklist_template_ProjectType` drop key `FK_checklist_template_projectType_id`;
+alter table `checklist_template_ProjectType` drop primary key;
+
+rename table `checklist_template_ProjectType` to `checklist_template_project_type`;
+
+alter table `checklist_template_project_type` rename column `projectType_id` to `project_type_id`;
+
+alter table `checklist_template_project_type` add primary key (checklist_template_id, project_type_id);
+
+alter table `checklist_template_project_type`
+    add constraint fk_ct_pt_checklist_template_id
+        foreign key (checklist_template_id) references checklist_template (id)
+            on delete cascade on update cascade;
+
+-- table: milestone_activity_template_ProjectType, except foreign key to coming table project_type
+
+alter table `milestone_activity_template_ProjectType` drop foreign key `FKFB3FC75180E42A0F`;
+alter table `milestone_activity_template_ProjectType` drop foreign key `FKFB3FC75157F6B071`;
+alter table `milestone_activity_template_ProjectType` drop key `FKFB3FC75180E42A0F`;
+alter table `milestone_activity_template_ProjectType` drop key `FKFB3FC75157F6B071`;
+alter table `milestone_activity_template_ProjectType` drop primary key;
+
+rename table `milestone_activity_template_ProjectType` to `milestone_activity_template_project_type`;
+
+alter table `milestone_activity_template_project_type` rename column `projectTypes_id` to `project_type_id`;
+
+alter table `milestone_activity_template_project_type` add primary key (`milestone_activity_template_id`, `project_type_id`);
+
+alter table `milestone_activity_template_project_type`
+    add constraint fk_ma_tpt_milestone_activity_template_id
+        foreign key (milestone_activity_template_id) references milestone_activity_template (id)
+            on delete cascade on update cascade;
+
+-- table: idea, we only remove foreign key from idea to ProjectType and rename the column projectType_id here.
+--        This table has many related tables and will be fixed later.
+
+alter table `idea` drop foreign key `FK_idea_projectType`;
+alter table `idea` drop key `FK_idea_projectType`;
+
+alter table `idea` rename column `projectType_id` to `project_type_id`;
+
+-- table: project, we only remove foreign key from project to ProjectType and rename the column projectType_id here.
+--        This table has many related tables and will be fixed later.
+
+alter table `project` drop foreign key `FK_project_projectType`;
+alter table `project` drop key `FKED904B19B2B6081F`;
+
+alter table `project` rename column `projectType_id` to `project_type_id`;
+
+/*
+ * Table target, projectPartner and ApplicationPeriodProjectType has not only foreign key referencing table ProjectType,
+ * but also foreign key referencing table ApplicationPeriod. Table ApplicationPeriodProjectType references to
+ * ActivityPlanTemplate as well.
+ *
+ * Table ActivityTemplate, ActivityPlanTemplate, ApplicationPeriod using camel case naming convention,
+ * ApplicationPeriod has a related table, applicationperiodexemption, and they all need to
+ * fixed as well, before ProjectType can be fixed. A foreign key from table idea to ApplicationPeriod needs to be removed
+ * before table ApplicationPeriod can be fixed.
+ *
+ * Removal of foreign keys and renaming of columns and table name must be fixed in following order:
+ *
+ * 1. target, projectPartner, ApplicationPeriodProjectType
+ * 2. ActivityTemplate and ActivityPlanTemplate
+ * 3. ApplicationPeriod, applicationperiodexcemption, and idea as well
+ *
+ * Foreign keys will be then added in reverse order, it's like a stack pop.
+ */
+
+-- >>> STACK PUSH: 1st table group: target, projectPartner, ApplicationPeriodProjectType
+
+-- table: target, except foreign key to coming table project_type, and application_period
+
+alter table `target` drop foreign key `target_user_id`;
+alter table `target` drop foreign key `FKCB7E7191A520201Eb`;
+alter table `target` drop foreign key `FKCB7E7191790761A4b`;
+alter table `target` drop key `FKCB7E7191A520201E`;
+alter table `target` drop key `FKCB7E7191790761A4`;
+alter table `target` drop primary key;
+
+alter table `target` rename column `applicationPeriodId` to `application_period_id`;
+alter table `target` rename column `projectTypeId` to `project_type_id`;
+
+alter table `target` add primary key (application_period_id, project_type_id, user_id);
+
+alter table `target`
+    add constraint fk_target_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: projectPartner, except foreign key to coming table project_type, and application_period
+
+alter table `projectPartner` drop foreign key `FK_project_partner_project_type`;
+alter table `projectPartner` drop foreign key `FK_ProjectPartner_ApplicationPeriod_applicationPeriod`;
+alter table `projectPartner` drop foreign key `FK1882B6F895349BF`;
+alter table `projectPartner` drop key `FK_ProjectPartner_ApplicationPeriod_applicationPeriod`;
+alter table `projectPartner` drop key `FK_project_partner_project_type`;
+alter table `projectPartner` drop key `FK1882B6F895349BF`;
+
+rename table `projectPartner` to `project_partner`;
+
+alter table `project_partner` rename column `infotext` to `info_text`;
+alter table `project_partner` rename column `projectType_id` to `project_type_id`;
+alter table `project_partner` rename column `applicationPeriod_id` to `application_period_id`;
+
+alter table `project_partner`
+    add constraint fk_project_partner_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: ApplicationPeriodProjectType, except foreign key to coming table application_period, project_type and activity_plan_template.
+
+alter table `ApplicationPeriodProjectType` drop foreign key `FK_hqebt63rl2mhogp66dy5m7upo`;
+alter table `ApplicationPeriodProjectType` drop foreign key `FK_546usee339qh4g5otguwka3hi`;
+alter table `ApplicationPeriodProjectType` drop foreign key `FK_3ku67jvegs1xxh8ykk023i7sb`;
+alter table `ApplicationPeriodProjectType` drop key `FK_3ku67jvegs1xxh8ykk023i7sb`;
+alter table `ApplicationPeriodProjectType` drop key `FK_546usee339qh4g5otguwka3hi`;
+alter table `ApplicationPeriodProjectType` drop key `FK_hqebt63rl2mhogp66dy5m7upo`;
+alter table `ApplicationPeriodProjectType` drop primary key;
+
+rename table `ApplicationPeriodProjectType` to `application_period_project_type`;
+
+alter table `application_period_project_type` rename column `applicationPeriod_id` to `application_period_id`;
+alter table `application_period_project_type` rename column `projectType_id` to `project_type_id`;
+alter table `application_period_project_type` rename column `activityPlanTemplate_id` to `activity_plan_template_id`;
+
+alter table `application_period_project_type` add primary key (application_period_id, project_type_id);
+
+-- >>> STACK PUSH: 2nd table group: ActivityPlanTemplate and ActivityTemplate
+
+-- table: ActivityTemplate, except foreign key to coming table activity_plan_template
+
+alter table `ActivityTemplate` drop foreign key `FK_ca5bhq3i6p2g292fo5l4fqtf`;
+alter table `ActivityTemplate` drop foreign key `FK_activity_template_checklist_template`;
+alter table `ActivityTemplate` drop key `FKD4434665C5FC509F`;
+alter table `ActivityTemplate` drop key `FK_ca5bhq3i6p2g292fo5l4fqtf`;
+alter table `ActivityTemplate` drop key `FK_667ye6la0yb5obk64v21knimn`;
+
+rename table `ActivityTemplate` to `activity_template`;
+
+alter table `activity_template` rename column `numberInOrder` to `number_in_order`;
+alter table `activity_template` rename column `activityPlanTemplate_id` to `activity_plan_template_id`;
+alter table `activity_template` rename column `daysOffset` to `days_offset`;
+alter table `activity_template` rename column `checkListTemplate_id` to `checklist_template_id`;
+
+alter table `activity_template`
+    add constraint fk_activity_template_checklist_template_id
+        foreign key (checklist_template_id) references checklist_template (id)
+            on delete set null on update cascade;
+
+-- table: ActivityPlanTemplate (at this stage, no any foreign key is referenced to ActivityPlanTemplate)
+
+alter table `ActivityPlanTemplate` drop foreign key `FK_rgwf80yvcy2msbb6g80bae10p`;
+alter table `ActivityPlanTemplate` drop key `FK_rgwf80yvcy2msbb6g80bae10p`;
+alter table `ActivityPlanTemplate` drop key `FKACCF6522E44F4DBE`;
+
+rename table `ActivityPlanTemplate` to `activity_plan_template`;
+
+alter table `activity_plan_template` rename column `isSysAdminTemplate` to `is_sys_admin_template`;
+alter table `activity_plan_template` rename column `creator_id` to `creator_user_id`;
+
+alter table `activity_plan_template`
+    add constraint fk_activity_plan_template_creator_user_id
+        foreign key (creator_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- Add back all foreign key references to activity_plan_template
+
+-- add foreign key reference from activity_template to activity_plan_template
+alter table `activity_template`
+    add constraint fk_activity_template_activity_plan_template_id
+        foreign key (activity_plan_template_id) references activity_plan_template (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from application_period_project_type to activity_plan_template
+alter table `application_period_project_type`
+    add constraint fk_ap_pt_activity_plan_template_id
+        foreign key (activity_plan_template_id) references activity_plan_template (id)
+            on delete cascade on update cascade;
+
+-- >>> STACK POP: 2nd table group (ActivityPlanTemplate and ActivityTemplate) is done!!!
+
+-- >>> STACK PUSH: 3rd table group: ApplicationPeriod, applicationperiodexemption, idea
+
+-- table: applicationperiodexeption, except foreign key reference to coming table application_period
+
+alter table `applicationperiodexemption` drop foreign key `fk_application_period_exemption_user`;
+alter table `applicationperiodexemption` drop foreign key `fk_application_period_exemption_application_period`;
+alter table `applicationperiodexemption` drop foreign key `FK_4p3he5fymtmdgbkl3xwrodq36`;
+alter table `applicationperiodexemption` drop key `i_user_application_period`;
+alter table `applicationperiodexemption` drop key `i_application_period`;
+alter table `applicationperiodexemption` drop key `i_user`;
+alter table `applicationperiodexemption` drop key `FK_4p3he5fymtmdgbkl3xwrodq36`;
+alter table `applicationperiodexemption` drop primary key;
+
+rename table `applicationperiodexemption` to `application_period_exemption`;
+
+alter table `application_period_exemption` rename column `endDate` to `end_date`;
+alter table `application_period_exemption` rename column `grantedBy_id` to `granted_by_id`;
+alter table `application_period_exemption` rename column `grantedOn` to `granted_on`;
+alter table `application_period_exemption` rename column `applicationPeriodId` to `application_period_id`;
+
+alter table `application_period_exemption` add primary key (`application_period_id`,`user_id`,`type`);
+
+alter table `application_period_exemption`
+    add constraint fk_ape_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `application_period_exemption`
+    add constraint fk_ape_granted_by_id
+        foreign key (granted_by_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: idea, we only remove foreign key from idea to ApplicationPeriod and rename the column applicationPeriod_id here.
+--        This table has many related tables and will be fixed later.
+
+alter table `idea` drop foreign key `FK6E051897BEC322C1`;
+alter table `idea` drop key `FK6E051897BEC322C1`;
+
+alter table `idea` rename column `applicationPeriod_id` to `application_period_id`;
+
+-- table: ApplicationPeriod  (at this stage, no any foreign key is referenced to ApplicationPeriod)
+
+rename table `ApplicationPeriod` to `application_period`;
+
+alter table `application_period` rename column `endDate` to `end_date`;
+alter table `application_period` rename column `startDate` to `start_date`;
+alter table `application_period` rename column `courseStartDate` to `course_start_date`;
+alter table `application_period` rename column `courseEndDate` to `course_end_date`;
+
+-- Add back all foreign key references to application_period, since table application_period is ready
+
+-- add back foreign key reference from ide to application_period
+alter table `idea`
+    add constraint fk_idea_application_period_id
+        foreign key (application_period_id) references application_period (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from application_period_exemption to application_period
+alter table `application_period_exemption`
+    add constraint fk_ape_application_period_id
+        foreign key (application_period_id) references application_period (id)
+            on delete cascade on update cascade;
+
+-- >>> STACK POP: 3rd table group: ApplicationPeriod, applicationperiodexemption, idea is done!!!
+
+-- add back foreign key reference from application_period_project_type to application_period
+alter table `application_period_project_type`
+    add constraint fk_ap_pt_application_period_id
+        foreign key (application_period_id) references application_period (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from project_partner to application_period
+alter table `project_partner`
+    add constraint fk_project_partner_application_period_id
+        foreign key (application_period_id) references application_period (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from target to application_period
+alter table `target`
+    add constraint fk_target_application_period_id
+        foreign key (application_period_id) references application_period (id)
+            on delete cascade on update cascade;
+
+-- table: ProjectType (finally!! at this stage, no any foreign key is referenced to ProjectType)
+
+rename table `ProjectType` to `project_type`;
+
+alter table `project_type` rename column `degreeType` to `degree_type`;
+
+-- Add back all foreign key references to project_type
+
+-- add back foreign key reference from application_period_project_type to project_type
+alter table `application_period_project_type`
+    add constraint fk_ap_pt_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from project_partner to project_type
+alter table `project_partner`
+    add constraint fk_project_partner_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from target to project_type
+alter table `target`
+    add constraint fk_target_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- >>> STACK POP: 1st table group: target, projectPartner, ApplicationPeriodProjectType is done!!!
+
+-- add back foreign key reference from project to project_type
+alter table `project`
+    add constraint fk_project_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from idea to project_type
+alter table `idea`
+    add constraint fk_idea_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from milestone_activity_template_project_type to project_type
+alter table `milestone_activity_template_project_type`
+    add constraint fk_ma_tpt_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from checklist_template_project_type to project_type
+alter table `checklist_template_project_type`
+    add constraint fk_ct_pt_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from grading_report_template to project_type
+alter table `grading_report_template`
+    add constraint fk_grading_report_template_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from project_type_settings to project_type
+alter table `project_type_settings`
+    add constraint fk_project_type_settings_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from project_type_project_module to project_type
+alter table `project_type_project_module`
+    add constraint fk_project_type_project_module_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from external_resource to project_type
+alter table `external_resource`
+    add constraint fk_external_resource_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from user_profile_project_type to project_type.
+alter table `user_profile_project_type`
+    add constraint fk_user_profile_project_type_project_type_id
+        foreign key (project_type_id) references project_type (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 7: checklist related tables
+ */
+
+-- table: checklist_checklist_question
+
+alter table `checklist_checklist_question` drop foreign key `FKC77ED98C64F9D54`;
+alter table `checklist_checklist_question` drop foreign key `FKC77ED981F327355`;
+alter table `checklist_checklist_question` drop key `FKC77ED981F327355`;
+alter table `checklist_checklist_question` drop key `FKC77ED98C64F9D54`;
+alter table `checklist_checklist_question` drop key `UK_o5ndj9lydqv17attv7uf8wlr`;
+alter table `checklist_checklist_question` drop key `questions_id`;
+alter table `checklist_checklist_question` drop primary key;
+
+alter table `checklist_checklist_question` rename column `questions_id` to `checklist_question_id`;
+
+alter table `checklist_checklist_question` add primary key (checklist_id, checklist_question_id);
+
+alter table `checklist_checklist_question` add constraint uk_ccq_checklist_question_id unique(checklist_question_id);
+
+alter table `checklist_checklist_question`
+    add constraint fk_ccq_checklist_question_id
+        foreign key (checklist_question_id) references checklist_question (id)
+            on delete cascade on update cascade;
+
+alter table `checklist_checklist_question`
+    add constraint fk_ccq_checklist_id
+        foreign key (checklist_id) references checklist (id)
+            on delete cascade on update cascade;
+
+-- table: Checklist_userLastOpenDate
+
+alter table `Checklist_userLastOpenDate` drop foreign key `FKF7E07AB26D025A9`;
+alter table `Checklist_userLastOpenDate` drop foreign key `FKF7E07AB21F327355`;
+alter table `Checklist_userLastOpenDate` drop key `FKF7E07AB26D025A9`;
+alter table `Checklist_userLastOpenDate` drop key `FKF7E07AB21F327355`;
+alter table `Checklist_userLastOpenDate` drop primary key;
+
+rename table `Checklist_userLastOpenDate` to `checklist_user_last_open_date`;
+
+alter table `checklist_user_last_open_date` rename column `CheckList_id` to `checklist_id`;
+alter table `checklist_user_last_open_date` rename column `userLastOpenDate` to `last_open_date`;
+alter table `checklist_user_last_open_date` rename column `userLastOpenDate_KEY` to `user_id`;
+
+alter table `checklist_user_last_open_date` add primary key (checklist_id, user_id);
+
+alter table `checklist_user_last_open_date`
+    add constraint fk_cu_lod_checklist_id
+        foreign key (checklist_id) references checklist(id)
+            on delete cascade on update cascade;
+
+alter table `checklist_user_last_open_date`
+    add constraint fk_cu_lod_user_id
+        foreign key (user_id) references user(id)
+            on delete cascade on update cascade;
+
+-- table: checklist_checklist_category
+
+alter table `checklist_checklist_category` drop foreign key `FK54F86EB08725F1D`;
+alter table `checklist_checklist_category` drop foreign key `FK54F86EB01F327355`;
+alter table `checklist_checklist_category` drop key `FK54F86EB08725F1D`;
+alter table `checklist_checklist_category` drop key `FK54F86EB01F327355`;
+
+alter table `checklist_checklist_category` rename column `categories_id` to `checklist_category_id`;
+
+alter table `checklist_checklist_category`
+    add constraint fk_cca_checklist_id
+        foreign key (checklist_id) references checklist (id)
+            on delete cascade on update cascade;
+
+alter table `checklist_checklist_category`
+    add constraint fk_cca_checklist_category_id
+        foreign key (checklist_category_id) references checklist_category (id)
+            on delete cascade on update cascade;
+
+-- table: checklist_category
+
+alter table `checklist_category` drop key `categoryName`;
+alter table `checklist_category` rename column `categoryName` to `category_name`;
+
+alter table `checklist_category` add constraint uk_checklist_category_category_name unique(category_name);
+
+-- table: checklist
+
+alter table `checklist` drop foreign key `FK_checklist_project`;
+alter table `checklist` drop key `I_checkList_activity`;
+
+alter table `checklist`
+    add constraint fk_checklist_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table : checklist_question_checklist_answer
+
+alter table `checklist_question_checklist_answer` drop foreign key `FK86395A5787D18D44`;
+alter table `checklist_question_checklist_answer` drop foreign key `FK86395A574BFBD702`;
+alter table `checklist_question_checklist_answer` drop key `FK86395A574BFBD702`;
+alter table `checklist_question_checklist_answer` drop key `UK_47is0po5b69467hxbgr4a2gph`;
+alter table `checklist_question_checklist_answer` drop key `answers_id`;
+
+alter table `checklist_question_checklist_answer` rename column `answers_id` to `checklist_answer_id`;
+
+alter table `checklist_question_checklist_answer` add constraint uk_cq_ca_checklist_answer_id unique(checklist_answer_id);
+
+alter table `checklist_question_checklist_answer`
+    add constraint fk_cq_ca_checklist_answer_id
+        foreign key (checklist_answer_id) references checklist_answer (id)
+            on delete cascade on update cascade;
+
+alter table `checklist_question_checklist_answer`
+    add constraint fk_cq_ca_checklist_question_id
+        foreign key (checklist_question_id) references checklist_question (id)
+            on delete cascade on update cascade;
+
+-- table: checklist_answer
+
+alter table `checklist_answer` drop foreign key `FK49936477895349BF`;
+alter table `checklist_answer` drop key `FK49936477895349BF`;
+
+alter table `checklist_answer`
+    add constraint fk_checklist_answer_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- update to NOT_APPLICABLE because of typo in code
+update `checklist_answer` set answer = 'NOT_APPLICABLE' where answer = 'NOT_APLICABLE';
+update `answer` set answer = 'NOT_APPLICABLE' where answer = 'NOT_APLICABLE';
+
+-- table: checklist_question
+
+alter table `checklist_question` rename column `questionNumber` to `question_number`;
+
+-- table: ChecklistTemplate_questions
+
+alter table `ChecklistTemplate_questions` drop foreign key `FK872F7C0E869F0235`;
+alter table `ChecklistTemplate_questions` drop key `FK872F7C0E869F0235`;
+
+rename table `ChecklistTemplate_questions` to `checklist_template_question`;
+
+alter table `checklist_template_question` rename column `CheckListTemplate_id` to `checklist_template_id`;
+alter table `checklist_template_question` rename column `questions` to `question`;
+
+alter table `checklist_template_question`
+    add constraint fk_ctq_checklist_template_id
+        foreign key (checklist_template_id) references checklist_template (id)
+            on delete cascade on update cascade;
+
+-- table: checklist_template_checklist_category
+
+alter table `checklist_template_checklist_category` drop foreign key `FK4E82F4438725F1D`;
+alter table `checklist_template_checklist_category` drop foreign key `FK4E82F44372B51E82`;
+alter table `checklist_template_checklist_category` drop key `FK4E82F4438725F1D`;
+alter table `checklist_template_checklist_category` drop key `FK4E82F44372B51E82`;
+
+alter table `checklist_template_checklist_category` rename column `categories_id` to `checklist_category_id`;
+
+alter table `checklist_template_checklist_category`
+    add constraint fk_ct_cc_checklist_template_id
+        foreign key (checklist_template_id) references checklist_template (id)
+            on delete cascade on update cascade;
+
+alter table `checklist_template_checklist_category`
+    add constraint fk_ct_cc_checklist_category_id
+        foreign key (checklist_category_id) references checklist_category (id)
+            on delete cascade on update cascade;
+
+-- table: checklist_template
+
+alter table `checklist_template` drop foreign key `FK14DA6F3E44F4DBE`;
+alter table `checklist_template` drop key `FK14DA6F3E44F4DBE`;
+
+alter table `checklist_template` rename column `creator_id` to `creator_user_id`;
+alter table `checklist_template` rename column `templateNumber` to `template_number`;
+
+alter table `checklist_template`
+    add constraint fk_checklist_template_creator_user_id
+        foreign key (creator_user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 8: Survey related related tables
+ */
+
+-- table: SurveyAnswer_multipleAnswers, except foreign key to coming table survey_answer
+
+alter table `SurveyAnswer_multipleAnswers` drop foreign key `FK_SA`;
+alter table `SurveyAnswer_multipleAnswers` drop key `FK_SA`;
+
+rename table `SurveyAnswer_multipleAnswers` to `survey_answer_multiple_answers`;
+
+alter table `survey_answer_multiple_answers` rename column `SurveyAnswer_id` to `survey_answer_id`;
+alter table `survey_answer_multiple_answers` rename column `multipleAnswers` to `multiple_answers`;
+
+-- table: SurveyAnswer, except foreign key to coming table survey and question
+
+alter table `SurveyAnswer` drop foreign key `FK_answer_question`;
+alter table `SurveyAnswer` drop foreign key `FK_answer_survey`;
+alter table `SurveyAnswer` drop key `FK_answer_question`;
+alter table `SurveyAnswer` drop key `FK_answer_survey`;
+
+rename table `SurveyAnswer` to `survey_answer`;
+
+-- add back foreign key reference from survey_answer_multiple_answers to survey_answer
+
+alter table `survey_answer_multiple_answers`
+    add constraint fk_sama_survey_answer_id
+        foreign key (survey_answer_id) references survey_answer (id)
+            on delete cascade on update cascade;
+
+-- table: Question_choices, except foreign key to coming table question
+
+alter table `Question_choices` drop foreign key `FK_question_choices_question`;
+alter table `Question_choices` drop key `FK_question_choices_question`;
+
+rename table `Question_choices` to `question_choices`;
+
+-- table: Question
+
+rename table `Question` to `question`;
+
+-- add back foreign key reference from question_choices to question
+
+alter table `question_choices`
+    add constraint fk_question_choices_question_id
+        foreign key (question_id) references question (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key references from survey_answer to question
+
+alter table `survey_answer`
+    add constraint fk_survey_answer_question_id
+        foreign key (question_id) references question (id)
+            on delete cascade on update cascade;
+
+-- table: survey
+
+alter table `Survey` drop foreign key `FK_survey_project`;
+alter table `Survey` drop key `FK_survey_project`;
+alter table `Survey` drop foreign key `FK_survey_user`;
+alter table `Survey` drop key `FK_survey_user`;
+
+rename table `Survey` to `survey`;
+
+alter table `survey`
+    add constraint fk_survey_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `survey`
+    add constraint fk_survey_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key references from survey_answer to survey
+
+alter table `survey_answer`
+    add constraint fk_survey_answer_survey_id
+        foreign key (survey_id) references survey (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 9: Keyword and Research Area related tables
+ */
+
+-- table: Keyword_researcharea, except foreign keys to coming table keyword and research_area
+
+alter table `Keyword_researcharea` drop foreign key `FKF8C66F5E98ED461`;
+alter table `Keyword_researcharea` drop key `FKF8C66F5E98ED461`;
+alter table `Keyword_researcharea` drop foreign key `FKF8C66F5E6F20ECBC`;
+alter table `Keyword_researcharea` drop key `FKF8C66F5E6F20ECBC`;
+
+rename table `Keyword_researcharea` to `keyword_research_area`;
+
+alter table `keyword_research_area` rename column `Keyword_id` to `keyword_id`;
+alter table `keyword_research_area` rename column `researchAreas_id` to `research_area_id`;
+
+-- table: idea_Keyword
+
+alter table `idea_Keyword` drop foreign key `FK3707EE21AE316F00`;
+alter table `idea_Keyword` drop key `FK3707EE21AE316F00`;
+alter table `idea_Keyword` drop foreign key `FK3707EE21BD1521C1`;
+
+alter table `idea_Keyword` drop primary key;
+
+rename table `idea_Keyword` to `idea_keyword`;
+
+alter table `idea_keyword` rename column `keywords_id` to `keyword_id`;
+
+alter table `idea_keyword` add primary key (idea_id, keyword_id);
+
+alter table `idea_keyword`
+    add constraint fk_idea_keyword_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+-- table: keyword
+
+alter table `Keyword` drop key `deleted_index`;
+
+rename table `Keyword` to `keyword`;
+
+create index idx_keyword_deleted on keyword (deleted);
+
+-- add back foreign key reference from table idea_keyword to table keyword
+
+alter table `idea_keyword`
+    add constraint fk_idea_keyword_keyword_id
+        foreign key (keyword_id) references keyword (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from table keyword_research_area to table keyword
+
+alter table `keyword_research_area`
+    add constraint fk_kra_keyword_id
+        foreign key (keyword_id) references keyword (id)
+            on delete cascade on update cascade;
+
+-- table: user_research_area
+
+alter table `user_research_area` drop foreign key `user_research_area_user_id`;
+alter table `user_research_area` drop foreign key `user_research_area_research_area_id`;
+alter table `user_research_area` drop key `user_research_area_research_area_id`;
+
+alter table `user_research_area`
+    add constraint fk_ura_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- drop foreign key from idea to table researcharea before we can proceed with that table,
+-- change foreign key column name as well
+
+alter table `idea` drop foreign key `FK6E0518974E257FBF`;
+alter table `idea` drop key `FK6E0518974E257FBF`;
+
+alter table `idea` rename column `researchArea_id` to `research_area_id`;
+
+-- drop foreign key from project to table researcharea before we can proceed with that table,
+-- change foreign key column name as well
+
+alter table `project` drop foreign key `FK_research_area_id`;
+alter table `project` drop key `FK_research_area_id`;
+
+alter table `project` rename column `researchArea_id` to `research_area_id`;
+
+-- table: researcharea
+
+alter table `researcharea` drop key `deleted_index`;
+alter table `researcharea` drop key `identifier`;
+
+rename table `researcharea` to `research_area`;
+
+create index idx_research_area_deleted on research_area (deleted);
+
+alter table `research_area` add constraint uk_research_area_identifier unique (identifier);
+
+-- add back foreign key reference from table project to table research_area
+
+alter table `project`
+    add constraint fk_project_research_area_id
+        foreign key (research_area_id) references research_area (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from table idea to table research_area
+
+alter table `idea`
+    add constraint fk_idea_research_area_id
+        foreign key (research_area_id) references research_area (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from table user_research_area to table research_area
+
+alter table `user_research_area`
+    add constraint fk_ura_research_area_id
+        foreign key (research_area_id) references research_area (id)
+            on delete cascade on update cascade;
+
+-- add back foreign key reference from table keyword_research_area to table research_area
+
+alter table `keyword_research_area`
+    add constraint fk_kra_research_area_id
+        foreign key (research_area_id) references research_area (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 10: idea related tables
+ */
+
+-- table: idea
+
+alter table `idea` drop foreign key `FK6E051897B9431B73`;
+alter table `idea` drop foreign key `FK6E051897C1813915`;
+alter table `idea` drop foreign key `FK6E051897E44F4DBE`;
+
+alter table `idea` drop key `FK6E051897C1813915`;
+alter table `idea` drop key `FK6E051897B9431B73`;
+alter table `idea` drop key `FK6E051897E44F4DBE`;
+
+alter table `idea` drop key `UK_only_one_idea_per_project`;
+
+alter table `idea` change `published` `published` bit(1) not null default b'1' after `type`;
+alter table `idea` change `cachedStatus` `cached_status` varchar(255) default null after `published`;
+alter table `idea` change `inactive` `inactive` tinyint(1) not null default 0 after `cached_status`;
+
+alter table `idea` change `practicalHow` `practical_how` longtext default null after `inactive`;
+alter table `idea` change `theoryHow` `theory_how` longtext default null after `practical_how`;
+alter table `idea` change `literature` `literature` longtext default null after `why`;
+
+alter table `idea` change `background` `background` longtext default null after `literature`;
+alter table `idea` change `problem` `problem` longtext default null after `background`;
+alter table `idea` change `method` `method` longtext default null after `problem`;
+alter table `idea` change `interests` `interests` longtext default null after `method`;
+
+alter table `idea` rename column `creator_id` to `creator_user_id`;
+alter table `idea` rename column `match_id` to `latest_match_id`;
+
+alter table `idea` add constraint uk_idea_project_id unique(project_id);
+
+alter table `idea`
+    add constraint fk_idea_creator_user_id
+        foreign key (creator_user_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `idea`
+    add constraint fk_idea_latest_match_id
+        foreign key (latest_match_id) references idea_match (id)
+            on delete cascade on update cascade;
+
+alter table `idea`
+    add constraint fk_idea_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: idea_language
+
+alter table `idea_language` drop foreign key `FK_idea_language_idea`;
+alter table `idea_language` drop key `FK_idea_language_idea`;
+
+alter table `idea_language`
+    add constraint fk_idea_language_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+-- table: idea_export
+
+alter table `idea_export` drop foreign key `FK68FA705CFCDADF61`;
+alter table `idea_export` drop key `FK68FA705CFCDADF61`;
+
+alter table `idea_export`
+    add constraint fk_idea_export_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+-- table: idea_first_meeting
+
+alter table `idea_first_meeting` drop foreign key `FK9393AA04FCDADF61`;
+alter table `idea_first_meeting` drop key `FK9393AA04FCDADF61`;
+
+alter table `idea_first_meeting` drop key `UK_k4m4tupnikallbq3cq3llvlmk`;
+alter table `idea_first_meeting` drop key `idea_id`;
+
+alter table `idea_first_meeting` rename column `firstMeetingDate` to `first_meeting_date`;
+alter table `idea_first_meeting` change `room` `room` longtext not null after `first_meeting_date`;
+
+alter table `idea_first_meeting`
+    add constraint fk_idea_first_meeting_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+alter table `idea_first_meeting`
+    add constraint uk_idea_first_meeting_idea_id unique(idea_id);
+
+-- table: idea_match
+
+alter table `idea_match` drop foreign key `FK87EA481DFCDADF61`;
+alter table `idea_match` drop foreign key `FK87EA481DA89FFB7F`;
+alter table `idea_match` drop foreign key `idea_match_supervisor_id`;
+
+alter table `idea_match` drop key `FK87EA481DFCDADF61`;
+alter table `idea_match` drop key `FK87EA481DA89FFB7F`;
+alter table `idea_match` drop key `idea_match_supervisor_id`;
+
+alter table `idea_match` rename column `changedBy_id` to `changed_by_user_id`;
+alter table `idea_match` rename column `supervisor_id` to `supervisor_user_id`;
+
+alter table `idea_match`
+    add constraint fk_idea_match_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+alter table `idea_match`
+    add constraint fk_idea_match_changed_by_user_id
+        foreign key (changed_by_user_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `idea_match`
+    add constraint fk_idea_match_supervisor_user_id
+        foreign key (supervisor_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: preliminary_match
+
+alter table `preliminary_match` drop foreign key `FK_preliminary_match_supervisor`;
+alter table `preliminary_match` drop foreign key `FK_preliminary_match_idea`;
+
+alter table `preliminary_match` drop key `FK_preliminary_match_supervisor`;
+alter table `preliminary_match` drop key `FK_preliminary_match_idea`;
+
+alter table `preliminary_match` change `comment` `comment` mediumtext default null after `version`;
+alter table `preliminary_match` rename column `supervisor_id` to `supervisor_user_id`;
+
+alter table `preliminary_match`
+    add constraint fk_preliminary_match_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+alter table `preliminary_match`
+    add constraint fk_preliminary_match_supervisor_user_id
+        foreign key (supervisor_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: idea_student
+
+alter table `idea_student` drop foreign key `idea_student_user_id`;
+alter table `idea_student` drop foreign key `FK9458BA93FCDADF61`;
+
+alter table `idea_student` drop key `idea_student_user_id`;
+alter table `idea_student` drop key `FK9458BA93FCDADF61`;
+alter table `idea_student` drop key `FK_c5py593l4g261jdkuvwdmcmgj`;
+
+alter table `idea_student` rename column `dateCreated` to `date_created`;
+alter table `idea_student` change `id` `id` bigint(20) not null auto_increment first;
+
+alter table `idea_student`
+    add constraint fk_idea_student_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+alter table `idea_student`
+    add constraint fk_idea_student_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 11: activity related tables
+ *
+ * Some tables of this group of tables need to be renamed. Because of how foreign keys reference to each other
+ * between them, the order and behavior of how the tables will be fixed looks like stack again.
+ *
+ * 1. Remove references from activity_final_seminar, activity_thread, project_first_meeting to activity,
+ *    the fix these three tables, but wait to later before foreign keys are added back to becoming activity table.
+ * 2. Remove reference from Activity to ActivtyPlan, and fix table Activity, without adding back foreign key to
+ *    becoming activity_plan table.
+ * 3. Fix ActivityPlan table, rename it to activity_plan.
+ * 4. Add back foreign key reference from activity to activity_plan
+ * 5. Add back foreign key reference from activity_final_seminar, activity_thread, project_first_meeting to
+ *    activity table.
+ */
+
+-- table: activity_final_seminar, except foreign key to becoming table activity
+
+alter table `activity_final_seminar` drop foreign key `activity_final_seminar_ibfk_2`;
+alter table `activity_final_seminar` drop foreign key `activity_final_seminar_ibfk_1`;
+
+alter table `activity_final_seminar` drop key `activity_id`;
+
+alter table `activity_final_seminar`
+    add constraint fk_afs_final_seminar_id
+        foreign key (final_seminar_id) references final_seminar (id)
+            on delete cascade on update cascade;
+
+-- table: activity_thread, except foreign key to becoming table activity
+
+alter table `activity_thread` drop foreign key `FK_activity_thread_project_thread`;
+alter table `activity_thread` drop foreign key `FK_activity_thread_activity`;
+
+alter table `activity_thread` drop key `FK_activity_thread_project_thread`;
+
+alter table `activity_thread`
+    add constraint fk_activity_thread_project_thread_id
+        foreign key (project_thread_id) references project_thread (id)
+            on delete cascade on update cascade;
+
+-- table: project_first_meeting, except foreign key to becoming table activity
+
+alter table `project_first_meeting` drop foreign key `FK_project_first_meeting_activity`;
+
+alter table `project_first_meeting` drop key `FK_project_first_meeting_activity`;
+
+alter table `project_first_meeting` change `room` `room` longtext not null after `version`;
+
+alter table `project_first_meeting` change `activity_id` `activity_id` bigint(20) not null after `room`;
+
+-- table: activity
+
+alter table `Activity` drop foreign key `FK_Activity_file_upload`;
+alter table `Activity` drop foreign key `FK_Activity_ActivityPlan`;
+alter table `Activity` drop foreign key `FK_activity_checkList`;
+
+alter table `Activity` drop key `FK_Activity_file_upload`;
+alter table `Activity` drop key `activityTemplate_id_index`;
+alter table `Activity` drop key `deleted_index`;
+alter table `Activity` drop key `UK_activity_checkList`;
+
+rename table `Activity` to `activity`;
+
+alter table `activity` change `title` `title` varchar(500) not null after `deleted`;
+alter table `activity` change `action` `action` varchar(64) not null default 'none' after `description`;
+alter table `activity` change `editable` `editable` bit(1) not null default b'1' after `action`;
+
+alter table `activity` rename column `activityTemplate_id` to `activity_plan_id`;
+alter table `activity` rename column `file_upload_reference_id` to `upload_file_reference_id`;
+
+alter table `activity` add constraint uk_activity_checklist_id unique (checklist_id);
+create index idx_activity_deleted on activity(deleted);
+
+alter table `activity`
+    add constraint `fk_activity_checklist_id`
+        foreign key (checklist_id) references checklist (id)
+            on delete cascade on update cascade ;
+
+alter table `activity`
+    add constraint `fk_activity_upload_file_reference_id`
+        foreign key (upload_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade ;
+
+-- table: ActivityPlan
+
+alter table `ActivityPlan` drop foreign key `fk_ActivityPlan_project_B`;
+alter table `ActivityPlan` drop key `project_id`;
+
+rename table `ActivityPlan` to `activity_plan`;
+
+alter table `activity_plan` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `activity_plan` change `startDate` `start_date` datetime default null after `version`;
+
+alter table `activity_plan` add constraint uk_activity_plan_project_id unique (project_id);
+
+alter table `activity_plan`
+    add constraint `fk_activity_plan_project_id`
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from activity to activity_plan
+
+alter table `activity`
+    add constraint fk_activity_activity_plan_id
+        foreign key (activity_plan_id) references activity_plan (id)
+            on delete cascade on update cascade;
+
+-- Add back all foreign key references to activity
+
+-- add foreign key reference from project_first_meeting to activity
+
+alter table `project_first_meeting`
+    add constraint fk_project_first_meeting_activity_id
+        foreign key (activity_id) references activity (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from activity_thread to activity
+
+alter table `activity_thread`
+    add constraint fk_activity_thread_activity_id
+        foreign key (activity_id) references activity (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from activity_final_seminar to activity
+
+alter table `activity_final_seminar`
+    add constraint fk_afs_activity_id
+        foreign key (activity_id) references activity (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 12: Peer Review related tables
+ */
+
+-- table: peer_request
+
+alter table `peer_request` drop foreign key `FK_peer_request_checklist_template`;
+alter table `peer_request` drop foreign key `FK_peer_request_file`;
+alter table `peer_request` drop foreign key `FK_ppnisfed4ipbg17rts8vbuqt8`;
+alter table `peer_request` drop foreign key `peer_request_reviewer_id`;
+
+alter table `peer_request` drop key `FK_peer_request_file`;
+alter table `peer_request` drop key `FK_ppnisfed4ipbg17rts8vbuqt8`;
+alter table `peer_request` drop key `peer_request_reviewer_id`;
+alter table `peer_request` drop key `FK514488B2869F0235`;
+alter table `peer_request` drop key `FK514488B2C1813915`;
+
+alter table `peer_request` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `peer_request` change `language` `language` varchar(255) not null after `status`;
+
+alter table `peer_request` rename column `checkListTemplate_id` to `checklist_template_id`;
+alter table `peer_request` rename column `requester_id` to `requester_user_id`;
+
+alter table `peer_request` change `checklist_template_id` `checklist_template_id` bigint(20) default null after `language`;
+alter table `peer_request` change `file_reference_id` `file_reference_id` bigint(20) not null after `checklist_template_id`;
+
+alter table `peer_request`
+    add constraint fk_peer_request_checklist_template_id
+        foreign key (checklist_template_id) references checklist_template (id)
+            on delete set null on update cascade;
+
+alter table `peer_request`
+    add constraint fk_peer_request_file_reference_id
+        foreign key (file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `peer_request`
+    add constraint fk_peer_request_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `peer_request`
+    add constraint fk_peer_request_requester_user_id
+        foreign key (requester_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: peer_review
+
+alter table `peer_review` drop foreign key `peer_review_reviewer_id`;
+alter table `peer_review` drop foreign key `FK_n5wj0qsev5cf8acm0xhfrqlpg`;
+alter table `peer_review` drop foreign key `FK_9ke7armwg3tfnghmschgo011f`;
+alter table `peer_review` drop foreign key `FK_peer_review_file`;
+
+alter table `peer_review` drop key `peer_review_reviewer_id`;
+alter table `peer_review` drop key `FK_n5wj0qsev5cf8acm0xhfrqlpg`;
+alter table `peer_review` drop key `FKB00C90D5C1813915`;
+alter table `peer_review` drop key `FK_9ke7armwg3tfnghmschgo011f`;
+alter table `peer_review` drop key `FKB00C90D5CEE8709B`;
+alter table `peer_review` drop key `FK_peer_review_file`;
+
+alter table `peer_review` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `peer_review` change `status` `status` varchar(255) not null after `comment`;
+alter table `peer_review` change `deadline` `deadline` datetime not null after `status`;
+
+alter table `peer_review` change `file_reference_id` `file_reference_id` bigint(20) default null after `deadline`;
+alter table `peer_review` change `peerRequest_id` `peer_request_id` bigint(20) not null;
+alter table `peer_review` change `reviewer_id` `reviewer_user_id` bigint(20) not null;
+
+alter table `peer_review`
+    add constraint fk_peer_review_file_reference_id
+        foreign key (file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `peer_review`
+    add constraint fk_peer_review_peer_request_id
+        foreign key (peer_request_id) references peer_request (id)
+            on delete cascade on update cascade;
+
+alter table `peer_review`
+    add constraint fk_peer_review_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `peer_review`
+    add constraint fk_peer_review_reviewer_user_id
+        foreign key (reviewer_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: answer
+
+alter table `answer` drop foreign key `FK_64r70sbiishrkuj1vn87vo53k`;
+
+alter table `answer` drop key `FK_64r70sbiishrkuj1vn87vo53k`;
+alter table `answer` drop key `FKABCA3FBE2C41A959`;
+
+alter table `answer` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `answer` change `question` `question` longtext not null after `version`;
+alter table `answer` change `answer` `answer` varchar(255) not null after `question`;
+
+alter table `answer` rename column `peerReview_id` to `peer_review_id`;
+
+alter table `answer`
+    add constraint fk_answer_peer_review_id
+        foreign key (peer_review_id) references peer_review (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 13: Milestone related tables
+ */
+
+-- table: milestone
+
+alter table `milestone` drop foreign key `FKC0841970667E5A5E`;
+alter table `milestone` drop foreign key `FKC0841970C1813915`;
+alter table `milestone` drop foreign key `milestone_user_id`;
+
+alter table `milestone` drop key `FKC0841970667E5A5E`;
+alter table `milestone` drop key `FKC0841970C1813915`;
+alter table `milestone` drop key `milestone_user_id`;
+
+alter table `milestone` rename column `activity_id` to `milestone_activity_template_id`;
+
+alter table `milestone`
+    add constraint fk_milestone_milestone_activity_template_id
+        foreign key (milestone_activity_template_id) references milestone_activity_template (id)
+            on delete cascade on update cascade;
+
+alter table `milestone`
+    add constraint fk_milestone_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `milestone`
+    add constraint fk_milestone_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: milestone_activity_template, except foreign key to becoming table event
+
+alter table `milestone_activity_template` drop foreign key `milestone_activity_template_ibfk_1`;
+alter table `milestone_activity_template` drop foreign key `FK42DAA8FE233E1A72`;
+
+alter table `milestone_activity_template` drop key `milestone_activity_template_ibfk_1`;
+alter table `milestone_activity_template` drop key `FK42DAA8FE233E1A72`;
+alter table `milestone_activity_template` drop key `deleted_index`;
+alter table `milestone_activity_template` drop key `code`;
+
+alter table `milestone_activity_template` change `description` `description` varchar(255) default null after `title`;
+alter table `milestone_activity_template` change `sortOrder` `sort_order` int(11) default null;
+alter table `milestone_activity_template` change `editableByStudents` `editable_by_students` bit(1) not null default b'0' after `sort_order`;
+
+alter table `milestone_activity_template` change `phase` `milestone_phase_template_id` bigint(20) not null;
+alter table `milestone_activity_template` change `activatedBy` `activated_by_event_name` varchar(191) default null;
+
+alter table `milestone_activity_template` add constraint uk_milestone_activity_template_code unique(code);
+
+create index idx_milestone_activity_template_deleted on milestone_activity_template (deleted);
+
+alter table `milestone_activity_template`
+    add constraint fk_mat_milestone_phase_template_id
+        foreign key (milestone_phase_template_id) references milestone_phase_template (id)
+            on delete cascade on update cascade;
+
+-- table: event
+
+rename table `Event` to `event`;
+
+-- add foreign key reference from milestone_activity_template to event
+alter table `milestone_activity_template`
+    add constraint fk_mat_activated_by_event_name
+        foreign key (activated_by_event_name) references event (name)
+            on delete cascade on update cascade;
+
+-- table: milestone_phase_template
+
+alter table `milestone_phase_template` drop key `deleted_index`;
+
+alter table `milestone_phase_template` change `description` `description` varchar(255) default null after `title`;
+
+alter table `milestone_phase_template` rename column `sortOrder` to `sort_order`;
+
+create index idx_milestone_phase_template_deleted on milestone_phase_template (deleted);
+
+/*
+ * Step 14: Final Seminar related tables
+ */
+
+-- table: final_seminar
+
+alter table `final_seminar` drop foreign key `FK_rv1p7wl0dnj25saiarmk55yvr`;
+alter table `final_seminar` drop foreign key `FK_final_seminar_document_reference`;
+
+alter table `final_seminar` drop key `FK_final_seminar_document_reference`;
+alter table `final_seminar` drop key `FK_rv1p7wl0dnj25saiarmk55yvr`;
+alter table `final_seminar` drop key `deleted_index`;
+alter table `final_seminar` drop key `FK49900D28C1813915`;
+
+alter table `final_seminar` drop key `UK_rv1p7wl0dnj25saiarmk55yvr`;
+
+alter table `final_seminar` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `final_seminar` change `deleted` `deleted` tinyint(1) not null after `version`;
+
+alter table `final_seminar` change `startDate` `start_date` datetime not null after `deleted`;
+alter table `final_seminar` change `room` `room` varchar(255) not null after start_date;
+alter table `final_seminar` change `maxOpponents` `max_opponents` int(11) not null after `room`;
+alter table `final_seminar` change `maxParticipants` `max_participants` int(11) not null after `max_opponents`;
+alter table `final_seminar` change `presentationLanguage` `presentation_lang` varchar(255) not null after `max_participants`;
+alter table `final_seminar` change `documentUploadDate` `document_upload_date` datetime default null after `presentation_lang`;
+alter table `final_seminar` change `extra_info` `extra_info` text default null after `document_upload_date`;
+alter table `final_seminar` change `creationReason` `creation_reason` mediumtext default null after `extra_info`;
+alter table `final_seminar` change `manualParticipants` `manual_participants` tinyint(1) not null default 0 after `creation_reason`;
+alter table `final_seminar` change `project_id` `project_id` bigint(20) not null after `document_reference_id`;
+
+alter table `final_seminar` rename column `document_reference_id` to `document_file_reference_id`;
+
+alter table `final_seminar` add constraint uk_final_seminar_project_id unique(project_id);
+
+create index idx_final_seminar_deleted on final_seminar (deleted);
+
+alter table `final_seminar`
+    add constraint fk_final_seminar_document_file_reference_id
+        foreign key (document_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar`
+    add constraint fk_final_seminar_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: final_seminar_active_participation
+
+alter table `final_seminar_active_participation` drop foreign key `final_seminar_active_participation_user_id`;
+alter table `final_seminar_active_participation` drop foreign key `FK_mk920fce29yhjgv33wr69fe8a`;
+alter table `final_seminar_active_participation` drop foreign key `FK_3si3rx7tv6ke9oeiq0hts3lm0`;
+
+alter table `final_seminar_active_participation` drop key `FK35AB727FF583C69F`;
+alter table `final_seminar_active_participation` drop key `FK35AB727FC1813915`;
+alter table `final_seminar_active_participation` drop key `FK_mk920fce29yhjgv33wr69fe8a`;
+alter table `final_seminar_active_participation` drop key `FK_3si3rx7tv6ke9oeiq0hts3lm0`;
+alter table `final_seminar_active_participation` drop key `final_seminar_active_participation_user_id`;
+
+alter table `final_seminar_active_participation` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `final_seminar_active_participation` change `grade` `grade` varchar(20) default null after `version`;
+
+alter table `final_seminar_active_participation` rename column `finalSeminar_id` to `final_seminar_id`;
+
+alter table `final_seminar_active_participation`
+    add constraint fk_fsap_final_seminar_id
+        foreign key (final_seminar_id) references final_seminar (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_active_participation`
+    add constraint fk_fsap_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_active_participation`
+    add constraint fk_fsap_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: final_seminar_opposition
+
+alter table `final_seminar_opposition` drop foreign key `FK_62i59u7j6x5ma0iydx9no6m4i`;
+alter table `final_seminar_opposition` drop foreign key `FK_final_seminar_opposition_report`;
+alter table `final_seminar_opposition` drop foreign key `FK_hilhyo3tgq89pm27i4pxjaua`;
+alter table `final_seminar_opposition` drop foreign key `final_seminar_opposition_user_id`;
+
+alter table `final_seminar_opposition` drop key `FK8CD13581F583C69F`;
+alter table `final_seminar_opposition` drop key `FK8CD13581C1813915`;
+alter table `final_seminar_opposition` drop key `FK_62i59u7j6x5ma0iydx9no6m4i`;
+alter table `final_seminar_opposition` drop key `FK_hilhyo3tgq89pm27i4pxjaua`;
+alter table `final_seminar_opposition` drop key `final_seminar_opposition_user_id`;
+alter table `final_seminar_opposition` drop key `FK_final_seminar_opposition_report`;
+
+alter table `final_seminar_opposition` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `final_seminar_opposition` change `finalSeminar_id` `final_seminar_id` bigint(20) not null after `feedback`;
+alter table `final_seminar_opposition` change `opponent_report_reference_id`
+    `opponent_report_file_reference_id` bigint(20) default null after `final_seminar_id`;
+alter table `final_seminar_opposition` change `project_id` `project_id` bigint(20) not null
+    after `opponent_report_file_reference_id`;
+
+alter table `final_seminar_opposition`
+    add constraint fk_fso_final_seminar_id
+        foreign key (final_seminar_id) references final_seminar (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_opposition`
+    add constraint fk_fso_opponent_report_file_reference_id
+        foreign key (opponent_report_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_opposition`
+    add constraint fk_fso_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_opposition`
+    add constraint fk_fso_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: final_seminar_respondent
+
+alter table `final_seminar_respondent` drop foreign key `final_seminar_respondent_user_id`;
+alter table `final_seminar_respondent` drop foreign key `FK_final_seminar_respondent_id`;
+
+alter table `final_seminar_respondent` drop key `FK_final_seminar_respondent_id`;
+alter table `final_seminar_respondent` drop key `final_seminar_respondent_user_id`;
+
+alter table `final_seminar_respondent` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `final_seminar_respondent` change `grade` `grade` varchar(20) default null after `version`;
+alter table `final_seminar_respondent` change `finalSeminar_id` `final_seminar_id` bigint(20) not null after `grade`;
+
+alter table `final_seminar_respondent`
+    add constraint fk_fsr_final_seminar_id
+        foreign key (final_seminar_id) references final_seminar (id)
+            on delete cascade on update cascade;
+
+alter table `final_seminar_respondent`
+    add constraint fk_fsr_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 14: Report and Criterion related tables
+ */
+
+-- table: report
+
+alter table `report` change `submitted` `submitted` tinyint(1) not null default 0 after `version`;
+
+-- table: opposition_report
+
+alter table `opposition_report` drop foreign key `opposition_report_ibfk_1`;
+alter table `opposition_report` drop foreign key `FK_opposition_report_seminar_opposition`;
+alter table `opposition_report` drop foreign key `FK_opposition_report_attachment`;
+
+alter table `opposition_report` drop key `FK_opposition_report_attachment`;
+alter table `opposition_report` drop key `FK_opposition_report_seminar_opposition`;
+
+alter table `opposition_report` drop key `UK_one_report_per_opponent`;
+
+alter table `opposition_report` change `thesisSummary` `thesis_summary` longtext default null after `id`;
+
+alter table `opposition_report` change `attachment_reference_id` `attachment_file_reference_id`
+    bigint(20) default null after `thesis_summary`;
+
+alter table `opposition_report` change `finalSeminarOpposition_id` `final_seminar_opposition_id`
+    bigint(20) not null after `attachment_file_reference_id`;
+
+alter table `opposition_report` add constraint uk_or_final_seminar_opposition_id
+    unique(final_seminar_opposition_id);
+
+alter table `opposition_report`
+    add constraint fk_or_id
+        foreign key (id) references report (id)
+            on delete cascade on update cascade;
+
+alter table `opposition_report`
+    add constraint fk_or_attachment_file_reference_id
+        foreign key (attachment_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `opposition_report`
+    add constraint fk_or_final_seminar_opposition_id
+        foreign key (final_seminar_opposition_id) references final_seminar_opposition (id)
+            on delete cascade on update cascade;
+
+-- table: criterion
+
+alter table `criterion` drop foreign key `FK_criterion_report`;
+
+alter table `criterion` drop key `FK_criterion_report`;
+
+alter table `criterion` change `title_sv` `title_sv` varchar(255) not null after `version`;
+alter table `criterion` change `title_en` `title_en` varchar(255) not null default '' after `title_sv`;
+alter table `criterion` change `description` `description_sv` varchar(2000) default null after `title_en`;
+alter table `criterion` change `descriptionEn` `description_en` varchar(2000) default null after `description_sv`;
+alter table `criterion` change `feedback` `feedback` longtext default null after `description_en`;
+alter table `criterion` change `report_id` `report_id` bigint(20) not null after `sort_order`;
+
+alter table `criterion`
+    add constraint fk_criterion_report_id
+        foreign key (report_id) references report (id)
+            on delete cascade on update cascade;
+
+-- table: GradingCriterionPoint, except foreign key to becoming table grading_criterion
+
+alter table `GradingCriterionPoint` drop foreign key `FK_GradingCriterion_id`;
+
+alter table `GradingCriterionPoint` drop key `FK_GradingCriterion_id`;
+
+alter table `GradingCriterionPoint` change `GradingCriterion_id` `grading_criterion_id` bigint(20) not null
+    after `description_en`;
+
+rename table `GradingCriterionPoint` to `grading_criterion_point`;
+
+-- table: GradingCriterion, except foreign key to becoming table grading_report
+
+alter table `GradingCriterion` drop foreign key `FK_k2ynx2lcpdl969alj5nt3f7xx`;
+
+alter table `GradingCriterion` drop key `FK_k2ynx2lcpdl969alj5nt3f7xx`;
+
+alter table `GradingCriterion` change `title_sv` `title_sv` varchar(255) not null after `version`;
+alter table `GradingCriterion` change `title_en` `title_en` varchar(255) not null default '' after `title_sv`;
+alter table `GradingCriterion` change `type` `type` varchar(64) not null after `title_en`;
+alter table `GradingCriterion` change `points_required_to_pass` `points_required_to_pass` int(11) not null after `type`;
+alter table `GradingCriterion` change `feedback` `feedback` longtext default null after `points`;
+alter table `GradingCriterion` change `gradingReport_id` `grading_report_id` bigint(20) not null after `flag`;
+
+rename table `GradingCriterion` to `grading_criterion`;
+
+-- add foreign key reference from grading_criterion_point to grading_criterion
+
+alter table `grading_criterion_point`
+    add constraint fk_gcp_grading_criterion_id
+        foreign key (grading_criterion_id) references grading_criterion (id)
+            on delete cascade on update cascade;
+
+-- table: SupervisorGradingReport, except foreign key to becoming table grading_report
+
+alter table `SupervisorGradingReport` drop foreign key `supervisor_grading_report_user_id`;
+alter table `SupervisorGradingReport` drop foreign key `FK_cwxdypciob8dmndx5elwi3fe5`;
+
+alter table `SupervisorGradingReport` drop key `supervisor_grading_report_user_id`;
+alter table `SupervisorGradingReport` drop key `FK_cwxdypciob8dmndx5elwi3fe5`;
+
+rename table `SupervisorGradingReport` to `supervisor_grading_report`;
+
+alter table `supervisor_grading_report`
+    add constraint fk_sgr_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: ReviewerGradingReport, except foreign key to becoming table grading_report
+
+alter table `ReviewerGradingReport` drop foreign key `FK_axsaeqbamfc41dhih1s62g998`;
+
+alter table `ReviewerGradingReport` drop key `FK_axsaeqbamfc41dhih1s62g998`;
+
+rename table `ReviewerGradingReport` to `reviewer_grading_report`;
+
+-- table: GradingReport
+
+alter table `GradingReport` drop foreign key `GradingReport_ibfk_1`;
+alter table `GradingReport` drop foreign key `FK_6ygpk1qq218jgwuuyx0bp6vui`;
+
+alter table `GradingReport` drop key `FK_6ygpk1qq218jgwuuyx0bp6vui`;
+
+rename table `GradingReport` to `grading_report`;
+
+alter table `grading_report`
+    add constraint fk_grading_report_id
+        foreign key (id) references report (id)
+            on delete cascade on update cascade;
+
+alter table `grading_report`
+    add constraint fk_grading_report_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from reviewer_grading_report to grading_report
+
+alter table `reviewer_grading_report`
+    add constraint fk_reviewer_grading_report_id
+        foreign key (id) references grading_report (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from supervisor_grading_report to grading_report
+
+alter table `supervisor_grading_report`
+    add constraint fk_sgr_id
+        foreign key (id) references grading_report (id)
+            on delete cascade on update cascade;
+
+-- add foreign key reference from grading_criterion to grading_report
+
+alter table `grading_criterion`
+    add constraint fk_grading_criterion_grading_report_id
+        foreign key (grading_report_id) references grading_report (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 15: project and related tables
+ */
+
+-- table: project
+
+alter table `project` drop foreign key `project_supervisor_id`;
+alter table `project` drop key `project_supervisor_id`;
+alter table `project` drop key `identifier`;
+
+alter table `project` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `project` change `title` `title` longtext not null after `version`;
+alter table `project` change `credits` `credits` int(11) not null default 0 after `title`;
+alter table `project` change `language` `language` varchar(255) default null after credits;
+alter table `project` change `start_date` `start_date` date not null after language;
+alter table `project` change `expected_end_date` `expected_end_date` date default null after `start_date`;
+alter table `project` change `externalOrganization` `external_organization` varchar(255) default null after `expected_end_date`;
+alter table `project` change `projectStatus` `project_status` varchar(255) default null after `external_organization`;
+alter table `project` change `fs_rule_exmpt` `final_seminar_rule_exmpt` bit(1) not null default b'0' after `project_status`;
+alter table `project` change `stateOfMind` `state_of_mind` varchar(255) default null after `final_seminar_rule_exmpt`;
+alter table `project` change `stateOfMindReason` `state_of_mind_reason` varchar(255) default null after `state_of_mind`;
+alter table `project` change `stateOfMindDate` `state_of_mind_date` datetime default null after `state_of_mind_reason`;
+alter table `project` change `identifier` `daisy_identifier` bigint(20) default null after `state_of_mind_date`;
+alter table `project` change `supervisor_id` `supervisor_id` bigint(20) not null after `research_area_id`;
+
+alter table `project` add constraint uk_project_daisy_identifier unique(daisy_identifier);
+
+alter table `project`
+    add constraint fk_project_supervisor_id
+        foreign key (supervisor_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: grading_history_rejections
+
+alter table `grading_history_rejections` drop foreign key `FK_grading_history_rejections_project`;
+
+alter table `grading_history_rejections` drop key `FK_grading_history_rejections_project`;
+
+alter table `grading_history_rejections` change `reason` `reason` text not null after `id`;
+alter table `grading_history_rejections` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `reason`;
+
+rename table `grading_history_rejections` to `grading_history_rejection`;
+
+alter table `grading_history_rejection`
+    add constraint fk_grading_history_rejections_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: grading_history_approvals
+
+alter table `grading_history_approvals` drop foreign key `FK_grading_history_approvals_project`;
+
+alter table `grading_history_approvals` drop key `FK_grading_history_approvals_project`;
+
+alter table `grading_history_approvals` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `id`;
+
+rename table `grading_history_approvals` to `grading_history_approval`;
+
+alter table `grading_history_approval`
+    add constraint fk_grading_history_approval_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: national_subject_category
+
+alter table `national_subject_category` drop key `U_national_subject_category_external_id`;
+
+alter table `national_subject_category` change `swedish_name` `name_sv` varchar(255) not null after `id`;
+alter table `national_subject_category` change `english_name` `name_en` varchar(255) not null after `name_sv`;
+alter table `national_subject_category` change `external_id` `external_id` int(11) not null after `preselected`;
+
+alter table `national_subject_category`
+    add constraint uk_national_subject_category_external_id unique(external_id);
+
+-- table: publication_metadata
+
+alter table `publication_metadata` drop foreign key `FK_publication_metadata_project`;
+alter table `publication_metadata` drop foreign key `FK_publication_metadata_national_subject_category`;
+
+alter table `publication_metadata` drop key `FK_publication_metadata_project`;
+alter table `publication_metadata` drop key `FK_publication_metadata_national_subject_category`;
+
+alter table `publication_metadata` change `project_id` `project_id` bigint(20) not null after `national_subject_category_id`;
+
+alter table `publication_metadata` change `abstract_swedish` `abstract_sv` text default null after `id`;
+alter table `publication_metadata` change `abstract_english` `abstract_en` text default null after `abstract_sv`;
+alter table `publication_metadata` change `keywords_swedish` `keywords_sv` text default null after `abstract_en`;
+alter table `publication_metadata` change `keywords_english` `keywords_en` text default null after `keywords_sv`;
+
+alter table `publication_metadata`
+    add constraint fk_publication_metadata_national_subject_category_id
+        foreign key (national_subject_category_id) references national_subject_category (id)
+            on delete cascade on update cascade;
+
+alter table `publication_metadata`
+    add constraint fk_publication_metadata_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 16: Many-to-Many tables between project and user.
+ */
+
+-- table: project_user_note (new changes from develop branch)
+
+alter table `project_user_note` drop foreign key `FK_project_user_note_user`;
+alter table `project_user_note` drop foreign key `FK_project_user_note_project`;
+alter table `project_user_note` drop key `FK_project_user_note_user`;
+
+alter table `project_user_note`
+    add constraint fk_project_user_note_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `project_user_note`
+    add constraint fk_project_user_note_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: project_cosupervisor
+
+alter table `project_cosupervisor` drop foreign key `FK_fj57t069dymdrnnhdxcnfvvnn`;
+alter table `project_cosupervisor` drop foreign key `FK_18x2poxkt8s2bw9kpr7vbmd5j`;
+
+alter table `project_cosupervisor` drop key `FK_fj57t069dymdrnnhdxcnfvvnn`;
+alter table `project_cosupervisor` drop key `FK_18x2poxkt8s2bw9kpr7vbmd5j`;
+
+alter table `project_cosupervisor` change `user_id` `user_id` bigint(20) not null after `project_id`;
+
+alter table `project_cosupervisor`
+    add constraint fk_project_cosupervisor_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `project_cosupervisor`
+    add constraint fk_project_cosupervisor_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: project_reviewer
+
+alter table `project_reviewer` drop foreign key `FK_g7yryw3e0dtmuuvgw5qjhphjm`;
+alter table `project_reviewer` drop foreign key `FK_6aik0jd18kv3383fbt09xd0pi`;
+
+alter table `project_reviewer` drop key `FK_6aik0jd18kv3383fbt09xd0pi`;
+alter table `project_reviewer` drop key `FK_g7yryw3e0dtmuuvgw5qjhphjm`;
+
+alter table `project_reviewer`
+    add constraint fk_project_reviewer_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `project_reviewer`
+    add constraint fk_project_reviewer_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: project_user
+
+alter table `project_user` drop foreign key `project_user_user_id`;
+alter table `project_user` drop foreign key `project_user_project_id`;
+
+alter table `project_user` drop key `project_user_project_id`;
+
+alter table `project_user` change `user_id` `user_id` bigint(20) not null after `project_id`;
+alter table `project_user` change `reflection` `reflection` text default null after `user_id`;
+
+alter table `project_user`
+    add constraint fk_project_user_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `project_user`
+    add constraint fk_project_user_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: grading_history_submissions
+
+alter table `grading_history_submissions` drop foreign key `FK_grading_history_submissions_project`;
+alter table `grading_history_submissions` drop foreign key `FK_grading_history_submissions_author`;
+
+alter table `grading_history_submissions` drop key `FK_grading_history_submissions_project`;
+alter table `grading_history_submissions` drop key `FK_grading_history_submissions_author`;
+
+rename table `grading_history_submissions` to `grading_history_submission`;
+
+alter table `grading_history_submission` change `when` `when` timestamp not null default '0000-00-00 00:00:00' after `id`;
+alter table `grading_history_submission` change `corrections` `corrections` text default null after `when`;
+alter table `grading_history_submission` change  `author_id` `author_user_id` bigint(20) not null after `corrections`;
+
+alter table `grading_history_submission`
+    add constraint fk_grading_history_submission_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `grading_history_submission`
+    add constraint fk_grading_history_submission_author_user_id
+        foreign key (author_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: externallink
+
+alter table `externallink` drop foreign key `FK_PROJECT`;
+alter table `externallink` drop foreign key `FK_USER`;
+
+alter table `externallink` drop key `FK_PROJECT`;
+alter table `externallink` drop key `FK_USER`;
+
+rename table `externallink` to `external_link`;
+
+alter table `external_link` change `description` `description` varchar(255) default null after `url`;
+
+alter table `external_link`
+    add constraint fk_external_link_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `external_link`
+    add constraint fk_external_link_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: grade
+
+alter table `grade` drop foreign key `FK_grade_user_reportedBy`;
+alter table `grade` drop foreign key `FK_grade_project`;
+
+alter table `grade` drop key `FK_grade_user_reportedBy`;
+alter table `grade` drop key `project_id`;
+
+alter table `grade` change `value` `value` varchar(255) not null after `id`;
+alter table `grade` change `reportedOn` `reported_when` date not null after `value`;
+alter table `grade` change `project_id` `project_id` bigint(20) not null after `reported_when`;
+alter table `grade` change `reportedBy` `reported_by_user_id` bigint(20) not null after `project_id`;
+
+alter table `grade` add constraint uk_grade_project_id unique(project_id);
+
+alter table `grade`
+    add constraint fk_grade_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `grade`
+    add constraint fk_grade_reported_by_user_id
+        foreign key (reported_by_user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 17: file_reference & file_description, FinalThesis and project_file
+ */
+
+-- table: file_description
+
+alter table `file_description` drop foreign key `file_description_user`;
+
+alter table `file_description` drop key `file_description_user`;
+alter table `file_description` drop key `file_description_identifier_index`;
+
+alter table `file_description` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `file_description` change `name` `name` varchar(255) default null after `version`;
+alter table `file_description` change `mimeType` `mime_type` varchar(255) default null after `name`;
+alter table `file_description` change `size` `size` bigint(20) default null after `mime_type`;
+alter table `file_description` change `identifier` `file_identifier` varchar(255) default null after `size`;
+alter table `file_description` change `type` `type` varchar(255) default null after `file_identifier`;
+alter table `file_description` change `userId` `user_id` bigint(20) default null after `type`;
+
+alter table `file_description`
+    add constraint fk_file_description_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: file_reference
+
+alter table file_reference drop foreign key `FK_file_reference_file_description`;
+
+alter table file_reference drop key `FK_file_reference_file_description`;
+
+alter table file_reference
+    add constraint fk_file_reference_file_description_id
+        foreign key (file_description_id) references file_description (id)
+            on delete cascade on update cascade;
+
+-- table: FinalThesis
+
+alter table FinalThesis drop foreign key `FK_final_thesis_text_matching_document_reference`;
+alter table FinalThesis drop foreign key `FK_final_thesis_project`;
+alter table FinalThesis drop foreign key `FK_final_thesis_document_reference`;
+
+alter table FinalThesis drop key `FK_final_thesis_text_matching_document_reference`;
+alter table FinalThesis drop key `FK_final_thesis_project`;
+
+rename table FinalThesis to `final_thesis`;
+
+alter table `final_thesis` change `swedishTitle` `title_sv` longtext default null after `version`;
+alter table `final_thesis` change `englishTitle` `title_en` longtext default null after `title_sv`;
+alter table `final_thesis` change `status` `status` varchar(32) not null after `title_en`;
+alter table `final_thesis` change `dateApproved` `date_approved` date default null after `status`;
+alter table `final_thesis` change `dateRejected` `date_rejected` date default null after `date_approved`;
+alter table `final_thesis` change `rejection_comment` `rejection_comment` text default null after `date_rejected`;
+alter table `final_thesis` change `text_matching_analysis` `text_matching_analysis` text default null after `rejection_comment`;
+alter table `final_thesis` change `text_matching_document_reference_id` `text_matching_document_reference_id` bigint(20) default null after `text_matching_analysis`;
+alter table `final_thesis` change `project_id` `project_id` bigint(20) not null after `document_reference_id`;
+
+alter table `final_thesis`
+    add constraint fk_final_thesis_text_matching_document_reference_id
+        foreign key (text_matching_document_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `final_thesis`
+    add constraint fk_final_thesis_document_reference_id
+        foreign key (document_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `final_thesis`
+    add constraint fk_final_thesis_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- table: project_file
+
+alter table `project_file` drop foreign key FK_project_file_project;
+alter table `project_file` drop foreign key FK_project_file_file;
+
+alter table `project_file` drop key FK_project_file_file;
+alter table `project_file` drop key FK_project_file_project;
+
+alter table `project_file` change `fileSource` `file_source` varchar(255) not null after `version`;
+alter table `project_file` change `project_id` `project_id` bigint(20) not null after `file_reference_id`;
+
+alter table `project_file`
+    add constraint fk_project_file_file_reference_id
+        foreign key (file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `project_file`
+    add constraint fk_project_file_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 18: Decision & ReviewerApproval
+ */
+
+-- table: Decision
+
+alter table `Decision` drop foreign key `fk_Decision_ReviewerApproval`;
+alter table `Decision` drop foreign key `FK_decision_reviewer`;
+alter table `Decision` drop foreign key `FK_Decision_thesis`;
+alter table `Decision` drop foreign key `FK_Decision_attachment`;
+
+alter table `Decision` drop key `FK_decision_reviewer`;
+alter table `Decision` drop key `FK_Decision_attachment`;
+alter table `Decision` drop key `FK_Decision_thesis`;
+alter table `Decision` drop key `fk_ReviewerApproval_Decision_idx`;
+
+rename table `Decision` to `decision`;
+
+alter table `decision` change `status` `status` varchar(255) default null after `id`;
+alter table `decision` change `requested` `requested_date` datetime not null;
+alter table `decision` change `decisionDate` `decision_date` datetime default null;
+alter table `decision` change `deadline` `deadline` datetime default null after `decision_date`;
+alter table `decision` change `assigned_reviewer_date` `assigned_reviewer_date` date default null after `deadline`;
+alter table `decision` change `assigned_reviewer_id` `assigned_reviewer_id` bigint(20) default null after `assigned_reviewer_date`;
+alter table `decision` change `attachment_reference_id` `attachment_reference_id` bigint(20) default null after `assigned_reviewer_id`;
+alter table `decision` change `reviewerApproval_id` `reviewer_approval_id` bigint(20) not null;
+
+alter table `decision`
+    add constraint fk_decision_assigned_reviewer_id
+        foreign key (assigned_reviewer_id) references user (id)
+            on delete cascade on update cascade;
+
+alter table `decision`
+    add constraint fk_decision_attachment_reference_id
+        foreign key (attachment_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `decision`
+    add constraint fk_decision_thesis_reference_id
+        foreign key (thesis_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+-- table: ReviewerApproval
+
+alter table `ReviewerApproval` drop foreign key `FK_9lr1dn8boyfc5a0477ld4q8rw`;
+
+alter table `ReviewerApproval` drop key `FK_9lr1dn8boyfc5a0477ld4q8rw`;
+
+rename table `ReviewerApproval` to `reviewer_approval`;
+
+alter table `reviewer_approval` change `type` `type` varchar(64) not null after `version`;
+alter table `reviewer_approval` change `project_id` `project_id` bigint(20) not null after `type`;
+
+alter table `reviewer_approval`
+    add constraint fk_reviewer_approval_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+-- add foreign key from decision to reviewer_approval
+
+alter table `decision`
+    add constraint fk_decision_reviewer_approval_id
+        foreign key (reviewer_approval_id) references reviewer_approval (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 19: urkund_submission & plagiarium_request
+ */
+
+-- table: urkund_submission
+
+alter table `urkund_submission` drop foreign key `FK_urkund_submission_receiver`;
+alter table `urkund_submission` drop foreign key `FK_urkund_submission_document_reference`;
+
+alter table `urkund_submission` drop key `FK_urkund_submission_document_reference`;
+alter table `urkund_submission` drop key `FK_urkund_submission_receiver`;
+
+alter table `urkund_submission` change `document_reference_id` `document_file_reference_id` bigint(20) not null;
+alter table `urkund_submission` change `receiver_id` `receiver_user_id` bigint(20) not null after `document_file_reference_id`;
+alter table `urkund_submission` change `submitted` `submitted_date` datetime not null;
+alter table `urkund_submission` change `nextPoll` `next_poll_date` datetime not null;
+alter table `urkund_submission` change `pollingDelay` `polling_delay` varchar(16) not null;
+alter table `urkund_submission` change `reportUrl` `report_url` varchar(255) default null;
+alter table `urkund_submission` change `analysisAddress` `analysis_address` varchar(255) default null;
+
+alter table `urkund_submission`
+    add constraint fk_urkund_submission_document_file_reference_id
+        foreign key (document_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `urkund_submission`
+    add constraint fk_urkund_submission_receiver_user_id
+        foreign key (receiver_user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: plagiarism_request
+
+alter table `plagiarism_request` drop foreign key `FK_plagiarism_request_receiver`;
+alter table `plagiarism_request` drop foreign key `FK_plagiarism_request_document_reference`;
+
+alter table `plagiarism_request` drop key `FK_plagiarism_request_document_reference`;
+alter table `plagiarism_request` drop key `FK_plagiarism_request_receiver`;
+
+alter table `plagiarism_request` change `document_reference_id` `document_file_reference_id` bigint(20) not null;
+alter table `plagiarism_request` change `receiver_id` `receiver_user_id` bigint(20) not null after `document_file_reference_id`;
+
+alter table `plagiarism_request`
+    add constraint fk_plagiarism_request_document_file_reference_id
+        foreign key (document_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+alter table `plagiarism_request`
+    add constraint fk_plagiarism_request_receiver_user_id
+        foreign key (receiver_user_id) references user (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 20: mail_event, mail_event_recipients and MailEvent_nonUserRecipients
+ */
+
+-- table: mail_event
+
+alter table `mail_event` drop foreign key `FK_mail_event_attachment`;
+
+alter table `mail_event` drop key `FK_mail_event_attachment`;
+
+alter table `mail_event` change `version` `version` int(4) not null default 0 after `last_modified`;
+alter table `mail_event` change `subject` `subject` varchar(255) not null after `version`;
+alter table `mail_event` change `fromName` `from_name` varchar(255) default null after `subject`;
+alter table `mail_event` change `fromEmail` `from_email` varchar(255) default null after `from_name`;
+alter table `mail_event` change `messageBody` `message_body` longtext not null after `from_email`;
+alter table `mail_event` change `sent` `sent` tinyint(1) not null default 0 after `message_body`;
+alter table `mail_event` change `messageID` `message_id` varchar(255) default null after `sent`;
+alter table `mail_event` change `notificationEventType` `notification_event_type` varchar(255) default null after `message_id`;
+alter table `mail_event` change `attachment_reference_id` `attachment_file_reference_id` bigint(20) default null after `notification_event_type`;
+
+alter table `mail_event`
+    add constraint fk_mail_event_attachment_file_reference_id
+        foreign key (attachment_file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+-- table: mail_event_recipients
+
+alter table `mail_event_recipients` drop foreign key `FK_mail_event_recipients_user`;
+alter table `mail_event_recipients` drop foreign key `FK41091C7FE7F98C6`;
+
+alter table `mail_event_recipients` drop key `FK41091C7B286D1B0`;
+alter table `mail_event_recipients` drop key `FK41091C7FE7F98C6`;
+
+alter table `mail_event_recipients` drop primary key;
+
+rename table `mail_event_recipients` to `mail_event_recipient`;
+
+alter table `mail_event_recipient` change `recipients_id` `recipient_id` bigint(20) not null after `mail_event_id`;
+
+alter table `mail_event_recipient` add primary key (mail_event_id, recipient_id);
+
+alter table `mail_event_recipient`
+    add constraint fk_mail_event_recipient_mail_event_id
+        foreign key (mail_event_id) references mail_event (id)
+            on delete cascade on update cascade;
+
+alter table `mail_event_recipient`
+    add constraint fk_mail_event_recipient_recipient_id
+        foreign key (recipient_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: MailEvent_nonUserRecipients
+
+alter table `MailEvent_nonUserRecipients` drop foreign key `FKD7F8996D0814DF5`;
+alter table `MailEvent_nonUserRecipients` drop key `FKD7F8996D0814DF5`;
+
+rename table `MailEvent_nonUserRecipients` to `mail_event_non_user_recipient`;
+
+alter table `mail_event_non_user_recipient` change `MailEvent_id` `mail_event_id` bigint(20) not null;
+alter table `mail_event_non_user_recipient` change `nonUserRecipients` `non_user_recipient` varchar(255) default null;
+
+alter table `mail_event_non_user_recipient`
+    add constraint fk_mail_event_non_user_recipient_mail_event_id
+        foreign key (mail_event_id) references mail_event (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 21: project_group and project_group_project
+ */
+
+-- table: project_group
+
+alter table `project_group` drop foreign key `FK_user_id`;
+alter table `project_group` drop key `FK_user_id`;
+
+alter table `project_group` change `active` `active` bit(1) not null after `description`;
+
+alter table `project_group`
+    add constraint fk_project_group_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: project_group_project
+
+alter table `project_group_project` drop foreign key `FK_project_id`;
+alter table `project_group_project` drop foreign key `FK_project_group_id`;
+
+alter table `project_group_project` drop key `FK_project_id`;
+alter table `project_group_project` drop key `FK_project_group_id`;
+
+alter table `project_group_project`
+    add constraint fk_project_group_project_project_group_id
+        foreign key (project_group_id) references project_group (id)
+            on delete cascade on update cascade;
+
+alter table `project_group_project`
+    add constraint fk_project_group_project_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 22: thread, forum_post and forum_post_file_description
+ */
+
+-- table: thread
+
+alter table `thread` change `deleted` `deleted` tinyint(1) not null after `subject`;
+
+-- table: forum_post
+
+alter table `forum_post` drop foreign key `forum_posts_thread`;
+alter table `forum_post` drop foreign key `FKEDDC4F35924F477B`;
+
+alter table `forum_post` drop key `deleted_index`;
+alter table `forum_post` drop key `FKEDDC4F355E9380A1`;
+alter table `forum_post` drop key `FKEDDC4F35924F477B`;
+
+alter table `forum_post` change `content` `content` longtext not null after `version`;
+alter table `forum_post` change `thread` `thread_id` bigint(20) not null after `deleted`;
+alter table `forum_post` change `user` `user_id` bigint(20) default null after `thread_id`;
+
+create index idx_forum_post_deleted on forum_post (deleted);
+
+alter table `forum_post`
+    add constraint fk_forum_post_thread_id
+        foreign key (thread_id) references thread (id)
+            on delete cascade on update cascade;
+
+alter table `forum_post`
+    add constraint fk_forum_post_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: forum_post_file_description
+
+alter table `forum_post_file_description` drop foreign key `FK_forum_post_file`;
+
+alter table `forum_post_file_description` drop key `I_forum_post_file_post`;
+alter table `forum_post_file_description` drop key `FK_forum_post_file`;
+
+rename table `forum_post_file_description` to `forum_post_file_reference`;
+
+alter table `forum_post_file_reference`
+    add constraint fk_forum_post_file_reference_forum_post_id
+        foreign key (forum_post_id) references forum_post (id)
+            on delete cascade on update cascade;
+
+alter table `forum_post_file_reference`
+    add constraint fk_forum_post_file_reference_file_reference_id
+        foreign key (file_reference_id) references file_reference (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 23: forum_post_read, project_thread, reviewer_thread and group_thread
+ */
+
+-- table: forum_post_read
+
+alter table `forum_post_read` drop foreign key `FK8A5DFC60DD74550D`;
+alter table `forum_post_read` drop foreign key `FK8A5DFC60924F477B`;
+
+alter table `forum_post_read` drop key `FK8A5DFC60DD74550D`;
+alter table `forum_post_read` drop key `FK8A5DFC60924F477B`;
+
+alter table `forum_post_read` drop primary key;
+
+rename table `forum_post_read` to `forum_post_read_state`;
+
+alter table `forum_post_read_state` change `read` `read` tinyint(1) not null after `post`;
+alter table `forum_post_read_state` change `user` `user_id` bigint(20) not null after `post`;
+alter table `forum_post_read_state` change `post` `forum_post_id` bigint(20) not null;
+
+alter table `forum_post_read_state` add primary key (forum_post_id, user_id);
+
+alter table `forum_post_read_state`
+    add constraint fk_forum_post_read_state_forum_post_id
+        foreign key (forum_post_id) references forum_post (id)
+            on delete cascade on update cascade;
+
+alter table `forum_post_read_state`
+    add constraint fk_forum_post_read_state_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: project_thread
+
+alter table `project_thread` drop foreign key `FK_project_thread_thread`;
+alter table `project_thread` drop foreign key `FK_project_thread_project`;
+
+alter table `project_thread` drop key `FK_project_thread_thread`;
+alter table `project_thread` drop key `FK_project_thread_project`;
+
+alter table `project_thread` change `project_id` `project_id` bigint(20) not null after `id`;
+
+alter table `project_thread`
+    add constraint fk_project_thread_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `project_thread`
+    add constraint fk_project_thread_thread_id
+        foreign key (thread_id) references thread (id)
+            on delete cascade on update cascade;
+
+-- table: reviewer_thread
+
+alter table `reviewer_thread` drop foreign key `FK_reviewer_thread_thread`;
+alter table `reviewer_thread` drop foreign key `FK_reviewer_thread_group`;
+
+alter table `reviewer_thread` drop key `FK_reviewer_thread_thread`;
+alter table `reviewer_thread` drop key `project_id`;
+
+alter table `reviewer_thread` change `thread_id` `thread_id` bigint(20) not null after `project_id`;
+
+alter table `reviewer_thread` add constraint uk_reviewer_thread_project_id unique(project_id, thread_id);
+
+alter table `reviewer_thread`
+    add constraint fk_reviewer_thread_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `reviewer_thread`
+    add constraint fk_reviewer_thread_thread_id
+        foreign key (thread_id) references thread (id)
+            on delete cascade on update cascade;
+
+-- table: group_thread
+
+alter table `group_thread` drop foreign key `FK_project_group_thread_thread`;
+alter table `group_thread` drop foreign key `FK_project_group_thread_group`;
+
+alter table `group_thread` drop key `FK_project_group_thread_thread`;
+alter table `group_thread` drop key `project_group`;
+
+rename table `group_thread` to `project_group_thread`;
+
+alter table `project_group_thread` change `group_id` `project_group_id` bigint(20) not null after `id`;
+
+alter table `project_group_thread`
+    add constraint fk_project_group_thread_project_group_id
+        foreign key (project_group_id) references project_group (id)
+            on delete cascade on update cascade;
+
+alter table `project_group_thread`
+    add constraint fk_project_group_thread_thread_id
+        foreign key (thread_id) references thread (id)
+            on delete cascade on update cascade;
+
+/*
+ * Step 24: forum_notification, Notification, NotificationData
+ */
+
+-- table: forum_notification,
+
+alter table `forum_notification` drop foreign key `FK_forum_notification_notification_event`;
+alter table `forum_notification` drop foreign key `FK_forum_notification_forum_post`;
+
+alter table `forum_notification` drop key `FK_forum_notification_notification_event`;
+
+alter table `forum_notification` drop primary key;
+
+alter table `forum_notification` change `forumPost_id` `forum_post_id` bigint(20) not null;
+alter table `forum_notification` change `notificationEvent_id` `notification_data_id` bigint(20) not null;
+
+alter table `forum_notification` add primary key (forum_post_id, notification_data_id);
+
+alter table `forum_notification`
+    add constraint fk_forum_notification_forum_post_id
+        foreign key (forum_post_id) references forum_post (id)
+            on delete cascade on update cascade;
+
+-- table: Notification
+
+alter table `Notification` drop foreign key `FK_notification_user`;
+alter table `Notification` drop foreign key `FK2D45DD0B599425F6`;
+
+alter table `Notification` drop key `FK2D45DD0B599425F6`;
+alter table `Notification` drop key `FK2D45DD0B895349BF`;
+
+rename table `Notification` to `notification`;
+
+alter table `notification` change `mailed` `mailed` bit(1) not null after `version`;
+alter table `notification` change `notificationData_id` `notification_data_id` bigint(20) default null;
+
+alter table `notification`
+    add constraint fk_notification_user_id
+        foreign key (user_id) references user (id)
+            on delete cascade on update cascade;
+
+-- table: NotificationData
+
+alter table `NotificationData` drop foreign key `FK_notification_data_user_caused_by`;
+alter table `NotificationData` drop foreign key `FK_notification_data_project`;
+alter table `NotificationData` drop foreign key `FK_notification_data_peer_review`;
+alter table `NotificationData` drop foreign key `FK_notification_data_milestone`;
+alter table `NotificationData` drop foreign key `FK_notification_data_group`;
+alter table `NotificationData` drop foreign key `FK2DCAC355FCDADF61`;
+alter table `NotificationData` drop foreign key `FK2DCAC3558D40D1B9`;
+alter table `NotificationData` drop foreign key `FK2DCAC3554D07E0A9`;
+
+alter table `NotificationData` drop key `FK_notification_data_group`;
+alter table `NotificationData` drop key `FK_notification_data_milestone`;
+alter table `NotificationData` drop key `FK2DCAC355FCDADF61`;
+alter table `NotificationData` drop key `FK2DCAC355B2E2AD78`;
+alter table `NotificationData` drop key `FK2DCAC3558D40D1B9`;
+alter table `NotificationData` drop key `FK2DCAC35542E9AC7B`;
+alter table `NotificationData` drop key `FK2DCAC355C1813915`;
+alter table `NotificationData` drop key `FK2DCAC3554D07E0A9`;
+
+rename table `NotificationData` to `notification_data`;
+
+alter table `notification_data` change `type` `type` varchar(255) default null after `event`;
+alter table `notification_data` change `source` `source` longtext default null after `type`;
+alter table `notification_data` change `additionalSource` `additional_source` longtext default null after `source`;
+alter table `notification_data` change `DTYPE` `subclass` varchar(31) not null after `additional_source`;
+
+alter table `notification_data` change `seminar_id` `final_seminar_id` bigint(20) default null after `subclass`;
+alter table `notification_data` change `idea_id` `idea_id` bigint(20) default null after `final_seminar_id`;
+alter table `notification_data` change `mileStone_id` `milestone_id` bigint(20) default null after `idea_id`;
+alter table `notification_data` change `request_id` `peer_request_id` bigint(20) default null after `milestone_id`;
+alter table `notification_data` change `review_id` `peer_review_id` bigint(20) default null after `peer_request_id`;
+alter table `notification_data` change `project_id` `project_id` bigint(20) default null after `peer_review_id`;
+alter table `notification_data` change `group_id` `project_group_id` bigint(20) default null after `project_id`;
+alter table `notification_data` change `causedBy_id` `caused_by_user_id` bigint(20) default null after `project_group_id`;
+
+alter table `notification_data`
+    add constraint fk_notification_data_final_seminar_id
+        foreign key (final_seminar_id) references final_seminar (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_idea_id
+        foreign key (idea_id) references idea (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_milestone_id
+        foreign key (milestone_id) references milestone (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_peer_request_id
+        foreign key (peer_request_id) references peer_request (id)
+            on delete set null on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_peer_review_id
+        foreign key (peer_review_id) references peer_review (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_project_id
+        foreign key (project_id) references project (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_project_group_id
+        foreign key (project_group_id) references project_group (id)
+            on delete cascade on update cascade;
+
+alter table `notification_data`
+    add constraint fk_notification_data_caused_by_user_id
+        foreign key (caused_by_user_id) references user (id)
+            on delete set null on update cascade;
+
+-- add foreign key from notification to notification_data
+
+alter table `notification`
+    add constraint fk_notification_notification_data_id
+        foreign key (notification_data_id) references notification_data (id)
+            on delete cascade on update cascade;
+
+-- add foreign key from forum_notification to notification_data
+
+alter table `forum_notification`
+    add constraint fk_forum_notification_notification_data_id
+        foreign key (notification_data_id) references notification_data (id)
+            on delete cascade on update cascade;
diff --git a/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql
new file mode 100644
index 0000000000..d80e266c9d
--- /dev/null
+++ b/core/src/main/resources/db/migration/V392_1__reflection_resubmission.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `project_user`
+    ADD COLUMN `reflection_status` VARCHAR(32) NOT NULL DEFAULT 'NOT_SUBMITTED';
+
+UPDATE `project_user` SET `reflection_status` = 'SUBMITTED' WHERE `reflection` IS NOT NULL;
diff --git a/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql
new file mode 100644
index 0000000000..f3cc5f2ce1
--- /dev/null
+++ b/core/src/main/resources/db/migration/V392_2__reflection_comment_by_supervisor.sql
@@ -0,0 +1 @@
+ALTER TABLE `project_user` ADD COLUMN `reflection_comment_by_supervisor` TEXT NULL;
diff --git a/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java b/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java
index 4c0f37379d..90cc242e77 100644
--- a/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/forum/ForumModuleTest.java
@@ -1,20 +1,15 @@
 package se.su.dsv.scipro.forum;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import se.su.dsv.scipro.date.DateService;
-import se.su.dsv.scipro.file.FileModule;
-import se.su.dsv.scipro.file.FileStore;
 import se.su.dsv.scipro.notifications.NotificationController;
 import se.su.dsv.scipro.notifications.NotificationService;
-import se.su.dsv.scipro.test.GuiceTest;
-import se.su.dsv.scipro.test.InMemoryFileStore;
+import se.su.dsv.scipro.test.SpringTest;
 
 @ExtendWith(MockitoExtension.class)
-public abstract class ForumModuleTest extends GuiceTest {
+public abstract class ForumModuleTest extends SpringTest {
     // TODO: Work towards removing these dependencies.
     @Mock
     private DateService dateService;
@@ -23,18 +18,4 @@ public abstract class ForumModuleTest extends GuiceTest {
     @Mock
     private NotificationService notificationService;
 
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                install(new ForumModule());
-                install(new FileModule());
-                bind(FileStore.class).to(InMemoryFileStore.class);
-                bind(DateService.class).toInstance(dateService);
-                bind(NotificationController.class).toInstance(notificationController);
-                bind(NotificationService.class).toInstance(notificationService);
-            }
-        };
-    }
 }
diff --git a/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java
index da314ab9c1..4a3e6dc33c 100644
--- a/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/group/GroupServiceImplTest.java
@@ -1,135 +1,135 @@
-package se.su.dsv.scipro.group;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import se.su.dsv.scipro.project.Project;
-import se.su.dsv.scipro.system.DegreeType;
-import se.su.dsv.scipro.system.ProjectType;
-import se.su.dsv.scipro.system.User;
-import se.su.dsv.scipro.test.IntegrationTest;
-
-import jakarta.inject.Inject;
-import java.time.LocalDate;
-import java.util.Collections;
-import java.util.HashSet;
-
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasItem;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class GroupServiceImplTest extends IntegrationTest {
-
-    @Inject
-    private GroupServiceImpl groupService;
-    private User author;
-    private User creator;
-    private User reviewer;
-    private User cosupervisor;
-    private Group group;
-    private ProjectType projectType;
-
-    @BeforeEach
-    public void setUp() throws Exception {
-        author = saveUser("author", "name", "author@example.com");
-        creator = saveUser("supervisor", "sup", "supervisor@example.com");
-        reviewer = saveUser("reviewer", "test", "reviewer@example.com");
-        cosupervisor = saveUser("cosupervisor", "test", "reviewer@example.com");
-        projectType = save(new ProjectType(DegreeType.BACHELOR, "b", "b"));
-        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
-        Project project = save(Project.builder().title("title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
-        project.addProjectParticipant(author);
-        project.addReviewer(reviewer);
-        project.addCoSupervisor(cosupervisor);
-        createGroup(project);
-    }
-
-    @Test
-    public void find_by_author() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setAuthor(author);
-        assertGroup(filter);
-    }
-
-    @Test
-    public void find_all() {
-        GroupService.Filter filter = new GroupService.Filter();
-        assertGroup(filter);
-    }
-
-    @Test
-    public void find_by_creator_fails() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setCreator(author);
-        assertTrue(groupService.findAll(filter).isEmpty());
-    }
-
-    @Test
-    public void find_by_creator() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setCreator(creator);
-        assertGroup(filter);
-    }
-
-    @Test
-    public void find_by_reviewer_involvee() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setNonAuthorInvolvee(reviewer);
-        assertThat(groupService.findAll(filter), not(hasItem(group)));
-    }
-
-    @Test
-    public void find_by_cosupervisor_involvee() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setNonAuthorInvolvee(cosupervisor);
-        assertGroup(filter);
-    }
-
-    @Test
-    public void find_active_groups() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setActive(true);
-        assertGroup(filter);
-
-        filter.setActive(false);
-        assertTrue(groupService.findAll(filter).isEmpty());
-    }
-
-    @Test
-    public void count() {
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setAuthor(author);
-        assertEquals(1, groupService.count(filter));
-    }
-
-    @Test
-    public void find_groups_by_project() {
-        Group another = new Group();
-        another.setTitle("hi");
-        another.setUser(creator);
-        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
-        Project anotherProject = save(Project.builder().title("another").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
-        another.setProjects(new HashSet<>(Collections.singletonList(anotherProject)));
-        save(another);
-        GroupService.Filter filter = new GroupService.Filter();
-        filter.setProject(anotherProject);
-        assertEquals(another, groupService.findAll(filter).get(0));
-    }
-
-    private void assertGroup(GroupService.Filter filter) {
-        assertThat(groupService.findAll(filter), hasItem(group));
-    }
-
-    private void createGroup(Project project) {
-        group = new Group();
-        group.setTitle("group title");
-        group.setProjects(new HashSet<>(Collections.singletonList(project)));
-        group.setUser(creator);
-        save(group);
-    }
-
-    private User saveUser(String firstName, String lastName, String emailAddress) {
-        return save(User.builder().firstName(firstName).lastName(lastName).emailAddress(emailAddress).build());
-    }
-}
+package se.su.dsv.scipro.group;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.DegreeType;
+import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.test.IntegrationTest;
+
+import jakarta.inject.Inject;
+import java.time.LocalDate;
+import java.util.Collections;
+import java.util.HashSet;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class GroupServiceImplTest extends IntegrationTest {
+
+    @Inject
+    private GroupServiceImpl groupService;
+    private User author;
+    private User creator;
+    private User reviewer;
+    private User cosupervisor;
+    private Group group;
+    private ProjectType projectType;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        author = saveUser("author", "name", "author@example.com");
+        creator = saveUser("supervisor", "sup", "supervisor@example.com");
+        reviewer = saveUser("reviewer", "test", "reviewer@example.com");
+        cosupervisor = saveUser("cosupervisor", "test", "reviewer@example.com");
+        projectType = save(new ProjectType(DegreeType.BACHELOR, "b", "b"));
+        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
+        Project project = save(Project.builder().title("title").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
+        project.addProjectParticipant(author);
+        project.addReviewer(reviewer);
+        project.addCoSupervisor(cosupervisor);
+        createGroup(project);
+    }
+
+    @Test
+    public void find_by_author() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setAuthor(author);
+        assertGroup(filter);
+    }
+
+    @Test
+    public void find_all() {
+        GroupService.Filter filter = new GroupService.Filter();
+        assertGroup(filter);
+    }
+
+    @Test
+    public void find_by_creator_fails() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setCreator(author);
+        assertTrue(groupService.findAll(filter).isEmpty());
+    }
+
+    @Test
+    public void find_by_creator() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setCreator(creator);
+        assertGroup(filter);
+    }
+
+    @Test
+    public void find_by_reviewer_involvee() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setNonAuthorInvolvee(reviewer);
+        assertThat(groupService.findAll(filter), not(hasItem(group)));
+    }
+
+    @Test
+    public void find_by_cosupervisor_involvee() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setNonAuthorInvolvee(cosupervisor);
+        assertGroup(filter);
+    }
+
+    @Test
+    public void find_active_groups() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setActive(true);
+        assertGroup(filter);
+
+        filter.setActive(false);
+        assertTrue(groupService.findAll(filter).isEmpty());
+    }
+
+    @Test
+    public void count() {
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setAuthor(author);
+        assertEquals(1, groupService.count(filter));
+    }
+
+    @Test
+    public void find_groups_by_project() {
+        Group another = new Group();
+        another.setTitle("hi");
+        another.setUser(creator);
+        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
+        Project anotherProject = save(Project.builder().title("another").projectType(projectType).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
+        another.setProjects(new HashSet<>(Collections.singletonList(anotherProject)));
+        save(another);
+        GroupService.Filter filter = new GroupService.Filter();
+        filter.setProject(anotherProject);
+        assertEquals(another, groupService.findAll(filter).get(0));
+    }
+
+    private void assertGroup(GroupService.Filter filter) {
+        assertThat(groupService.findAll(filter), hasItem(group));
+    }
+
+    private void createGroup(Project project) {
+        group = new Group();
+        group.setTitle("group title");
+        group.setProjects(new HashSet<>(Collections.singletonList(project)));
+        group.setUser(creator);
+        save(group);
+    }
+
+    private User saveUser(String firstName, String lastName, String emailAddress) {
+        return save(User.builder().firstName(firstName).lastName(lastName).emailAddress(emailAddress).build());
+    }
+}
diff --git a/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java b/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java
index 63417a754b..7a189d32f4 100644
--- a/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/match/MatchModuleTest.java
@@ -1,9 +1,6 @@
 package se.su.dsv.scipro.match;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
-import com.google.inject.name.Names;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
@@ -13,10 +10,10 @@ import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
 import se.su.dsv.scipro.mail.MailEventService;
 import se.su.dsv.scipro.notifications.NotificationController;
 import se.su.dsv.scipro.project.ProjectService;
-import se.su.dsv.scipro.test.GuiceTest;
+import se.su.dsv.scipro.test.SpringTest;
 
 @ExtendWith(MockitoExtension.class)
-public abstract class MatchModuleTest extends GuiceTest {
+public abstract class MatchModuleTest extends SpringTest {
     // ToDo:The system services should be move to a system module that other modules can depend on
     @Mock
     protected DateService dateService;
@@ -34,28 +31,4 @@ public abstract class MatchModuleTest extends GuiceTest {
     @Mock
     protected ProjectService projectService;
 
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                install(new MatchModule());
-                bind(GeneralSystemSettingsService.class).toInstance(generalSystemSettingsService);
-                bind(NotificationController.class).toInstance(notificationController);
-                bind(DateService.class).toInstance(dateService);
-                bind(MailEventService.class).toInstance(mailEventService);
-                bind(ActivityPlanFacade.class).toInstance(activityPlanFacade);
-                bind(EventBus.class).toInstance(eventBus);
-                bind(ProjectService.class).toInstance(projectService);
-
-                // Work towards removing the dependency on NotificationSourceURL
-                bindConstant().annotatedWith(Names.named("source.export.fail.supervisor")).to("");
-                bindConstant().annotatedWith(Names.named("source.export.fail.user")).to("");
-                bindConstant().annotatedWith(Names.named("source.export.success.supervisor")).to("");
-                bindConstant().annotatedWith(Names.named("source.export.success.user")).to("");
-                bindConstant().annotatedWith(Names.named("source.project.supervisor")).to("");
-                bindConstant().annotatedWith(Names.named("source.project.student")).to("");
-            }
-        };
-    }
 }
diff --git a/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java b/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java
index e42ccafdfc..fed52e8629 100644
--- a/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/milestones/service/MilestoneActivatorTest.java
@@ -66,7 +66,7 @@ public class MilestoneActivatorTest {
         author.setId(123L);
 
         ProjectType bachelor = new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor");
-        bachelor.getProjectTypeSettings().setMinimumActiveParticipationsToBeGraded(2);
+        bachelor.getProjectTypeSettings().setMinActiveParticipationsToBeGraded(2);
         project = Project.builder()
                 .title("Project title")
                 .projectType(bachelor)
diff --git a/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java b/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java
index 6453a0f537..6c770e1a9d 100755
--- a/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/notifications/NotificationControllerImplTest.java
@@ -1,6 +1,5 @@
 package se.su.dsv.scipro.notifications;
 
-import com.google.inject.util.Providers;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
@@ -55,7 +54,7 @@ public class NotificationControllerImplTest {
                 notificationService,
                 mailFormatter,
                 mailEventService,
-                receiverConfiguration, deliveryConfiguration, Providers.of(currentUser));
+                receiverConfiguration, deliveryConfiguration, () -> currentUser);
 
         when(mailFormatter.format(isA(Notification.class))).thenReturn(new NotificationMail("Subject", "Body"));
         when(deliveryConfiguration.isDelivery(isA(Notification.Type.class), isA(Enum.class), isA(DeliveryMethod.class), isA(Optional.class))).thenReturn(true);
diff --git a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java
index a2eb62c871..8b113e1524 100644
--- a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSettingsRepositoryTest.java
@@ -1,35 +1,16 @@
 package se.su.dsv.scipro.plagiarism.urkund;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
 import org.junit.jupiter.api.Test;
-import se.su.dsv.scipro.file.FileModule;
-import se.su.dsv.scipro.file.FileStore;
-import se.su.dsv.scipro.sukat.SukatModule;
-import se.su.dsv.scipro.test.GuiceTest;
-import se.su.dsv.scipro.test.InMemoryFileStore;
+import se.su.dsv.scipro.test.SpringTest;
 
 import jakarta.inject.Inject;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class UrkundSettingsRepositoryTest extends GuiceTest {
+public class UrkundSettingsRepositoryTest extends SpringTest {
     @Inject
     private UrkundSettingsRepository urkundSettingsRepository;
 
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                install(new SukatModule());
-                install(new UrkundModule());
-                install(new FileModule());
-                bind(FileStore.class).to(InMemoryFileStore.class);
-            }
-        };
-    }
-
     @Test
     public void change_settings() {
         final UrkundSettings settings = urkundSettingsRepository.getSettings();
diff --git a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java
index 0d2599f5fd..6120fe3468 100644
--- a/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/plagiarism/urkund/UrkundSubmissionRepositoryTest.java
@@ -1,18 +1,12 @@
 package se.su.dsv.scipro.plagiarism.urkund;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.jupiter.api.Test;
 import se.su.dsv.scipro.file.FileDescription;
-import se.su.dsv.scipro.file.FileModule;
 import se.su.dsv.scipro.file.FileReference;
-import se.su.dsv.scipro.file.FileStore;
-import se.su.dsv.scipro.sukat.Sukat;
-import se.su.dsv.scipro.test.GuiceTest;
-import se.su.dsv.scipro.test.InMemoryFileStore;
+import se.su.dsv.scipro.test.SpringTest;
 
 import jakarta.inject.Inject;
 import java.time.Instant;
@@ -22,23 +16,10 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-public class UrkundSubmissionRepositoryTest extends GuiceTest {
+public class UrkundSubmissionRepositoryTest extends SpringTest {
 
     @Inject
     private UrkundSubmissionRepository submissionRepository;
-    
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                install(new UrkundModule());
-                bind(Sukat.class).toInstance((username) -> Optional.empty());
-                install(new FileModule());
-                bind(FileStore.class).to(InMemoryFileStore.class);
-            }
-        };
-    }
 
     @Test
     public void save() {
diff --git a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
index 8d8d462e31..745def4bcd 100644
--- a/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/reflection/ReflectionServiceTest.java
@@ -101,6 +101,26 @@ public class ReflectionServiceTest extends IntegrationTest {
         assertTrue(reflectionService.hasReachedReflectionProcess(project));
     }
 
+    @Test
+    public void request_resubmission() {
+        LocalDate seminarDate = scheduleSeminar();
+        clock.setDate(seminarDate.plusDays(1));
+        assertTrue(reflectionService.hasToFillInReflection(project, author),
+                "After the final seminar the author should be required to submit a reflection");
+
+        String myReflection = "my reflection";
+        reflectionService.submitReflection(project, author, myReflection);
+        assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author));
+        assertFalse(reflectionService.hasToFillInReflection(project, author),
+                "After submitting the initial reflection it should no longer be required");
+
+        reflectionService.requestNewReflection(project, author, "Very bad reflection");
+        assertTrue(reflectionService.hasToFillInReflection(project, author),
+                "After supervisor requests resubmission the author should now be required to submit a new reflection");
+        assertEquals(myReflection, reflectionService.getSubmittedReflection(project, author),
+                "The old reflection should be saved to make it easier for the student to update it");
+    }
+
     private LocalDate scheduleSeminar() {
         project.setFinalSeminarRuleExempted(true); // to bypass rough draft approval
         FinalSeminarDetails details = new FinalSeminarDetails("Zoom", false, 1, 1, Language.SWEDISH, Language.ENGLISH, "zoom id 123");
diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java
index 8d59c17234..ba058fcce1 100644
--- a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java
@@ -1,18 +1,6 @@
 package se.su.dsv.scipro.reviewing;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
 import se.su.dsv.scipro.test.IntegrationTest;
 
 public abstract class ReviewingModuleTest extends IntegrationTest {
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                install(ReviewingModuleTest.super.moduleUnderTest());
-                bind(ReviewerAssignedDeadline.class).asEagerSingleton();
-            }
-        };
-    }
 }
diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java
index 56398d9f29..dd4ad1a076 100644
--- a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingServiceImplTest.java
@@ -1,161 +1,161 @@
-package se.su.dsv.scipro.reviewing;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentMatchers;
-import se.su.dsv.scipro.file.FileUpload;
-import se.su.dsv.scipro.project.Project;
-import se.su.dsv.scipro.system.DegreeType;
-import se.su.dsv.scipro.system.Page;
-import se.su.dsv.scipro.system.ProjectType;
-import se.su.dsv.scipro.system.User;
-import se.su.dsv.scipro.util.Either;
-
-import jakarta.inject.Inject;
-import java.time.LocalDate;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Function;
-
-import static org.hamcrest.CoreMatchers.hasItem;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ReviewingServiceImplTest extends ReviewingModuleTest {
-    private static final TestPage ALL = new TestPage(0, Long.MAX_VALUE);
-
-    @Inject
-    private ReviewingServiceImpl reviewingService;
-    @Inject
-    private FinalSeminarApprovalServiceImpl finalSeminarApprovalService;
-    @Inject
-    private RoughDraftApprovalServiceImpl roughDraftApprovalService;
-
-    private Project project;
-    private User reviewer;
-    private Project project3;
-
-    @BeforeEach
-    public void setUp() throws Exception {
-        reviewer = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build());
-        User reviewer2 = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build());
-        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
-        ProjectType bachelor = save(new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor"));
-        project = save(Project.builder().title("My project").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
-        project.addReviewer(reviewer);
-        Project project2 = save(Project.builder().title("My project 2").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
-        project2.addReviewer(reviewer2);
-        project3 = save(Project.builder().title("My project 3").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
-        project3.addReviewer(reviewer);
-    }
-
-    @Test
-    public void count() {
-        finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertEquals(1, reviewingService.countDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL)));
-    }
-
-    private MyReviewService.Filter getFilter(ReviewerApproval.Step step) {
-        MyReviewService.Filter filter = new MyReviewService.Filter();
-        filter.setUser(reviewer);
-        filter.setStep(step);
-        return filter;
-    }
-
-    @Test
-    public void find_undecided() {
-        finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(FinalSeminarApproval.class))));
-    }
-
-    @Test
-    public void find_undecided_rough_draft_approvals() {
-        roughDraftApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(RoughDraftApproval.class))));
-    }
-
-    @Test
-    public void count_undecided_rough_drafts() {
-        roughDraftApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertEquals(reviewingService.countUndecidedRoughDraft(reviewer), 1);
-    }
-
-    @Test
-    public void back_and_forth() {
-        assertTrue(finalSeminarApprovalService.requiresUpload(project));
-        Either<AlreadyRequested, FinalSeminarApproval> first = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertFalse(finalSeminarApprovalService.requiresUpload(project));
-
-        first.foreach(firstFinalSeminarApproval -> reviewingService.reject(firstFinalSeminarApproval, "Very bad", Optional.of(createFileUpload())));
-
-        assertTrue(finalSeminarApprovalService.requiresUpload(project));
-        Either<AlreadyRequested, FinalSeminarApproval> second = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
-        assertFalse(finalSeminarApprovalService.requiresUpload(project));
-
-        second.foreach(secondFinalSeminarApproval -> reviewingService.approve(secondFinalSeminarApproval, "Very good", Optional.empty()));
-        assertFalse(finalSeminarApprovalService.requiresUpload(project));
-    }
-
-    @Test
-    public void only_fetches_my_reviews() {
-        Either<AlreadyRequested, RoughDraftApproval> myRequest =
-                roughDraftApprovalService.requestApproval(project, createFileUpload(), "my request");
-        assertTrue(myRequest.isRight());
-
-        List<Decision> requests = reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL);
-        assertEquals(1, requests.size());
-    }
-
-    @Test
-    public void sort_by_requested() {
-        Either<AlreadyRequested, RoughDraftApproval> request1 =
-                roughDraftApprovalService.requestApproval(project, createFileUpload(), "request 1");
-        assertTrue(request1.isRight());
-
-        Either<AlreadyRequested, RoughDraftApproval> request2 =
-                roughDraftApprovalService.requestApproval(project3, createFileUpload(), "request 2");
-        assertTrue(request2.isRight());
-
-        var sortByRequested = new Page.Sort<>(MyReviewService.Sort.TITLE, Page.Direction.DESCENDING);
-        TestPage page = new TestPage(0, Long.MAX_VALUE, sortByRequested);
-        List<Decision> requests =
-                reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), page);
-
-        assertEquals(2, requests.size());
-        assertEquals(request2.right(), requests.get(0).getReviewerApproval());
-        assertEquals(request1.right(), requests.get(1).getReviewerApproval());
-    }
-
-    private FileUpload createFileUpload() {
-        FileUpload fileUpload = mock(FileUpload.class);
-        when(fileUpload.handleData(ArgumentMatchers.any())).thenReturn(null);
-        return fileUpload;
-    }
-
-    record TestPage(long offset, long limit, Sort<MyReviewService.Sort> sort) implements Page<MyReviewService.Sort> {
-        TestPage(long offset, long limit) {
-            this(offset, limit, new Sort<>(MyReviewService.Sort.TITLE, Direction.ASCENDING));
-        }
-    }
-
-    private static <A, B> Matcher<A> where(Function<A, B> f, Matcher<? extends B> matcher) {
-        return new TypeSafeMatcher<>() {
-            @Override
-            protected boolean matchesSafely(A a) {
-                return matcher.matches(f.apply(a));
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("an object where ")
-                        .appendDescriptionOf(matcher);
-            }
-        };
-    }
-}
+package se.su.dsv.scipro.reviewing;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import se.su.dsv.scipro.file.FileUpload;
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.system.DegreeType;
+import se.su.dsv.scipro.system.Page;
+import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.util.Either;
+
+import jakarta.inject.Inject;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ReviewingServiceImplTest extends ReviewingModuleTest {
+    private static final TestPage ALL = new TestPage(0, Long.MAX_VALUE);
+
+    @Inject
+    private ReviewingServiceImpl reviewingService;
+    @Inject
+    private FinalSeminarApprovalServiceImpl finalSeminarApprovalService;
+    @Inject
+    private RoughDraftApprovalServiceImpl roughDraftApprovalService;
+
+    private Project project;
+    private User reviewer;
+    private Project project3;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        reviewer = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build());
+        User reviewer2 = save(User.builder().firstName("Ronny").lastName("Reviewer").emailAddress("reviewer@dsv.su.se").build());
+        User headSupervisor = save(User.builder().firstName("John").lastName("Doe").emailAddress("john@example.com").build());
+        ProjectType bachelor = save(new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor"));
+        project = save(Project.builder().title("My project").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
+        project.addReviewer(reviewer);
+        Project project2 = save(Project.builder().title("My project 2").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
+        project2.addReviewer(reviewer2);
+        project3 = save(Project.builder().title("My project 3").projectType(bachelor).startDate(LocalDate.now()).headSupervisor(headSupervisor).build());
+        project3.addReviewer(reviewer);
+    }
+
+    @Test
+    public void count() {
+        finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertEquals(1, reviewingService.countDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL)));
+    }
+
+    private MyReviewService.Filter getFilter(ReviewerApproval.Step step) {
+        MyReviewService.Filter filter = new MyReviewService.Filter();
+        filter.setUser(reviewer);
+        filter.setStep(step);
+        return filter;
+    }
+
+    @Test
+    public void find_undecided() {
+        finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.FINAL_SEMINAR_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(FinalSeminarApproval.class))));
+    }
+
+    @Test
+    public void find_undecided_rough_draft_approvals() {
+        roughDraftApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertThat(reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL), hasItem(where(Decision::getReviewerApproval, instanceOf(RoughDraftApproval.class))));
+    }
+
+    @Test
+    public void count_undecided_rough_drafts() {
+        roughDraftApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertEquals(reviewingService.countUndecidedRoughDraft(reviewer), 1);
+    }
+
+    @Test
+    public void back_and_forth() {
+        assertTrue(finalSeminarApprovalService.requiresUpload(project));
+        Either<AlreadyRequested, FinalSeminarApproval> first = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertFalse(finalSeminarApprovalService.requiresUpload(project));
+
+        first.foreach(firstFinalSeminarApproval -> reviewingService.reject(firstFinalSeminarApproval, "Very bad", Optional.of(createFileUpload())));
+
+        assertTrue(finalSeminarApprovalService.requiresUpload(project));
+        Either<AlreadyRequested, FinalSeminarApproval> second = finalSeminarApprovalService.requestApproval(project, createFileUpload(), "test");
+        assertFalse(finalSeminarApprovalService.requiresUpload(project));
+
+        second.foreach(secondFinalSeminarApproval -> reviewingService.approve(secondFinalSeminarApproval, "Very good", Optional.empty()));
+        assertFalse(finalSeminarApprovalService.requiresUpload(project));
+    }
+
+    @Test
+    public void only_fetches_my_reviews() {
+        Either<AlreadyRequested, RoughDraftApproval> myRequest =
+                roughDraftApprovalService.requestApproval(project, createFileUpload(), "my request");
+        assertTrue(myRequest.isRight());
+
+        List<Decision> requests = reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), ALL);
+        assertEquals(1, requests.size());
+    }
+
+    @Test
+    public void sort_by_requested() {
+        Either<AlreadyRequested, RoughDraftApproval> request1 =
+                roughDraftApprovalService.requestApproval(project, createFileUpload(), "request 1");
+        assertTrue(request1.isRight());
+
+        Either<AlreadyRequested, RoughDraftApproval> request2 =
+                roughDraftApprovalService.requestApproval(project3, createFileUpload(), "request 2");
+        assertTrue(request2.isRight());
+
+        var sortByRequested = new Page.Sort<>(MyReviewService.Sort.TITLE, Page.Direction.DESCENDING);
+        TestPage page = new TestPage(0, Long.MAX_VALUE, sortByRequested);
+        List<Decision> requests =
+                reviewingService.findAllDecisions(getFilter(ReviewerApproval.Step.ROUGH_DRAFT_APPROVAL), page);
+
+        assertEquals(2, requests.size());
+        assertEquals(request2.right(), requests.get(0).getReviewerApproval());
+        assertEquals(request1.right(), requests.get(1).getReviewerApproval());
+    }
+
+    private FileUpload createFileUpload() {
+        FileUpload fileUpload = mock(FileUpload.class);
+        when(fileUpload.handleData(ArgumentMatchers.any())).thenReturn(null);
+        return fileUpload;
+    }
+
+    record TestPage(long offset, long limit, Sort<MyReviewService.Sort> sort) implements Page<MyReviewService.Sort> {
+        TestPage(long offset, long limit) {
+            this(offset, limit, new Sort<>(MyReviewService.Sort.TITLE, Direction.ASCENDING));
+        }
+    }
+
+    private static <A, B> Matcher<A> where(Function<A, B> f, Matcher<? extends B> matcher) {
+        return new TypeSafeMatcher<>() {
+            @Override
+            protected boolean matchesSafely(A a) {
+                return matcher.matches(f.apply(a));
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("an object where ")
+                        .appendDescriptionOf(matcher);
+            }
+        };
+    }
+}
diff --git a/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java b/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java
deleted file mode 100644
index 6d2667ef5c..0000000000
--- a/core/src/test/java/se/su/dsv/scipro/test/GuiceTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package se.su.dsv.scipro.test;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-import com.google.inject.persist.PersistService;
-import com.google.inject.persist.UnitOfWork;
-import com.google.inject.persist.jpa.JpaPersistModule;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.EntityTransaction;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-
-import jakarta.inject.Inject;
-import jakarta.inject.Provider;
-import java.time.Clock;
-
-public abstract class GuiceTest {
-    @Inject
-    private UnitOfWork unitOfWork;
-    @Inject
-    private PersistService persistService;
-    @Inject
-    private Provider<EntityManager> entityManager;
-
-    @BeforeEach
-    public final void prepareGuice() {
-        Injector injector = Guice.createInjector(
-                new JpaPersistModule("testPersistenceUnit"),
-                new AbstractModule() {
-                    @Override
-                    protected void configure() {
-                        final MutableFixedClock clock = new MutableFixedClock(Clock.systemDefaultZone());
-                        bind(Clock.class).toInstance(clock);
-                        bind(MutableFixedClock.class).toInstance(clock);
-                    }
-                },
-                moduleUnderTest());
-
-        // Have to start the PersistService and UnitOfWork manually since they are no longer
-        // automatically started as an EntityManager is injected
-        injector.getInstance(PersistService.class).start();
-        injector.getInstance(UnitOfWork.class).begin();
-
-        injector.injectMembers(this);
-
-        persistService.start();
-        EntityTransaction transaction = entityManager.get().getTransaction();
-        transaction.begin();
-        transaction.setRollbackOnly();
-    }
-
-    protected abstract Module moduleUnderTest();
-
-    @AfterEach
-    public final void shutDownPersistence() {
-        entityManager.get().getTransaction().rollback();
-        unitOfWork.end();
-        persistService.stop();
-    }
-
-    protected <T> T save(T entity) {
-        EntityManager em = entityManager.get();
-        if (em.contains(entity)) {
-            return em.merge(entity);
-        }
-        else {
-            em.persist(entity);
-            return entity;
-        }
-    }
-}
diff --git a/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java b/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java
index 4833f0e4bd..837f58dc90 100644
--- a/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/test/IntegrationTest.java
@@ -1,57 +1,5 @@
 package se.su.dsv.scipro.test;
 
-import com.google.inject.AbstractModule;
-import com.google.inject.Module;
-import com.google.inject.name.Names;
-import modules.CoreModule;
-import se.su.dsv.scipro.file.FileModule;
-import se.su.dsv.scipro.file.FileStore;
-import se.su.dsv.scipro.grading.GradingHistory;
-import se.su.dsv.scipro.grading.GradingHistoryEventRepository;
-import se.su.dsv.scipro.grading.GradingHistoryEventRepositoryImpl;
-import se.su.dsv.scipro.grading.GradingModule;
-import se.su.dsv.scipro.grading.ThesisSubmissionHistoryService;
-import se.su.dsv.scipro.plagiarism.urkund.UrkundModule;
-import se.su.dsv.scipro.reviewing.ReviewingModule;
-import se.su.dsv.scipro.sukat.SukatModule;
-import se.su.dsv.scipro.system.CurrentUser;
-import se.su.dsv.scipro.system.User;
+public abstract class IntegrationTest extends SpringTest {
 
-import jakarta.inject.Singleton;
-
-public abstract class IntegrationTest extends GuiceTest {
-
-    @Override
-    protected Module moduleUnderTest() {
-        return new AbstractModule() {
-            @Override
-            protected void configure() {
-                bindConstant().annotatedWith(Names.named("profile")).to("TEST");
-                install(new CoreModule());
-                install(new FileModule());
-                install(new ReviewingModule());
-                install(new SukatModule());
-                install(new UrkundModule());
-                bind(ThesisSubmissionHistoryService.class).to(GradingHistory.class);
-                bind(GradingHistoryEventRepository.class).to(GradingHistoryEventRepositoryImpl.class);
-                bind(CurrentUser.class).to(TestUser.class);
-                bind(FileStore.class).to(InMemoryFileStore.class);
-            }
-        };
-    }
-
-    @Singleton
-    private static class TestUser implements CurrentUser {
-
-        private User user;
-
-        public void set(User user) {
-            this.user = user;
-        }
-
-        @Override
-        public User get() {
-            return user;
-        }
-    }
 }
diff --git a/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java b/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java
new file mode 100644
index 0000000000..eae4492265
--- /dev/null
+++ b/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java
@@ -0,0 +1,92 @@
+package se.su.dsv.scipro.test;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.EntityTransaction;
+import jakarta.persistence.Persistence;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import se.su.dsv.scipro.profiles.CurrentProfile;
+import se.su.dsv.scipro.sukat.Sukat;
+import se.su.dsv.scipro.system.CurrentUser;
+import se.su.dsv.scipro.CoreConfig;
+import se.su.dsv.scipro.RepositoryConfiguration;
+
+import java.time.Clock;
+import java.util.Optional;
+
+public abstract class SpringTest {
+    private EntityManager entityManager;
+    private EntityManagerFactory entityManagerFactory;
+
+    @BeforeEach
+    public final void prepareSpring() {
+        entityManagerFactory = Persistence.createEntityManagerFactory("testPersistenceUnit");
+        this.entityManager = entityManagerFactory.createEntityManager();
+        EntityTransaction transaction = entityManager.getTransaction();
+        transaction.begin();
+        transaction.setRollbackOnly();
+
+        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
+        annotationConfigApplicationContext.register(TestContext.class);
+        annotationConfigApplicationContext.getBeanFactory()
+                .registerSingleton("entityManager", this.entityManager);
+        annotationConfigApplicationContext.refresh();
+        annotationConfigApplicationContext.getAutowireCapableBeanFactory()
+                .autowireBean(this);
+    }
+
+    @AfterEach
+    public final void shutDownPersistence() {
+        entityManager.getTransaction().rollback();
+        entityManager.close();
+        entityManagerFactory.close();
+    }
+
+    protected <T> T save(T entity) {
+        EntityManager em = entityManager;
+        if (em.contains(entity)) {
+            return em.merge(entity);
+        }
+        else {
+            em.persist(entity);
+            return entity;
+        }
+    }
+
+    @Configuration(proxyBeanMethods = false)
+    @Import({CoreConfig.class, RepositoryConfiguration.class})
+    public static class TestContext {
+        @Bean
+        public InMemoryFileStore inMemoryFileStore() {
+            return new InMemoryFileStore();
+        }
+
+        @Bean
+        public MutableFixedClock clock() {
+            return new MutableFixedClock(Clock.systemDefaultZone());
+        }
+
+        @Bean
+        public Sukat sukat() {
+            return (username) -> Optional.empty();
+        }
+
+        @Bean
+        public CurrentUser currentUser() {
+            return () -> null;
+        }
+
+        @Bean
+        public CurrentProfile currentProfile() {
+            CurrentProfile currentProfile = new CurrentProfile();
+            currentProfile.setCurrentProfileString("DEV");
+            return currentProfile;
+        }
+    }
+}
diff --git a/daisy-integration/pom.xml b/daisy-integration/pom.xml
index 891a45a81e..3d94bb165c 100644
--- a/daisy-integration/pom.xml
+++ b/daisy-integration/pom.xml
@@ -17,8 +17,8 @@
             <artifactId>core</artifactId>
         </dependency>
         <dependency>
-            <groupId>com.google.inject.extensions</groupId>
-            <artifactId>guice-servlet</artifactId>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
         </dependency>
         <dependency>
             <groupId>jakarta.servlet</groupId>
diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java
index 3d4acbe581..3f78ffd415 100755
--- a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java
+++ b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ExternalImporterDaisyImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.daisyExternal.impl;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import se.su.dsv.scipro.system.PageRequest;
diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java
index 0fe1dd6e51..9e6ea05554 100644
--- a/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java
+++ b/daisy-integration/src/main/java/se/su/dsv/scipro/daisyExternal/impl/ImporterTransactionsImpl.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.daisyExternal.impl;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import jakarta.ws.rs.core.Response;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java
new file mode 100644
index 0000000000..1a50b0c056
--- /dev/null
+++ b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyIntegrationConfiguration.java
@@ -0,0 +1,182 @@
+package se.su.dsv.scipro.integration.daisy;
+
+import com.google.common.eventbus.EventBus;
+import jakarta.inject.Provider;
+import jakarta.persistence.EntityManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import se.su.dsv.scipro.daisyExternal.ExternalImporter;
+import se.su.dsv.scipro.daisyExternal.ImporterTransactions;
+import se.su.dsv.scipro.daisyExternal.http.DaisyAPI;
+import se.su.dsv.scipro.daisyExternal.impl.ExternalImporterDaisyImpl;
+import se.su.dsv.scipro.daisyExternal.impl.ImporterTransactionsImpl;
+import se.su.dsv.scipro.finalseminar.FinalSeminarService;
+import se.su.dsv.scipro.finalthesis.FinalThesisService;
+import se.su.dsv.scipro.forum.ProjectForumService;
+import se.su.dsv.scipro.grading.NationalSubjectCategoryService;
+import se.su.dsv.scipro.grading.ThesisApprovedHistoryService;
+import se.su.dsv.scipro.grading.ThesisRejectionHistoryService;
+import se.su.dsv.scipro.integration.daisy.workers.GradingCompletedMilestoneActivator;
+import se.su.dsv.scipro.integration.daisy.workers.ImportNationalCategories;
+import se.su.dsv.scipro.integration.daisy.workers.ProjectExporter;
+import se.su.dsv.scipro.integration.daisy.workers.ProjectFinalizer;
+import se.su.dsv.scipro.integration.daisy.workers.RejectedThesisWorker;
+import se.su.dsv.scipro.integration.daisy.workers.UserImportWorker;
+import se.su.dsv.scipro.io.ExternalExporter;
+import se.su.dsv.scipro.io.facade.ExporterFacade;
+import se.su.dsv.scipro.io.impl.ExternalExporterDaisyImpl;
+import se.su.dsv.scipro.match.ProgramService;
+import se.su.dsv.scipro.project.ProjectRepo;
+import se.su.dsv.scipro.project.ProjectService;
+import se.su.dsv.scipro.report.GradingReportService;
+import se.su.dsv.scipro.springdata.services.UnitService;
+import se.su.dsv.scipro.system.MergeService;
+import se.su.dsv.scipro.system.MergeServiceImpl;
+import se.su.dsv.scipro.system.ResearchAreaService;
+import se.su.dsv.scipro.system.UserNameService;
+import se.su.dsv.scipro.system.UserService;
+import se.su.dsv.scipro.war.PluginConfiguration;
+import se.su.dsv.scipro.workerthreads.Scheduler;
+
+@Configuration
+public class DaisyIntegrationConfiguration implements PluginConfiguration {
+    @Bean
+    public Daisy daisy(ExporterFacade exporterFacade, ExternalExporter externalExporter) {
+        return new Daisy(exporterFacade, externalExporter);
+    }
+
+    @Bean
+    public ExporterFacade exporterFacade(ExternalExporter externalExporter) {
+        return new ExporterFacade(externalExporter);
+    }
+
+    @Bean
+    public ExternalExporterDaisyImpl externalExporter(DaisyAPI daisyApi) {
+        return new ExternalExporterDaisyImpl(daisyApi);
+    }
+
+    @Bean
+    public DaisyWorkerInitialization daisyWorkerInitialization(
+            Scheduler scheduler,
+            Provider<ProjectExporter> projectExporter,
+            Provider<UserImportWorker> userImportWorker,
+            Provider<ProjectFinalizer> projectFinalizer,
+            Provider<RejectedThesisWorker> rejectedThesisWorkerProvider,
+            Provider<GradingCompletedMilestoneActivator> gradingFinalizer,
+            Provider<ImportNationalCategories> importNationalCategories)
+    {
+        return new DaisyWorkerInitialization(scheduler, projectExporter, userImportWorker, projectFinalizer,
+                rejectedThesisWorkerProvider, gradingFinalizer, importNationalCategories);
+    }
+
+    @Bean
+    public ProjectExporter projectExporter(
+            ExporterFacade exporterFacade,
+            ProjectRepo projectRepo,
+            DaisyAPI daisyApi,
+            ExternalExporter externalExporter,
+            FinalSeminarService finalSeminarService,
+            FinalThesisService finalThesisService)
+    {
+        return new ProjectExporter(projectRepo, exporterFacade, daisyApi, externalExporter, finalSeminarService,
+                finalThesisService);
+    }
+
+    @Bean
+    public UserImportWorker userImportWorker(
+            DaisyAPI daisyApi,
+            ImporterTransactions importerTransactions,
+            ExternalImporter externalImporter,
+            MergeService mergeService,
+            UserService userService,
+            ProgramService programService,
+            Provider<EntityManager> entityManager,
+            ResearchAreaService researchAreaService)
+    {
+        return new UserImportWorker(daisyApi, importerTransactions, externalImporter, mergeService, userService,
+                programService, entityManager, researchAreaService);
+    }
+
+    @Bean
+    public ProjectFinalizer projectFinalizer(
+            ProjectService projectService,
+            DaisyAPI daisyApi,
+            ThesisApprovedHistoryService thesisApprovedHistoryService)
+    {
+        return new ProjectFinalizer(projectService, daisyApi, thesisApprovedHistoryService);
+    }
+
+    @Bean
+    public RejectedThesisWorker rejectedThesisWorker(
+            GradingReportService gradingReportService,
+            ProjectService projectService,
+            FinalThesisService finalThesisService,
+            ProjectForumService projectForumService,
+            ThesisRejectionHistoryService thesisRejectionHistoryService,
+            DaisyAPI daisyApi)
+    {
+        return new RejectedThesisWorker(gradingReportService, projectService, finalThesisService, projectForumService,
+                thesisRejectionHistoryService, daisyApi);
+    }
+
+    @Bean
+    public GradingCompletedMilestoneActivator gradingFinalizer(
+            ProjectService projectService,
+            DaisyAPI daisyApi,
+            EventBus eventBus,
+            UserService userService)
+    {
+        return new GradingCompletedMilestoneActivator(projectService, daisyApi, eventBus, userService);
+    }
+
+    @Bean
+    public ImportNationalCategories importNationalCategories(
+            DaisyAPI daisyApi,
+            NationalSubjectCategoryService nationalSubjectCategoryService)
+    {
+        return new ImportNationalCategories(daisyApi, nationalSubjectCategoryService);
+    }
+
+    @Bean
+    public ImporterTransactionsImpl importerTransactions(
+            UserService userService,
+            ResearchAreaService researchAreaService,
+            ProjectService projectService,
+            UserNameService userNameService,
+            DaisyAPI daisyApi,
+            ProgramService programService)
+    {
+        return new ImporterTransactionsImpl(userService, researchAreaService, projectService, userNameService,
+                daisyApi, programService);
+    }
+
+    @Bean
+    public ExternalImporterDaisyImpl externalImporter(
+            DaisyAPI daisyApi,
+            ImporterTransactions importerTransactions,
+            UserService userService,
+            UnitService unitService)
+    {
+        return new ExternalImporterDaisyImpl(userService, unitService, daisyApi, importerTransactions);
+    }
+
+    @Bean
+    public MergeServiceImpl mergeService(UserService userService, UserNameService userNameService) {
+        return new MergeServiceImpl(userNameService, userService);
+    }
+
+    @Bean
+    SyncReviewerWithDaisy syncReviewerWithDaisy(DaisyAPI daisyApi, EventBus eventBus) {
+        return new SyncReviewerWithDaisy(daisyApi, eventBus);
+    }
+
+    @Bean
+    public DaisyUserSearchService daisyUserSearchService(DaisyAPI daisyApi, UserService userService) {
+        return new DaisyUserSearchService(daisyApi, userService);
+    }
+
+    @Bean
+    DaisyConsentService daisyConsentService(DaisyAPI daisyApi) {
+        return new DaisyConsentService(daisyApi);
+    }
+}
diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java b/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java
deleted file mode 100644
index ffedb6c3c1..0000000000
--- a/daisy-integration/src/main/java/se/su/dsv/scipro/integration/daisy/DaisyModule.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package se.su.dsv.scipro.integration.daisy;
-
-import com.google.inject.multibindings.Multibinder;
-import com.google.inject.multibindings.OptionalBinder;
-import com.google.inject.servlet.ServletModule;
-import se.su.dsv.scipro.daisyExternal.ExternalImporter;
-import se.su.dsv.scipro.daisyExternal.ImporterTransactions;
-import se.su.dsv.scipro.daisyExternal.impl.ExternalImporterDaisyImpl;
-import se.su.dsv.scipro.daisyExternal.impl.ImporterTransactionsImpl;
-import se.su.dsv.scipro.finalthesis.PublishingConsentService;
-import se.su.dsv.scipro.integration.daisy.workers.ProjectExporter;
-import se.su.dsv.scipro.integration.daisy.workers.UserImportWorker;
-import se.su.dsv.scipro.io.ExternalExporter;
-import se.su.dsv.scipro.io.impl.ExternalExporterDaisyImpl;
-import se.su.dsv.scipro.match.IdeaCreationJudge;
-import se.su.dsv.scipro.system.UserImportService;
-import se.su.dsv.scipro.system.UserSearchProvider;
-
-public class DaisyModule extends ServletModule {
-    @Override
-    protected void configureServlets() {
-        bind(ExternalImporter.class).to(ExternalImporterDaisyImpl.class);
-        bind(ImporterTransactions.class).to(ImporterTransactionsImpl.class);
-
-        OptionalBinder.newOptionalBinder(binder(), IdeaCreationJudge.class)
-                .setBinding().to(Daisy.class);
-
-        bind(ExternalExporter.class).to(ExternalExporterDaisyImpl.class);
-        bind(UserImportWorker.class);
-        bind(ProjectExporter.class);
-        bind(DaisyWorkerInitialization.class).asEagerSingleton();
-        bind(SyncReviewerWithDaisy.class).asEagerSingleton();
-
-        Multibinder.newSetBinder(binder(), UserImportService.class)
-                .addBinding().to(ExternalImporterDaisyImpl.class);
-
-        Multibinder.newSetBinder(binder(), UserSearchProvider.class)
-                .addBinding().to(DaisyUserSearchService.class);
-
-        OptionalBinder.newOptionalBinder(binder(), PublishingConsentService.class)
-                .setBinding().to(DaisyConsentService.class);
-    }
-
-}
diff --git a/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java b/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java
index 4d7c11803d..75400ab642 100755
--- a/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java
+++ b/daisy-integration/src/main/java/se/su/dsv/scipro/io/facade/ExporterFacade.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.io.facade;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import se.su.dsv.scipro.io.ExternalExporter;
 import se.su.dsv.scipro.io.dto.Role;
 import se.su.dsv.scipro.io.exceptions.ExternalExportException;
diff --git a/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module b/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module
deleted file mode 100644
index f216e38b02..0000000000
--- a/daisy-integration/src/main/resources/META-INF/services/com.google.inject.Module
+++ /dev/null
@@ -1 +0,0 @@
-se.su.dsv.scipro.integration.daisy.DaisyModule
diff --git a/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration b/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration
new file mode 100644
index 0000000000..39148f50a9
--- /dev/null
+++ b/daisy-integration/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration
@@ -0,0 +1 @@
+se.su.dsv.scipro.integration.daisy.DaisyIntegrationConfiguration
diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java
index b583b29e21..f51c23592a 100644
--- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java
+++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/GradingCompletedMilestoneActivatorTest.java
@@ -1,10 +1,6 @@
 package se.su.dsv.scipro.integration.daisy.workers;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.persist.UnitOfWork;
-import com.google.inject.util.Providers;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.EntityTransaction;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -23,6 +19,7 @@ import se.su.dsv.scipro.system.User;
 import se.su.dsv.scipro.system.UserService;
 import se.su.dsv.scipro.workerthreads.WorkerData;
 import se.su.dsv.scipro.workerthreads.WorkerDataService;
+import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
 
 import java.util.*;
 
@@ -47,22 +44,16 @@ public class GradingCompletedMilestoneActivatorTest {
     @Mock
     private EventBus eventBus;
     @Mock
-    private UnitOfWork unitOfWork;
-    @Mock
-    private EntityManager entityManager;
-    @Mock
-    private EntityTransaction entityTransaction;
+    private WorkerTransactionManager workerTransactionManager;
     @Mock
     private WorkerDataService workerDataService;
 
     @BeforeEach
     public void setup() {
         gradingCompletedMilestoneActivator = new GradingCompletedMilestoneActivator(projectService, daisyAPI, eventBus, userService);
-        gradingCompletedMilestoneActivator.setUnitOfWork(unitOfWork);
-        gradingCompletedMilestoneActivator.setTxManager(Providers.of(entityManager));
+        gradingCompletedMilestoneActivator.setTxManager(workerTransactionManager);
         gradingCompletedMilestoneActivator.setWorkerDataService(workerDataService);
         when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
-        when(entityManager.getTransaction()).thenReturn(entityTransaction);
 
         project.setId(3493L);
         project.setIdentifier(234);
diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java
index f4165842bb..dfd523ad4f 100644
--- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java
+++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectExporterTest.java
@@ -1,10 +1,6 @@
 package se.su.dsv.scipro.integration.daisy.workers;
 
-import com.google.inject.persist.UnitOfWork;
-import com.google.inject.util.Providers;
 import com.querydsl.core.types.Predicate;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.EntityTransaction;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -26,6 +22,7 @@ import se.su.dsv.scipro.system.Unit;
 import se.su.dsv.scipro.system.User;
 import se.su.dsv.scipro.workerthreads.WorkerData;
 import se.su.dsv.scipro.workerthreads.WorkerDataService;
+import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
 
 import java.time.LocalDate;
 import java.util.*;
@@ -45,10 +42,8 @@ public class ProjectExporterTest {
     private @Mock ExporterFacade exporterFacade;
     private @Mock DaisyAPI daisyAPI;
     private @Mock ExternalExporter externalExporter;
-    private @Mock EntityManager entityManager;
-    private @Mock EntityTransaction entityTransaction;
+    private @Mock WorkerTransactionManager workerTransactionManager;
     private @Mock WorkerDataService workerDataService;
-    private @Mock UnitOfWork unitOfWork;
     private @Mock FinalSeminarService finalSeminarService;
     private @Mock FinalThesisService finalThesisService;
 
@@ -61,11 +56,9 @@ public class ProjectExporterTest {
     @BeforeEach
     public void setUp() {
         projectExporter = new ProjectExporter(projectRepo, exporterFacade, daisyAPI, externalExporter, finalSeminarService, finalThesisService);
-        projectExporter.setTxManager(Providers.of(entityManager));
+        projectExporter.setTxManager(workerTransactionManager);
         projectExporter.setWorkerDataService(workerDataService);
-        projectExporter.setUnitOfWork(unitOfWork);
         when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
-        when(entityManager.getTransaction()).thenReturn(entityTransaction);
 
         Unit unit = new Unit();
         unit.setIdentifier(239478);
diff --git a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java
index 576409136a..048d2165e7 100644
--- a/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java
+++ b/daisy-integration/src/test/java/se/su/dsv/scipro/integration/daisy/workers/ProjectFinalizerTest.java
@@ -1,7 +1,5 @@
 package se.su.dsv.scipro.integration.daisy.workers;
 
-import com.google.inject.persist.UnitOfWork;
-import com.google.inject.util.Providers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -18,8 +16,8 @@ import se.su.dsv.scipro.project.QProject;
 import se.su.dsv.scipro.workerthreads.WorkerData;
 import se.su.dsv.scipro.workerthreads.WorkerDataService;
 
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.EntityTransaction;
+import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
+
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
@@ -38,9 +36,7 @@ public class ProjectFinalizerTest {
 
     private @Mock DaisyAPI daisyAPI;
     private @Mock ProjectService projectService;
-    private @Mock UnitOfWork unitOfWork;
-    private @Mock EntityManager entityManager;
-    private @Mock EntityTransaction entityTransaction;
+    private @Mock WorkerTransactionManager workerTransactionManager;
     private @Mock WorkerDataService workerDataService;
     private @Mock ThesisApprovedHistoryService thesisApprovedHistoryService;
 
@@ -48,11 +44,9 @@ public class ProjectFinalizerTest {
     @BeforeEach
     public void setup() {
         projectFinalizer = new ProjectFinalizer(projectService, daisyAPI, thesisApprovedHistoryService);
-        projectFinalizer.setUnitOfWork(unitOfWork);
-        projectFinalizer.setTxManager(Providers.of(entityManager));
+        projectFinalizer.setTxManager(workerTransactionManager);
         projectFinalizer.setWorkerDataService(workerDataService);
         when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
-        when(entityManager.getTransaction()).thenReturn(entityTransaction);
 
         project.setId(3493L);
         project.setIdentifier(234);
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000..637455a39e
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,15 @@
+services:
+  oauth2:
+    container_name: scipro-dev-oauth2
+    build:
+      context: https://github.com/dsv-su/toker.git
+      dockerfile: embedded.Dockerfile
+    restart: on-failure
+    ports:
+      - '59733:8080'
+    environment:
+      - CLIENT_ID=get-token
+      - CLIENT_SECRET=get-token-secret
+      - CLIENT_REDIRECT_URI=http://localhost:59732/
+      - RESOURCE_SERVER_ID=scipro-api-client
+      - RESOURCE_SERVER_SECRET=scipro-api-secret
diff --git a/pom.xml b/pom.xml
index d222069a72..c96cb4a122 100755
--- a/pom.xml
+++ b/pom.xml
@@ -13,6 +13,8 @@
         <module>core</module>
         <module>view</module>
         <module>daisy-integration</module>
+        <module>war</module>
+        <module>api</module>
     </modules>
 
     <properties>
@@ -36,7 +38,6 @@
         <mockito.version>5.3.1</mockito.version>
         <flyway.version>9.19.1</flyway.version>
         <jersey.version>3.1.6</jersey.version>
-        <guice.version>7.0.0</guice.version>
         <poi.version>5.2.5</poi.version>
         <jackson.version>2.17.0</jackson.version>
 
@@ -88,9 +89,22 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.wicket</groupId>
-                <artifactId>wicket-guice</artifactId>
+                <artifactId>wicket-ioc</artifactId>
                 <version>${wicket.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.wicket</groupId>
+                <artifactId>wicket-spring</artifactId>
+                <version>${wicket.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>3.2.5</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
 
             <!--  Servlet API, needed for compilation. -->
             <dependency>
@@ -189,13 +203,6 @@
                 <artifactId>guava</artifactId>
                 <version>32.0.1-jre</version>
             </dependency>
-            <dependency>
-                <groupId>com.google.inject</groupId>
-                <artifactId>guice-bom</artifactId>
-                <version>${guice.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
 
             <dependency>
                 <groupId>jakarta.mail</groupId>
@@ -260,6 +267,11 @@
                 <artifactId>flyway-mysql</artifactId>
                 <version>${flyway.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+                <version>2.5.0</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
diff --git a/view/pom.xml b/view/pom.xml
index c359d76206..9cdd26f28b 100644
--- a/view/pom.xml
+++ b/view/pom.xml
@@ -13,15 +13,6 @@
     <packaging>war</packaging>
 
     <dependencies>
-        <dependency>
-            <groupId>com.google.inject.extensions</groupId>
-            <artifactId>guice-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.google.inject.extensions</groupId>
-            <artifactId>guice-persist</artifactId>
-        </dependency>
-
         <dependency>
             <groupId>se.su.dsv.scipro</groupId>
             <artifactId>core</artifactId>
@@ -44,7 +35,7 @@
         </dependency>
         <dependency>
             <groupId>org.apache.wicket</groupId>
-            <artifactId>wicket-guice</artifactId>
+            <artifactId>wicket-ioc</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.wicket</groupId>
@@ -55,6 +46,11 @@
             <artifactId>wicket-tester</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.wicket</groupId>
+            <artifactId>wicket-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>org.wicketstuff</groupId>
             <artifactId>wicketstuff-jasperreports</artifactId>
@@ -144,6 +140,15 @@
     </dependencies>
 
     <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <attachClasses>true</attachClasses>
+                </configuration>
+            </plugin>
+        </plugins>
         <resources>
             <resource>
                 <filtering>true</filtering>
diff --git a/view/src/main/java/ApplicationBootstrap.java b/view/src/main/java/ApplicationBootstrap.java
deleted file mode 100644
index d5631e6f1c..0000000000
--- a/view/src/main/java/ApplicationBootstrap.java
+++ /dev/null
@@ -1,68 +0,0 @@
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Module;
-import com.google.inject.name.Names;
-import com.google.inject.persist.PersistFilter;
-import com.google.inject.servlet.GuiceServletContextListener;
-import com.google.inject.servlet.ServletModule;
-import org.apache.wicket.guice.GuiceWebApplicationFactory;
-import org.apache.wicket.protocol.http.WicketFilter;
-
-import jakarta.servlet.ServletContext;
-import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.time.Clock;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ServiceLoader;
-
-public class ApplicationBootstrap extends GuiceServletContextListener {
-    @Override
-    protected Injector getInjector() {
-        // preserve cookies when using Jersey which will use the logged in session cookie from
-        // Daisy API thus drastically speeding up the batch jobs
-        CookieHandler.setDefault(new CookieManager());
-        return Guice.createInjector(
-                new ServletModule() {
-                    @Override
-                    protected void configureServlets() {
-                        final ServletContext servletContext = getServletContext();
-                        final Enumeration<String> initParameterNames = servletContext.getInitParameterNames();
-                        while (initParameterNames.hasMoreElements()) {
-                            final String parameterName = initParameterNames.nextElement();
-                            final String value = servletContext.getInitParameter(parameterName);
-                            bindConstant().annotatedWith(Names.named(parameterName)).to(value);
-                        }
-                    }
-                },
-                new ServletModule() {
-                    @Override
-                    protected void configureServlets() {
-                        filter("/*").through(PersistFilter.class);
-                    }
-                },
-                new AbstractModule() {
-                    @Override
-                    protected void configure() {
-                        bind(Clock.class).toInstance(Clock.systemDefaultZone());
-                        ServiceLoader<Module> modules = ServiceLoader.load(Module.class);
-                        for (Module module : modules) {
-                            install(module);
-                        }
-                    }
-                },
-                new ServletModule() {
-                    @Override
-                    protected void configureServlets() {
-                        Map<String,String> params = new HashMap<>();
-                        params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*");
-                        params.put(WicketFilter.APP_FACT_PARAM, GuiceWebApplicationFactory.class.getName());
-                        params.put("injectorContextAttribute", Injector.class.getName());
-                        filter("/*").through(new WicketFilter(), params);
-                    }
-                }
-        );
-    }
-}
diff --git a/view/src/main/java/DatabaseMigration.java b/view/src/main/java/DatabaseMigration.java
deleted file mode 100644
index 442e3003e4..0000000000
--- a/view/src/main/java/DatabaseMigration.java
+++ /dev/null
@@ -1,35 +0,0 @@
-import org.flywaydb.core.Flyway;
-
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import jakarta.servlet.ServletContextEvent;
-import jakarta.servlet.ServletContextListener;
-import javax.sql.DataSource;
-
-public class DatabaseMigration implements ServletContextListener {
-    @Override
-    public void contextInitialized(ServletContextEvent sce) {
-        migrateDatabase();
-    }
-
-    private void migrateDatabase() {
-        Flyway flyway = Flyway.configure()
-                .dataSource(getDataSource())
-                .baselineOnMigrate(true)
-                .table("schema_version")
-                .load();
-        flyway.migrate();
-    }
-
-    private DataSource getDataSource() {
-        try {
-            return InitialContext.doLookup("java:comp/env/jdbc/sciproDS");
-        } catch (NamingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent sce) {
-    }
-}
diff --git a/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java b/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java
index 7e80019776..3d0eafc255 100644
--- a/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java
+++ b/view/src/main/java/se/su/dsv/scipro/FileSystemStore.java
@@ -12,7 +12,7 @@ import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.StandardOpenOption;
 
-class FileSystemStore implements FileStore {
+public class FileSystemStore implements FileStore {
     private static final int FILES_PER_SUBDIRECTORY = 1000;
     private static final String FILE_ROOT = "/scipro-files";
 
diff --git a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java
index ebbc21afa8..521595f7c3 100755
--- a/view/src/main/java/se/su/dsv/scipro/SciProApplication.java
+++ b/view/src/main/java/se/su/dsv/scipro/SciProApplication.java
@@ -53,7 +53,6 @@ import se.su.dsv.scipro.milestones.pages.SupervisorMileStonePage;
 import se.su.dsv.scipro.nonworkdays.NonWorkDaysPage;
 import se.su.dsv.scipro.notes.NotesPage;
 import se.su.dsv.scipro.notifications.NotificationLoader;
-import se.su.dsv.scipro.notifications.NotificationModule;
 import se.su.dsv.scipro.notifications.pages.NotificationLandingPage;
 import se.su.dsv.scipro.notifications.pages.NotificationsPage;
 import se.su.dsv.scipro.notifications.pages.SupervisorNotificationSettingsPage;
@@ -347,7 +346,7 @@ public class SciProApplication extends LifecycleManagedWebApplication {
 
     private void mountNotificationAndSettingsPages() {
         mountPage("notes", NotesPage.class);
-        mountPage(NotificationModule.NOTIFICATION_RELATIVE_PAGE_URL, NotificationLandingPage.class);
+        mountPage("notification", NotificationLandingPage.class);
         mountPage("notifications", NotificationsPage.class);
         mountPage("settings", BasicProfilePage.class);
         mountPage("settings/supervisorprofile", SupervisorProfilePage.class);
diff --git a/view/src/main/java/se/su/dsv/scipro/SciProModule.java b/view/src/main/java/se/su/dsv/scipro/SciProModule.java
deleted file mode 100644
index 26e7f0a6ba..0000000000
--- a/view/src/main/java/se/su/dsv/scipro/SciProModule.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package se.su.dsv.scipro;
-
-import com.google.inject.Singleton;
-import com.google.inject.multibindings.Multibinder;
-import com.google.inject.persist.jpa.JpaPersistModule;
-import com.google.inject.servlet.ServletModule;
-import com.google.inject.servlet.SessionScoped;
-import modules.CoreModule;
-import org.apache.wicket.protocol.http.WebApplication;
-import se.su.dsv.scipro.file.FileModule;
-import se.su.dsv.scipro.file.FileStore;
-import se.su.dsv.scipro.security.auth.AuthenticationModule;
-import se.su.dsv.scipro.system.CurrentUser;
-import se.su.dsv.scipro.system.Lifecycle;
-import se.su.dsv.scipro.workerthreads.WorkerModule;
-
-public class SciProModule extends ServletModule {
-    @Override
-    protected void configureServlets() {
-        install(new JpaPersistModule("defaultPersistenceUnit"));
-        install(new CoreModule());
-        install(new FileModule());
-        bind(FileStore.class).to(FileSystemStore.class);
-        install(new WorkerModule());
-        install(new AuthenticationModule());
-
-        bind(WebApplication.class).to(SciProApplication.class).in(Singleton.class);
-
-        bind(CurrentUser.class).to(CurrentUserFromWicketSession.class).in(SessionScoped.class);
-        Multibinder<Lifecycle> lifecycles = Multibinder.newSetBinder(binder(), Lifecycle.class);
-        lifecycles.addBinding().to(DataInitializer.class);
-    }
-}
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java b/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java
index 5b1e8d22fe..0b3b45f8ae 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/pages/AdminCreateProjectConfirmationPage.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.admin.pages;
 
-import com.google.inject.Inject;
+import jakarta.inject.Inject;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.link.Link;
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java
index 48e268a040..eb36d66e9e 100644
--- a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminEditFooterAddressPanel.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.admin.panels;
 
-import com.google.inject.persist.Transactional;
+import jakarta.transaction.Transactional;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.RequiredTextField;
 import org.apache.wicket.markup.html.panel.Panel;
diff --git a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java
index ad084a3436..8284ab8966 100755
--- a/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/admin/panels/AdminProjectTypePanel.java
@@ -54,16 +54,16 @@ public class AdminProjectTypePanel extends Panel {
             NumberTextField<Integer> minimumOppositionsToBeGraded = new NumberTextField<>(
                     "minimum_oppositions_to_be_graded",
                     LambdaModel.of(settings,
-                            ProjectTypeSettings::getMinimumOppositionsToBeGraded,
-                            ProjectTypeSettings::setMinimumOppositionsToBeGraded),
+                            ProjectTypeSettings::getMinOppositionsToBeGraded,
+                            ProjectTypeSettings::setMinOppositionsToBeGraded),
                     Integer.class);
             minimumOppositionsToBeGraded.setMinimum(0);
             add(minimumOppositionsToBeGraded);
             NumberTextField<Integer> minimumActiveParticipationsToBeGraded = new NumberTextField<>(
                     "minimum_active_participations_to_be_graded",
                     LambdaModel.of(settings,
-                            ProjectTypeSettings::getMinimumActiveParticipationsToBeGraded,
-                            ProjectTypeSettings::setMinimumActiveParticipationsToBeGraded),
+                            ProjectTypeSettings::getMinActiveParticipationsToBeGraded,
+                            ProjectTypeSettings::setMinActiveParticipationsToBeGraded),
                     Integer.class);
             minimumActiveParticipationsToBeGraded.setMinimum(0);
             add(minimumActiveParticipationsToBeGraded);
diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java
index 5e54b3e4a9..a300022d1b 100644
--- a/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/checklists/AnswerPanel.java
@@ -27,7 +27,7 @@ public abstract class AnswerPanel extends Panel {
         ANSWER_IMAGES.put(ChecklistAnswerEnum.GREEN, "images/icons/bullet_ball_glass_green.png");
         ANSWER_IMAGES.put(ChecklistAnswerEnum.YELLOW, "images/icons/bullet_ball_glass_yellow.png");
         ANSWER_IMAGES.put(ChecklistAnswerEnum.RED, "images/icons/bullet_ball_glass_red.png");
-        ANSWER_IMAGES.put(ChecklistAnswerEnum.NOT_APLICABLE, "images/icons/bullet_ball_glass_grey.png");
+        ANSWER_IMAGES.put(ChecklistAnswerEnum.NOT_APPLICABLE, "images/icons/bullet_ball_glass_grey.png");
     }
 
     public static final String CLICK_ICON = "images/icons/bullet_ball_glass_click.png";
diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java
index 1af096eee2..250d82e7e7 100644
--- a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.java
@@ -55,7 +55,7 @@ public class ChecklistOverviewPanel extends GenericPanel<Project> {
                 ChecklistAnswerEnum.GREEN,
                 ChecklistAnswerEnum.YELLOW,
                 ChecklistAnswerEnum.RED,
-                ChecklistAnswerEnum.NOT_APLICABLE);
+                ChecklistAnswerEnum.NOT_APPLICABLE);
         add(new ListView<>("answersBreakdown", answers) {
             @Override
             protected void populateItem(ListItem<ChecklistAnswerEnum> item) {
diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties
index 9ad8928894..0d30f3ea89 100644
--- a/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/checklists/ChecklistOverviewPanel.utf8.properties
@@ -1,4 +1,4 @@
 ChecklistAnswerEnum.GREEN = Ok
 ChecklistAnswerEnum.YELLOW = Minor corrections
 ChecklistAnswerEnum.RED = Not done
-ChecklistAnswerEnum.NOT_APLICABLE = Not applicable
+ChecklistAnswerEnum.NOT_APPLICABLE = Not applicable
diff --git a/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java b/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java
index 51e779ba99..60482c38a8 100644
--- a/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/checklists/TrafficLightPanel.java
@@ -54,7 +54,7 @@ public class TrafficLightPanel extends FormComponentPanel<ChecklistAnswerEnum> {
         greenLink = new TrafficLightLink("greenLink", ChecklistAnswerEnum.GREEN, selectedGreen, greenImage);
         redLink = new TrafficLightLink("redLink", ChecklistAnswerEnum.RED, selectedRed, redImage);
         yellowLink = new TrafficLightLink("yellowLink", ChecklistAnswerEnum.YELLOW, selectedYellow, yellowImage);
-        noAnswerLink = new TrafficLightLink("noAnswerLink", ChecklistAnswerEnum.NOT_APLICABLE, selectedNotApplicable, noAnswerImage);
+        noAnswerLink = new TrafficLightLink("noAnswerLink", ChecklistAnswerEnum.NOT_APPLICABLE, selectedNotApplicable, noAnswerImage);
         add(greenLink);
         add(yellowLink);
         add(redLink);
diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java
deleted file mode 100644
index fc50e7ff37..0000000000
--- a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package se.su.dsv.scipro.crosscutting;
-
-import com.google.common.eventbus.EventBus;
-import com.google.inject.AbstractModule;
-import se.su.dsv.scipro.reviewing.ReviewerAssignedDeadline;
-
-public class CrosscuttingModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        requireBinding(EventBus.class);
-        bind(ReviewingNotifications.class).asEagerSingleton();
-        bind(ReviewerSupportMailer.class).asEagerSingleton();
-        bind(ReviewerAssignedNotifications.class).asEagerSingleton();
-        bind(ReviewerAssignedDeadline.class).asEagerSingleton();
-        bind(ForwardPhase2Feedback.class).asEagerSingleton();
-    }
-}
diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java
new file mode 100644
index 0000000000..867703dde2
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/crosscutting/NotifyFailedReflection.java
@@ -0,0 +1,46 @@
+package se.su.dsv.scipro.crosscutting;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import jakarta.inject.Inject;
+import se.su.dsv.scipro.data.dataobjects.Member;
+import se.su.dsv.scipro.notifications.NotificationController;
+import se.su.dsv.scipro.notifications.dataobject.NotificationSource;
+import se.su.dsv.scipro.notifications.dataobject.ProjectEvent;
+import se.su.dsv.scipro.reflection.ReflectionImprovementsRequestedEvent;
+import se.su.dsv.scipro.reflection.ReflectionImprovementsSubmittedEvent;
+
+import java.util.Set;
+
+public class NotifyFailedReflection {
+    private final NotificationController notificationController;
+
+    @Inject
+    public NotifyFailedReflection(NotificationController notificationController, EventBus eventBus) {
+        this.notificationController = notificationController;
+        eventBus.register(this);
+    }
+
+    @Subscribe
+    public void reflectionImprovementsRequested(ReflectionImprovementsRequestedEvent event) {
+        NotificationSource source = new NotificationSource();
+        source.setMessage(event.supervisorComment());
+        notificationController.notifyCustomProject(
+                event.project(),
+                ProjectEvent.Event.REFLECTION_IMPROVEMENTS_REQUESTED,
+                source,
+                Set.of(new Member(event.author(), Member.Type.AUTHOR)));
+    }
+
+    @Subscribe
+    public void reflectionImprovementsSubmittted(ReflectionImprovementsSubmittedEvent event) {
+        NotificationSource source = new NotificationSource();
+        source.setMessage(event.reflection());
+        source.setAdditionalMessage(event.author().getFullName());
+        notificationController.notifyCustomProject(
+                event.project(),
+                ProjectEvent.Event.REFLECTION_IMPROVEMENTS_SUBMITTED,
+                source,
+                Set.of(new Member(event.project().getHeadSupervisor(), Member.Type.SUPERVISOR)));
+    }
+}
diff --git a/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java b/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java
index 158b6ec5d9..40bb5744a8 100644
--- a/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/finalseminar/ProjectActiveParticipationListPanel.java
@@ -36,7 +36,7 @@ public class ProjectActiveParticipationListPanel extends GenericPanel<Project> {
                 IModel<Integer> countRequired = model
                         .map(Project::getProjectType)
                         .map(ProjectType::getProjectTypeSettings)
-                        .map(ProjectTypeSettings::getMinimumActiveParticipationsToBeGraded);
+                        .map(ProjectTypeSettings::getMinActiveParticipationsToBeGraded);
                 item.add(new Label("count_required", countRequired));
                 IModel<Long> countPerformed = participations.map(this::countApproved);
                 item.add(new Label("count_approved", countPerformed));
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java
index fbf8b36a5f..f24d065eb0 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/grading/AbstractExaminationsPanel.java
@@ -213,8 +213,8 @@ abstract class AbstractExaminationsPanel extends GenericPanel<User> {
                     .filter(FinalSeminarActiveParticipation::isApproved)
                     .count();
             final ProjectTypeSettings projectTypeSettings = project.getProjectType().getProjectTypeSettings();
-            final int requiredOppositions = projectTypeSettings.getMinimumOppositionsToBeGraded();
-            final int requiredActiveParticipations = projectTypeSettings.getMinimumActiveParticipationsToBeGraded();
+            final int requiredOppositions = projectTypeSettings.getMinOppositionsToBeGraded();
+            final int requiredActiveParticipations = projectTypeSettings.getMinActiveParticipationsToBeGraded();
             return new SeminarParticipationGradingRequirements(
                     new Requirement(requiredOppositions, completedOppositions),
                     new Requirement(requiredActiveParticipations, completedParticipations));
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
index 079fb7b067..8794749252 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.html
@@ -49,10 +49,16 @@
                 </div>
             </wicket:fragment>
         </div>
-        <wicket:container wicket:id="reflection">
+        <div wicket:id="reflection">
+            <wicket:enclosure>
+                <div class="alert alert-danger">
+                    <h4 class="alert-heading">Improvements requested</h4>
+                    <wicket:container wicket:id="improvementsNeeded"/>
+                </div>
+            </wicket:enclosure>
             <a wicket:id="showReflection" href="#">View reflection</a>
             <div wicket:id="modal"></div>
-        </wicket:container>
+        </div>
     </fieldset>
 </wicket:panel>
 </body>
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
index e5475c42ed..011cb74f9f 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/grading/CriteriaPanel.java
@@ -30,10 +30,12 @@ import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.finalseminar.FinalSeminarService;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
 import se.su.dsv.scipro.reflection.ReflectionService;
 import se.su.dsv.scipro.report.AbstractGradingCriterion;
 import se.su.dsv.scipro.report.GradingCriterion;
 import se.su.dsv.scipro.report.GradingCriterionPoint;
+import se.su.dsv.scipro.report.GradingReport;
 import se.su.dsv.scipro.report.SupervisorGradingReport;
 import se.su.dsv.scipro.system.Language;
 import se.su.dsv.scipro.system.User;
@@ -264,14 +266,33 @@ public class CriteriaPanel extends GenericPanel<SupervisorGradingReport> {
             super(id, author);
             this.gradingCriterion = gradingCriterion;
 
-            IModel<String> reflection = LoadableDetachableModel.of(() -> {
+            IModel<Reflection> reflection = LoadableDetachableModel.of(() -> {
                 Project project = CriteriaPanel.this.getModelObject().getProject();
-                return reflectionService.getSubmittedReflection(project, author.getObject());
+                return reflectionService.getReflection(project, author.getObject());
+            });
+            IModel<String> improvementsNeeded = reflection
+                    .as(Reflection.ImprovementsNeeded.class)
+                    .map(Reflection.ImprovementsNeeded::commentBySupervisor);
+
+            add(new MultiLineLabel("improvementsNeeded", improvementsNeeded) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisible(!getDefaultModelObjectAsString().isBlank());
+                }
             });
 
             modal = new LargeModalWindow("modal");
             modal.setTitle("Reflection");
-            modal.setContent(id_ -> new MultiLineLabel(id_, new NullReplacementModel(reflection, "No reflection filled in.")));
+            modal.setContent(modalBodyId -> {
+                IModel<Project> projectModel = CriteriaPanel.this.getModel().map(GradingReport::getProject);
+                return new ReflectionModalBodyPanel(modalBodyId, projectModel, author);
+            });
+            this.setOutputMarkupId(true);
+            this.setOutputMarkupPlaceholderTag(true);
+            modal.onClose(target -> {
+                target.add(ReflectionFeedbackPanel.this);
+            });
             add(modal);
 
             WebMarkupContainer showReflection = new WebMarkupContainer("showReflection") {
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java
index d76881782b..6dff147635 100644
--- a/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/grading/IndividualAuthorAssessmentPanel.java
@@ -128,7 +128,7 @@ public class IndividualAuthorAssessmentPanel extends GenericPanel<User> {
 
         IModel<Integer> minimumActiveParticipationsToBeGraded = LoadableDetachableModel.of(() -> {
             Project project = projectModel.getObject();
-            return project.getProjectType().getProjectTypeSettings().getMinimumActiveParticipationsToBeGraded();
+            return project.getProjectType().getProjectTypeSettings().getMinActiveParticipationsToBeGraded();
         });
         IModel<Integer> completedParticipations = LoadableDetachableModel.of(() -> {
             Project project = projectModel.getObject();
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html
new file mode 100644
index 0000000000..7840492505
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.html
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+<body>
+<wicket:panel>
+    <wicket:enclosure>
+        <div class="alert alert-info">
+            <h4 class="alert-heading">
+                <wicket:message key="improvements_requested">
+                    You've requested improvements to the submitted version.
+                </wicket:message>
+            </h4>
+            <wicket:container wicket:id="improvements_needed_supervisor_feedback">
+                [Supervisor feedback on needed improvements]
+            </wicket:container>
+        </div>
+    </wicket:enclosure>
+
+    <wicket:container wicket:id="reflection_text">
+        [Authors submitted reflection]
+    </wicket:container>
+
+    <button class="btn btn-outline-secondary" wicket:id="show_edit_reflection_form">
+        <wicket:message key="edit_reflection">
+            Edit reflection
+        </wicket:message>
+    </button>
+    <button class="btn btn-outline-secondary" wicket:id="show_request_improvements_form">
+        <wicket:message key="request_improvements">
+            Request improvements
+        </wicket:message>
+    </button>
+
+    <form wicket:id="request_improvements_form">
+        <hr>
+        <p>
+            <wicket:message key="request_improvements_text">
+                Please provide feedback on what improvements are needed in the submitted version.
+            </wicket:message>
+        </p>
+        <div class="mb-3">
+            <label class="form-label" wicket:for="comment">
+                <wicket:message key="comment">
+                    Comment
+                </wicket:message>
+            </label>
+            <textarea class="form-control" wicket:id="comment" rows="5"></textarea>
+        </div>
+        <button class="btn btn-primary" wicket:id="submit">
+            <wicket:message key="request_improvements">
+                Request improvements
+            </wicket:message>
+        </button>
+        <button class="btn btn-link" wicket:id="cancel">
+            <wicket:message key="cancel">
+                Cancel
+            </wicket:message>
+        </button>
+    </form>
+
+    <form wicket:id="edit_reflection_form">
+        <div class="mb-3">
+            <label class="form-label">
+                <wicket:message key="reflection">
+                    Reflection
+                </wicket:message>
+            </label>
+            <textarea class="form-control" wicket:id="reflection" rows="10"></textarea>
+        </div>
+        <button class="btn btn-primary" wicket:id="submit">
+            <wicket:message key="save">
+                Save
+            </wicket:message>
+        </button>
+        <button class="btn btn-link" wicket:id="cancel">
+            <wicket:message key="cancel">
+                Cancel
+            </wicket:message>
+        </button>
+    </form>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java
new file mode 100644
index 0000000000..895e65018f
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.java
@@ -0,0 +1,191 @@
+package se.su.dsv.scipro.grading;
+
+import jakarta.inject.Inject;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.basic.MultiLineLabel;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
+import se.su.dsv.scipro.reflection.ReflectionService;
+import se.su.dsv.scipro.system.User;
+
+/**
+ * This is not meant to be a re-usable panel and is made specifically to be used
+ * as the body of the modal dialog that opens when a supervisor views the
+ * author's reflection as they're doing their final individual assessment.
+ */
+class ReflectionModalBodyPanel extends Panel {
+    @Inject
+    private ReflectionService reflectionService;
+
+    private final IModel<Project> projectModel;
+    private final IModel<User> authorModel;
+
+    private enum State { VIEWING, REQUESTING_IMPROVEMENTS, EDITING }
+
+    private State state = State.VIEWING;
+
+    ReflectionModalBodyPanel(String id, IModel<Project> projectModel, IModel<User> authorModel) {
+        super(id);
+        this.projectModel = projectModel;
+        this.authorModel = authorModel;
+
+        setOutputMarkupPlaceholderTag(true); // enable ajax refreshing of the entire body
+
+        IModel<Reflection> reflectionModel = projectModel.combineWith(authorModel, reflectionService::getReflection);
+
+        add(new MultiLineLabel("reflection_text", reflectionModel.map(this::getReflectionText)) {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                setVisible(state != State.EDITING);
+            }
+        });
+
+        add(new MultiLineLabel("improvements_needed_supervisor_feedback", reflectionModel
+                .as(Reflection.ImprovementsNeeded.class)
+                .map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                setVisible(!getDefaultModelObjectAsString().isBlank());
+            }
+        });
+
+        add(new RequestImprovementsForm("request_improvements_form", reflectionModel));
+        add(new SupervisorEditReflectionForm("edit_reflection_form", reflectionModel));
+
+        add(new AjaxLink<>("show_request_improvements_form", reflectionModel) {
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                ReflectionModalBodyPanel.this.state = State.REQUESTING_IMPROVEMENTS;
+                target.add(ReflectionModalBodyPanel.this);
+            }
+
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                Reflection reflection = getModelObject();
+                boolean canRequestImprovements = reflection instanceof Reflection.Submitted;
+                setVisible(state == State.VIEWING && canRequestImprovements && isEnabledInHierarchy());
+            }
+        });
+
+        add(new AjaxLink<>("show_edit_reflection_form", reflectionModel) {
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                ReflectionModalBodyPanel.this.state = State.EDITING;
+                target.add(ReflectionModalBodyPanel.this);
+            }
+
+            @Override
+            protected void onConfigure() {
+                super.onConfigure();
+                Reflection reflection = getModelObject();
+                boolean canEditReflection = reflection instanceof Reflection.Submitted || reflection instanceof Reflection.ImprovementsNeeded;
+                setVisible(state == State.VIEWING && canEditReflection && isEnabledInHierarchy());
+            }
+        });
+    }
+
+    private String getReflectionText(Reflection reflection) {
+        if (reflection instanceof Reflection.Submitted submitted) {
+            return submitted.reflection();
+        } else if (reflection instanceof Reflection.ImprovementsNeeded improvementsNeeded) {
+            return improvementsNeeded.oldReflection();
+        } else {
+            return getString("reflection_not_submitted");
+        }
+    }
+
+    @Override
+    protected void onDetach() {
+        this.projectModel.detach();
+        this.authorModel.detach();
+        super.onDetach();
+    }
+
+    private class RequestImprovementsForm extends Form<Reflection> {
+        public RequestImprovementsForm(String id, IModel<Reflection> reflectionModel) {
+            super(id, reflectionModel);
+
+            IModel<String> commentModel = new Model<>();
+
+            TextArea<String> comment = new TextArea<>("comment", commentModel);
+            comment.setRequired(true);
+            add(comment);
+
+            add(new AjaxSubmitLink("submit") {
+                @Override
+                protected void onSubmit(AjaxRequestTarget target) {
+                    super.onSubmit(target);
+
+                    reflectionService.requestNewReflection(
+                            projectModel.getObject(),
+                            authorModel.getObject(),
+                            commentModel.getObject());
+
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+            add(new AjaxLink<>("cancel") {
+                @Override
+                public void onClick(AjaxRequestTarget target) {
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+        }
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            setVisible(state == State.REQUESTING_IMPROVEMENTS && getModelObject() instanceof Reflection.Submitted);
+        }
+    }
+
+    private class SupervisorEditReflectionForm extends Form<Reflection> {
+        public SupervisorEditReflectionForm(String id, IModel<Reflection> reflectionModel) {
+            super(id, reflectionModel);
+
+            IModel<String> reflectionTextModel = new Model<>(getReflectionText(reflectionModel.getObject()));
+
+            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionTextModel);
+            reflectionTextArea.setRequired(true);
+            add(reflectionTextArea);
+
+            add(new AjaxSubmitLink("submit") {
+                @Override
+                protected void onSubmit(AjaxRequestTarget target) {
+                    reflectionService.submitReflection(
+                            projectModel.getObject(),
+                            authorModel.getObject(),
+                            reflectionTextModel.getObject());
+
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+            add(new AjaxLink<>("cancel") {
+                @Override
+                public void onClick(AjaxRequestTarget target) {
+                    ReflectionModalBodyPanel.this.state = State.VIEWING;
+                    target.add(ReflectionModalBodyPanel.this);
+                }
+            });
+        }
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            setVisible(state == State.EDITING);
+        }
+    }
+}
diff --git a/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties
new file mode 100644
index 0000000000..cf818f1e92
--- /dev/null
+++ b/view/src/main/java/se/su/dsv/scipro/grading/ReflectionModalBodyPanel.utf8.properties
@@ -0,0 +1,10 @@
+improvements_requested=You've requested improvements to the submitted version.
+request_improvements=Request improvements
+comment=Comment
+reflection_not_submitted=Reflection not submitted yet
+request_improvements_text=If the submitted reflection does not meet the minimum requirements \
+  you can request improvements from the student. The student will be notified and can submit a new reflection. \
+  Use the comment field to provide feedback to the student.
+edit_reflection=Edit reflection
+reflection=Reflection
+cancel=Cancel
diff --git a/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java b/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java
index da362486f4..51f921ae60 100644
--- a/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/match/SupervisorIdeaDetailsPage.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.match;
 
-import com.google.inject.Inject;
+import jakarta.inject.Inject;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.util.string.StringValue;
 import se.su.dsv.scipro.components.menuhighlighting.MenuHighlightSupervisorMyIdeas;
diff --git a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
index b3b73a4bec..0fc12af49a 100644
--- a/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
+++ b/view/src/main/java/se/su/dsv/scipro/notifications/pages/NotificationLandingPage.java
@@ -158,7 +158,7 @@ public class NotificationLandingPage extends WebPage {
                     setResponsePage(RoughDraftApprovalDecisionPage.class, reviewerParameters);
                 }
                 break;
-            case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED:
+            case REVIEWER_GRADING_INITIAL_ASSESSMENT_DONE, REVIEWER_GRADING_REPORT_SUBMITTED, REFLECTION_IMPROVEMENTS_SUBMITTED:
                 if (project.isSupervisor(currentUser)) {
                     setResponsePage(SupervisorGradingReportPage.class, pp);
                 }
diff --git a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java
index 2c6818bb3e..7679a75eba 100644
--- a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.java
@@ -38,7 +38,7 @@ public class DisplayQuestionPanel extends GenericPanel<Answer> {
                 return "images/icons/bullet_ball_glass_red.png";
             case GREEN:
                 return "images/icons/bullet_ball_glass_green.png";
-            case NOT_APLICABLE:
+            case NOT_APPLICABLE:
                 return "images/icons/bullet_ball_glass_grey.png";
             default:
                 throw new IllegalStateException("unknown answer");
diff --git a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties
index 83808b9c7e..a2d4ad4158 100644
--- a/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties
+++ b/view/src/main/java/se/su/dsv/scipro/peer/DisplayQuestionPanel.properties
@@ -2,4 +2,4 @@ no.motivation= No motivation written
 YELLOW= Minor corrections
 RED= Not done
 GREEN= Ok
-NOT_APLICABLE= Not applicable
\ No newline at end of file
+NOT_APPLICABLE= Not applicable
\ No newline at end of file
diff --git a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java
index 5cca6a2310..144dd24f30 100644
--- a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewFilterDetailsPanel.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.peer;
 
-import com.google.inject.Inject;
+import jakarta.inject.Inject;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.Model;
diff --git a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java
index 18381874c6..2193555a56 100644
--- a/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/peer/PeerReviewStatusStatisticsPanel.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.peer;
 
-import com.google.inject.Inject;
+import jakarta.inject.Inject;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
index a50d6d7828..6cc7d5661d 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.html
@@ -38,6 +38,30 @@
                 <div wicket:id="current_thesis_file"></div>
             </div>
         </wicket:enclosure>
+        <wicket:enclosure child="old_reflection">
+            <div class="alert alert-info">
+                <h4 class="alert-heading">
+                    <wicket:message key="reflection_improvements_needed_heading">
+                        Reflection improvements needed
+                    </wicket:message>
+                </h4>
+                <p>
+                    <wicket:message key="reflection_improvements_needed">
+                        Your supervisor has requested that you improve and resubmit your reflection.
+                        See their comments below about what changes are necessary.
+                    </wicket:message>
+                </p>
+                <p wicket:id="supervisor_comment">
+                    [You need to reflect more on the methods you used.]
+                </p>
+            </div>
+            <h4>
+                <wicket:message key="old_reflection">
+                    Your previous reflection
+                </wicket:message>
+            </h4>
+            <p wicket:id="old_reflection"></p>
+        </wicket:enclosure>
         <div class="mb-3">
             <label class="form-label" wicket:for="reflection">
                 <wicket:message key="reflection">[Reflection]</wicket:message>
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
index 0283f15c13..95d9fb319a 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.java
@@ -24,6 +24,7 @@ import se.su.dsv.scipro.grading.PublicationMetadata;
 import se.su.dsv.scipro.grading.PublicationMetadataFormComponentPanel;
 import se.su.dsv.scipro.grading.PublicationMetadataService;
 import se.su.dsv.scipro.project.Project;
+import se.su.dsv.scipro.reflection.Reflection;
 import se.su.dsv.scipro.reflection.ReflectionService;
 import se.su.dsv.scipro.session.SciProSession;
 
@@ -45,17 +46,20 @@ public class FinalStepsPanel extends GenericPanel<Project> {
 
         add(new FencedFeedbackPanel("feedback", this));
 
-        IModel<String> reflection = LoadableDetachableModel.of(() ->
-                reflectionService.getSubmittedReflection(projectModel.getObject(), SciProSession.get().getUser()));
-        add(new MultiLineLabel("reflection", reflection) {
+        IModel<Reflection> currentReflection = LoadableDetachableModel.of(() ->
+                reflectionService.getReflection(projectModel.getObject(), SciProSession.get().getUser()));
+        IModel<String> reflectionText = currentReflection
+                .as(Reflection.Submitted.class)
+                .map(Reflection.Submitted::reflection);
+        add(new MultiLineLabel("reflection", reflectionText) {
             @Override
             protected void onConfigure() {
                 super.onConfigure();
-                setVisible(getDefaultModelObject() != null);
+                setVisible(!getDefaultModelObjectAsString().isBlank());
             }
         });
 
-        add(new FinalStepsForm("submit_reflection", projectModel));
+        add(new FinalStepsForm("submit_reflection", projectModel, currentReflection));
     }
 
     @Override
@@ -67,22 +71,49 @@ public class FinalStepsPanel extends GenericPanel<Project> {
     private class FinalStepsForm extends Form<Project> {
         private final FinalThesisUploadComponent thesisFileUpload;
         private final IModel<PublicationMetadata> publicationMetadataModel;
+        private final IModel<Reflection> currentReflection;
         private IModel<String> reflectionModel;
         private IModel<PublishingConsentService.Level> levelModel;
 
-        public FinalStepsForm(String id, IModel<Project> projectModel) {
+        public FinalStepsForm(String id, IModel<Project> projectModel, IModel<Reflection> currentReflection) {
             super(id, projectModel);
 
+            this.currentReflection = currentReflection;
+
+            IModel<Reflection.ImprovementsNeeded> improvementsNeeded = this.currentReflection.as(Reflection.ImprovementsNeeded.class);
+
+            IModel<String> oldReflection = improvementsNeeded.map(Reflection.ImprovementsNeeded::oldReflection);
+            add(new MultiLineLabel("old_reflection", oldReflection) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
+                }
+            });
+
+            add(new MultiLineLabel("supervisor_comment", improvementsNeeded.map(Reflection.ImprovementsNeeded::commentBySupervisor)) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisibilityAllowed(!getDefaultModelObjectAsString().isBlank());
+                }
+            });
 
             reflectionModel = new Model<>();
-            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel);
+            TextArea<String> reflectionTextArea = new TextArea<>("reflection", reflectionModel) {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisible(FinalStepsForm.this.currentReflection.getObject().isSubmittable());
+                }
+            };
             reflectionTextArea.setRequired(true);
             add(reflectionTextArea);
 
             IModel<PublishingConsentService.PublishingConsent> publishingConsent = LoadableDetachableModel.of(() ->
                     publishingConsentService.getPublishingConsent(getModelObject(), SciProSession.get().getUser()));
 
-            levelModel = new Model<>();
+            levelModel = new Model<>(publishingConsent.getObject().selected());
             FormComponent<PublishingConsentService.Level> publishingConsentLevel = new BootstrapRadioChoice<>(
                     "publishingConsentLevel",
                     levelModel,
@@ -111,7 +142,13 @@ public class FinalStepsPanel extends GenericPanel<Project> {
             currentThesisFile.add(new OppositeVisibility(thesisFileUpload));
             add(currentThesisFile);
             publicationMetadataModel = LoadableDetachableModel.of(() -> publicationMetadataService.getByProject(getModelObject()));
-            WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata");
+            WebMarkupContainer publicationMetadata = new WebMarkupContainer("publication_metadata") {
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setEnabled(finalThesisService.isUploadAllowed(FinalStepsPanel.FinalStepsForm.this.getModelObject()));
+                }
+            };
             add(publicationMetadata);
             publicationMetadata.add(new PublicationMetadataFormComponentPanel("publication_metadata_components", publicationMetadataModel));
         }
@@ -119,7 +156,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
         @Override
         protected void onConfigure() {
             super.onConfigure();
-            setVisibilityAllowed(reflectionService.hasToFillInReflection(getModelObject(), SciProSession.get().getUser()));
+            setVisibilityAllowed(currentReflection.getObject().isSubmittable());
         }
 
         @Override
@@ -131,6 +168,7 @@ public class FinalStepsPanel extends GenericPanel<Project> {
                         new WicketProjectFileUpload(finalThesisUpload.fileUpload(), FinalStepsPanel.this.getModelObject()),
                         finalThesisUpload.englishTitle(),
                         finalThesisUpload.swedishTitle());
+                success(getString("final_thesis_uploaded"));
             }
             reflectionService.submitReflection(getModelObject(), SciProSession.get().getUser(), reflectionModel.getObject());
             if (levelModel.getObject() != null) {
diff --git a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
index a0f79eb71a..f21ad3bd37 100644
--- a/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/project/panels/FinalStepsPanel.utf8.properties
@@ -9,3 +9,8 @@ current_final_thesis=Final thesis
 publication_metadata_why=Please provide the following metadata.
 englishTitle=English title
 swedishTitle=Swedish title
+reflection_improvements_needed_heading=Reflection improvements needed
+reflection_improvements_needed=Your supervisor has requested that you improve and resubmit your reflection. \
+See their comments below about what changes are necessary.
+old_reflection=Your previous reflection
+final_thesis_uploaded=Final thesis uploaded
diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html
index bf546f6a76..13c72afcac 100644
--- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html
+++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn$ViewAndEditNoteForm.html
@@ -6,7 +6,7 @@
         <div wicket:id="feedback"></div>
         <div class="mb-3">
             <label wicket:for="note" class="sr-only">Note</label>
-            <textarea wicket:id="note" rows="20" class="form-control"></textarea>
+            <textarea wicket:id="note" rows="7" class="form-control"></textarea>
         </div>
         <button wicket:id="save" type="submit" class="btn btn-primary">Save</button>
     </form>
diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java
index b35962f891..77424cf02a 100644
--- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java
+++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/ProjectNoteColumn.java
@@ -51,11 +51,8 @@ public class ProjectNoteColumn extends AbstractExportableColumn<Project, String>
     }
 
     @Override
-    public void populateItem(
-            Item<ICellPopulator<Project>> cellItem,
-            String componentId,
-            IModel<Project> rowModel)
-    {
+    public void populateItem(Item<ICellPopulator<Project>> cellItem, String componentId,
+                             IModel<Project> rowModel) {
         cellItem.add(new ViewAndEditNoteCellPanel(componentId, rowModel));
     }
 
diff --git a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java
index 3a39a1088c..32920d25d7 100644
--- a/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/supervisor/panels/SupervisorApprovalPanel.java
@@ -1,6 +1,6 @@
 package se.su.dsv.scipro.supervisor.panels;
 
-import com.google.inject.Inject;
+import jakarta.inject.Inject;
 import org.apache.wicket.feedback.FencedFeedbackPanel;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.OnEventHeaderItem;
diff --git a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
index 74aa56c867..97ea5d57c3 100644
--- a/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
+++ b/view/src/main/java/se/su/dsv/scipro/wicket-package.utf8.properties
@@ -65,6 +65,8 @@ ProjectEvent.FIRST_MEETING = First meeting created. (with date, time, place/room
 ProjectEvent.OPPOSITION_FAILED = An author fails their opposition.
 ProjectEvent.PARTICIPATION_APPROVED = An author's active participation is approved.
 ProjectEvent.PARTICIPATION_FAILED = An author fails their active participation.
+ProjectEvent.REFLECTION_IMPROVEMENTS_REQUESTED = Reflection improvements requested.
+ProjectEvent.REFLECTION_IMPROVEMENTS_SUBMITTED = Reflection improvements submitted.
 
 ProjectForumEvent.NEW_FORUM_POST = Forum thread created.
 ProjectForumEvent.NEW_FORUM_POST_COMMENT = Comment posted in forum thread.
diff --git a/view/src/main/resources/META-INF/services/com.google.inject.Module b/view/src/main/resources/META-INF/services/com.google.inject.Module
deleted file mode 100644
index c0c493be41..0000000000
--- a/view/src/main/resources/META-INF/services/com.google.inject.Module
+++ /dev/null
@@ -1,15 +0,0 @@
-se.su.dsv.scipro.SciProModule
-se.su.dsv.scipro.reviewing.ReviewingModule
-se.su.dsv.scipro.crosscutting.CrosscuttingModule
-se.su.dsv.scipro.integration.activityfinalseminar.ActivityFinalSeminarModule
-se.su.dsv.scipro.integration.activityforum.ActivityForumModule
-se.su.dsv.scipro.peer.PeerModule
-se.su.dsv.scipro.firstmeeting.FirstMeetingModule
-se.su.dsv.scipro.forum.notifications.ForumNotificationsModule
-se.su.dsv.scipro.daisyExternal.DaisyExternalModule
-se.su.dsv.scipro.plagiarism.urkund.UrkundModule
-se.su.dsv.scipro.sukat.SukatModule
-se.su.dsv.scipro.oauth.OAuthModule
-se.su.dsv.scipro.grading.GradingModule
-se.su.dsv.scipro.gdpr.GDPRModule
-se.su.dsv.scipro.survey.SurveyModule
diff --git a/view/src/main/webapp/WEB-INF/web.xml b/view/src/main/webapp/WEB-INF/web.xml
deleted file mode 100755
index bf2a938984..0000000000
--- a/view/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
-         version="4.0" metadata-complete="true">
-
-    <display-name>SciPro</display-name>
-
-    <filter>
-        <filter-name>guiceFilter</filter-name>
-        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
-    </filter>
-    <filter-mapping>
-        <filter-name>guiceFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
-    <listener>
-        <listener-class>ApplicationBootstrap</listener-class>
-    </listener>
-
-    <listener>
-        <listener-class>DatabaseMigration</listener-class>
-    </listener>
-
-    <session-config>
-        <session-timeout>480</session-timeout>
-    </session-config>
-</web-app>
diff --git a/view/src/test/java/se/su/dsv/scipro/SciProTest.java b/view/src/test/java/se/su/dsv/scipro/SciProTest.java
index ee39fc8b41..2b469c39ec 100755
--- a/view/src/test/java/se/su/dsv/scipro/SciProTest.java
+++ b/view/src/test/java/se/su/dsv/scipro/SciProTest.java
@@ -1,17 +1,13 @@
 package se.su.dsv.scipro;
 
 import com.google.common.eventbus.EventBus;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.multibindings.Multibinder;
-import com.google.inject.name.Names;
 import org.apache.wicket.Component;
 import org.apache.wicket.Page;
 import org.apache.wicket.Session;
-import org.apache.wicket.guice.GuiceComponentInjector;
 import org.apache.wicket.request.Request;
 import org.apache.wicket.request.Response;
+import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
+import org.apache.wicket.spring.test.ApplicationContextMock;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -143,6 +139,7 @@ import java.util.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
 public abstract class SciProTest {
@@ -364,9 +361,12 @@ public abstract class SciProTest {
     @BeforeEach
     public void setUpApplication() {
         final Class<? extends SciProTest> clazz = getClass();
-        final Injector injector = Guice.createInjector(new MockModule(clazz));
+        ApplicationContextMock applicationContext = new MockModule(clazz);
 
-        SciProApplication application = new SciProApplication(injector.getInstance(CurrentProfile.class)) {
+        CurrentProfile currentProfile = new CurrentProfile();
+        currentProfile.setCurrentProfileString("TEST");
+
+        SciProApplication application = new SciProApplication(currentProfile) {
 
             @Override
             public Session newSession(Request request, Response response) {
@@ -374,7 +374,7 @@ public abstract class SciProTest {
             }
         };
         application.getComponentInstantiationListeners().add(
-                new GuiceComponentInjector(application, injector));
+                new SpringComponentInjector(application, applicationContext));
         tester = new WicketTester(application, System.getProperty("user.dir") + "/src/main/webapp");
 
         setLoggedIn(true);
@@ -391,6 +391,8 @@ public abstract class SciProTest {
                     publicationMetadata.setProject(answer.getArgument(0));
                     return publicationMetadata;
                 });
+        lenient().when(publishingConsentService.getPublishingConsent(any(), any()))
+                .thenReturn(new PublishingConsentService.PublishingConsent(null, List.of()));
     }
 
     @BeforeEach
@@ -467,27 +469,23 @@ public abstract class SciProTest {
         return sb.toString();
     }
 
-    private class MockModule extends AbstractModule {
+    private class MockModule extends ApplicationContextMock {
         private final Class<? extends SciProTest> clazz;
 
         public MockModule(Class<? extends SciProTest> clazz) {
             this.clazz = clazz;
+            configure();
         }
 
         @SuppressWarnings("unchecked")
-        @Override
-        protected void configure() {
-            Multibinder.newSetBinder(binder(), Lifecycle.class);
-            Multibinder.newSetBinder(binder(), UserImportService.class)
-                    .addBinding().toInstance(userImportService);
-            bindConstant().annotatedWith(Names.named("profile")).to("TEST");
-            bind(Clock.class).toInstance(Clock.systemDefaultZone());
+        private void configure() {
+            putBean(Clock.systemDefaultZone());
             for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
                 for (Field f : c.getDeclaredFields()) {
                     if (f.getAnnotation(Mock.class) != null && f.trySetAccessible()) {
                         try {
                             Class<Object> type = (Class<Object>) f.getType();
-                            bind(type).toInstance(f.get(SciProTest.this));
+                            putBean(f.getName(), f.get(SciProTest.this));
                         } catch (IllegalAccessException e) {
                             throw new RuntimeException(e);
                         }
diff --git a/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java b/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java
index d8785aca19..b6c0e57856 100644
--- a/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java
+++ b/view/src/test/java/se/su/dsv/scipro/checklists/TrafficLightPanelTest.java
@@ -25,7 +25,7 @@ public class TrafficLightPanelTest extends SciProTest {
 
     @Test
     public void renders_not_applicable() {
-        startPanel(Model.of(ChecklistAnswerEnum.NOT_APLICABLE));
+        startPanel(Model.of(ChecklistAnswerEnum.NOT_APPLICABLE));
     }
 
     @Test
diff --git a/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java b/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java
index 56212cd5d9..fbb66e7b45 100644
--- a/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java
+++ b/view/src/test/java/se/su/dsv/scipro/peer/DisplayQuestionPanelTest.java
@@ -28,7 +28,7 @@ public class DisplayQuestionPanelTest extends SciProTest {
 
     @Test
     public void renders_with_not_applicable_answer() {
-        startPanel(ChecklistAnswerEnum.NOT_APLICABLE, "motivation");
+        startPanel(ChecklistAnswerEnum.NOT_APPLICABLE, "motivation");
     }
 
     @Test
diff --git a/war/pom.xml b/war/pom.xml
new file mode 100644
index 0000000000..2c4ad17242
--- /dev/null
+++ b/war/pom.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>se.su.dsv.scipro</groupId>
+        <artifactId>SciPro</artifactId>
+        <version>0.1-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>war</artifactId>
+    <packaging>war</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <!-- exclude default logging implementation (logback) since we want log4j2 -->
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-orm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate.orm</groupId>
+            <artifactId>hibernate-core</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.wicket</groupId>
+            <artifactId>wicket-spring</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>se.su.dsv.scipro</groupId>
+            <artifactId>view</artifactId>
+            <version>${project.version}</version>
+            <type>war</type>
+        </dependency>
+        <dependency>
+            <!-- needed only at compile time -->
+            <!-- the classes will be moved as part of the overlay by the war plugin -->
+            <groupId>se.su.dsv.scipro</groupId>
+            <artifactId>view</artifactId>
+            <version>${project.version}</version>
+            <classifier>classes</classifier>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>se.su.dsv.scipro</groupId>
+            <artifactId>api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.4.0</version>
+                <configuration>
+                    <overlays>
+                        <overlay>
+                            <groupId>se.su.dsv.scipro</groupId>
+                            <artifactId>view</artifactId>
+                            <type>war</type>
+                        </overlay>
+                    </overlays>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java b/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java
new file mode 100644
index 0000000000..f8b410b8aa
--- /dev/null
+++ b/war/src/main/java/se/su/dsv/scipro/war/ApiConfig.java
@@ -0,0 +1,72 @@
+package se.su.dsv.scipro.war;
+
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
+import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
+
+import java.util.List;
+
+@Configuration(proxyBeanMethods = false)
+@ComponentScan("se.su.dsv.scipro.api")
+public class ApiConfig {
+    @Bean
+    @Order(1)
+    public SecurityFilterChain documentationSecurity(
+            HttpSecurity http,
+            HandlerMappingIntrospector introspector,
+            WebMvcProperties webMvcProperties)
+            throws Exception
+    {
+        MvcRequestMatcher.Builder mvc = new MvcRequestMatcher.Builder(introspector)
+                .servletPath(webMvcProperties.getServlet().getPath());
+        return http
+                .securityMatchers(matchers -> matchers
+                        .requestMatchers(
+                                mvc.pattern("/v3/api-docs/**"),
+                                mvc.pattern("/swagger"),
+                                mvc.pattern("/swagger-ui/**")))
+                .authorizeHttpRequests(authorize -> authorize.anyRequest().permitAll())
+                .build();
+    }
+
+    @Bean
+    @Order(2)
+    public SecurityFilterChain apiSecurity(
+            HttpSecurity http,
+            HandlerMappingIntrospector introspector,
+            WebMvcProperties webMvcProperties)
+            throws Exception
+    {
+        MvcRequestMatcher.Builder mvc = new MvcRequestMatcher.Builder(introspector)
+                .servletPath(webMvcProperties.getServlet().getPath());
+        return http
+                .securityMatcher(mvc.pattern("/**"))
+                .authorizeHttpRequests(authorize -> authorize
+                        .anyRequest().authenticated())
+                .oauth2ResourceServer(oauth2 -> oauth2.opaqueToken(Customizer.withDefaults()))
+                .build();
+    }
+
+    @Bean
+    public OpenAPI customOpenAPI() {
+        return new OpenAPI()
+                .security(List.of(new SecurityRequirement().addList("access-token")))
+                .components(new Components()
+                        .addSecuritySchemes("access-token", new SecurityScheme()
+                                .type(SecurityScheme.Type.HTTP)
+                                .in(SecurityScheme.In.HEADER)
+                                .scheme("bearer")
+                                .bearerFormat("opaque")));
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/mail/MailModule.java b/war/src/main/java/se/su/dsv/scipro/war/MailConfig.java
similarity index 52%
rename from core/src/main/java/se/su/dsv/scipro/mail/MailModule.java
rename to war/src/main/java/se/su/dsv/scipro/war/MailConfig.java
index c23bc66811..a96c89f56c 100644
--- a/core/src/main/java/se/su/dsv/scipro/mail/MailModule.java
+++ b/war/src/main/java/se/su/dsv/scipro/war/MailConfig.java
@@ -1,38 +1,40 @@
-package se.su.dsv.scipro.mail;
-
-import com.google.inject.Exposed;
-import com.google.inject.PrivateModule;
-import com.google.inject.Provides;
-import se.su.dsv.scipro.file.FileService;
-import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
-import se.su.dsv.scipro.profiles.CurrentProfile;
+package se.su.dsv.scipro.war;
 
 import jakarta.mail.Session;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import se.su.dsv.scipro.data.facade.MailFacade;
+import se.su.dsv.scipro.file.FileService;
+import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
+import se.su.dsv.scipro.mail.Mail;
+import se.su.dsv.scipro.mail.Mailer;
+import se.su.dsv.scipro.mail.PrintingMailer;
+import se.su.dsv.scipro.mail.RedirectingMailer;
+import se.su.dsv.scipro.profiles.CurrentProfile;
+
 import java.util.Properties;
 
-public class MailModule extends PrivateModule {
-
-    private static final String TEST_MAIL_SINK = "scipro-mailtest@dsv.su.se";
-
-    @Override
-    protected void configure() {
-        requireBinding(CurrentProfile.class);
-        requireBinding(GeneralSystemSettingsService.class);
-        bind(MailEventService.class).to(MailEventServiceImpl.class);
-        expose(MailEventService.class);
+@Configuration(proxyBeanMethods = false)
+public class MailConfig {
+    @Bean
+    public MailFacade mailFacade() {
+        return new MailFacade();
     }
 
-    @Provides
-    @Exposed
-    public Mailer mailer(CurrentProfile currentProfile, Session session, FileService fileDescriptionService) {
+    @Bean
+    public Mailer mailer(
+            CurrentProfile currentProfile,
+            Session session,
+            FileService fileDescriptionService)
+    {
         return switch (currentProfile.getCurrentProfile()) {
             case DEV -> new PrintingMailer();
             case PROD -> new Mail(session, fileDescriptionService);
-            case TEST -> new RedirectingMailer(session, TEST_MAIL_SINK, fileDescriptionService);
+            case TEST -> new RedirectingMailer(session, "scipro-mailtest@dsv.su.se", fileDescriptionService);
         };
     }
 
-    @Provides
+    @Bean
     public Session session(GeneralSystemSettingsService generalSystemSettings) {
         String smtpHost = generalSystemSettings.getGeneralSystemSettingsInstance().getSmtpServer();
         Properties properties = new Properties();
diff --git a/war/src/main/java/se/su/dsv/scipro/war/Main.java b/war/src/main/java/se/su/dsv/scipro/war/Main.java
new file mode 100644
index 0000000000..026130dd7d
--- /dev/null
+++ b/war/src/main/java/se/su/dsv/scipro/war/Main.java
@@ -0,0 +1,168 @@
+package se.su.dsv.scipro.war;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.servlet.ServletContainerInitializer;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilderCustomizer;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.orm.jpa.SharedEntityManagerCreator;
+import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
+import se.su.dsv.scipro.CoreConfig;
+import se.su.dsv.scipro.CurrentUserFromWicketSession;
+import se.su.dsv.scipro.FileSystemStore;
+import se.su.dsv.scipro.RepositoryConfiguration;
+import se.su.dsv.scipro.file.FileStore;
+import se.su.dsv.scipro.finalthesis.PublishingConsentService;
+import se.su.dsv.scipro.finalthesis.PublishingConsentUnavailable;
+import se.su.dsv.scipro.profiles.CurrentProfile;
+import se.su.dsv.scipro.system.AggregateUserSearch;
+import se.su.dsv.scipro.system.Lifecycle;
+import se.su.dsv.scipro.system.ResearchArea;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.system.UserImportService;
+import se.su.dsv.scipro.system.UserSearchProvider;
+import se.su.dsv.scipro.system.UserSearchService;
+import se.su.dsv.scipro.system.UserService;
+
+import java.time.Clock;
+import java.util.List;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+@SpringBootApplication(proxyBeanMethods = false)
+@EntityScan("se.su.dsv.scipro")
+@Import({
+        CoreConfig.class,
+        ApiConfig.class,
+        WorkerConfig.class,
+        MailConfig.class,
+        RepositoryConfiguration.class,
+        WicketConfiguration.class
+})
+public class Main extends SpringBootServletInitializer implements ServletContainerInitializer {
+    @Override
+    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
+        onStartup(ctx);
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+        for (PluginConfiguration pluginConfiguration : ServiceLoader.load(PluginConfiguration.class)) {
+            builder.sources(pluginConfiguration.getClass());
+        }
+        return builder.sources(Main.class);
+    }
+
+    @Bean
+    public EntityManagerFactoryBuilderCustomizer entityManagerFactoryCustomizer() {
+        return factoryBuilder -> {
+            factoryBuilder.setBootstrapExecutor(new SimpleAsyncTaskExecutor());
+        };
+    }
+
+    @Bean
+    public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() {
+        return new OpenEntityManagerInViewFilter();
+    }
+
+    @Bean
+    public CurrentProfile currentProfile(@Value("${profile}" ) String profile) {
+        CurrentProfile currentProfile = new CurrentProfile();
+        currentProfile.setCurrentProfileString(profile);
+        return currentProfile;
+    }
+
+    @Bean
+    public CurrentUserFromWicketSession currentUserFromWicketSession() {
+        return new CurrentUserFromWicketSession();
+    }
+
+    @Bean
+    public FileStore fileStore() {
+        return new FileSystemStore();
+    }
+
+    @Bean
+    public Clock clock() {
+        return Clock.systemDefaultZone();
+    }
+
+    /**
+     * Allow injecting of {@link EntityManager} directly instead of {@link EntityManagerFactory}
+     */
+    @Bean
+    public EntityManager entityManager(EntityManagerFactory emf) {
+        return SharedEntityManagerCreator.createSharedEntityManager(emf);
+    }
+
+    /**
+     * Exists because Spring refuses to inject a collection of beans if there are no beans of that type.
+     */
+    @Bean
+    public UserImportService dummyUserImportService() {
+        return new UserImportService() {
+            @Override
+            public Optional<User> importUser(String userName) {
+                return Optional.empty();
+            }
+
+            @Override
+            public List<ImportableUser> search(String searchTerm) {
+                return List.of();
+            }
+
+            @Override
+            public void importUser(ImportableUser importableUser) {
+                // do nothing
+            }
+
+            @Override
+            public Set<ResearchArea> importResearchAreasForSupervisor(User supervisor) {
+                return Set.of();
+            }
+        };
+    }
+
+    /**
+     * Exists because Spring refuses to inject a collection of beans if there are no beans of that type.
+     */
+    @Bean
+    public Lifecycle dummyLifecycle() {
+        return new Lifecycle() {
+            @Override
+            public void start() {
+                // do nothing
+            }
+
+            @Override
+            public void stop() {
+                // do nothing
+            }
+        };
+    }
+
+    @Bean
+    public UserSearchService aggregateSearchService(
+            Set<UserSearchProvider> userSearchProviders,
+            UserService userService)
+    {
+        return new AggregateUserSearch(userSearchProviders, userService);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean(PublishingConsentService.class)
+    public PublishingConsentUnavailable publishingConsentService() {
+        return new PublishingConsentUnavailable();
+    }
+}
diff --git a/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java b/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java
new file mode 100644
index 0000000000..ae66a50e36
--- /dev/null
+++ b/war/src/main/java/se/su/dsv/scipro/war/SpringManagedWorkerTransactions.java
@@ -0,0 +1,50 @@
+package se.su.dsv.scipro.war;
+
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
+
+public class SpringManagedWorkerTransactions implements WorkerTransactionManager {
+    private final PlatformTransactionManager platformTransactionManager;
+
+    private TransactionStatus activeTransaction;
+
+    public SpringManagedWorkerTransactions(PlatformTransactionManager platformTransactionManager) {
+        this.platformTransactionManager = platformTransactionManager;
+    }
+
+    @Override
+    public void rollbackIfActive() {
+        if (this.activeTransaction != null) {
+            platformTransactionManager.rollback(this.activeTransaction);
+            this.activeTransaction = null;
+        }
+    }
+
+    @Override
+    public void begin() {
+        if (this.activeTransaction != null) {
+            throw new IllegalStateException("A transaction is already active");
+        }
+        this.activeTransaction = platformTransactionManager.getTransaction(TransactionDefinition.withDefaults());
+    }
+
+    @Override
+    public void commit() {
+        if (this.activeTransaction == null) {
+            throw new IllegalStateException("A transaction is not active");
+        }
+        platformTransactionManager.commit(this.activeTransaction);
+        this.activeTransaction = null;
+    }
+
+    @Override
+    public void rollback() {
+        if (this.activeTransaction == null) {
+            throw new IllegalStateException("A transaction is not active");
+        }
+        platformTransactionManager.rollback(this.activeTransaction);
+        this.activeTransaction = null;
+    }
+}
diff --git a/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java
new file mode 100644
index 0000000000..bb255d4915
--- /dev/null
+++ b/war/src/main/java/se/su/dsv/scipro/war/WicketConfiguration.java
@@ -0,0 +1,100 @@
+package se.su.dsv.scipro.war;
+
+import com.google.common.eventbus.EventBus;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.http.WicketFilter;
+import org.apache.wicket.spring.injection.annot.SpringComponentInjector;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import se.su.dsv.scipro.SciProApplication;
+import se.su.dsv.scipro.crosscutting.ForwardPhase2Feedback;
+import se.su.dsv.scipro.crosscutting.NotifyFailedReflection;
+import se.su.dsv.scipro.crosscutting.ReviewerAssignedNotifications;
+import se.su.dsv.scipro.crosscutting.ReviewerSupportMailer;
+import se.su.dsv.scipro.crosscutting.ReviewingNotifications;
+import se.su.dsv.scipro.forum.ProjectForumService;
+import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
+import se.su.dsv.scipro.mail.MailEventService;
+import se.su.dsv.scipro.notifications.NotificationController;
+import se.su.dsv.scipro.profiles.CurrentProfile;
+import se.su.dsv.scipro.reviewing.FinalSeminarApprovalService;
+import se.su.dsv.scipro.reviewing.RoughDraftApprovalService;
+
+@Configuration
+public class WicketConfiguration {
+    @Bean
+    public FilterRegistrationBean<WicketFilter> wicket(
+            WebApplication webApplication,
+            ApplicationContext applicationContext)
+    {
+        webApplication.getComponentInstantiationListeners()
+                .add(new SpringComponentInjector(webApplication, applicationContext));
+
+        WicketFilter filter = new WicketFilter(webApplication);
+        filter.setFilterPath("");
+
+        FilterRegistrationBean<WicketFilter> registration = new FilterRegistrationBean<>();
+        registration.setFilter(filter);
+        registration.addUrlPatterns("/*");
+        registration.setMatchAfter(true);
+        return registration;
+    }
+
+    @Bean
+    public WebApplication webApplication(CurrentProfile currentProfile) {
+        return new SciProApplication(currentProfile);
+    }
+
+    @Bean
+    public ReviewingNotifications reviewingNotifications(
+            EventBus eventBus,
+            NotificationController notificationController,
+            GeneralSystemSettingsService generalSystemSettingsService,
+            WebApplication webApplication)
+    {
+        return new ReviewingNotifications(eventBus, notificationController, generalSystemSettingsService,
+                webApplication);
+    }
+
+    @Bean
+    public ForwardPhase2Feedback forwardPhase2Feedback(
+            EventBus eventBus,
+            WebApplication webApplication,
+            ProjectForumService projectForumService)
+    {
+        return new ForwardPhase2Feedback(webApplication, projectForumService, eventBus);
+    }
+
+    // Not sure why this dependency lives in the view module
+    @Bean
+    public ReviewerSupportMailer reviewerSupportMailer(
+            EventBus eventBus,
+            GeneralSystemSettingsService generalSystemSettingsService,
+            MailEventService mailEventService)
+    {
+        return new ReviewerSupportMailer(eventBus, mailEventService, generalSystemSettingsService);
+    }
+
+    // Not sure why this dependency lives in the view module
+    @Bean
+    public ReviewerAssignedNotifications reviewerAssignedNotifications(
+            EventBus eventBus,
+            NotificationController notificationController,
+            RoughDraftApprovalService roughDraftApprovalService,
+            FinalSeminarApprovalService finalSeminarApprovalService)
+    {
+        return new ReviewerAssignedNotifications(roughDraftApprovalService,
+                finalSeminarApprovalService, notificationController, eventBus);
+    }
+
+    // Not sure why this dependency lives in the view module
+    @Bean
+    public NotifyFailedReflection notifyFailedReflection(
+            EventBus eventBus,
+            NotificationController notificationController)
+    {
+        return new NotifyFailedReflection(notificationController, eventBus);
+    }
+}
diff --git a/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java b/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java
new file mode 100644
index 0000000000..076bc219fc
--- /dev/null
+++ b/war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java
@@ -0,0 +1,245 @@
+package se.su.dsv.scipro.war;
+
+import com.google.common.eventbus.EventBus;
+import jakarta.inject.Provider;
+import jakarta.persistence.EntityManagerFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Scope;
+import org.springframework.transaction.PlatformTransactionManager;
+import se.su.dsv.scipro.file.FileService;
+import se.su.dsv.scipro.finalseminar.FinalSeminarService;
+import se.su.dsv.scipro.firstmeeting.FirstMeetingReminderWorker;
+import se.su.dsv.scipro.firstmeeting.FirstMeetingService;
+import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
+import se.su.dsv.scipro.mail.MailEventService;
+import se.su.dsv.scipro.mail.MailEventWorker;
+import se.su.dsv.scipro.mail.Mailer;
+import se.su.dsv.scipro.match.AllowAllIdeaCreationJudge;
+import se.su.dsv.scipro.match.ApplicationPeriodService;
+import se.su.dsv.scipro.match.IdeaCreationJudge;
+import se.su.dsv.scipro.match.IdeaService;
+import se.su.dsv.scipro.misc.DaysService;
+import se.su.dsv.scipro.peer.ExpiredRequestWorker;
+import se.su.dsv.scipro.peer.ExpiredReviewResetWorker;
+import se.su.dsv.scipro.peer.PeerWorkerSchedules;
+import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepository;
+import se.su.dsv.scipro.plagiarism.PlagiarismSubmitter;
+import se.su.dsv.scipro.plagiarism.urkund.StatusPollingWorker;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundApi;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundService;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSettings;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepository;
+import se.su.dsv.scipro.plagiarism.urkund.UrkundSubmissionRepository;
+import se.su.dsv.scipro.project.ProjectService;
+import se.su.dsv.scipro.projectpartner.ProjectPartnerRepository;
+import se.su.dsv.scipro.projectpartner.RemoveFulfilledPartnerAdsWorker;
+import se.su.dsv.scipro.reviewing.MyReviewService;
+import se.su.dsv.scipro.reviewing.ReviewerDecisionReminderWorker;
+import se.su.dsv.scipro.sukat.Sukat;
+import se.su.dsv.scipro.workerthreads.GradeFinalSeminarParticipantReminderWorker;
+import se.su.dsv.scipro.workerthreads.IdeaExportWorker;
+import se.su.dsv.scipro.workerthreads.ManualMatchRemindWorker;
+import se.su.dsv.scipro.workerthreads.NotificationCompilationWorker;
+import se.su.dsv.scipro.workerthreads.Scheduler;
+import se.su.dsv.scipro.workerthreads.SchedulerImpl;
+import se.su.dsv.scipro.workerthreads.TemporaryWorkerScheduler;
+import se.su.dsv.scipro.workerthreads.ThesisUploadDeadlineWorker;
+import se.su.dsv.scipro.workerthreads.ThesisUploadReminderWorker;
+import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
+
+import java.time.Clock;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+@Configuration(proxyBeanMethods = false)
+@Import(WorkerConfig.Workers.class)
+public class WorkerConfig {
+    private static final int NUMBER_OF_WORKER_THREADS = 4;
+
+    @Bean
+    public ScheduledExecutorService scheduledExecutorService() {
+        return Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS);
+    }
+
+    @Bean
+    public SchedulerImpl scheduler(
+            ScheduledExecutorService scheduledExecutorService,
+            EntityManagerFactory entityManagerFactory)
+    {
+        return new SchedulerImpl(scheduledExecutorService, entityManagerFactory);
+    }
+
+    @Bean
+    public TemporaryWorkerScheduler temporaryWorkerScheduler(
+            Scheduler scheduler,
+            Provider<MailEventWorker> mailEventWorker,
+            Provider<NotificationCompilationWorker> notificationCompilationWorker,
+            Provider<IdeaExportWorker> ideaExportWorker,
+            Provider<ThesisUploadReminderWorker> thesisUploadReminderWorker,
+            Provider<ThesisUploadDeadlineWorker> thesisUploadDeadlineWorker,
+            Provider<ManualMatchRemindWorker> manualMatchRemindWorkerProvider,
+            Provider<ReviewerDecisionReminderWorker> reviewerDecisionReminderWorker,
+            Provider<PlagiarismSubmitter> plagiarismSubmitter,
+            Provider<StatusPollingWorker> urkundPoller,
+            Provider<RemoveFulfilledPartnerAdsWorker> removeFulfilledPartnerAds,
+            Provider<GradeFinalSeminarParticipantReminderWorker> gradeFinalSeminarParticipantReminderWorkerProvider)
+    {
+        return new TemporaryWorkerScheduler(scheduler, mailEventWorker, notificationCompilationWorker, ideaExportWorker, thesisUploadReminderWorker, thesisUploadDeadlineWorker, manualMatchRemindWorkerProvider, reviewerDecisionReminderWorker, plagiarismSubmitter, urkundPoller, removeFulfilledPartnerAds, gradeFinalSeminarParticipantReminderWorkerProvider);
+    }
+
+    @Bean
+    public FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule firstMeetingReminderWorkerScheduler(
+            Scheduler scheduler,
+            Provider<FirstMeetingReminderWorker> firstMeetingReminderWorkerProvider)
+    {
+        return new FirstMeetingReminderWorker.FirstMeetingReminderWorkerSchedule(scheduler, firstMeetingReminderWorkerProvider);
+    }
+
+    @Bean
+    public PeerWorkerSchedules peerWorkerSchedules(
+            Scheduler scheduler,
+            Provider<ExpiredRequestWorker> expiredRequestWorker,
+            Provider<ExpiredReviewResetWorker> expiredReviewResetWorker)
+    {
+        return new PeerWorkerSchedules(scheduler, expiredRequestWorker, expiredReviewResetWorker);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean(IdeaCreationJudge.class)
+    public IdeaCreationJudge ideaCreationJudge() {
+        return new AllowAllIdeaCreationJudge();
+    }
+
+    @Bean
+    public PlagiarismSubmitter plagiarismSubmitter(
+            Provider<UrkundSettings> urkundSettings,
+            PlagiarismRequestRepository plagiarismRequestRepository,
+            UrkundService urkundService,
+            FileService fileService)
+    {
+        return new PlagiarismSubmitter(urkundSettings, plagiarismRequestRepository, urkundService, fileService);
+    }
+
+    @Bean
+    public UrkundSettings urkundSettings(UrkundSettingsRepository urkundSettingsRepository) {
+        return urkundSettingsRepository.getSettings();
+    }
+
+    @Bean
+    @Scope("prototype")
+    public WorkerTransactionManager workerTransactionManager(PlatformTransactionManager platformTransactionManager) {
+        return new SpringManagedWorkerTransactions(platformTransactionManager);
+    }
+
+    @Configuration
+    public static class Workers {
+        @Bean
+        public MailEventWorker mailEventWorker(
+                MailEventService mailEventService,
+                GeneralSystemSettingsService generalSystemSettingsService,
+                Mailer mailer)
+        {
+            return new MailEventWorker(mailEventService, generalSystemSettingsService, mailer);
+        }
+
+        @Bean
+        public NotificationCompilationWorker notificationCompilationWorker() {
+            return new NotificationCompilationWorker();
+        }
+
+        @Bean
+        public IdeaExportWorker ideaExportWorker(
+                IdeaService ideaService,
+                MailEventService mailEventService,
+                ProjectService projectService,
+                IdeaCreationJudge ideaCreationJudge,
+                EventBus eventBus,
+                FirstMeetingService firstMeetingService)
+        {
+            return new IdeaExportWorker(ideaService, mailEventService, projectService, ideaCreationJudge, eventBus,
+                    firstMeetingService);
+        }
+
+        @Bean
+        public ThesisUploadReminderWorker thesisUploadReminderWorker() {
+            return new ThesisUploadReminderWorker();
+        }
+
+        @Bean
+        public ThesisUploadDeadlineWorker thesisUploadDeadlineWorker() {
+            return new ThesisUploadDeadlineWorker();
+        }
+
+        @Bean
+        public ManualMatchRemindWorker manualMatchRemindWorker(
+                ApplicationPeriodService applicationPeriodService,
+                MailEventService mailEventService,
+                GeneralSystemSettingsService generalSystemSettingsService,
+                IdeaService ideaService,
+                Clock clock)
+        {
+            return new ManualMatchRemindWorker(applicationPeriodService, mailEventService, generalSystemSettingsService,
+                    ideaService, clock);
+        }
+
+        @Bean
+        public ReviewerDecisionReminderWorker reviewerDecisionReminderWorker(
+                MyReviewService myReviewService,
+                DaysService daysService,
+                MailEventService mailEventService)
+        {
+            return new ReviewerDecisionReminderWorker(myReviewService, daysService, mailEventService);
+        }
+
+        @Bean
+        public StatusPollingWorker statusPollingWorker(
+                UrkundSubmissionRepository urkundSubmissionRepository,
+                UrkundApi urkundApi,
+                Provider<UrkundSettings> urkundSettingsProvider,
+                Sukat sukat)
+        {
+            return new StatusPollingWorker(urkundSubmissionRepository, urkundApi, urkundSettingsProvider, sukat);
+        }
+
+        @Bean
+        public RemoveFulfilledPartnerAdsWorker removeFulfilledPartnerAdsWorker(
+                IdeaService ideaService,
+                ProjectPartnerRepository projectPartnerRepository)
+        {
+            return new RemoveFulfilledPartnerAdsWorker(ideaService, projectPartnerRepository);
+        }
+
+        @Bean
+        public GradeFinalSeminarParticipantReminderWorker gradeFinalSeminarParticipantReminderWorker(
+                MailEventService mailEventService,
+                GeneralSystemSettingsService generalSystemSettingsService,
+                FinalSeminarService finalSeminarService)
+        {
+            return new GradeFinalSeminarParticipantReminderWorker(finalSeminarService, mailEventService, generalSystemSettingsService);
+        }
+
+        @Bean
+        public FirstMeetingReminderWorker firstMeetingReminderWorker(
+                IdeaService ideaService,
+                DaysService daysService,
+                MailEventService mailEventService,
+                GeneralSystemSettingsService generalSystemSettingsService,
+                Clock clock)
+        {
+            return new FirstMeetingReminderWorker(ideaService, daysService, mailEventService, generalSystemSettingsService, clock);
+        }
+
+        @Bean
+        public ExpiredReviewResetWorker expiredReviewResetWorker() {
+            return new ExpiredReviewResetWorker();
+        }
+
+        @Bean
+        public ExpiredRequestWorker expiredRequestWorker() {
+            return new ExpiredRequestWorker();
+        }
+    }
+}
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java b/war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java
similarity index 63%
rename from core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java
rename to war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java
index d8ecf35252..0acb56920c 100755
--- a/core/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java
+++ b/war/src/main/java/se/su/dsv/scipro/workerthreads/SchedulerImpl.java
@@ -1,12 +1,18 @@
 package se.su.dsv.scipro.workerthreads;
 
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.orm.jpa.EntityManagerHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
 import se.su.dsv.scipro.system.Lifecycle;
 
 import jakarta.inject.Inject;
 import jakarta.inject.Provider;
 import jakarta.inject.Singleton;
+
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
@@ -19,13 +25,15 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
     private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerImpl.class);
 
     private final ScheduledExecutorService scheduledExecutorService;
+    private final EntityManagerFactory emf;
 
     private final Set<Task> tasks = new TreeSet<>(new Task.ByDescriptionComparator());
     private final Set<Task> runningWorkers = Collections.synchronizedSet(new HashSet<>());
 
     @Inject
-    public SchedulerImpl(ScheduledExecutorService scheduledExecutorService) {
+    public SchedulerImpl(ScheduledExecutorService scheduledExecutorService, EntityManagerFactory emf) {
         this.scheduledExecutorService = scheduledExecutorService;
+        this.emf = emf;
     }
 
     @Override
@@ -43,6 +51,14 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
     private Runnable tracked(final Task task) {
         return () -> {
             try {
+                // Since we're not in a web request when running a scheduled job, Spring's OpenEntityManagerInView
+                // filter is not active. Therefore, we need to manually bind a new EntityManager to the current thread
+                // to be shared by all DAOs. If we do not, we will get problems with detached entity passed to persist
+                // since every read and write from the database will be in a new EntityManager.
+                EntityManager em = emf.createEntityManager();
+                EntityManagerHolder emHolder = new EntityManagerHolder(em);
+                TransactionSynchronizationManager.bindResource(emf, emHolder);
+
                 runningWorkers.add(task);
                 task.execute();
             }
@@ -51,6 +67,11 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
             }
             finally {
                 runningWorkers.remove(task);
+
+                // Clean up the shared EntityManager
+                EntityManagerHolder emHolder = (EntityManagerHolder)
+                        TransactionSynchronizationManager.unbindResource(emf);
+                EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
             }
         };
     }
diff --git a/core/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java b/war/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java
similarity index 100%
rename from core/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java
rename to war/src/main/java/se/su/dsv/scipro/workerthreads/TaskScheduling.java
diff --git a/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer b/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
new file mode 100644
index 0000000000..ad4ffa3bbd
--- /dev/null
+++ b/war/src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer
@@ -0,0 +1 @@
+se.su.dsv.scipro.war.Main
diff --git a/war/src/main/resources/application.properties b/war/src/main/resources/application.properties
new file mode 100644
index 0000000000..753d0e323c
--- /dev/null
+++ b/war/src/main/resources/application.properties
@@ -0,0 +1,20 @@
+spring.datasource.jndi-name=java:/comp/env/jdbc/sciproDS
+spring.flyway.table=schema_version
+
+# Spring Boot changes Hibernates default naming strategy to convert camelCase to snake_case
+# We currently rely on the names to be treated as they are in Java, so we need to set it back to the default
+spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
+
+# We also need to set the implicit strategy to be JPA compliant, as we rely on this naming strategy for certain
+# join tables (idea_Keyword vs idea_keyword)
+spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
+
+spring.mvc.servlet.path=/api
+
+springdoc.swagger-ui.path=/swagger
+springdoc.swagger-ui.persist-authorization=true
+
+# These will be overwritten by configuration in the environment of servers it is deployed to
+spring.security.oauth2.resourceserver.opaquetoken.client-id=scipro-api-client
+spring.security.oauth2.resourceserver.opaquetoken.client-secret=scipro-api-secret
+spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=http://localhost:59733/introspect
diff --git a/war/src/main/webapp/WEB-INF/web.xml b/war/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000000..9741e82487
--- /dev/null
+++ b/war/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
+         version="4.0" metadata-complete="true">
+
+    <display-name>SciPro</display-name>
+
+    <!-- disables Spring's built in ServletContainerInitializer which causes a slow class path scanning -->
+    <absolute-ordering/>
+
+    <session-config>
+        <session-timeout>480</session-timeout>
+
+        <!--
+            By default, Tomcat will use a cookie to track the session.
+            However, if there is no cookie sent by the browser it will append
+            the session id to the URL. The way it does this is by adding a
+            ";jsessionid=..." to the end. This is not a problem in itself, but
+            it can enable session hijacking if the URL is shared and ";" is
+            a blocked character by the default Spring Security configuration.
+            (see StrictHttpFirewall).
+
+            So what happens is a user navigates to SciPro. No session cookie is
+            sent since this is the first request. SciPro sees that the user is
+            not authenticated and redirects the user to the login page.
+            When SciPro checks for authentication it checks the session which
+            will instruct Tomcat to create a session. Since Tomcat sees no
+            cookie it will append the session id to the redirect URL to try and
+            track the session. After the user has logged in it is redirected
+            back to SciPro with the session id in the URL which is then blocked
+            by Spring's StrictHttpFirewall.
+
+            To avoid this, we can set the tracking mode to *only* COOKIE.
+        -->
+        <tracking-mode>COOKIE</tracking-mode>
+    </session-config>
+</web-app>
diff --git a/core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java b/war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java
similarity index 83%
rename from core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java
rename to war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java
index 45e9ec4f67..f79a05cd26 100644
--- a/core/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java
+++ b/war/src/test/java/se/su/dsv/scipro/workerthreads/SchedulerImplTest.java
@@ -1,8 +1,10 @@
 package se.su.dsv.scipro.workerthreads;
 
-import com.google.inject.util.Providers;
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
@@ -24,6 +26,8 @@ public class SchedulerImplTest {
     private Worker abstractWorker;
     @Mock
     private Task task;
+    @Mock(answer = Answers.RETURNS_MOCKS)
+    private EntityManagerFactory emf;
     @InjectMocks
     private SchedulerImpl scheduler;
 
@@ -31,7 +35,7 @@ public class SchedulerImplTest {
     public void schedules_correctly() {
         long period = 1;
         TimeUnit timeUnit = TimeUnit.SECONDS;
-        scheduler.schedule("My worker").runBy(Providers.of(abstractWorker)).every(period, timeUnit);
+        scheduler.schedule("My worker").runBy(() -> abstractWorker).every(period, timeUnit);
         verify(scheduledExecutorService).scheduleAtFixedRate(any(Runnable.class), eq(period), eq(period), eq(timeUnit));
     }