diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc5783d255e9f744522aba2363bce9e1484be850..502e79f049f750072a0d2bfd1514ccfdc3e2551b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,12 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## [Unreleased]
 
 ### Added
+ - Admins and programme coordinators can now add or remove TA coordinators. @rwbackx
 
 ### Changed
-
-### Changed
+ - Job information, hiring message, and reject message are now edited through the job details page, to facilitate bigger textareas. @rwbackx
+ - The edition create dialog now has some explanation about what to fill in. @rwbackx
 
 ### Fixed
+ - Fixed a bug where anyone without a role in a course edition could see the full job offer details. @rwbackx
 
 ## [2.1.2]
 
@@ -31,8 +33,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Importing job offers now provided better insight in what is wrong with the input file @rwbackx
 * CSVs can now be imported with any supported separator, the separator used will be auto-detected @rwbackx
 * Teachers can now indicate that applications should respond to the job information @rwbackx
-
-### Changed
 * FlexDelft export for extra work now shows approved hours, not maximum hours @toberhuber
 * Rejected by student job offers are now displayed if the student rejected after they were offered a position @rwbackx
 
diff --git a/build.gradle.kts b/build.gradle.kts
index b98d346eddfe05538ecb21618735a649f34abb1a..5e7782bd1b2f376db1f94260563b7cd73c403aaf 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,7 +8,7 @@ version = "2.1.2"
 
 val javaVersion = JavaVersion.VERSION_17
 
-val labradoorVersion = "1.3.5"
+val labradoorVersion = "1.3.6-SNAPSHOT"
 val libradorVersion = "1.0.3-SNAPSHOT7"
 val chihuahUIVersion = "1.0.0-beta"
 val guavaVersion = "31.1-jre"
diff --git a/src/main/java/nl/tudelft/tam/DevDatabaseLoader.java b/src/main/java/nl/tudelft/tam/DevDatabaseLoader.java
index f54b9b212f6f0896bc8802bcb8fa25a77f5570fb..731f47e390db1302656f2b5bff6c6a380bfe8815 100644
--- a/src/main/java/nl/tudelft/tam/DevDatabaseLoader.java
+++ b/src/main/java/nl/tudelft/tam/DevDatabaseLoader.java
@@ -232,11 +232,15 @@ public class DevDatabaseLoader {
 				.id(9L).emailNotifications(false).build());
 		csestudent2 = profileRepository.save(nl.tudelft.tam.model.Profile.builder()
 				.id(10L).emailNotifications(false).build());
+		var admin1 = profileRepository.save(nl.tudelft.tam.model.Profile.builder()
+				.id(1L).emailNotifications(false).build());
 
 		// Teacher 1 => Coordinator CSE
 		coordinatorRepository.save(Coordinator.builder().personId(cseteacher1.getId()).programId(1L).build());
 		// Teacher 2 => Coordinator EE
 		coordinatorRepository.save(Coordinator.builder().personId(cseteacher2.getId()).programId(2L).build());
