diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java
index 61876bd402f13ce74003c41efe440aca9fa4165b..4e0940d8a4cd12dc6acf8970c7cae612e4aac9be 100644
--- a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java
+++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java
@@ -44,6 +44,7 @@ public interface Command {
 	public String getCreatedBy();
 	public String getCreatedByName();
 	public CommandStatus getStatus();
+	String getCreatedByClientName();
 
 	public Map<String, Object> getBodyObject();
 	public Map<String, String> getBody();
diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7c08bc4538b8cc2bc93d1489a1609ab927dc0b9
--- /dev/null
+++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.command;
+
+public class VorgangLockedEvent extends CommandExecutedEvent {
+
+	public VorgangLockedEvent(Command command) {
+		super(command);
+	}
+}
diff --git a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java
index 3ebddf936e18f8c1576ca81400a5a93cd1f7ec07..98a46f1f9f5423cf0b04d51e208e985dfaa607d7 100644
--- a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java
+++ b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java
@@ -21,6 +21,7 @@ public class TestCommand implements Command {
 	private ZonedDateTime finishedAt;
 	private String createdBy;
 	private String createdByName;
+	private String createdByClientName;
 
 	private CommandStatus status;
 
diff --git a/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto b/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto
index b1c4bad8c989562a34bd0f821ed472b28a0cebcf..5f9efe1e4c9399cf8eecada3d7a23b1e89909f02 100644
--- a/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto
+++ b/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto
@@ -63,6 +63,13 @@ message GrpcVorgangWithEingang {
 
 message GrpcVorgangHead {
   GrpcServiceKonto serviceKonto = 1;
+  GrpcLock lock = 2;
+}
+
+message GrpcLock {
+  string clientName = 1;
+  string lockedSince = 2;
+  string reason = 3;
 }
 
 message GrpcEingang {
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
index ff7653e640230c195b26595b3b50c0589f305303..7ff69bdda006fb2d969558ea1f60dc7cc23f99e3 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
@@ -54,6 +54,7 @@ import de.ozgcloud.vorgang.callcontext.CurrentUserService;
 import de.ozgcloud.vorgang.callcontext.User;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
 import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException;
+import de.ozgcloud.vorgang.vorgang.VorgangService;
 import lombok.NonNull;
 
 @Service
@@ -65,15 +66,24 @@ public class CommandService {
 	@Autowired
 	private ApplicationEventPublisher publisher;
 
+	@Autowired
+	private VorgangService vorgangService;
 	@Autowired
 	private CurrentUserService userService;
 
 	public Command createCommand(CreateCommandRequest request) {
+		validateVorgang(request.getVorgangId());
 		var persisted = saveCommand(buildCommand(request));
 		publisher.publishEvent(new CommandCreatedEvent(persisted));
 		return persisted;
 	}
 
+	void validateVorgang(String vorgangId) {
+		if (vorgangService.isVorgangLocked(vorgangId)) {
+			throw new TechnicalException("Cannot create command. Vorgang %s is locked.".formatted(vorgangId));
+		}
+	}
+
 	private Command buildCommand(CreateCommandRequest request) {
 		var builder = PersistedCommand.builder()
 				.id(UUID.randomUUID().toString())
@@ -87,6 +97,7 @@ public class CommandService {
 				.body(request.getBody())
 				.bodyObject(request.getBodyObject());
 
+		userService.findUser().map(CallContextUser::getClientName).ifPresent(builder::createdByClientName);
 		builder = addUserIfExists(builder, Optional.ofNullable(request.getCallContext()).map(CallContext::getUser), userService.findUser());
 		return builder.build();
 	}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
index 7bdcc47b4fc18edd75dc50802ecc6a8c3a7ca980..f51468b4f6c1b2b2021edea87a9e3fb718e764b4 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java
@@ -40,6 +40,7 @@ public enum Order {
 	VORGANG_WIEDEREROEFFNEN,
 	VORGANG_ZUM_LOESCHEN_MARKIEREN,
 	VORGANG_LOESCHEN,
+	LOCK_VORGANG,
 
 	ASSIGN_USER,
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java
index 71964af4d27968376adf98bb011157c544c41e37..7e045d3e121d5971d33c910c5c717b1a5822d045 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java
@@ -63,6 +63,7 @@ public class PersistedCommand implements Command {
 
 	private String createdBy;
 	private String createdByName;
+	private String createdByClientName;
 
 	@Setter
 	private CommandStatus status;
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
new file mode 100644
index 0000000000000000000000000000000000000000..a888e0ea88582596dc39af16e2007bc66a507c3e
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang;
+
+import java.time.ZonedDateTime;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+class Lock {
+
+	static final String FIELD_CLIENT_NAME = "clientName";
+	static final String FIELD_LOCKED_SINCE = "lockedSince";
+	static final String FIELD_REASON = "reason";
+
+	private final String clientName;
+	private final ZonedDateTime lockedSince;
+	private final String reason;
+
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java
index 88557e44c95e469d95f17dbd1f413c3e941b19fc..979de7347065ba922cf5b41c2eb4151bfc293013 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java
@@ -50,6 +50,7 @@ public class Vorgang {
 	static final String MONGODB_FIELDNAME_CREATED_AT = "createdAt";
 	public static final String MONGODB_FIELDNAME_ASSIGNED_TO = "assignedTo";
 	public static final String MONGODB_FIELDNAME_IN_CREATION = "inCreation";
+	public static final String MONGODB_FIELDNAME_HEADER = "header";
 
 	public static final String FIELD_EINGANGSKENNZ = "eingangs.header.requestId";
 	public static final String FIELD_AKTENZEICHEN = "aktenzeichen";
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
index 4433839167a3ecf15dfe1667f920e6d2b2a38757..fe62492f032f6f357a8df8db7fbecee6ce1031c2 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java
@@ -35,6 +35,9 @@ import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.command.CommandRevokeFailedEvent;
+import de.ozgcloud.command.CommandRevokedEvent;
+import de.ozgcloud.command.RevokeCommandEvent;
 import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.Order;
 import de.ozgcloud.vorgang.files.FileService;
@@ -54,6 +57,9 @@ public class VorgangEventListener {
 	public static final Predicate<Command> IS_LOESCHEN_COMMAND = command -> Order.VORGANG_LOESCHEN.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_SET_AKTENZEICHEN_COMMAND = command -> Order.SET_AKTENZEICHEN.isMeant(command.getOrder());
 
+	private static final String IS_LOCK_VORGANG_COMMAND = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOCK_VORGANG_ORDER.test(event.getSource())}";
+	public static final Predicate<Command> IS_LOCK_VORGANG_ORDER = command -> Order.LOCK_VORGANG.isMeant(command.getOrder());
+
 	@Autowired
 	private StatusService statusService;
 	@Autowired
@@ -111,6 +117,29 @@ public class VorgangEventListener {
 		}
 	}
 
+	@EventListener(condition = IS_LOCK_VORGANG_COMMAND)
+	public void onLockVorgang(CommandCreatedEvent event) {
+		var command = event.getSource();
+		try {
+			vorgangService.lockVorgang(command);
+		} catch (RuntimeException e) {
+			LOG.error("Error locking vorgang.", e);
+			publisher.publishEvent(new CommandFailedEvent(command.getId(), e.getMessage()));
+		}
+	}
+
+	@EventListener(condition = IS_LOCK_VORGANG_COMMAND)
+	public void onRevokeLockVorgang(RevokeCommandEvent event) {
+		var command = event.getSource();
+		try {
+			vorgangService.unlockVorgang(command);
+			publisher.publishEvent(new CommandRevokedEvent(command));
+		} catch (RuntimeException e) {
+			LOG.error("Error unlocking vorgang.", e);
+			publisher.publishEvent(new CommandRevokeFailedEvent(command.getId(), e.getMessage()));
+		}
+	}
+
 	void publishEvent(CommandExecutedEvent event) {
 		LOG.debug("Command {} executed", event.getSource());
 		publisher.publishEvent(event);
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java
index 13e858035e377296843b70740e23c96ca3c3485e..2f3cb7ddde140b25b2e624da26d1594735bddaf7 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java
@@ -11,9 +11,13 @@ import lombok.Getter;
 @TypeAlias("VorgangHeader")
 public class VorgangHead {
 
+	public static final String FIELD_LOCK = "lock";
+
 	private ServiceKonto serviceKonto;
 
 	private String organisationsEinheitId;
 	@Builder.Default
 	private int collaborationLevel = 0;
+
+	private final Lock lock;
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
index 6c73fec3e55592fdde6648d3c0e449dcd86eb341..26d04339e3b70b7d4223f9767b369769565e4d2b 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java
@@ -31,31 +31,22 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Stream;
 
-import jakarta.annotation.PostConstruct;
-
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Update;
 import org.springframework.stereotype.Repository;
 
-import com.mongodb.client.result.UpdateResult;
-
 import de.ozgcloud.vorgang.common.db.CollisionVerifier;
 import de.ozgcloud.vorgang.common.db.CriteriaUtil;
+import lombok.RequiredArgsConstructor;
 
 @Repository
+@RequiredArgsConstructor
 class VorgangRepository {
 
-	@Autowired
-	private MongoOperations mongoOperations;
+	private final MongoOperations mongoOperations;
 
-	private CollisionVerifier collisionVerifier;
-
-	@PostConstruct
-	void init() {
-		collisionVerifier = new CollisionVerifier(this::exists);
-	}
+	private final CollisionVerifier collisionVerifier = new CollisionVerifier(this::exists);
 
 	public Optional<Vorgang> findById(String vorgangId) {
 		return Optional.ofNullable(findOne(CriteriaUtil.isId(vorgangId)));
@@ -85,16 +76,16 @@ class VorgangRepository {
 		var update = new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1);
 		patch.forEach(update::set);
 
-		updateFirst(whereIdAndVersion(vorgangId, version), update);
+		updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), update);
 	}
 
 	public void setAktenzeichen(String vorgangId, long version, String akteneinsicht) {
-		var updateResult = updateFirst(whereIdAndVersion(vorgangId, version), new Update().set(Vorgang.FIELD_AKTENZEICHEN, akteneinsicht));
-		collisionVerifier.verify(updateResult, vorgangId);
+		updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), new Update().set(Vorgang.FIELD_AKTENZEICHEN, akteneinsicht));
 	}
 
-	private UpdateResult updateFirst(Criteria queryObj, Update update) {
-		return mongoOperations.updateFirst(query(queryObj), update, Vorgang.class);
+	private void updateFirst(String vorgangId, Criteria queryObj, Update update) {
+		var updateResult = mongoOperations.updateFirst(query(queryObj), update, Vorgang.class);
+		collisionVerifier.verify(updateResult, vorgangId);
 	}
 
 	private Criteria whereIdAndVersion(String vorgangId, long version) {
@@ -112,4 +103,13 @@ class VorgangRepository {
 								.andOperator(isNotDeleted()))),
 				Vorgang.class);
 	}
+
+	public boolean isVorgangLocked(String vorgangId) {
+		return mongoOperations.exists(query(whereIdAndLock(vorgangId)), Vorgang.class);
+	}
+
+	Criteria whereIdAndLock(String vorgangId) {
+		return new Criteria().andOperator(CriteriaUtil.isId(vorgangId), CriteriaUtil.isNotDeleted(),
+				Criteria.where(VorgangService.KEY_HEADER_LOCK).ne(null));
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
index 67678fb2648931db32733b0f3c113d43e0d87bc5..bb11f2d9dd746310ba8ca7a2aa792347ae74498d 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java
@@ -23,10 +23,13 @@
  */
 package de.ozgcloud.vorgang.vorgang;
 
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -44,6 +47,8 @@ import org.springframework.validation.annotation.Validated;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.VorgangAssignedEvent;
 import de.ozgcloud.command.VorgangCreatedEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
+import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeMap;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap;
@@ -57,6 +62,7 @@ public class VorgangService {
 
 	private static final String BODY_ASSIGNED_TO_FIELD = "assignedTo";
 	public static final String BODY_OBJECT_AKTENZEICHEN = "aktenzeichen";
+	static final String KEY_HEADER_LOCK = "%s.%s".formatted(Vorgang.MONGODB_FIELDNAME_HEADER, VorgangHead.FIELD_LOCK);
 
 	@Autowired
 	private VorgangAuthorizationService vorgangAuthenticationService;
@@ -223,4 +229,40 @@ public class VorgangService {
 	Vorgang loadById(String vorgangId) {
 		return repository.findById(vorgangId).orElseThrow(() -> new NotFoundException(Vorgang.class, vorgangId));
 	}
+
+	public void lockVorgang(Command command) {
+		validateLockCommand(command);
+		repository.patch(command.getVorgangId(), command.getRelationVersion(), buildLockPatch(command));
+		publisher.publishEvent(new VorgangLockedEvent(command));
+	}
+
+	void validateLockCommand(Command command) {
+		if (Objects.isNull(command.getCreatedByClientName())) {
+			throw new TechnicalException("Missing client name in lock command");
+		}
+		if (Objects.isNull(getReason(command.getBodyObject()))) {
+			throw new TechnicalException("Missing reason in lock command");
+		}
+	}
+
+	Map<String, Object> buildLockPatch(Command command) {
+		return Map.of(KEY_HEADER_LOCK, Map.of(
+				Lock.FIELD_CLIENT_NAME, command.getCreatedByClientName(),
+				Lock.FIELD_LOCKED_SINCE, ZonedDateTime.now(ZoneId.of("UTC")),
+				Lock.FIELD_REASON, getReason(command.getBodyObject())));
+	}
+
+	String getReason(Map<String, Object> commandBody) {
+		return StringUtils.trimToNull(MapUtils.getString(commandBody, Lock.FIELD_REASON));
+	}
+
+	public boolean isVorgangLocked(String vorgangId) {
+		return repository.isVorgangLocked(vorgangId);
+	}
+
+	public void unlockVorgang(Command command) {
+		// TODO wird implementiert in OZG-6992
+		// publisher.publishEvent(new CommandRevokedEvent(command));
+		throw new UnsupportedOperationException("Not yet implemented");
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
index 3f4d68d90efa91280762ec75d49a7692d352a175..a129a4c389de52dbf8d0ef358efdec8ea5e6771c 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
@@ -35,6 +35,7 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -59,6 +60,7 @@ import de.ozgcloud.vorgang.callcontext.CurrentUserService;
 import de.ozgcloud.vorgang.callcontext.UserTestFactory;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
 import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException;
+import de.ozgcloud.vorgang.vorgang.VorgangService;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 class CommandServiceTest {
@@ -73,6 +75,8 @@ class CommandServiceTest {
 	private ApplicationEventPublisher publisher;
 	@Mock
 	private CurrentUserService currentUserService;
+	@Mock
+	private VorgangService vorgangService;
 
 	@Nested
 	class TestCreateCommand {
@@ -82,6 +86,13 @@ class CommandServiceTest {
 		@Captor
 		private ArgumentCaptor<Command> commandCaptor;
 
+		@Test
+		void shouldCallValidateVorgang() {
+			service.createCommand(request);
+
+			verify(service).validateVorgang(VorgangTestFactory.ID);
+		}
+
 		@Test
 		void shouldCallOperationRepository() {
 			service.createCommand(request);
@@ -102,6 +113,15 @@ class CommandServiceTest {
 			assertThat(command.getRelationVersion()).isEqualTo(CreateCommandRequestTestFactory.RELATION_VERSION);
 		}
 
+		@Test
+		void shouldSetClientName() {
+			when(currentUserService.findUser()).thenReturn(Optional.of(CallContextUserTestFactory.create()));
+
+			var command = (PersistedCommand) service.createCommand(request);
+
+			assertThat(command.getCreatedByClientName()).isEqualTo(CallContextTestFactory.CLIENT);
+		}
+
 		@Test
 		void shouldHandleMissingCallContext() {
 			var request = CreateCommandRequestTestFactory.createBuilder().callContext(null).build();
@@ -157,6 +177,25 @@ class CommandServiceTest {
 		}
 	}
 
+	@Nested
+	class TestValidateVorgang {
+
+		@Test
+		void shouldCallIsVorgangLocked() {
+			service.validateVorgang(VorgangTestFactory.ID);
+
+			verify(vorgangService).isVorgangLocked(VorgangTestFactory.ID);
+		}
+
+		@Test
+		void shouldThrowExceptionIfVorgangLocked() {
+			when(vorgangService.isVorgangLocked(anyString())).thenReturn(true);
+
+			Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID));
+		}
+
+	}
+
 	@Nested
 	class TestGetVorgangCommand {
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java
index ff3e080efe5ba9eaa41c46b74820bcda8427dd5c..c87132fce74264ffcb34a894b036e0f6351fe7e7 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java
@@ -29,6 +29,7 @@ import java.util.UUID;
 
 import de.ozgcloud.command.CommandStatus;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
+import de.ozgcloud.vorgang.callcontext.CallContextTestFactory;
 import de.ozgcloud.vorgang.callcontext.UserTestFactory;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
@@ -39,6 +40,7 @@ public class CommandTestFactory {
 	public static final ZonedDateTime CREATED_AT = ZonedDateTime.parse(CREATED_AT_STR);
 	public static final String CREATED_BY = UserTestFactory.ID;
 	public static final String CREATED_BY_NAME = UserTestFactory.NAME;
+	public static final String CREATED_BY_CLIENT = CallContextTestFactory.CLIENT;
 	public static final CommandStatus STATUS = CommandStatus.PENDING;
 
 	public static final String RELATION_ID = VorgangAttachedItemTestFactory.ID;
@@ -59,6 +61,7 @@ public class CommandTestFactory {
 				.createdAt(CREATED_AT)
 				.createdBy(CREATED_BY)
 				.createdByName(CREATED_BY_NAME)
+				.createdByClientName(CREATED_BY_CLIENT)
 				.status(STATUS)
 				.relationId(RELATION_ID)
 				.relationVersion(RELATION_VERSION)
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
index e890e4ea2097781bba11e16db414d51370c90562..784f0e26762198dfac1d195b47e7e5ed64512648 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
@@ -10,6 +10,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -39,6 +40,7 @@ import de.ozgcloud.vorgang.grpc.command.GrpcCreateCommandRequest;
 import de.ozgcloud.vorgang.grpc.command.GrpcFindCommandsRequest;
 import de.ozgcloud.vorgang.grpc.command.GrpcRevokeCommandRequest;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
+import de.ozgcloud.vorgang.vorgang.VorgangHeadTestFactory;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 import io.grpc.StatusRuntimeException;
 import lombok.extern.log4j.Log4j2;
@@ -110,6 +112,20 @@ class GrpcCommandServiceITCase {
 				assertThat(commands).hasSize(1).first().extracting(Command::getStatus).isEqualTo(CommandStatus.FINISHED);
 			});
 		}
+
+		@Test
+		void shouldNotPersistCommand() {
+			var lockedVorgang = mongoOperations.save(buildLockedVorgang());
+			var request = GrpcCreateCommandRequestTestFactory.createBuilder().setVorgangId(lockedVorgang.getId()).build();
+
+			assertThrows(StatusRuntimeException.class, () -> serviceBlockingStub.createCommand(request));
+
+			assertThat(mongoOperations.findAll(Command.class)).isEmpty();
+		}
+
+		Vorgang buildLockedVorgang() {
+			return VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build();
+		}
 	}
 
 	@Nested
@@ -215,6 +231,14 @@ class GrpcCommandServiceITCase {
 			});
 		}
 
+		@Test
+		void shouldFailOnLockedVorgang() {
+			mongoOperations.save(vorgang.toBuilder().header(VorgangHeadTestFactory.create()).build());
+			var request = buildAddSubCommandsRequest(parentCommand.getId(), buildCreateCommand());
+
+			Assertions.assertThrows(StatusRuntimeException.class, () -> serviceBlockingStub.addSubCommands(request));
+		}
+
 		private GrpcCommand createParentCommand() {
 			var createParentCommandRequest = GrpcCreateCommandRequestTestFactory.createBuilder()
 					.setVorgangId(vorgang.getId())
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
index 6807b332b138383be4bff92001a809aba224d3ac..c906cab1c71d690a375b705dac310cd0844ea1bd 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
@@ -93,7 +93,8 @@ class GrpcCommandServiceTest {
 		private StreamObserver<GrpcCommandResponse> responseObserver;
 		@Captor
 		private ArgumentCaptor<GrpcCommandResponse> responseCaptor;
-		private final GrpcCreateCommandRequest request = GrpcCreateCommandRequest.newBuilder().build();
+
+		private final GrpcCreateCommandRequest request = GrpcCreateCommandRequestTestFactory.create();
 		private final CreateCommandRequest createComandRequest = CreateCommandRequestTestFactory.create();
 		private final GrpcCommandResponse response = GrpcCommandResponse.newBuilder().build();
 		private final Command persistedCommand = CommandTestFactory.create();
@@ -107,28 +108,28 @@ class GrpcCommandServiceTest {
 		}
 
 		@Test
-		void shouldCallPolicyService() throws Exception {
+		void shouldCallPolicyService() {
 			callCreateCommand();
 
-			verify(policyService).checkPermission(anyString());
+			verify(policyService).checkPermission(VorgangTestFactory.ID);
 		}
 
 		@Test
-		void shouldCallCommandRequestMapper() throws Exception {
+		void shouldCallCommandRequestMapper() {
 			callCreateCommand();
 
 			verify(createCommandRequestMapper).fromGrpc(request);
 		}
 
 		@Test
-		void shouldCallCommandService() throws Exception {
+		void shouldCallCommandService() {
 			callCreateCommand();
 
 			verify(commandService).createCommand(createComandRequest);
 		}
 
 		@Test
-		void shouldReturnValue() throws Exception {
+		void shouldReturnValue() {
 			callCreateCommand();
 
 			var values = responseCaptor.getValue();
@@ -136,7 +137,7 @@ class GrpcCommandServiceTest {
 			assertThat(values).isEqualTo(response);
 		}
 
-		private void callCreateCommand() throws Exception {
+		private void callCreateCommand() {
 			service.createCommand(request, responseObserver);
 
 			verify(responseObserver).onNext(responseCaptor.capture());
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d1a76fea6b05042afa532bf250c5beee236666e
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang;
+
+public class GrpcLockTestFactory {
+
+	public static GrpcLock create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcLock.Builder createBuilder() {
+		return GrpcLock.newBuilder()
+				.setClientName(LockTestFactory.CLIENT_NAME)
+				.setLockedSince(LockTestFactory.LOCKED_SINCE_STR)
+				.setReason(LockTestFactory.REASON);
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java
index 2dad17c7bcb3ef89ddb5c8a1aea0f39d5af7bd8b..9cf5020e2d1cbbf5f9bd105e3887d4ac45c4ca14 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java
@@ -4,12 +4,15 @@ import de.ozgcloud.vorgang.servicekonto.GrpcServiceKontoTestFactory;
 
 public class GrpcVorgangHeadTestFactory {
 
+	public static final GrpcLock LOCK = GrpcLockTestFactory.create();
+
 	public static GrpcVorgangHead create() {
 		return createBuilder().build();
 	}
 
 	public static GrpcVorgangHead.Builder createBuilder() {
 		return GrpcVorgangHead.newBuilder()
-				.setServiceKonto(GrpcServiceKontoTestFactory.create());
+				.setServiceKonto(GrpcServiceKontoTestFactory.create())
+				.setLock(LOCK);
 	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b4905e5280cf65dc77a65dae4888feb035e7f01
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.vorgang.vorgang;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Map;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.vorgang.vorgang.Lock.LockBuilder;
+
+public class LockTestFactory {
+
+	public static final String CLIENT_NAME = LoremIpsum.getInstance().getFirstName() + "-Client";
+	public static final String REASON = LoremIpsum.getInstance().getWords(5);
+	public static final String LOCKED_SINCE_STR = ZonedDateTime.now().withNano(0).format(DateTimeFormatter.ISO_INSTANT);
+	public static final ZonedDateTime LOCKED_SINCE = ZonedDateTime.parse(LOCKED_SINCE_STR);
+
+	public static Lock create() {
+		return createBuilder().build();
+	}
+
+	public static LockBuilder createBuilder() {
+		return Lock.builder()
+				.clientName(CLIENT_NAME)
+				.lockedSince(LOCKED_SINCE)
+				.reason(REASON);
+	}
+
+	public static Map<String, Object> asMap() {
+		return Map.of(
+				Lock.FIELD_CLIENT_NAME, CLIENT_NAME,
+				Lock.FIELD_LOCKED_SINCE, LOCKED_SINCE,
+				Lock.FIELD_REASON, REASON
+		);
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
index 8b81f437d748490a869bf45321ea8e73c02856ed..d57886aa60ea449c2003ecdbdf979614a259dc89 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java
@@ -46,6 +46,9 @@ import com.thedeanda.lorem.LoremIpsum;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.command.CommandRevokeFailedEvent;
+import de.ozgcloud.command.CommandRevokedEvent;
+import de.ozgcloud.command.RevokeCommandEvent;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
 import de.ozgcloud.vorgang.command.CommandService;
@@ -231,4 +234,77 @@ class VorgangEventListenerTest {
 		}
 	}
 
+	@Nested
+	class TestOnLockVorgang {
+
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> eventCaptor;
+
+		@Test
+		void shouldCallLockVorgang() {
+			var command = CommandTestFactory.create();
+
+			listener.onLockVorgang(CommandCreatedEventTestFactory.create(command));
+
+			verify(service).lockVorgang(command);
+		}
+
+		@Test
+		void shouldPublishCommandFailedEvent() {
+			var command = CommandTestFactory.create();
+			var errorMessage = "error message";
+			doThrow(new RuntimeException(errorMessage)).when(service).lockVorgang(command);
+
+			listener.onLockVorgang(CommandCreatedEventTestFactory.create(command));
+
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue()).satisfies(event -> {
+				assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID);
+				assertThat(event.getErrorMessage()).isEqualTo(errorMessage);
+			});
+		}
+	}
+
+	@Nested
+	class TestRevokeLockVorgang {
+
+		@Captor
+		private ArgumentCaptor<CommandRevokedEvent> commandRevokedEventCaptor;
+		@Captor
+		private ArgumentCaptor<CommandRevokeFailedEvent> commandRevokeFailedEventCaptor;
+
+		@Test
+		void shouldCallUnlockVorgang() {
+			var command = CommandTestFactory.create();
+
+			listener.onRevokeLockVorgang(new RevokeCommandEvent(command));
+
+			verify(service).unlockVorgang(command);
+		}
+
+		@Test
+		void shouldPublishCommandRevokedEvent() {
+			var command = CommandTestFactory.create();
+
+			listener.onRevokeLockVorgang(new RevokeCommandEvent(command));
+
+			verify(publisher).publishEvent(commandRevokedEventCaptor.capture());
+			assertThat(commandRevokedEventCaptor.getValue().getSource()).isSameAs(command);
+		}
+
+		@Test
+		void shouldPublishCommandFailedEvent() {
+			var command = CommandTestFactory.create();
+			var errorMessage = "error message";
+			doThrow(new RuntimeException(errorMessage)).when(service).unlockVorgang(command);
+
+			listener.onRevokeLockVorgang(new RevokeCommandEvent(command));
+
+			verify(publisher).publishEvent(commandRevokeFailedEventCaptor.capture());
+			assertThat(commandRevokeFailedEventCaptor.getValue()).satisfies(event -> {
+				assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID);
+				assertThat(event.getErrorMessage()).isEqualTo(errorMessage);
+			});
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java
index 3df7b94939e7c79fcf36323a02036948d29340d3..fa00c709994f056c37eab9475c82472ff88dee49 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java
@@ -1,15 +1,20 @@
 package de.ozgcloud.vorgang.vorgang;
 
+import de.ozgcloud.vorgang.servicekonto.ServiceKonto;
 import de.ozgcloud.vorgang.servicekonto.ServiceKontoTestFactory;
 
 public class VorgangHeadTestFactory {
 
+	public static final Lock LOCK = LockTestFactory.create();
+	public static final ServiceKonto SERVICE_KONTO = ServiceKontoTestFactory.create();
+
 	public static VorgangHead create() {
 		return createBuilder().build();
 	}
 
 	public static VorgangHead.VorgangHeadBuilder createBuilder() {
 		return VorgangHead.builder()
-				.serviceKonto(ServiceKontoTestFactory.create());
+				.serviceKonto(SERVICE_KONTO)
+				.lock(LOCK);
 	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
index f8e53b21c3330f11204100db26086e1d5274c4c7..9d19e8a701453ad636c4458f45d9de1f30b2927b 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java
@@ -340,7 +340,7 @@ class VorgangRepositoryITCase {
 		}
 
 		@Test
-		void  should() {
+		void should() {
 			assertThat(mongoOperations.findAll(Vorgang.class)).isEmpty();
 
 			repository.setAktenzeichen(VorgangTestFactory.ID, VorgangTestFactory.VERSION, VorgangTestFactory.AKTENZEICHEN);
@@ -360,4 +360,27 @@ class VorgangRepositoryITCase {
 			return mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class);
 		}
 	}
+
+	@Nested
+	class TestIsVorgangLocked {
+
+		@Test
+		void shouldReturnTrue() {
+			var vorgang = mongoOperations.save(
+					VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build());
+
+			var isLocked = repository.isVorgangLocked(vorgang.getId());
+
+			assertThat(isLocked).isTrue();
+		}
+
+		@Test
+		void shouldReturnFalseWhenNoLock() {
+			var vorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0).build());
+
+			var isLocked = repository.isVorgangLocked(vorgang.getId());
+
+			assertThat(isLocked).isFalse();
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
index c6a8daf26e2d1696cad785c5cb1c66cf1d73f33a..5e4c2e4690780c92555b58237d9662f6dafe91c8 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java
@@ -28,10 +28,13 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+import org.assertj.core.api.InstanceOfAssertFactories;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -49,6 +52,8 @@ import org.springframework.security.access.AccessDeniedException;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.VorgangAssignedEvent;
 import de.ozgcloud.command.VorgangCreatedEvent;
+import de.ozgcloud.command.VorgangLockedEvent;
+import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
@@ -507,4 +512,124 @@ class VorgangServiceTest {
 			verify(repository).setAktenzeichen(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, null);
 		}
 	}
+
+	@Nested
+	class TestLockVorgang {
+
+		private static final Command LOCK_COMMAND = CommandTestFactory.create();
+		private static final Map<String, Object> LOCK_PATCH = Map.of("key", "value");
+
+		@Captor
+		private ArgumentCaptor<VorgangLockedEvent> eventCaptor;
+
+		@BeforeEach
+		void init() {
+			doNothing().when(service).validateLockCommand(any());
+			doReturn(LOCK_PATCH).when(service).buildLockPatch(any());
+		}
+
+		@Test
+		void shouldCallValidateLockCommand() {
+			service.lockVorgang(LOCK_COMMAND);
+
+			verify(service).validateLockCommand(LOCK_COMMAND);
+		}
+
+		@Test
+		void shouldCallBuildLockPatch() {
+			service.lockVorgang(LOCK_COMMAND);
+
+			verify(service).buildLockPatch(LOCK_COMMAND);
+		}
+
+		@Test
+		void shouldCallRepository() {
+			service.lockVorgang(LOCK_COMMAND);
+
+			verify(repository).patch(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, LOCK_PATCH);
+		}
+
+		@Test
+		void shouldCallPublishEvent() {
+			service.lockVorgang(LOCK_COMMAND);
+
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getCommand()).isSameAs(LOCK_COMMAND);
+		}
+	}
+
+	@Nested
+	class TestValidateLockCommand {
+
+		@Test
+		void shouldThrowExceptionOnMissingClient() {
+			var command = CommandTestFactory.createBuilder().createdByClientName(null).build();
+
+			assertThrows(TechnicalException.class, () -> service.validateLockCommand(command));
+		}
+
+		@Test
+		void shouldThrowExceptionOnMissingReason() {
+			var command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build();
+
+			assertThrows(TechnicalException.class, () -> service.validateLockCommand(command));
+		}
+
+		@Test
+		void shouldAcceptValidCommand() {
+			var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
+
+			assertDoesNotThrow(() -> service.validateLockCommand(command));
+		}
+	}
+
+	@Nested
+	class TestBuildLockPatch {
+
+		 private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build();
+
+		@Test
+		void shouldSetClientName() {
+			var result = service.buildLockPatch(command);
+
+			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP)
+					.containsEntry(Lock.FIELD_CLIENT_NAME, CommandTestFactory.CREATED_BY_CLIENT);
+		}
+
+		@Test
+		void shouldSetLockedSince() {
+			var result = service.buildLockPatch(command);
+
+			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP)
+					.extractingByKey(Lock.FIELD_LOCKED_SINCE, InstanceOfAssertFactories.ZONED_DATE_TIME)
+					.isCloseTo(ZonedDateTime.now(), within(1, ChronoUnit.SECONDS));
+		}
+
+		@Test
+		void shouldSetReason() {
+			var result = service.buildLockPatch(command);
+
+			assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP).containsEntry(Lock.FIELD_REASON, LockTestFactory.REASON);
+		}
+	}
+
+	@Nested
+	class TestIsVorgangLocked {
+
+		@Test
+		void shouldCallRepository() {
+			service.isVorgangLocked(VorgangTestFactory.ID);
+
+			verify(repository).isVorgangLocked(VorgangTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnResult() {
+			when(repository.isVorgangLocked(anyString())).thenReturn(true);
+
+			var result = service.isVorgangLocked(VorgangTestFactory.ID);
+
+			assertThat(result).isTrue();
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java
index ab5b9993fd21163e0584405f38972ca7b1970675..f3631378b23be339f5be8a007839fb39cf730e76 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java
@@ -75,7 +75,7 @@ public class VorgangTestFactory {
 				.nummer(VORGANG_NUMMER)
 				.status(STATUS)
 				.createdAt(CREATED_AT)
-				.header(VorgangHeadTestFactory.create())
+				.header(VorgangHeadTestFactory.createBuilder().lock(null).build())
 				.eingang(EINGANG)
 				.version(VERSION)
 				.assignedTo(UserTestFactory.ID)
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java
index fb2835b2c69b35167c8a9c5d5a50a8d1a0fa70df..a231605a85030e5bb12a810d00dc9f3fe56c2fb3 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java
@@ -70,7 +70,7 @@ class VorgangWithEingangMapperTest {
 			var vorgangWithEingang = callMapper();
 
 			assertThat(vorgangWithEingang).usingRecursiveComparison()
-					.ignoringFields("eingang_", "clientAttributes_", "memoizedHashCode", "header_")
+					.ignoringFields("eingang_", "clientAttributes_", "memoizedHashCode")
 					.isEqualTo(GrpcVorgangWithEingangTestFactory.create());
 		}
 
@@ -81,15 +81,9 @@ class VorgangWithEingangMapperTest {
 			assertThat(eingang).usingRecursiveComparison().isEqualTo(GrpcEingangTestFactory.create());
 		}
 
-		@Test
-		void shouldMapHeader() {
-			var header = callMapper().getHeader();
-
-			assertThat(header).usingRecursiveComparison().isEqualTo(GrpcVorgangHeadTestFactory.create());
-		}
-
 		private GrpcVorgangWithEingang callMapper() {
-			return mapper.toVorgangWithEingang(VorgangTestFactory.create());
+			var vorgang = VorgangTestFactory.createBuilder().header(VorgangHeadTestFactory.createBuilder().lock(VorgangHeadTestFactory.LOCK).build());
+			return mapper.toVorgangWithEingang(vorgang.build());
 		}
 	}
 }
\ No newline at end of file