diff --git a/core/pom.xml b/core/pom.xml
index d2a9506ee7..cda6ec6cdd 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -32,6 +32,10 @@
             <groupId>org.glassfish.jersey.media</groupId>
             <artifactId>jersey-media-json-jackson</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.inject</groupId>
+            <artifactId>jersey-hk2</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
diff --git a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
index 352c43456a..bdcf367030 100644
--- a/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
+++ b/core/src/main/java/se/su/dsv/scipro/CoreConfig.java
@@ -349,14 +349,16 @@ public class CoreConfig {
         ForumPostReadStateRepository readStateRepository,
         AbstractThreadRepository threadRepository,
         FileService fileService,
-        EventBus eventBus
+        EventBus eventBus,
+        CurrentUser currentUser
     ) {
         return new BasicForumServiceImpl(
             forumPostRepository,
             readStateRepository,
             threadRepository,
             fileService,
-            eventBus
+            eventBus,
+            currentUser
         );
     }
 
diff --git a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumService.java b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumService.java
index 6a680ad26f..44ff9f407a 100644
--- a/core/src/main/java/se/su/dsv/scipro/forum/BasicForumService.java
+++ b/core/src/main/java/se/su/dsv/scipro/forum/BasicForumService.java
@@ -23,4 +23,12 @@ public interface BasicForumService extends Serializable {
     ForumThread createThread(String subject);
 
     long countUnreadThreads(List<ForumThread> forumThreadList, User user);
+
+    ForumPost getLastPost(ForumThread forumThread);
+
+    boolean hasAttachments(ForumThread forumThread);
+
+    boolean canDelete(ForumPost forumPost);
+
+    void deletePost(ForumPost post);
 }
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 c48e3cab91..c74a6fecab 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
@@ -10,6 +10,7 @@ import se.su.dsv.scipro.file.FileService;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.forum.dataobjects.ForumPostReadState;
 import se.su.dsv.scipro.forum.dataobjects.ForumThread;