+		// Admin 1 => Coordinator CSE
+		coordinatorRepository.save(Coordinator.builder().personId(admin1.getId()).programId(1L).build());
 	}
 
 	private void initApplications() {
diff --git a/src/main/java/nl/tudelft/tam/controller/CoordinatorController.java b/src/main/java/nl/tudelft/tam/controller/CoordinatorController.java
index 50442bc18ea8fdbd73f2a8eac3c09c5b5671a8c2..1eee365b245784e2398963888585ebf7e44a9a5e 100644
--- a/src/main/java/nl/tudelft/tam/controller/CoordinatorController.java
+++ b/src/main/java/nl/tudelft/tam/controller/CoordinatorController.java
@@ -26,6 +26,7 @@ import nl.tudelft.labracore.api.dto.ProgramDetailsDTO;
 import nl.tudelft.labracore.lib.security.user.AuthenticatedPerson;
 import nl.tudelft.labracore.lib.security.user.Person;
 import nl.tudelft.tam.dto.patch.CoordinatorDefaultPatchDTO;
+import nl.tudelft.tam.model.Coordinator;
 import nl.tudelft.tam.model.CoordinatorDefault;
 import nl.tudelft.tam.model.TrainingType;
 import nl.tudelft.tam.service.*;
@@ -43,9 +44,15 @@ public class CoordinatorController {
 	@Autowired
 	CoordinatorDefaultService coordinatorDefaultService;
 
+	@Autowired
+	CoordinatorService coordinatorService;
+
 	@Autowired
 	ProgramService programService;
 
+	@Autowired
+	PersonService personService;
+
 	@Autowired
 	TrainingTypeService trainingTypeService;
 
@@ -73,6 +80,12 @@ public class CoordinatorController {
 		}
 
 		model.addAttribute("coordinatingPrograms", coordinatingPrograms);
+		model.addAttribute("coordinators",
+				coordinatingPrograms.stream()
+						.collect(Collectors.toMap(ProgramDetailsDTO::getId,
+								p -> personService
+										.getPeopleById(coordinatorService.getCoordinatorsByProgram(p.getId())
+												.stream().map(Coordinator::getPersonId).toList()))));
 
 		return "coordinator/manage";
 	}
diff --git a/src/main/java/nl/tudelft/tam/controller/EditionController.java b/src/main/java/nl/tudelft/tam/controller/EditionController.java
index 7b6bf1a8028cbb127a46e5c10087e5360170de1a..15458634d18d572e3fbacfe47b4f594e5ad8b902 100644
--- a/src/main/java/nl/tudelft/tam/controller/EditionController.java
+++ b/src/main/java/nl/tudelft/tam/controller/EditionController.java
@@ -67,7 +67,7 @@ public class EditionController {
 				.name(tamCreateDto.getName())
 				.course(tamCreateDto.getCourse())
 				.cohort(tamCreateDto.getCohort())
-				.enrollability(tamCreateDto.getEnrollability())
+				.enrollability(EditionCreateDTO.EnrollabilityEnum.OPEN)
 				.startDate(LocalDateTime.of(tamCreateDto.getStartDate(), LocalTime.of(0, 0)))
 				.endDate(LocalDateTime.of(tamCreateDto.getEndDate(), LocalTime.of(23, 59)));
 
diff --git a/src/main/java/nl/tudelft/tam/controller/JobOfferController.java b/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
index 8b6dabf8518879cd10fae3aae106b6b065e7f971..2adb1bf2be7bfbc065692a75b86b09a2f38b7d4b 100644
--- a/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
+++ b/src/main/java/nl/tudelft/tam/controller/JobOfferController.java
@@ -31,6 +31,7 @@ import nl.tudelft.labracore.lib.security.user.AuthenticatedPerson;
 import nl.tudelft.labracore.lib.security.user.Person;
 import nl.tudelft.tam.dto.create.JobOfferCreateDTO;
 import nl.tudelft.tam.dto.create.MissingEditionsJobOfferImportDTO;
+import nl.tudelft.tam.dto.patch.JobOfferMessagePatchDTO;
 import nl.tudelft.tam.dto.patch.JobOfferPatchDTO;
 import nl.tudelft.tam.dto.view.details.ApplicationDetailsJobOfferDTO;
 import nl.tudelft.tam.dto.view.details.ApplicationDetailsPersonDTO;
@@ -328,6 +329,21 @@ public class JobOfferController {
 		return "redirect:/job-offer/" + id;
 	}
 
+	/**
+	 * Edits an existing job offer's message
+	 *
+	 * @param  id  The id of the job offer
+	 * @param  dto The new message data of the job offer
+	 * @return     The specific job offer page
+	 */
+	@PatchMapping("{id}/messages")
+	@PreAuthorize("@authorisationService.isManagerOfJob(#id)")
+	public String patchJobOffer(@PathVariable Long id,
+			@Valid JobOfferMessagePatchDTO dto) {
+		jobOfferService.patchJobOffer(id, dto);
+		return "redirect:/job-offer/" + id;
+	}
+
 	/**
 	 * Closes a job offer (ie. sets deadline to past)
 	 *
diff --git a/src/main/java/nl/tudelft/tam/controller/ProgramController.java b/src/main/java/nl/tudelft/tam/controller/ProgramController.java
new file mode 100644
index 0000000000000000000000000000000000000000..bfb375761feeb1752f3ae38ae19ce071f788b46d
--- /dev/null
+++ b/src/main/java/nl/tudelft/tam/controller/ProgramController.java
@@ -0,0 +1,55 @@
+/*
+ * TAM
+ * Copyright (C) 2021 - Delft University of Technology
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+package nl.tudelft.tam.controller;
+
+import java.util.Arrays;
+
+import nl.tudelft.tam.service.CoordinatorService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping("program")
+public class ProgramController {
+
+	private final CoordinatorService coordinatorService;
+
+	@Autowired
+	public ProgramController(CoordinatorService coordinatorService) {
+		this.coordinatorService = coordinatorService;
+	}
+
+	/**
+	 * Sets the coordinators of the programme to a new lists of coordinators.
+	 *
+	 * @return Redirect to the manage page
+	 */
+	@PatchMapping("{id}/coordinators")
+	@PreAuthorize("@authorisationService.canEditCoordinatorsForProgram(#id)")
+	public String updateCoordinators(@PathVariable Long id, String coordinators) {
+		coordinatorService.setCoordinatorsForProgram(id,
+				Arrays.stream(coordinators.split("\n")).map(String::trim).filter(s -> !s.isBlank()).toList());
+		return "redirect:/coordinator/manage";
+	}
+
+}
diff --git a/src/main/java/nl/tudelft/tam/controller/TAMProfileController.java b/src/main/java/nl/tudelft/tam/controller/TAMProfileController.java
index 3a0e8f5b80fb71a0cf232373a65a5c1375d63cfa..5b515064c940bb71adc3ad2365fefdb55ed3c925 100644
--- a/src/main/java/nl/tudelft/tam/controller/TAMProfileController.java
+++ b/src/main/java/nl/tudelft/tam/controller/TAMProfileController.java
@@ -17,18 +17,20 @@
  */
 package nl.tudelft.tam.controller;
 
+import java.util.List;
+
 import javax.transaction.Transactional;
 
 import nl.tudelft.labracore.api.dto.PersonSummaryDTO;
+import nl.tudelft.labracore.api.dto.RoleEditionDetailsDTO;
 import nl.tudelft.labracore.lib.security.user.AuthenticatedPerson;
 import nl.tudelft.labracore.lib.security.user.Person;
+import nl.tudelft.tam.cache.EditionCacheManager;
 import nl.tudelft.tam.dto.patch.NotificationPatchDTO;
 import nl.tudelft.tam.dto.patch.ShirtPatchDTO;
 import nl.tudelft.tam.dto.view.summary.RaiseRequestSummaryDTO;
 import nl.tudelft.tam.model.Profile;
-import nl.tudelft.tam.service.PersonService;
-import nl.tudelft.tam.service.ProfileService;
-import nl.tudelft.tam.service.RaiseRequestService;
+import nl.tudelft.tam.service.*;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -49,6 +51,12 @@ public class TAMProfileController {
 	@Autowired
 	private PersonService personService;
 
+	@Autowired
+	private RoleService roleService;
+
+	@Autowired
+	private EditionCacheManager editionCache;
+
 	/**
 	 * Loads the profile page.
 	 *
@@ -70,6 +78,10 @@ public class TAMProfileController {
 
 		model.addAttribute("poloPatch", new ShirtPatchDTO());
 
+		List<RoleEditionDetailsDTO> roles = roleService.getTARolesForPerson(person.getId());
+		editionCache.get(roles.stream().map(r -> r.getEdition().getId()).distinct());
+		model.addAttribute("roles", roles);
+
 		return "profile/view";
 	}
 
@@ -89,6 +101,10 @@ public class TAMProfileController {
 		model.addAttribute("person", person);
 		model.addAttribute("teacherView", true);
 
+		List<RoleEditionDetailsDTO> roles = roleService.getTARolesForPerson(person.getId());
+		editionCache.get(roles.stream().map(r -> r.getEdition().getId()).distinct());
+		model.addAttribute("roles", roles);
+
 		return "profile/view";
 	}
 
diff --git a/src/main/java/nl/tudelft/tam/dto/create/TamEditionCreateDTO.java b/src/main/java/nl/tudelft/tam/dto/create/TamEditionCreateDTO.java
index 15976a5a3390de002cd9f4915012a277c4f8fcb9..80a7a40bca37df78f486ff48e4aaa0798e16f9e7 100644
--- a/src/main/java/nl/tudelft/tam/dto/create/TamEditionCreateDTO.java
+++ b/src/main/java/nl/tudelft/tam/dto/create/TamEditionCreateDTO.java
@@ -28,7 +28,6 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import nl.tudelft.labracore.api.dto.CohortIdDTO;
 import nl.tudelft.labracore.api.dto.CourseIdDTO;
-import nl.tudelft.labracore.api.dto.EditionCreateDTO;
 
 import org.springframework.format.annotation.DateTimeFormat;
 
@@ -47,9 +46,6 @@ public class TamEditionCreateDTO {
 	@NotNull
 	private CohortIdDTO cohort;
 
-	@NotNull
-	private EditionCreateDTO.EnrollabilityEnum enrollability;
-
 	@NotNull
 	@DateTimeFormat(pattern = "yyyy-MM-dd")
 	private LocalDate startDate;
diff --git a/src/main/java/nl/tudelft/tam/dto/patch/JobOfferMessagePatchDTO.java b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferMessagePatchDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..be0be3682cf2ec9eeed47d00613cb7445cfefe90
--- /dev/null
+++ b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferMessagePatchDTO.java
@@ -0,0 +1,51 @@
+/*
+ * TAM
+ * Copyright (C) 2021 - Delft University of Technology
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+package nl.tudelft.tam.dto.patch;
+
+import lombok.*;
+import nl.tudelft.librador.dto.patch.Patch;
+import nl.tudelft.tam.model.JobOffer;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = false)
+public class JobOfferMessagePatchDTO extends Patch<JobOffer> {
+
+	private String description;
+
+	private String hiringMessage;
+
+	private String rejectMessage;
+
+	@Builder.Default
+	private Boolean requireApplicationText = false;
+
+	@Override
+	protected void applyOneToOne() {
+		updateNonNull(description, data::setDescription);
+		updateNonNull(hiringMessage, data::setHiringMessage);
+		updateNonNull(rejectMessage, data::setRejectMessage);
+		updateNonNull(requireApplicationText, data::setRequireApplicationText);
+	}
+
+	@Override
+	protected void validate() {
+	}
+}
diff --git a/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java
index a5ac560d66cf2f1414e1bab89fddfe72c73d8599..431427738a6b3f14a1d5a8ac562151ad36c083d2 100644
--- a/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java
+++ b/src/main/java/nl/tudelft/tam/dto/patch/JobOfferPatchDTO.java
@@ -52,15 +52,6 @@ public class JobOfferPatchDTO extends Patch<JobOffer> {
 	@DateTimeFormat(pattern = "yyyy-MM-dd")
 	private LocalDate deadline;
 
-	private String description;
-
-	private String hiringMessage;
-
-	private String rejectMessage;
-
-	@Builder.Default
-	private Boolean requireApplicationText = false;
-
 	@Override
 	protected void applyOneToOne() {
 		updateNonNull(name, data::setName);
@@ -70,10 +61,6 @@ public class JobOfferPatchDTO extends Patch<JobOffer> {
 		updateNonNull(baanCode, data::setBaanCode);
 		data.setMaxHours(maxHours);
 		data.setDeadline(deadline);
-		data.setDescription(description != null && description.isBlank() ? null : description);
-		data.setHiringMessage(hiringMessage);
-		data.setRejectMessage(rejectMessage);
-		updateNonNull(requireApplicationText, data::setRequireApplicationText);
 	}
 
 	@Override
diff --git a/src/main/java/nl/tudelft/tam/security/AuthorisationService.java b/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
index af0541a3ac62cdd86b11be7c03964b9f4cea8cc6..da770b4921f456a6fc463cca5140ee83445f2cda 100644
--- a/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
+++ b/src/main/java/nl/tudelft/tam/security/AuthorisationService.java
@@ -18,6 +18,7 @@
 package nl.tudelft.tam.security;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -68,6 +69,9 @@ public class AuthorisationService {
 	@Autowired
 	private CoordinatorService coordinatorService;
 
+	@Autowired
+	private ProgramService programService;
+
 	/**
 	 * Returns the authenticated person from the user principal.
 	 *
@@ -124,7 +128,20 @@ public class AuthorisationService {
 	 */
 	public boolean isCoordinatorForProgram(Long programId) {
 		return isAdmin()
-				|| coordinatorService.existsByPersonIdAndProgramId(getAuthPerson().getId(), programId);
+				|| coordinatorService.existsByPersonIdAndProgramId(getAuthPerson().getId(), programId)
+				|| programService.get(programId).getCoordinators().stream()
+						.anyMatch(c -> Objects.equals(c.getId(), getAuthPerson().getId()));
+	}
+
+	/**
+	 * Checks if the person can edit the coordinators for a programme
+	 *
+	 * @param  programId the id of the programme
+	 * @return           True iff the authenticated person can edit the coordinators for the programme
+	 */
+	public boolean canEditCoordinatorsForProgram(Long programId) {
+		return isAdmin() || programService.get(programId).getCoordinators().stream()
+				.anyMatch(c -> Objects.equals(c.getId(), getAuthPerson().getId()));
 	}
 
 	/**
@@ -186,7 +203,7 @@ public class AuthorisationService {
 		List<RoleDetailsDTO> roles = roleService
 				.getRolesById(List.of(editionId),
 						List.of(getAuthPerson().getId()));
-		return roles.size() != 1 || roles.get(0).getType().equals(RoleDetailsDTO.TypeEnum.TEACHER);
+		return roles.size() == 1 && roles.get(0).getType().equals(RoleDetailsDTO.TypeEnum.TEACHER);
 	}
 
 	/**
diff --git a/src/main/java/nl/tudelft/tam/service/CoordinatorService.java b/src/main/java/nl/tudelft/tam/service/CoordinatorService.java
index 41bba00c11d95e84d4692f7cb63097f998337ea8..9bd7a9b8a9d8f051e3acd3ccd1b2bd41adb1e50f 100644
--- a/src/main/java/nl/tudelft/tam/service/CoordinatorService.java
+++ b/src/main/java/nl/tudelft/tam/service/CoordinatorService.java
@@ -18,14 +18,18 @@
 package nl.tudelft.tam.service;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import nl.tudelft.labracore.api.PersonControllerApi;
+import nl.tudelft.labracore.api.dto.PersonSummaryDTO;
 import nl.tudelft.tam.model.Coordinator;
 import nl.tudelft.tam.repository.CoordinatorRepository;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 @Service
 public class CoordinatorService {
@@ -39,6 +43,9 @@ public class CoordinatorService {
 	@Autowired
 	CourseService courseService;
 
+	@Autowired
+	PersonControllerApi personApi;
+
 	/**
 	 * Finds all coordinator objects by person id
 	 *
@@ -81,6 +88,16 @@ public class CoordinatorService {
 				.map(Coordinator::getProgramId).collect(Collectors.toSet());
 	}
 
+	/**
+	 * Finds all coordinators by program id
+	 *
+	 * @param  programId The program id to search by
+	 * @return           The list of coordinators
+	 */
+	public List<Coordinator> getCoordinatorsByProgram(Long programId) {
+		return coordinatorRepository.findAllByProgramId(programId);
+	}
+
 	/**
 	 * Finds all coordinators by edition id
 	 *
@@ -92,4 +109,27 @@ public class CoordinatorService {
 		Long programId = courseService.getOrThrow(courseId).getProgram().getId();
 		return coordinatorRepository.findAllByProgramId(programId);
 	}
+
+	/**
+	 * Sets the coordinators for the given programme to the people corresponding to the specified usernames.
+	 *
+	 * @param programId The id of the programme
+	 * @param usernames The usernames of the new coordinators
+	 */
+	@Transactional
+	public void setCoordinatorsForProgram(Long programId, List<String> usernames) {
+		List<PersonSummaryDTO> coordinators = personApi.searchForPeople(usernames).block().getPeople();
+		for (Coordinator coordinator : coordinatorRepository.findAllByProgramId(programId)) {
+			if (coordinators.stream().noneMatch(c -> Objects.equals(coordinator.getId(), c.getId()))) {
+				coordinatorRepository.delete(coordinator);
+			}
+		}
+		for (PersonSummaryDTO coordinator : coordinators) {
+			if (!coordinatorRepository.existsByPersonIdAndProgramId(coordinator.getId(), programId)) {
+				coordinatorRepository.save(
+						Coordinator.builder().programId(programId).personId(coordinator.getId()).build());
+			}
+		}
+	}
+
 }
diff --git a/src/main/java/nl/tudelft/tam/service/JobOfferService.java b/src/main/java/nl/tudelft/tam/service/JobOfferService.java
index 01d16ef4431dcf9c4ee9054fdac9870c720ad962..1a565d898c72d6b991f782aa8eabd959642e311b 100644
--- a/src/main/java/nl/tudelft/tam/service/JobOfferService.java
+++ b/src/main/java/nl/tudelft/tam/service/JobOfferService.java
@@ -29,10 +29,10 @@ import javax.transaction.Transactional;
 import javax.validation.constraints.NotNull;
 
 import nl.tudelft.labracore.api.dto.*;
+import nl.tudelft.librador.dto.patch.Patch;
 import nl.tudelft.librador.dto.view.View;
 import nl.tudelft.tam.dto.create.JobOfferCreateDTO;
 import nl.tudelft.tam.dto.create.MissingEditionsJobOfferImportDTO;
-import nl.tudelft.tam.dto.patch.JobOfferPatchDTO;
 import nl.tudelft.tam.dto.view.details.JobOfferDetailsDTO;
 import nl.tudelft.tam.dto.view.summary.JobOfferSummaryDTO;
 import nl.tudelft.tam.enums.Status;
@@ -175,7 +175,7 @@ public class JobOfferService {
 	 * @param dto the changed job offer.
 	 */
 	@Transactional
-	public void patchJobOffer(Long id, JobOfferPatchDTO dto) {
+	public void patchJobOffer(Long id, Patch<JobOffer> dto) {
 		dto.apply(jobOfferRepository.findByIdOrThrow(id));
 	}
 
diff --git a/src/main/java/nl/tudelft/tam/service/RoleService.java b/src/main/java/nl/tudelft/tam/service/RoleService.java
index a008fc3cf5acb138bc390371fbc23133531a64a1..7c1717c3144e4212e7b6c262cc2bc3cf1231484a 100644
--- a/src/main/java/nl/tudelft/tam/service/RoleService.java
+++ b/src/main/java/nl/tudelft/tam/service/RoleService.java
@@ -17,10 +17,15 @@
  */
 package nl.tudelft.tam.service;
 
+import static nl.tudelft.labracore.api.dto.RoleEditionDetailsDTO.TypeEnum.HEAD_TA;
+import static nl.tudelft.labracore.api.dto.RoleEditionDetailsDTO.TypeEnum.TA;
+
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.stream.Collectors;
 
+import nl.tudelft.labracore.api.PersonControllerApi;
 import nl.tudelft.labracore.api.RoleControllerApi;
 import nl.tudelft.labracore.api.dto.*;
 
@@ -42,6 +47,20 @@ public class RoleService {
 	@Autowired
 	RoleControllerApi roleControllerApi;
 
+	@Autowired
+	PersonControllerApi personApi;
+
+	/**
+	 * Get all the TA and Head TA roles for a person.
+	 *
+	 * @param  personId The id of the person
+	 * @return          The list of roles
+	 */
+	public List<RoleEditionDetailsDTO> getTARolesForPerson(Long personId) {
+		return personApi.getRolesForPerson(personId).collectList().block().stream()
+				.filter(r -> Set.of(TA, HEAD_TA).contains(r.getType())).toList();
+	}
+
 	/**
 	 * Checks if a person has a role in an edition
 	 *
diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties
index 36b4e507bbd4fb8ee6822713513c00ded2ce1b60..24faf53feb3b8ffc99f68d43784ca67165f08a0d 100644
--- a/src/main/resources/messages.properties
+++ b/src/main/resources/messages.properties
@@ -58,8 +58,11 @@ edition.cohort = Cohort
 edition.cohort.import = Import participants from cohort
 edition.startDate = Start Date
 edition.startDate.enter = Enter start date... (dd-mm-yyyy HH:mm)
+edition.startDate.tooltip = Enter the date from which you want job offers to be visible.
 edition.endDate = End Date
 edition.endDate.enter = Enter end date... (dd-mm-yyyy HH:mm)
+edition.endDate.tooltip = Enter a date after the last resit for this edition.
+edition.name.tooltip = Enter only the 'edition' part of the name, e.g. '23/24 Q1'
 edition.enrollability = Enrollment Policy
 edition.enrollability.open = Open
 edition.enrollability.open_to_program = Open to Program
@@ -87,6 +90,8 @@ profile.notifications.emailOff = Emails Disabled
 profile.notifications.edit = Edit Notification Preferences
 profile.notifications.email = Email Notifications
 profile.notifications.frequency = Email Frequency
+profile.experience = Experience
+profile.noExperience = No previous TA experience
 
 jobOffer = Job Offer
 jobOffer.many = Job Offers
@@ -106,6 +111,7 @@ jobOffer.retract = Retract
 jobOffer.retract.confirm = Confirm Retraction
 jobOffer.retract.confirm.desc = Are you sure you would like to retract your application for the following positions:
 jobOffer.description = Job Description
+jobOffer.description.none = This job offer has no information
 jobOffer.contractName = Contract Name
 jobOffer.contractName.enter = Enter a name for the FlexDelft contract...
 jobOffer.contractStartDate = Contract Start Date
@@ -203,6 +209,10 @@ application.noContent = No response
 application.enterContent = Enter response
 application.viewContent = View response
 
+role = Role
+role.ta = TA
+role.head_ta = Head TA
+
 extraWork = Contract Request
 extraWork.many = Contract Requests
 extraWork.description = Work Description
@@ -363,9 +373,11 @@ training.import.success.title = Successfully Imported Training
 training.import.success.desc = Successfully imported training for student(s)!
 
 coordinator = Coordinator
+coordinators = Coordinators
 coordinator.manage = Manage Programmes
 coordinator.search = Programme...
 coordinator.empty = Sadly, you are not a coordinator for any programmes (yet?)
+coordinator.enterUsernames = Enter the NetIDs of the TA coordinators
 # Training
 coordinator.training = TA Training
 coordinator.training.empty = No TA trainings have been created. Try adding one!
diff --git a/src/main/resources/templates/coordinator/manage.html b/src/main/resources/templates/coordinator/manage.html
index c073a7bae6f0aa48cc39e945c0477dec73f4425f..c67a06345ead062bdf4d6b4d6eb70c5795ef2feb 100644
--- a/src/main/resources/templates/coordinator/manage.html
+++ b/src/main/resources/templates/coordinator/manage.html
@@ -61,7 +61,14 @@
                             data-style="outlined"
                             th:href="@{|/coordinator/defaults/${program.id}|}"
                             th:text="|#{general.manage} #{coordinator.defaults}|"></a>
+                        <button
+                            th:if="${@authorisationService.canEditCoordinatorsForProgram(program.id)}"
+                            class="button grow"
+                            data-style="outlined"
+                            th:data-dialog="|edit-coordinators-${program.id}-overlay|"
+                            th:text="|#{general.manage} #{coordinators}|"></button>
                     </div>
+                    <th:block th:replace="~{coordinator/manage_coordinators :: overlay}"></th:block>
                 </div>
             </div>
 
diff --git a/src/main/resources/templates/coordinator/manage_coordinators.html b/src/main/resources/templates/coordinator/manage_coordinators.html
new file mode 100644
index 0000000000000000000000000000000000000000..d555a965ef22d3d86b1a8490966965a9935bcf66
--- /dev/null
+++ b/src/main/resources/templates/coordinator/manage_coordinators.html
@@ -0,0 +1,58 @@
+<!--
+
+    TAM
+    Copyright (C) 2021 - Delft University of Technology
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as
+    published by the Free Software Foundation, either version 3 of the
+    License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+-->
+<!DOCTYPE html>
+<html
+    lang="en"
+    xmlns:th="http://www.thymeleaf.org"
+    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
+    <body>
+        <dialog
+            th:fragment="overlay"
+            th:if="${@authorisationService.isCoordinatorForProgram(program.id)}"
+            th:id="|edit-coordinators-${program.id}-overlay|"
+            class="dialog">
+            <form
+                th:method="patch"
+                th:action="@{/program/{programId}/coordinators(programId=${program.id})}"
+                class="flex vertical p-7">
+                <h1 class="underlined font-500" th:text="|#{general.manage} #{coordinators}|"></h1>
+
+                <label for="coordinators" th:text="#{coordinator.enterUsernames}"></label>
+                <textarea
+                    class="textfield"
+                    rows="5"
+                    id="coordinators"
+                    name="coordinators"
+                    th:text="${#strings.listJoin(coordinators[program.id].![username], '&#10;')}"></textarea>
+
+                <div class="flex space-between">
+                    <button
+                        type="button"
+                        class="button p-less"
+                        data-type="error"
+                        data-style="outlined"
+                        th:text="#{general.cancel}"
+                        data-cancel></button>
+                    <button type="submit" class="button p-less" th:text="#{general.edit}"></button>
+                </div>
+            </form>
+        </dialog>
+    </body>
+</html>
diff --git a/src/main/resources/templates/edition/create.html b/src/main/resources/templates/edition/create.html
index fc2f06e424e3891f72d6df42375d0cba9de3537c..31cd7c5b659bf30a1067fbf93c9f41bf55af5afb 100644
--- a/src/main/resources/templates/edition/create.html
+++ b/src/main/resources/templates/edition/create.html
@@ -36,7 +36,15 @@
                 <h1 class="underlined font-500" th:text="#{edition.create}"></h1>
 
                 <div class="grid gap-3 align-center" style="grid-template-columns: 8rem 1fr">
-                    <label for="name" th:text="#{general.name}"></label>
+                    <div>
+                        <label for="name" th:text="#{general.name}"></label>
+                        <div class="tooltip">
+                            <span class="tooltip__control fa-solid fa-question"></span>
+                            <div role="tooltip">
+                                <p th:text="#{edition.name.tooltip}"></p>
+                            </div>
+                        </div>
+                    </div>
                     <input
                         id="name"
                         th:name="name"
@@ -63,7 +71,15 @@
                         </select>
                     </div>
 
-                    <label for="start-date" th:text="#{edition.startDate}"></label>
+                    <div>
+                        <label for="start-date" th:text="#{edition.startDate}"></label>
+                        <div class="tooltip">
+                            <span class="tooltip__control fa-solid fa-question"></span>
+                            <div role="tooltip">
+                                <p th:text="#{edition.startDate.tooltip}"></p>
+                            </div>
+                        </div>
+                    </div>
                     <input
                         id="start-date"
                         th:name="startDate"
@@ -72,7 +88,15 @@
                         class="textfield"
                         required />
 
-                    <label for="end-date" th:text="#{edition.endDate}"></label>
+                    <div>
+                        <label for="end-date" th:text="#{edition.endDate}"></label>
+                        <div class="tooltip">
+                            <span class="tooltip__control fa-solid fa-question"></span>
+                            <div role="tooltip">
+                                <p th:text="#{edition.endDate.tooltip}"></p>
+                            </div>
+                        </div>
+                    </div>
                     <input
                         id="end-date"
                         th:name="endDate"
@@ -80,14 +104,6 @@
                         type="date"
                         class="textfield"
                         required />
-
-                    <label for="enrollment" th:text="#{edition.enrollability}"></label>
-                    <select id="enrollment" th:name="enrollability" class="textfield">
-                        <option
-                            th:each="option : ${T(nl.tudelft.labracore.api.dto.EditionDetailsDTO.EnrollabilityEnum).values()}"
-                            th:text="#{|edition.enrollability.${#strings.toLowerCase(option.name())}|}"
-                            th:value="${option}"></option>
-                    </select>
                 </div>
 
                 <div class="flex space-between">
diff --git a/src/main/resources/templates/job_offer/create.html b/src/main/resources/templates/job_offer/create.html
index fb924845eef8079682a9780683c4986c0b5b8213..152609d3711520fc17aa1d7b75219950f43388fc 100644
--- a/src/main/resources/templates/job_offer/create.html
+++ b/src/main/resources/templates/job_offer/create.html
@@ -60,64 +60,6 @@
                         class="textfield"
                         required />
 
-                    <label
-                        for="new-job-offer-description"
-                        th:text="#{jobOffer.descriptionMessage}"></label>
-                    <textarea
-                        id="new-job-offer-description"
-                        th:name="description"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.descriptionMessage.enter}"
-                        maxlength="2047"></textarea>
-                    <div></div>
-                    <div>
-                        <input
-                            id="new-job-offer-require-response"
-                            name="requireApplicationText"
-                            type="checkbox" />
-                        <label
-                            for="new-job-offer-require-response"
-                            th:text="#{jobOffer.requireResponse}"></label>
-                        <script>
-                            const requireResponse = document.getElementById(
-                                "new-job-offer-require-response"
-                            );
-                            const description = document.getElementById(
-                                "new-job-offer-description"
-                            );
-                            requireResponse.addEventListener("change", function () {
-                                if (requireResponse.checked) {
-                                    description.setAttribute("required", "");
-                                } else {
-                                    description.removeAttribute("required");
-                                }
-                            });
-                        </script>
-                    </div>
-
-                    <label
-                        for="new-job-offer-hiring-message"
-                        th:text="#{jobOffer.hiringMessage}"></label>
-                    <textarea
-                        id="new-job-offer-hiring-message"
-                        th:name="hiringMessage"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.hiringMessage.enter}"
-                        maxlength="255"></textarea>
-
-                    <label
-                        for="new-job-offer-reject-message"
-                        th:text="#{jobOffer.rejectMessage}"></label>
-                    <textarea
-                        id="new-job-offer-reject-message"
-                        th:name="rejectMessage"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.rejectMessage.enter}"
-                        maxlength="255"></textarea>
-
                     <label
                         for="new-job-offer-contract-name"
                         th:text="#{jobOffer.contractName}"></label>
diff --git a/src/main/resources/templates/job_offer/edit.html b/src/main/resources/templates/job_offer/edit.html
index 928d412ce31df1b532a17d826e449fb6d1252144..926d053bd1add32876176dcc3e1f6a5da8853148 100644
--- a/src/main/resources/templates/job_offer/edit.html
+++ b/src/main/resources/templates/job_offer/edit.html
@@ -46,69 +46,6 @@
                         th:value="${offer.name}"
                         required />
 
-                    <label
-                        for="new-job-offer-description"
-                        th:text="#{jobOffer.descriptionMessage}"></label>
-                    <textarea
-                        id="new-job-offer-description"
-                        th:name="description"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.descriptionMessage.enter}"
-                        th:text="${offer.description}"
-                        th:required="${offer.requireApplicationText}"
-                        maxlength="2047"></textarea>
-                    <div></div>
-                    <div>
-                        <input
-                            id="new-job-offer-require-response"
-                            name="requireApplicationText"
-                            type="checkbox"
-                            th:checked="${offer.requireApplicationText}" />
-                        <label
-                            for="new-job-offer-require-response"
-                            th:text="#{jobOffer.requireResponse}"></label>
-                        <script>
-                            const requireResponse = document.getElementById(
-                                "new-job-offer-require-response"
-                            );
-                            const description = document.getElementById(
-                                "new-job-offer-description"
-                            );
-                            requireResponse.addEventListener("change", function () {
-                                if (requireResponse.checked) {
-                                    description.setAttribute("required", "");
-                                } else {
-                                    description.removeAttribute("required");
-                                }
-                            });
-                        </script>
-                    </div>
-
-                    <label
-                        for="new-job-offer-hiring-message"
-                        th:text="#{jobOffer.hiringMessage}"></label>
-                    <textarea
-                        id="new-job-offer-hiring-message"
-                        th:name="hiringMessage"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.hiringMessage.enter}"
-                        th:text="${offer.hiringMessage}"
-                        maxlength="255"></textarea>
-
-                    <label
-                        for="new-job-offer-reject-message"
-                        th:text="#{jobOffer.rejectMessage}"></label>
-                    <textarea
-                        id="new-job-offer-reject-message"
-                        th:name="rejectMessage"
-                        class="textfield"
-                        type="text"
-                        th:placeholder="#{jobOffer.rejectMessage.enter}"
-                        th:text="${offer.rejectMessage}"
-                        maxlength="255"></textarea>
-
                     <label
                         for="new-job-offer-contract-name"
                         th:text="#{jobOffer.contractName}"></label>
diff --git a/src/main/resources/templates/job_offer/manage.html b/src/main/resources/templates/job_offer/manage.html
index 0ece549026b5b85d3a6fe7f176b1959f435bd690..884b67dd9c1c4a7afc1b08044aa6c94c2d6c767f 100644
--- a/src/main/resources/templates/job_offer/manage.html
+++ b/src/main/resources/templates/job_offer/manage.html
@@ -148,11 +148,18 @@
                                     class="link"
                                     th:href="@{|/job-offer/${offer.id}|}"
                                     th:text="${offer.name}"></a>
-                                <span
-                                    th:if="${@applicationService.getNumberOfUnhandledApplications(offer.id)} > 0"
-                                    th:text="|${@applicationService.getNumberOfUnhandledApplications(offer.id)} pending|"
-                                    class="chip"
-                                    data-type="warning"></span>
+                                <div>
+                                    <span
+                                        th:if="${offer.deadline?.isBefore(#temporals.createToday())} ?: false"
+                                        th:text="#{jobOffer.deadline.closed}"
+                                        class="chip"
+                                        data-type="info"></span>
+                                    <span
+                                        th:if="${@applicationService.getNumberOfUnhandledApplications(offer.id)} > 0"
+                                        th:text="|${@applicationService.getNumberOfUnhandledApplications(offer.id)} pending|"
+                                        class="chip"
+                                        data-type="warning"></span>
+                                </div>
                             </li>
                         </ul>
                     </div>
diff --git a/src/main/resources/templates/job_offer/view_one.html b/src/main/resources/templates/job_offer/view_one.html
index 2882b8365ac71c48e7cb603ce351cf4184d211bc..be04f8f37c8f4d7722b6a777a5031af9c296e749 100644
--- a/src/main/resources/templates/job_offer/view_one.html
+++ b/src/main/resources/templates/job_offer/view_one.html
@@ -113,9 +113,151 @@
                 </div>
             </div>
 
-            <div class="surface" th:if="${offer.description}">
-                <h2 class="underlined font-500 mb-5" th:text="#{jobOffer.descriptionMessage}"></h2>
-                <div class="article" th:utext="${offer.descriptionHtml}"></div>
+            <div class="surface">
+                <h2 class="underlined font-500 mb-5">Messages</h2>
+                <div class="tabs mb-3" role="tablist">
+                    <button
+                        role="tab"
+                        id="job-information-tab"
+                        aria-selected="true"
+                        aria-controls="job-information">
+                        Job information
+                    </button>
+                    <button
+                        role="tab"
+                        id="hiring-message-tab"
+                        aria-selected="false"
+                        aria-controls="hiring-message">
+                        Hiring message
+                    </button>
+                    <button
+                        role="tab"
+                        id="rejection-message-tab"
+                        aria-selected="false"
+                        aria-controls="rejection-message">
+                        Rejection message
+                    </button>
+                </div>
+
+                <div id="job-information" aria-labelledby="job-information-tab">
+                    <div class="flex vertical gap-3" id="view-information">
+                        <div
+                            th:if="${offer.description}"
+                            class="article"
+                            th:utext="${offer.descriptionHtml}"></div>
+                        <p
+                            th:unless="${offer.description}"
+                            th:text="#{jobOffer.description.none}"></p>
+                        <div>
+                            <button id="edit-information-button" class="button">
+                                <span class="fa-solid fa-pencil"></span>
+                                <span>Edit</span>
+                            </button>
+                        </div>
+                    </div>
+                    <form
+                        class="flex vertical gap-3 hidden"
+                        id="edit-information"
+                        th:method="patch"
+                        th:action="@{/job-offer/{id}/messages(id=${offer.id})}">
+                        <textarea
+                            class="textfield"
+                            data-style="variant"
+                            placeholder="Enter job information"
+                            th:text="${offer.description}"
+                            rows="4"
+                            name="description"
+                            aria-label="Job information"
+                            id="description"
+                            required></textarea>
+                        <div>
+                            <input
+                                id="new-job-offer-require-response"
+                                name="requireApplicationText"
+                                type="checkbox"
+                                th:checked="${offer.requireApplicationText}" />
+                            <label
+                                for="new-job-offer-require-response"
+                                th:text="#{jobOffer.requireResponse}"></label>
+                        </div>
+                        <div class="flex gap-3">
+                            <button
+                                id="cancel-edit-information-button"
+                                type="button"
+                                class="button"
+                                data-style="outlined">
+                                <span class="fa-solid fa-xmark"></span>
+                                <span>Cancel</span>
+                            </button>
+                            <button type="submit" class="button">
+                                <span class="fa-solid fa-save"></span>
+                                <span>Save</span>
+                            </button>
+                        </div>
+                    </form>
+                    <script>
+                        document.addEventListener("DOMContentLoaded", function () {
+                            const editButton = document.getElementById("edit-information-button");
+                            const cancelButton = document.getElementById(
+                                "cancel-edit-information-button"
+                            );
+                            const viewDesc = document.getElementById("view-information");
+                            const editDesc = document.getElementById("edit-information");
+                            const descField = document.getElementById("description");
+                            let originalDesc;
+                            editButton.addEventListener("click", function () {
+                                viewDesc.classList.add("hidden");
+                                editDesc.classList.remove("hidden");
+                                originalDesc = descField.value;
+                            });
+                            cancelButton.addEventListener("click", function () {
+                                viewDesc.classList.remove("hidden");
+                                editDesc.classList.add("hidden");
+                                descField.value = originalDesc;
+                            });
+                        });
+                    </script>
+                </div>
+
+                <div id="hiring-message" aria-labelledby="hiring-message-tab" hidden>
+                    <form
+                        class="flex vertical gap-3"
+                        th:method="patch"
+                        th:action="@{/job-offer/{id}/messages(id=${offer.id})}">
+                        <textarea
+                            class="textfield"
+                            data-style="variant"
+                            placeholder="Enter hiring message"
+                            th:text="${offer.hiringMessage}"
+                            rows="4"></textarea>
+                        <div>
+                            <button class="button">
+                                <span class="fa-solid fa-save"></span>
+                                <span>Save</span>
+                            </button>
+                        </div>
+                    </form>
+                </div>
+
+                <div id="rejection-message" aria-labelledby="rejection-message-tab" hidden>
+                    <form
+                        class="flex vertical gap-3"
+                        th:method="patch"
+                        th:action="@{/job-offer/{id}/messages(id=${offer.id})}">
+                        <textarea
+                            class="textfield"
+                            data-style="variant"
+                            placeholder="Enter rejection message"
+                            th:text="${offer.rejectMessage}"
+                            rows="4"></textarea>
+                        <div>
+                            <button class="button">
+                                <span class="fa-solid fa-save"></span>
+                                <span>Save</span>
+                            </button>
+                        </div>
+                    </form>
+                </div>
             </div>
 
             <div class="surface flex space-around">
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html
index 64d30ab46b73c70510f9e5123feefcb8a90bf6ab..31a0629eac0fbbe48878132c32e55988a6c8ac21 100644
--- a/src/main/resources/templates/layout.html
+++ b/src/main/resources/templates/layout.html
@@ -24,13 +24,13 @@
     xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
     <head>
         <link rel="stylesheet" href="/webjars/font-awesome/css/all.min.css" />
-        <link rel="stylesheet" href="/webjars/chihuahui/main.css" />
+        <link rel="stylesheet" href="/webjars/chihuahui/1.0.0/main.css" />
 
         <script src="/webjars/jquery/jquery.min.js"></script>
         <script src="/webjars/momentjs/2.29.4/min/moment.min.js"></script>
-        <script type="module" src="/webjars/chihuahui/components.js"></script>
-        <script src="/webjars/chihuahui/selectbox.js"></script>
-        <script src="/webjars/chihuahui/theme.js"></script>
+        <script type="module" src="/webjars/chihuahui/1.0.0/components.js"></script>
+        <script src="/webjars/chihuahui/1.0.0/selectbox.js"></script>
+        <script src="/webjars/chihuahui/1.0.0/theme.js"></script>
         <script th:src="@{/js/main.js}"></script>
 
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
diff --git a/src/main/resources/templates/profile/view.html b/src/main/resources/templates/profile/view.html
index 836b23d0a2dbeeac0860fb8e57dd2be7f16476ea..b820434f6fcb59d64e5f0e8a62e0633d573be04e 100644
--- a/src/main/resources/templates/profile/view.html
+++ b/src/main/resources/templates/profile/view.html
@@ -81,7 +81,7 @@
                     th:unless="${@authorisationService.isStaff() && !teacherView}">
                     <h2 class="underlined font-500" th:text="#{profile.payscale}"></h2>
                     <span th:text="${profile.payScale.detailedString()}"></span>
-                    <div>
+                    <div th:unless="${teacherView}">
                         <button
                             class="button"
                             data-style="outlined"
@@ -90,6 +90,11 @@
                             th:unless="${profile.payScale.equals(T(nl.tudelft.tam.enums.PayScale).SA4)}"></button>
                     </div>
                 </div>
+
+                <div class="surface flex vertical" th:if="${roles.isEmpty()}">
+                    <h2 class="underlined font-500" th:text="#{profile.experience}"></h2>
+                    <p th:text="#{profile.noExperience}"></p>
+                </div>
             </div>
 
             <div class="grid auto-fit" style="--col-width: 20rem">
@@ -114,6 +119,22 @@
                 </div>
             </div>
 
+            <div class="flex vertical" th:unless="${roles.isEmpty()}">
+                <h2 class="underlined font-500" th:text="#{profile.experience}"></h2>
+                <table class="table" data-style="surface">
+                    <tr class="table__header">
+                        <th class="fit-content" th:text="#{course}"></th>
+                        <th th:text="#{role}"></th>
+                    </tr>
+                    <tr th:each="role : ${roles}">
+                        <td
+                            class="fit-content single-line"
+                            th:text="|${@editionCacheManager.getOrThrow(role.edition.id).course.name} - ${role.edition.name}|"></td>
+                        <td th:text="#{|role.${role.type.name().toLowerCase()}|}"></td>
+                    </tr>
+                </table>
+            </div>
+
             <div th:replace="~{profile/edit_polo :: overlay}" th:unless="${teacherView}"></div>
             <div th:replace="~{profile/view_training_details :: overlay}"></div>
             <div
diff --git a/src/test/java/nl/tudelft/tam/controller/EditionControllerTest.java b/src/test/java/nl/tudelft/tam/controller/EditionControllerTest.java
index 95a925617ced1b2d21a77474df95251369817ac4..96ddc9d9eefd7fbf88eb6f76a67014ee603a5361 100644
--- a/src/test/java/nl/tudelft/tam/controller/EditionControllerTest.java
+++ b/src/test/java/nl/tudelft/tam/controller/EditionControllerTest.java
@@ -75,7 +75,6 @@ public class EditionControllerTest {
 		tamEditionCreateDto.setName("Test");
 		tamEditionCreateDto.setStartDate(LocalDate.now());
 		tamEditionCreateDto.setEndDate(LocalDate.now().plusYears(1));
-		tamEditionCreateDto.setEnrollability(EditionCreateDTO.EnrollabilityEnum.OPEN);
 		tamEditionCreateDto.setCohort(new CohortIdDTO().id(1L));
 		tamEditionCreateDto.setCourse(new CourseIdDTO().id(1L));
 
@@ -83,7 +82,7 @@ public class EditionControllerTest {
 				.name(tamEditionCreateDto.getName())
 				.course(tamEditionCreateDto.getCourse())
 				.cohort(tamEditionCreateDto.getCohort())
-				.enrollability(tamEditionCreateDto.getEnrollability())
+				.enrollability(EditionCreateDTO.EnrollabilityEnum.OPEN)
 				.startDate(LocalDateTime.of(tamEditionCreateDto.getStartDate(), LocalTime.of(0, 0)))
 				.endDate(LocalDateTime.of(tamEditionCreateDto.getEndDate(), LocalTime.of(23, 59)));
 	}
diff --git a/src/test/java/nl/tudelft/tam/controller/ProgramControllerTest.java b/src/test/java/nl/tudelft/tam/controller/ProgramControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3b1cbd9ab2de7a62a98c1e73f7d478fbfdf09d0
--- /dev/null
+++ b/src/test/java/nl/tudelft/tam/controller/ProgramControllerTest.java
@@ -0,0 +1,63 @@
+/*
+ * TAM
+ * Copyright (C) 2021 - Delft University of Technology
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+package nl.tudelft.tam.controller;
+
+import static org.mockito.Mockito.verify;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.List;
+
+import javax.transaction.Transactional;
+
+import nl.tudelft.tam.service.CoordinatorService;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.security.test.context.support.WithUserDetails;
+import org.springframework.test.web.servlet.MockMvc;
+
+import application.test.TestTAMApplication;
+
+@AutoConfigureMockMvc
+@SpringBootTest(classes = TestTAMApplication.class)
+@Transactional
+public class ProgramControllerTest {
+
+	@Autowired
+	private MockMvc mvc;
+
+	@Autowired
+	private ProgramController programController;
+
+	@MockBean
+	private CoordinatorService coordinatorService;
+
+	@Test
+	@WithUserDetails("admin")
+	void updateCoordinators() throws Exception {
+		mvc.perform(patch("/program/1/coordinators?coordinators=user1\nuser2").with(csrf()))
+				.andExpect(status().is3xxRedirection());
+		verify(coordinatorService).setCoordinatorsForProgram(1L, List.of("user1", "user2"));
+	}
+
+}
diff --git a/src/test/java/nl/tudelft/tam/controller/TAMProfileControllerTest.java b/src/test/java/nl/tudelft/tam/controller/TAMProfileControllerTest.java
index cc2db9cb2c8c4a81308be9112c991de44d42f149..c7c02c71eaa6c798ab0058a27b3e653e54a8f27d 100644
--- a/src/test/java/nl/tudelft/tam/controller/TAMProfileControllerTest.java
+++ b/src/test/java/nl/tudelft/tam/controller/TAMProfileControllerTest.java
@@ -37,6 +37,7 @@ import nl.tudelft.tam.model.Profile;
 import nl.tudelft.tam.security.AuthorisationService;
 import nl.tudelft.tam.service.PersonService;
 import nl.tudelft.tam.service.ProfileService;
+import nl.tudelft.tam.service.RoleService;
 import nl.tudelft.tam.test.TestUserDetailsService;
 
 import org.junit.jupiter.api.BeforeEach;
@@ -72,6 +73,9 @@ class TAMProfileControllerTest {
 	@MockBean
 	PersonService personService;
 
+	@MockBean
+	RoleService roleService;
+
 	Profile profile;
 
 	@BeforeEach
diff --git a/src/test/java/nl/tudelft/tam/security/AuthorisationServiceTest.java b/src/test/java/nl/tudelft/tam/security/AuthorisationServiceTest.java
index c5187c8ee758341ac9bc61116a30b6c6b91d8a4b..162b5943307deb2aa0581f23c3d8837d0ed369c9 100644
--- a/src/test/java/nl/tudelft/tam/security/AuthorisationServiceTest.java
+++ b/src/test/java/nl/tudelft/tam/security/AuthorisationServiceTest.java
@@ -19,12 +19,14 @@ package nl.tudelft.tam.security;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.*;
 
+import java.util.Collections;
 import java.util.List;
 
+import nl.tudelft.labracore.api.ProgramControllerApi;
 import nl.tudelft.labracore.api.dto.CourseSummaryDTO;
+import nl.tudelft.labracore.api.dto.ProgramDetailsDTO;
 import nl.tudelft.labracore.lib.security.user.DefaultRole;
 import nl.tudelft.labracore.lib.security.user.Person;
 import nl.tudelft.tam.service.CoordinatorService;
@@ -32,10 +34,12 @@ import nl.tudelft.tam.service.CourseService;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.boot.test.mock.mockito.SpyBean;
 
+import reactor.core.publisher.Mono;
 import application.test.TestTAMApplication;
 
 @SpringBootTest(classes = TestTAMApplication.class)
@@ -50,6 +54,9 @@ public class AuthorisationServiceTest {
 	@MockBean
 	CourseService courseService;
 
+	@Autowired
+	ProgramControllerApi programApi;
+
 	Person admin, teacher, student;
 
 	@BeforeEach
@@ -94,6 +101,9 @@ public class AuthorisationServiceTest {
 
 	@Test
 	void isCoordinatorForProgramTest() {
+		when(programApi.getProgramById(anyLong()))
+				.thenReturn(Mono.just(new ProgramDetailsDTO().coordinators(Collections.emptyList())));
+
 		doReturn(admin).when(service).getAuthPerson();
 		assertThat(service.isCoordinatorForProgram(1L)).isTrue();
 
diff --git a/src/test/java/nl/tudelft/tam/service/CoordinatorServiceTest.java b/src/test/java/nl/tudelft/tam/service/CoordinatorServiceTest.java
index c0e39a49bb657b1219f5acd81ee60da101112ba4..e80e3c7b5f9f8d1687768762fbefc58dc016a86d 100644
--- a/src/test/java/nl/tudelft/tam/service/CoordinatorServiceTest.java
+++ b/src/test/java/nl/tudelft/tam/service/CoordinatorServiceTest.java
@@ -18,9 +18,14 @@
 package nl.tudelft.tam.service;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.*;
 
 import java.util.List;
 
+import nl.tudelft.labracore.api.PersonControllerApi;
+import nl.tudelft.labracore.api.dto.PersonSearchDTO;
+import nl.tudelft.labracore.api.dto.PersonSummaryDTO;
 import nl.tudelft.tam.model.Coordinator;
 import nl.tudelft.tam.repository.CoordinatorRepository;
 
@@ -30,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.transaction.annotation.Transactional;
 
+import reactor.core.publisher.Mono;
 import application.test.TestTAMApplication;
 
 @SpringBootTest(classes = TestTAMApplication.class)
@@ -46,6 +52,9 @@ public class CoordinatorServiceTest {
 	@Autowired
 	CoordinatorRepository repository;
 
+	@Autowired
+	PersonControllerApi personApi;
+
 	@BeforeEach
 	void setup() {
 		Coordinator tempCoord = new Coordinator();
@@ -72,4 +81,14 @@ public class CoordinatorServiceTest {
 		assertThat(service.existsByPersonIdAndProgramId(2L, 2L)).isFalse();
 	}
 
+	@Test
+	void setCoordinators() {
+		when(personApi.searchForPeople(anyList()))
+				.thenReturn(Mono.just(new PersonSearchDTO().people(List.of(new PersonSummaryDTO().id(5L)))));
+		service.setCoordinatorsForProgram(1L, List.of("username"));
+		List<Coordinator> coordinators = service.getCoordinatorsByProgram(1L);
+		assertThat(coordinators).hasSize(1);
+		assertThat(coordinators.get(0).getPersonId()).isEqualTo(5L);
+	}
+
 }