+import se.su.dsv.scipro.system.CurrentUser;
 import se.su.dsv.scipro.system.User;
 
 public class BasicForumServiceImpl implements BasicForumService {
@@ -19,6 +20,7 @@ public class BasicForumServiceImpl implements BasicForumService {
     private final ForumPostReadStateRepository readStateRepository;
     private final FileService fileService;
     private final EventBus eventBus;
+    private final CurrentUser currentUserProvider;
 
     @Inject
     public BasicForumServiceImpl(
@@ -26,13 +28,15 @@ public class BasicForumServiceImpl implements BasicForumService {
         final ForumPostReadStateRepository readStateRepository,
         AbstractThreadRepository threadRepository,
         final FileService fileService,
-        final EventBus eventBus
+        final EventBus eventBus,
+        final CurrentUser currentUserProvider
     ) {
         this.postRepository = postRepository;
         this.readStateRepository = readStateRepository;
         this.threadRepository = threadRepository;
         this.fileService = fileService;
         this.eventBus = eventBus;
+        this.currentUserProvider = currentUserProvider;
     }
 
     @Override
@@ -66,7 +70,7 @@ public class BasicForumServiceImpl implements BasicForumService {
 
     @Override
     public boolean isThreadRead(User user, ForumThread forumThread) {
-        for (ForumPost post : forumThread.getPosts()) {
+        for (ForumPost post : getPosts(forumThread)) {
             if (!getReadState(user, post).isRead()) {
                 return false;
             }
@@ -133,4 +137,56 @@ public class BasicForumServiceImpl implements BasicForumService {
 
         return post;
     }
+
+    @Override
+    public ForumPost getLastPost(ForumThread forumThread) {
+        return Collections.max(
+            getPosts(forumThread),
+            Comparator.comparing(ForumPost::getDateCreated).thenComparing(ForumPost::getId)
+        );
+    }
+
+    @Override
+    public boolean hasAttachments(ForumThread forumThread) {
+        for (ForumPost post : getPosts(forumThread)) {
+            if (!post.getAttachments().isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean canDelete(ForumPost forumPost) {
+        ForumPost initialPost = forumPost.getForumThread().getPosts().get(0);
+        if (forumPost.equals(initialPost)) {
+            // The initial post in a thread can never be deleted
+            return false;
+        }
+
+        User user = currentUserProvider.get();
+        // Current user can be null meaning the call came from the system
+        if (user == null) {
+            // Allow the system to delete any post
+            return true;
+        }
+        return Objects.equals(forumPost.getPostedBy(), user);
+    }
+
+    @Override
+    @Transactional
+    public void deletePost(ForumPost post) {
+        if (!canDelete(post)) {
+            throw new PostCantBeDeletedException();
+        }
+        post.setDeleted(true);
+        postRepository.save(post);
+    }
+
+    private static final class PostCantBeDeletedException extends IllegalArgumentException {
+
+        public PostCantBeDeletedException() {
+            super("User is not allowed to delete post");
+        }
+    }
 }
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 1c61c2c563..f1933e89c0 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
@@ -116,13 +116,4 @@ public class ForumThread extends LazyDeletableDomainObject {
     public User getCreatedBy() {
         return getPosts().get(0).getPostedBy();
     }
-
-    public boolean hasAttachments() {
-        for (ForumPost post : posts) {
-            if (!post.getAttachments().isEmpty()) {
-                return true;
-            }
-        }
-        return false;
-    }
 }
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 08845a8a3f..2e97a2b07a 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
@@ -235,10 +235,8 @@ public class IdeaServiceImpl extends AbstractServiceImpl<Idea, Long> implements
             if (authorParticipatingOnActiveIdea(coAuthor, ap)) {
                 return new Pair<>(Boolean.FALSE, PARTNER_ALREADY_PARTICIPATING_ERROR);
             }
-            if (
-                coAuthor.getDegreeType() != ProjectType.UNKNOWN &&
-                coAuthor.getDegreeType() != idea.getProjectType().getDegreeType()
-            ) {
+            List<ProjectType> typesForCoAuthor = applicationPeriodService.getTypesForStudent(ap, coAuthor);
+            if (!typesForCoAuthor.contains(idea.getProjectType())) {
                 return new Pair<>(Boolean.FALSE, WRONG_LEVEL_FOR_YOUR_PARTNER);
             }
             if (!projectService.getActiveProjectsByUserAndProjectType(coAuthor, idea.getProjectType()).isEmpty()) {
diff --git a/core/src/main/xsd/daisy_api.xsd b/core/src/main/xsd/daisy_api.xsd
index fa68eef856..7ff97ec5a7 100755
--- a/core/src/main/xsd/daisy_api.xsd
+++ b/core/src/main/xsd/daisy_api.xsd
@@ -559,7 +559,7 @@
 
     <xs:complexType name="course">
         <xs:sequence>
-            <xs:element name="courseCode" type="xs:string" minOccurs="0">
+            <xs:element name="courseCode" type="xs:string" minOccurs="1">
             </xs:element>
             <xs:element name="credits" type="xs:float" minOccurs="1">
             </xs:element>
@@ -567,6 +567,8 @@
             </xs:element>
             <xs:element name="level" type="educationalLevel" minOccurs="0">
             </xs:element>
+            <xs:element name="degreeThesisCourse" type="xs:boolean" minOccurs="1">
+            </xs:element>
             <xs:element name="eduInstDesignation" type="xs:string" minOccurs="1">
             </xs:element>
         </xs:sequence>
diff --git a/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceImplTest.java
index de6288d6f4..6846f54411 100644
--- a/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceImplTest.java
@@ -121,6 +121,8 @@ public class BasicForumServiceImplTest {
         ForumThread forumThread = new ForumThread();
         forumThread.addPost(post);
 
+        when(postRepository.findByThread(forumThread)).thenReturn(List.of(post));
+
         when(readStateRepository.find(eq(goodUser), isA(ForumPost.class))).thenReturn(readState);
         when(readStateRepository.find(eq(badUser), isA(ForumPost.class))).thenReturn(notReadState);
 
diff --git a/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceIntegrationTest.java b/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceIntegrationTest.java
new file mode 100644
index 0000000000..ec5d815af7
--- /dev/null
+++ b/core/src/test/java/se/su/dsv/scipro/forum/BasicForumServiceIntegrationTest.java
@@ -0,0 +1,83 @@
+package se.su.dsv.scipro.forum;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import jakarta.inject.Inject;
+import java.util.Set;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import se.su.dsv.scipro.forum.dataobjects.ForumPost;
+import se.su.dsv.scipro.forum.dataobjects.ForumThread;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.test.IntegrationTest;
+
+public class BasicForumServiceIntegrationTest extends IntegrationTest {
+
+    @Inject
+    BasicForumService basicForumService;
+
+    private User op;
+    private User commenter;
+
+    @BeforeEach
+    public void setUp() {
+        User op = User.builder().firstName("Bill").lastName("Gates").emailAddress("bill@example.com").build();
+        this.op = save(op);
+
+        User commenter = User.builder().firstName("Steve").lastName("Jobs").emailAddress("steve@example.com").build();
+        this.commenter = save(commenter);
+    }
+
+    @Test
+    public void can_not_delete_original_post() {
+        ForumThread thread = basicForumService.createThread("Test thread");
+        ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
+
+        setLoggedInAs(op);
+
+        assertFalse(basicForumService.canDelete(originalPost));
+        assertThrows(IllegalArgumentException.class, () -> basicForumService.deletePost(originalPost));
+    }
+
+    @Test
+    public void can_delete_reply_to_original_post() {
+        ForumThread thread = basicForumService.createThread("Test thread");
+        ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
+        ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
+
+        setLoggedInAs(commenter);
+
+        assertTrue(basicForumService.canDelete(reply));
+        assertDoesNotThrow(() -> basicForumService.deletePost(reply));
+    }
+
+    @Test
+    public void can_not_delete_someone_elses_reply() {
+        ForumThread thread = basicForumService.createThread("Test thread");
+        ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
+        ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
+
+        setLoggedInAs(op);
+
+        assertFalse(basicForumService.canDelete(reply));
+        assertThrows(IllegalArgumentException.class, () -> basicForumService.deletePost(reply));
+    }
+
+    @Test
+    public void system_can_delete_all_replies() {
+        ForumThread thread = basicForumService.createThread("Test thread");
+        ForumPost originalPost = basicForumService.createReply(thread, op, "Test post", Set.of());
+        ForumPost reply = basicForumService.createReply(thread, commenter, "Test reply", Set.of());
+        ForumPost secondReply = basicForumService.createReply(thread, op, "Test post", Set.of());
+
+        setLoggedInAs(null);
+
+        assertTrue(basicForumService.canDelete(reply));
+        assertDoesNotThrow(() -> basicForumService.deletePost(reply));
+        assertTrue(basicForumService.canDelete(secondReply));
+        assertDoesNotThrow(() -> basicForumService.deletePost(secondReply));
+    }
+}
diff --git a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
index 6365ba546a..871ea15351 100755
--- a/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/match/IdeaServiceImplTest.java
@@ -241,6 +241,7 @@ public class IdeaServiceImplTest {
         when(generalSystemSettingsService.getGeneralSystemSettingsInstance()).thenReturn(new GeneralSystemSettings());
         Idea idea = createBachelorIdea(Idea.Status.UNMATCHED);
         when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(bachelor));
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
 
         Pair<Boolean, String> acceptance = ideaService.validateStudentAcceptance(
             idea,
@@ -401,6 +402,39 @@ public class IdeaServiceImplTest {
         assertEquals(expected, ideaService.countAuthorsByApplicationPeriod(applicationPeriod, params));
     }
 
+    @Test
+    public void wrong_type_for_author() {
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, student)).thenReturn(List.of(master));
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(bachelor));
+
+        assertPair(
+            false,
+            "The idea is the wrong level for you, please pick another one.",
+            ideaService.validateStudentAcceptance(
+                createBachelorIdea(Idea.Status.UNMATCHED),
+                student,
+                coAuthor,
+                applicationPeriod
+            )
+        );
+    }
+
+    @Test
+    public void wrong_type_for_partner() {
+        when(applicationPeriodService.getTypesForStudent(applicationPeriod, coAuthor)).thenReturn(List.of(master));
+
+        assertPair(
+            false,
+            "The idea is the wrong level for your partner, please pick another one.",
+            ideaService.validateStudentAcceptance(
+                createBachelorIdea(Idea.Status.UNMATCHED),
+                student,
+                coAuthor,
+                applicationPeriod
+            )
+        );
+    }
+
     private Idea mockInactiveIdea() {
         Idea idea = new Idea();
         Match match = new Match();
diff --git a/core/src/test/java/se/su/dsv/scipro/report/GradingReportServiceImplIntegrationTest.java b/core/src/test/java/se/su/dsv/scipro/report/GradingReportServiceImplIntegrationTest.java
index 597396bbea..63808671e3 100644
--- a/core/src/test/java/se/su/dsv/scipro/report/GradingReportServiceImplIntegrationTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/report/GradingReportServiceImplIntegrationTest.java
@@ -6,7 +6,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import com.google.common.eventbus.EventBus;
+import com.sun.net.httpserver.HttpServer;
 import jakarta.inject.Inject;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.Month;
 import java.util.*;
@@ -15,6 +19,9 @@ import org.junit.jupiter.api.Test;
 import se.su.dsv.scipro.finalseminar.FinalSeminar;
 import se.su.dsv.scipro.finalseminar.FinalSeminarOpposition;
 import se.su.dsv.scipro.finalseminar.OppositionApprovedEvent;
+import se.su.dsv.scipro.grading.GetGradeError;
+import se.su.dsv.scipro.grading.GradingServiceImpl;
+import se.su.dsv.scipro.grading.Result;
 import se.su.dsv.scipro.project.Project;
 import se.su.dsv.scipro.security.auth.roles.Roles;
 import se.su.dsv.scipro.system.DegreeType;
@@ -149,6 +156,44 @@ public class GradingReportServiceImplIntegrationTest extends IntegrationTest {
         assertNull(oppositionCriterion.getFeedback());
     }
 
+    @Test
+    public void test_json_deserialization() throws IOException {
+        String json =
+            """
+            {
+                "grade": "A",
+                "reported": "2021-01-01"
+            }
+            """;
+        HttpServer httpServer = startHttpServerWithJsonResponse(json);
+
+        int port = httpServer.getAddress().getPort();
+
+        GradingServiceImpl gradingService = new GradingServiceImpl("http://localhost:" + port);
+        Either<GetGradeError, Optional<Result>> result = gradingService.getResult("token", 1, 2, 3);
+
+        Optional<Result> right = result.right();
+        assertTrue(right.isPresent());
+        assertEquals(LocalDate.of(2021, 1, 1), right.get().reported());
+
+        httpServer.stop(0);
+    }
+
+    private static HttpServer startHttpServerWithJsonResponse(String json) throws IOException {
+        HttpServer httpServer = HttpServer.create();
+        httpServer.createContext("/", exchange -> {
+            try (exchange) {
+                byte[] response = json.getBytes(StandardCharsets.UTF_8);
+                exchange.getResponseHeaders().add("Content-Type", "application/json");
+                exchange.sendResponseHeaders(200, response.length);
+                exchange.getResponseBody().write(response);
+            }
+        });
+        httpServer.bind(new InetSocketAddress("localhost", 0), 0);
+        httpServer.start();
+        return httpServer;
+    }
+
     private void addOppositionCriterion() {
         gradingReportTemplate = createOppositionCriteria(gradingReportTemplate, 2);
         gradingReport = createGradingReport(project, student);
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
index 2d52bd0d36..363fc8b80c 100644
--- a/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java
+++ b/core/src/test/java/se/su/dsv/scipro/test/SpringTest.java
@@ -1,6 +1,7 @@
 package se.su.dsv.scipro.test;
 
 import com.google.common.eventbus.EventBus;
+import jakarta.inject.Inject;
 import jakarta.persistence.EntityManager;
 import jakarta.persistence.EntityManagerFactory;
 import jakarta.persistence.EntityTransaction;
@@ -28,6 +29,7 @@ import se.su.dsv.scipro.RepositoryConfiguration;
 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.system.User;
 
 @Testcontainers
 public abstract class SpringTest {
@@ -38,6 +40,9 @@ public abstract class SpringTest {
     @Container
     static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
 
+    @Inject
+    private TestUser testUser;
+
     private CapturingEventBus capturingEventBus;
 
     @BeforeEach
@@ -64,6 +69,8 @@ public abstract class SpringTest {
         annotationConfigApplicationContext.getBeanFactory().registerSingleton("entityManager", this.entityManager);
         annotationConfigApplicationContext.refresh();
         annotationConfigApplicationContext.getAutowireCapableBeanFactory().autowireBean(this);
+
+        testUser.setUser(null); // default to system
     }
 
     @AfterEach
@@ -83,6 +90,10 @@ public abstract class SpringTest {
         }
     }
 
+    protected void setLoggedInAs(User user) {
+        this.testUser.setUser(user);
+    }
+
     protected List<Object> getPublishedEvents() {
         return capturingEventBus.publishedEvents;
     }
@@ -108,7 +119,7 @@ public abstract class SpringTest {
 
         @Bean
         public CurrentUser currentUser() {
-            return () -> null;
+            return new TestUser();
         }
 
         @Bean
@@ -129,4 +140,18 @@ public abstract class SpringTest {
             super.post(event);
         }
     }
+
+    private static class TestUser implements CurrentUser {
+
+        private User user;
+
+        @Override
+        public User get() {
+            return user;
+        }
+
+        private void setUser(User user) {
+            this.user = user;
+        }
+    }
 }
diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
index 1dd6b18132..56bb1313a4 100644
--- a/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
@@ -1,6 +1,9 @@
 package se.su.dsv.scipro.testdata;
 
+import java.util.List;
+import se.su.dsv.scipro.match.Keyword;
 import se.su.dsv.scipro.system.ProjectType;
+import se.su.dsv.scipro.system.ResearchArea;
 
 /// All the base test data that can be re-used in different test cases.
 ///
@@ -16,4 +19,11 @@ public interface BaseData {
     ProjectType bachelor();
     ProjectType magister();
     ProjectType master();
+
+    /**
+     * @return generic research area with some keywords attached to it
+     */
+    ResearchAreaAndKeywords researchArea();
+
+    record ResearchAreaAndKeywords(ResearchArea researchArea, List<Keyword> keywords) {}
 }
diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
index cf01ab2315..c12cb602b2 100644
--- a/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/DataInitializer.java
@@ -2193,6 +2193,11 @@ public class DataInitializer implements Lifecycle, BaseData, Factory {
         return createEmployee(firstName);
     }
 
+    @Override
+    public ResearchAreaAndKeywords researchArea() {
+        return new ResearchAreaAndKeywords(researchArea1, List.of(keyword1, keyword2));
+    }
+
     private static final class SimpleTextFile implements FileUpload {
 
         private final User uploader;
diff --git a/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
new file mode 100644
index 0000000000..c490d0b069
--- /dev/null
+++ b/test-data/src/main/java/se/su/dsv/scipro/testdata/populators/PartnerTypeExemption.java
@@ -0,0 +1,68 @@
+package se.su.dsv.scipro.testdata.populators;
+
+import jakarta.inject.Inject;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Set;
+import org.springframework.stereotype.Service;
+import se.su.dsv.scipro.match.ApplicationPeriod;
+import se.su.dsv.scipro.match.ApplicationPeriodService;
+import se.su.dsv.scipro.match.Idea;
+import se.su.dsv.scipro.match.IdeaService;
+import se.su.dsv.scipro.match.Target;
+import se.su.dsv.scipro.match.TargetService;
+import se.su.dsv.scipro.system.User;
+import se.su.dsv.scipro.testdata.BaseData;
+import se.su.dsv.scipro.testdata.Factory;
+import se.su.dsv.scipro.testdata.TestDataPopulator;
+
+@Service
+public class PartnerTypeExemption implements TestDataPopulator {
+
+    private final ApplicationPeriodService applicationPeriodService;
+    private final IdeaService ideaService;
+    private final TargetService targetService;
+
+    @Inject
+    public PartnerTypeExemption(
+        ApplicationPeriodService applicationPeriodService,
+        IdeaService ideaService,
+        TargetService targetService
+    ) {
+        this.applicationPeriodService = applicationPeriodService;
+        this.ideaService = ideaService;
+        this.targetService = targetService;
+    }
+
+    @Override
+    public void populate(BaseData baseData, Factory factory) {
+        factory.createAuthor("Oskar");
+
+        User johan = factory.createAuthor("Johan");
+        johan.setDegreeType(baseData.master().getDegreeType());
+
+        User supervisor = factory.createSupervisor("Elsa");
+
+        ApplicationPeriod applicationPeriod = new ApplicationPeriod("Supervisor ideas");
+        applicationPeriod.setStartDate(LocalDate.now());
+        applicationPeriod.setEndDate(LocalDate.now().plusDays(14));
+        applicationPeriod.setCourseStartDateTime(LocalDateTime.now().plusDays(15));
+        applicationPeriod.setProjectTypes(Set.of(baseData.bachelor()));
+        applicationPeriodService.save(applicationPeriod);
+
+        Target target = targetService.findOne(applicationPeriod, supervisor, baseData.bachelor());
+        target.setTarget(10);
+        targetService.save(target);
+
+        Idea idea = new Idea();
+        idea.setPublished(true);
+        idea.setTitle("The next gen AI 2.0 turbo edition");
+        idea.setPrerequisites("Hacker experience");
+        idea.setDescription("Better than all the rest");
+        idea.setProjectType(baseData.bachelor());
+        idea.setApplicationPeriod(applicationPeriod);
+        idea.setResearchArea(baseData.researchArea().researchArea());
+
+        ideaService.saveSupervisorIdea(idea, supervisor, baseData.researchArea().keywords(), true);
+    }
+}
diff --git a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.html b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.html
index eba931f634..b09f0405ca 100644
--- a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.html
+++ b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.html
@@ -7,9 +7,10 @@
 <body>
 <wicket:panel>
     <div class="messageWrap">
-        <div class="forumBlueBackground">
+        <div class="forumBlueBackground d-flex justify-content-between">
             <!-- DATE ROW-->
-            <wicket:container wicket:id="dateCreated"/>
+            <span wicket:id="dateCreated"></span>
+            <button wicket:id="delete" class="btn btn-sm btn-outline-danger ms-auto">Delete</button>
         </div>
         <div class="forumGrayBackground">
             <div class="vertAlign">
diff --git a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.java b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.java
index 004d99561a..225240d8e1 100644
--- a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ForumPostPanel.java
@@ -1,7 +1,9 @@
 package se.su.dsv.scipro.forum.panels.threaded;
 
+import jakarta.inject.Inject;
 import org.apache.wicket.Component;
 import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.LambdaModel;
@@ -11,9 +13,11 @@ import se.su.dsv.scipro.components.ListAdapterModel;
 import se.su.dsv.scipro.components.SmarterLinkMultiLineLabel;
 import se.su.dsv.scipro.data.enums.DateStyle;
 import se.su.dsv.scipro.file.FileReference;
+import se.su.dsv.scipro.forum.BasicForumService;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.profile.UserLinkPanel;
 import se.su.dsv.scipro.repository.panels.ViewAttachmentPanel;
+import se.su.dsv.scipro.session.SciProSession;
 
 public class ForumPostPanel extends Panel {
 
@@ -22,6 +26,9 @@ public class ForumPostPanel extends Panel {
     public static final String CONTENT = "content";
     public static final String ATTACHMENT = "attachment";
 
+    @Inject
+    private BasicForumService basicForumService;
+
     public ForumPostPanel(String id, final IModel<ForumPost> model) {
         super(id);
         add(new UserLinkPanel(POSTED_BY, LambdaModel.of(model, ForumPost::getPostedBy, ForumPost::setPostedBy)));
@@ -62,5 +69,28 @@ public class ForumPostPanel extends Panel {
                 }
             }
         );
+
+        add(
+            new Link<>("delete", model) {
+                @Override
+                public void onClick() {
+                    ForumPost post = getModelObject();
+                    basicForumService.deletePost(post);
+                    onPostDeleted();
+                }
+
+                @Override
+                protected void onConfigure() {
+                    super.onConfigure();
+                    setVisible(allowDeletion() && basicForumService.canDelete(getModelObject()));
+                }
+            }
+        );
     }
+
+    protected boolean allowDeletion() {
+        return false;
+    }
+
+    protected void onPostDeleted() {}
 }
diff --git a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanel.java b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanel.java
index 02a9d00bd5..d0e7e1c55d 100644
--- a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanel.java
@@ -1,8 +1,7 @@
 package se.su.dsv.scipro.forum.panels.threaded;
 
+import jakarta.inject.Inject;
 import java.io.Serializable;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
@@ -15,6 +14,7 @@ import org.apache.wicket.model.LambdaModel;
 import org.apache.wicket.model.LoadableDetachableModel;
 import se.su.dsv.scipro.components.DateLabel;
 import se.su.dsv.scipro.data.enums.DateStyle;
+import se.su.dsv.scipro.forum.BasicForumService;
 import se.su.dsv.scipro.forum.Discussable;
 import se.su.dsv.scipro.forum.dataobjects.ForumPost;
 import se.su.dsv.scipro.forum.dataobjects.ForumThread;
@@ -23,6 +23,9 @@ import se.su.dsv.scipro.system.User;
 
 public class ThreadsOverviewPanel<A> extends Panel {
 
+    @Inject
+    private BasicForumService basicForumService;
+
     public ThreadsOverviewPanel(
         final String id,
         final IModel<List<A>> model,
@@ -41,7 +44,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
                             @Override
                             protected void onConfigure() {
                                 super.onConfigure();
-                                setVisibilityAllowed(discussion.getObject().hasAttachments());
+                                setVisibilityAllowed(basicForumService.hasAttachments(discussion.getObject()));
                             }
                         }
                     );
@@ -80,7 +83,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
         BookmarkablePageLink<Void> newThreadLink(String id, IModel<A> thread);
     }
 
-    private static class LastPostColumn extends WebMarkupContainer {
+    private class LastPostColumn extends WebMarkupContainer {
 
         public LastPostColumn(String id, final IModel<ForumThread> model) {
             super(id);
@@ -110,10 +113,7 @@ public class ThreadsOverviewPanel<A> extends Panel {
             return new LoadableDetachableModel<>() {
                 @Override
                 protected ForumPost load() {
-                    return Collections.max(
-                        model.getObject().getPosts(),
-                        Comparator.comparing(ForumPost::getDateCreated).thenComparing(ForumPost::getId)
-                    );
+                    return basicForumService.getLastPost(model.getObject());
                 }
             };
         }
diff --git a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ViewForumThreadPanel.java b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ViewForumThreadPanel.java
index 9c62f77122..06b89d7e14 100644
--- a/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ViewForumThreadPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/forum/panels/threaded/ViewForumThreadPanel.java
@@ -58,7 +58,21 @@ public class ViewForumThreadPanel<A> extends GenericPanel<A> {
             new ListView<>(POST_LIST, new PostProvider()) {
                 @Override
                 protected void populateItem(ListItem<ForumPost> item) {
-                    item.add(new ForumPostPanel(POST, item.getModel()));
+                    ListView<ForumPost> listView = this;
+                    item.add(
+                        new ForumPostPanel(POST, item.getModel()) {
+                            @Override
+                            protected boolean allowDeletion() {
+                                return true;
+                            }
+
+                            @Override
+                            protected void onPostDeleted() {
+                                // Refresh the list of posts
+                                listView.detach();
+                            }
+                        }
+                    );
                 }
             }
         );
diff --git a/view/src/main/java/se/su/dsv/scipro/group/EditGroupPanel.java b/view/src/main/java/se/su/dsv/scipro/group/EditGroupPanel.java
index 831986ffad..05b8396ffa 100644
--- a/view/src/main/java/se/su/dsv/scipro/group/EditGroupPanel.java
+++ b/view/src/main/java/se/su/dsv/scipro/group/EditGroupPanel.java
@@ -59,6 +59,11 @@ public class EditGroupPanel extends Panel {
             });
             add(
                 new ListView<>("available_projects", availableProjects) {
+                    {
+                        // must re-use list items to maintain form component (checkboxes) state
+                        setReuseItems(true);
+                    }
+
                     @Override
                     protected void populateItem(ListItem<Project> item) {
                         CheckBox checkbox = new CheckBox("selected", new SelectProjectModel(model, item.getModel()));
diff --git a/view/src/test/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanelTest.java b/view/src/test/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanelTest.java
index 8c99db6c4f..614f92e7cd 100644
--- a/view/src/test/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanelTest.java
+++ b/view/src/test/java/se/su/dsv/scipro/forum/panels/threaded/ThreadsOverviewPanelTest.java
@@ -9,6 +9,7 @@ import org.apache.wicket.model.Model;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 import se.su.dsv.scipro.SciProTest;
 import se.su.dsv.scipro.forum.Discussable;
@@ -20,11 +21,13 @@ import se.su.dsv.scipro.system.User;
 public class ThreadsOverviewPanelTest extends SciProTest {
 
     private List<ForumThread> threads;
+    private ForumPost post;
 
     @BeforeEach
     public void setUp() throws Exception {
         ForumThread forumThread = createThread();
         threads = Arrays.asList(forumThread);
+        Mockito.when(basicForumService.getLastPost(forumThread)).thenReturn(post);
     }
 
     @Test
@@ -54,7 +57,7 @@ public class ThreadsOverviewPanelTest extends SciProTest {
 
     private ForumThread createThread() {
         User bob = User.builder().firstName("Bob").lastName("the Builder").emailAddress("bob@building.com").build();
-        ForumPost post = new ForumPost();
+        post = new ForumPost();
         post.setPostedBy(bob);
         ForumThread groupForumThread = new ForumThread();
         groupForumThread.addPost(post);