From 35b953e5b1e192fb66ce7611642de2ada843a2f4 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Tue, 7 Oct 2025 15:00:40 +0200
Subject: [PATCH 01/23] - simplified AbstractActionAPI

---
 .../spring/actions/AbstractActionAPI.java     | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java
new file mode 100644
index 0000000000..e8632f2bdb
--- /dev/null
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java
@@ -0,0 +1,47 @@
+package com.netgrif.application.engine.adapter.spring.actions;
+
+import com.netgrif.application.engine.objects.petrinet.domain.Transition;
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.Field;
+import com.netgrif.application.engine.objects.workflow.domain.Case;
+import com.netgrif.application.engine.objects.workflow.domain.Task;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.filter.Predicate;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public abstract class AbstractActionAPI {
+
+    public abstract void make(List<Field<?>> field, String behavior, Transition on);
+
+    public abstract void change(Field<?> field, Case targetCase, Task optionalTargetTask, String attribute, Object newValue);
+
+    public abstract Page<Case> findCases(Predicate predicate, Pageable pageable);
+
+    public abstract Page<Case> findCases(List<String> elasticStringQueries, String loggedUserId, Pageable pageable, Locale locale, boolean isIntersection);
+
+    public abstract Case createCase(String identifier, String title, String color, String userId, Locale locale, Map<String, String> params);
+
+    public abstract Page<Task> findTasks(Predicate predicate, Pageable pageable);
+
+    public abstract Page<Task> findTasks(List<String> elasticStringQueries, String loggedUserId, Pageable pageable, Locale locale, boolean isIntersection);
+
+    public abstract Task assignTask(String taskId, String userId, Map<String, String> params);
+
+    public abstract Task cancelTask(String taskId, String userId, Map<String, String> params);
+
+    public abstract Task finishTask(String taskId, String finishedById, Map<String, String> params);
+
+    public abstract void assignRole(String roleId, String userId, Map<String, String> params);
+
+    public abstract void removeRole(String roleId, String userId, Map<String, String> params);
+
+    public abstract SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params);
+
+    public abstract Map<String, Field<?>> getData(String taskId, Map<String, String> params);
+
+
+}

From c50012bd17e4b3f52f227a010a699922e41b3f51 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Thu, 9 Oct 2025 13:43:43 +0200
Subject: [PATCH 02/23] Add Action API implementation and related
 configurations

Introduced `ActionApi` interface and its implementation `ActionApiImpl` to standardize and handle various workflow operations like task assignment, case creation, and data
---
 .../actions/ActionApiConfiguration.java       |  16 ++
 .../engine/actions/ActionApiImpl.java         | 152 ++++++++++++++++++
 .../ElasticTaskSearchRequest.java             |   2 +
 .../objects/auth/dto/AuthPrincipalDto.java    |  17 ++
 .../spring/actions/AbstractActionAPI.java     |  47 ------
 .../adapter/spring/actions/ActionApi.java     |  46 ++++++
 .../spring/actions/ActionApiMethods.java      |  34 ++++
 7 files changed, 267 insertions(+), 47 deletions(-)
 create mode 100644 application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
 create mode 100644 application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
 create mode 100644 nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
 delete mode 100644 nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java
 create mode 100644 nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
 create mode 100644 nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
new file mode 100644
index 0000000000..4ea84c3976
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
@@ -0,0 +1,16 @@
+package com.netgrif.application.engine.actions;
+
+import com.netgrif.application.engine.adapter.spring.actions.ActionApi;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ActionApiConfiguration {
+
+    @Bean
+    @ConditionalOnMissingBean
+    public ActionApi actionApi() {
+        return new ActionApiImpl();
+    }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
new file mode 100644
index 0000000000..b8486507cd
--- /dev/null
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -0,0 +1,152 @@
+package com.netgrif.application.engine.actions;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.netgrif.application.engine.adapter.spring.actions.ActionApi;
+import com.netgrif.application.engine.auth.service.UserService;
+import com.netgrif.application.engine.elastic.service.interfaces.IElasticCaseService;
+import com.netgrif.application.engine.elastic.service.interfaces.IElasticTaskService;
+import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchRequest;
+import com.netgrif.application.engine.elastic.web.requestbodies.ElasticTaskSearchRequest;
+import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
+import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
+import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
+import com.netgrif.application.engine.objects.workflow.domain.Case;
+import com.netgrif.application.engine.objects.workflow.domain.Task;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.CreateCaseEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.DeleteCaseEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.GetDataEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.CancelTaskEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.FinishTaskEventOutcome;
+import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
+import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
+import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
+import com.querydsl.core.types.Predicate;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+@Slf4j
+public class ActionApiImpl implements ActionApi {
+
+    private UserService userService;
+
+    private IDataService dataService;
+
+    private ITaskService taskService;
+
+    private IWorkflowService workflowService;
+
+    private IElasticCaseService elasticCaseService;
+
+    private IElasticTaskService elasticTaskService;
+
+    public void setDataService(@Autowired IDataService dataService) {
+        this.dataService = dataService;
+    }
+
+    public void setTaskService(@Autowired ITaskService taskService) {
+        this.taskService = taskService;
+    }
+
+    public void setWorkflowService(@Autowired IWorkflowService workflowService) {
+        this.workflowService = workflowService;
+    }
+
+    public void setElasticCaseService(@Autowired IElasticCaseService elasticCaseService) {
+        this.elasticCaseService = elasticCaseService;
+    }
+
+    public void setUserService(@Autowired UserService userService) {
+        this.userService = userService;
+    }
+
+    @Override
+    public GetDataEventOutcome getData(String taskId, Map<String, String> params) {
+        return dataService.getData(taskId, params);
+    }
+
+    @Override
+    public SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException {
+        ObjectMapper mapper = new ObjectMapper();
+        String json = mapper.writeValueAsString(dataSet);
+        ObjectNode values = (ObjectNode) mapper.readTree(json);
+        return dataService.setData(taskId, values, params);
+    }
+
+    @Override
+    public Page<Case> searchCases(Predicate predicate, Pageable pageable) {
+        return workflowService.search(predicate, pageable);
+    }
+
+    @Override
+    public Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection) {
+        List<CaseSearchRequest> caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList();
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        Locale locale = LocaleContextHolder.getLocale();
+        return elasticCaseService.search(caseSearchRequests, loggedUser, pageable, locale, isIntersection);
+    }
+
+    @Override
+    public CreateCaseEventOutcome createCase(String netId, String title, String color, Map<String, String> params) {
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        Locale locale = LocaleContextHolder.getLocale();
+        return workflowService.createCase(netId, title, color, loggedUser, locale, params);
+    }
+
+    @Override
+    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, Map<String, String> params) {
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        Locale locale = LocaleContextHolder.getLocale();
+        return workflowService.createCaseByIdentifier(identifier, title, color, loggedUser, locale, params);
+    }
+
+    @Override
+    public DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params) {
+        return workflowService.deleteCase(caseId, params);
+    }
+
+    @Override
+    public Page<Task> searchTasks(Predicate predicate, Pageable pageable) {
+        return taskService.search(predicate, pageable);
+    }
+
+    @Override
+    public Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection) {
+        List<ElasticTaskSearchRequest> taskSearchRequests = elasticStringQueries.stream().map(query -> ElasticTaskSearchRequest.builder().query(query).build()).toList();
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        Locale locale = LocaleContextHolder.getLocale();
+        return elasticTaskService.search(taskSearchRequests, loggedUser, pageable, locale, isIntersection);
+    }
+
+    @Override
+    public AssignTaskEventOutcome assignTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException {
+        Task task = taskService.findOne(taskId);
+        AbstractUser user = userService.findById(userId, realmId);
+        return taskService.assignTask(task, user, params);
+    }
+
+    @Override
+    public CancelTaskEventOutcome cancelTask(String taskId, String userId, String realmId, Map<String, String> params) {
+        Task task = taskService.findOne(taskId);
+        AbstractUser user = userService.findById(userId, realmId);
+        return taskService.cancelTask(task, user, params);
+    }
+
+    @Override
+    public FinishTaskEventOutcome finishTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException {
+        Task task = taskService.findOne(taskId);
+        AbstractUser user = userService.findById(userId, realmId);
+        return taskService.finishTask(task, user, params);
+    }
+}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/elastic/web/requestbodies/ElasticTaskSearchRequest.java b/application-engine/src/main/java/com/netgrif/application/engine/elastic/web/requestbodies/ElasticTaskSearchRequest.java
index a01e639ae7..f30bd91155 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/elastic/web/requestbodies/ElasticTaskSearchRequest.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/elastic/web/requestbodies/ElasticTaskSearchRequest.java
@@ -4,12 +4,14 @@
 import com.netgrif.application.engine.workflow.web.requestbodies.taskSearch.PetriNet;
 import com.netgrif.application.engine.workflow.web.requestbodies.taskSearch.TaskSearchCaseRequest;
 import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.NoArgsConstructor;
 
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+@Builder
 @NoArgsConstructor
 @AllArgsConstructor
 public class ElasticTaskSearchRequest extends TaskSearchRequest {
diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
new file mode 100644
index 0000000000..bf3d90f923
--- /dev/null
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
@@ -0,0 +1,17 @@
+package com.netgrif.application.engine.objects.auth.dto;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+@Data
+public class AuthPrincipalDto implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 6725518942728316525L;
+
+    private String username;
+    private String realmId;
+    private String sessionId;
+}
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java
deleted file mode 100644
index e8632f2bdb..0000000000
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/AbstractActionAPI.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.netgrif.application.engine.adapter.spring.actions;
-
-import com.netgrif.application.engine.objects.petrinet.domain.Transition;
-import com.netgrif.application.engine.objects.petrinet.domain.dataset.Field;
-import com.netgrif.application.engine.objects.workflow.domain.Case;
-import com.netgrif.application.engine.objects.workflow.domain.Task;
-import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome;
-import com.netgrif.application.engine.objects.workflow.domain.filter.Predicate;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-public abstract class AbstractActionAPI {
-
-    public abstract void make(List<Field<?>> field, String behavior, Transition on);
-
-    public abstract void change(Field<?> field, Case targetCase, Task optionalTargetTask, String attribute, Object newValue);
-
-    public abstract Page<Case> findCases(Predicate predicate, Pageable pageable);
-
-    public abstract Page<Case> findCases(List<String> elasticStringQueries, String loggedUserId, Pageable pageable, Locale locale, boolean isIntersection);
-
-    public abstract Case createCase(String identifier, String title, String color, String userId, Locale locale, Map<String, String> params);
-
-    public abstract Page<Task> findTasks(Predicate predicate, Pageable pageable);
-
-    public abstract Page<Task> findTasks(List<String> elasticStringQueries, String loggedUserId, Pageable pageable, Locale locale, boolean isIntersection);
-
-    public abstract Task assignTask(String taskId, String userId, Map<String, String> params);
-
-    public abstract Task cancelTask(String taskId, String userId, Map<String, String> params);
-
-    public abstract Task finishTask(String taskId, String finishedById, Map<String, String> params);
-
-    public abstract void assignRole(String roleId, String userId, Map<String, String> params);
-
-    public abstract void removeRole(String roleId, String userId, Map<String, String> params);
-
-    public abstract SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params);
-
-    public abstract Map<String, Field<?>> getData(String taskId, Map<String, String> params);
-
-
-}
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
new file mode 100644
index 0000000000..1ae8b867ed
--- /dev/null
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -0,0 +1,46 @@
+package com.netgrif.application.engine.adapter.spring.actions;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
+import com.netgrif.application.engine.objects.workflow.domain.Case;
+import com.netgrif.application.engine.objects.workflow.domain.Task;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.CreateCaseEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.caseoutcomes.DeleteCaseEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.GetDataEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.AssignTaskEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.CancelTaskEventOutcome;
+import com.netgrif.application.engine.objects.workflow.domain.eventoutcomes.taskoutcomes.FinishTaskEventOutcome;
+import com.querydsl.core.types.Predicate;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ActionApi {
+
+    GetDataEventOutcome getData(String taskId, Map<String, String> params);
+
+    SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException;
+
+    Page<Case> searchCases(Predicate predicate, Pageable pageable);
+
+    Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
+
+    CreateCaseEventOutcome createCase(String netId, String title, String color, Map<String, String> params);
+
+    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, Map<String, String> params);
+
+    DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params);
+
+    Page<Task> searchTasks(Predicate predicate, Pageable pageable);
+
+    Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
+
+    AssignTaskEventOutcome assignTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException;
+
+    CancelTaskEventOutcome cancelTask(String taskId, String userId, String realmId, Map<String, String> params);
+
+    FinishTaskEventOutcome finishTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException;
+}
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
new file mode 100644
index 0000000000..2ad39d2f34
--- /dev/null
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -0,0 +1,34 @@
+package com.netgrif.application.engine.adapter.spring.actions;
+
+import java.util.Arrays;
+
+public enum ActionApiMethods {
+
+    GET_DATA("getData"),
+    SET_DATA("setData"),
+    SEARCH_CASES("searchCases"),
+    CREATE_CASE("createCase"),
+    CREATE_CASE_BY_IDENTIFIER("createCaseByIdentifier"),
+    DELETE_CASE("deleteCase"),
+    SEARCH_TASKS("searchTasks"),
+    ASSIGN_TASK("assignTask"),
+    CANCEL_TASK("cancelTask"),
+    FINISH_TASK("finishTask"),;
+
+    private String methodName;
+
+    ActionApiMethods(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public static ActionApiMethods fromMethodName(String methodName) {
+        return Arrays.stream(ActionApiMethods.values())
+                .filter(type -> type.methodName.equals(methodName))
+                .findFirst()
+                .orElse(null);
+    }
+}

From 78de22f36066778be498b9ff5d5a2156b5689f35 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Wed, 15 Oct 2025 13:35:24 +0200
Subject: [PATCH 03/23] Refactor ActionApi methods to enhance type safety and
 clarity

Updated `Map` to `HashMap` for parameters to ensure consistent type usage. Added `processIdentifier` parameter to `searchCases` and `searchTasks` methods. Replaced `userId` with `username` in task-related methods to better align with modern practices. Removed unused `createCase` method to eliminate redundancy.
---
 .../engine/actions/ActionApiImpl.java         | 53 +++++++++----------
 .../adapter/spring/actions/ActionApi.java     | 21 ++++----
 .../spring/actions/ActionApiMethods.java      |  1 -
 3 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index b8486507cd..dc7019d0e0 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -32,9 +32,7 @@
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 public class ActionApiImpl implements ActionApi {
@@ -51,33 +49,38 @@ public class ActionApiImpl implements ActionApi {
 
     private IElasticTaskService elasticTaskService;
 
-    public void setDataService(@Autowired IDataService dataService) {
+    @Autowired
+    public void setDataService(IDataService dataService) {
         this.dataService = dataService;
     }
 
-    public void setTaskService(@Autowired ITaskService taskService) {
+    @Autowired
+    public void setTaskService(ITaskService taskService) {
         this.taskService = taskService;
     }
 
-    public void setWorkflowService(@Autowired IWorkflowService workflowService) {
+    @Autowired
+    public void setWorkflowService(IWorkflowService workflowService) {
         this.workflowService = workflowService;
     }
 
-    public void setElasticCaseService(@Autowired IElasticCaseService elasticCaseService) {
+    @Autowired
+    public void setElasticCaseService(IElasticCaseService elasticCaseService) {
         this.elasticCaseService = elasticCaseService;
     }
 
-    public void setUserService(@Autowired UserService userService) {
+    @Autowired
+    public void setUserService(UserService userService) {
         this.userService = userService;
     }
 
     @Override
-    public GetDataEventOutcome getData(String taskId, Map<String, String> params) {
+    public GetDataEventOutcome getData(String taskId, HashMap<String, String> params) {
         return dataService.getData(taskId, params);
     }
 
     @Override
-    public SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException {
+    public SetDataEventOutcome setData(String taskId, HashMap<String, HashMap<String, String>> dataSet, HashMap<String, String> params) throws JsonProcessingException {
         ObjectMapper mapper = new ObjectMapper();
         String json = mapper.writeValueAsString(dataSet);
         ObjectNode values = (ObjectNode) mapper.readTree(json);
@@ -85,7 +88,7 @@ public SetDataEventOutcome setData(String taskId, Map<String, Map<String, String
     }
 
     @Override
-    public Page<Case> searchCases(Predicate predicate, Pageable pageable) {
+    public Page<Case> searchCases(String processIdentifier, Predicate predicate, Pageable pageable) {
         return workflowService.search(predicate, pageable);
     }
 
@@ -98,26 +101,19 @@ public Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageab
     }
 
     @Override
-    public CreateCaseEventOutcome createCase(String netId, String title, String color, Map<String, String> params) {
-        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
-        Locale locale = LocaleContextHolder.getLocale();
-        return workflowService.createCase(netId, title, color, loggedUser, locale, params);
-    }
-
-    @Override
-    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, Map<String, String> params) {
+    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, HashMap<String, String> params) {
         LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
         Locale locale = LocaleContextHolder.getLocale();
         return workflowService.createCaseByIdentifier(identifier, title, color, loggedUser, locale, params);
     }
 
     @Override
-    public DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params) {
+    public DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params) {
         return workflowService.deleteCase(caseId, params);
     }
 
     @Override
-    public Page<Task> searchTasks(Predicate predicate, Pageable pageable) {
+    public Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pageable pageable) {
         return taskService.search(predicate, pageable);
     }
 
@@ -130,23 +126,26 @@ public Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageab
     }
 
     @Override
-    public AssignTaskEventOutcome assignTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException {
+    public AssignTaskEventOutcome assignTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
-        AbstractUser user = userService.findById(userId, realmId);
+        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
+        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
         return taskService.assignTask(task, user, params);
     }
 
     @Override
-    public CancelTaskEventOutcome cancelTask(String taskId, String userId, String realmId, Map<String, String> params) {
+    public CancelTaskEventOutcome cancelTask(String taskId, String username, String realmId, HashMap<String, String> params) {
         Task task = taskService.findOne(taskId);
-        AbstractUser user = userService.findById(userId, realmId);
+        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
+        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
         return taskService.cancelTask(task, user, params);
     }
 
     @Override
-    public FinishTaskEventOutcome finishTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException {
+    public FinishTaskEventOutcome finishTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
-        AbstractUser user = userService.findById(userId, realmId);
+        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
+        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
         return taskService.finishTask(task, user, params);
     }
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 1ae8b867ed..cfd1131efd 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -15,32 +15,31 @@
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public interface ActionApi {
 
-    GetDataEventOutcome getData(String taskId, Map<String, String> params);
+    GetDataEventOutcome getData(String taskId, HashMap<String, String> params);
 
-    SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException;
+    SetDataEventOutcome setData(String taskId, HashMap<String, HashMap<String, String>> dataSet, HashMap<String, String> params) throws JsonProcessingException;
 
-    Page<Case> searchCases(Predicate predicate, Pageable pageable);
+    Page<Case> searchCases(String processIdentifier, Predicate predicate, Pageable pageable);
 
     Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
 
-    CreateCaseEventOutcome createCase(String netId, String title, String color, Map<String, String> params);
+    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, HashMap<String, String> params);
 
-    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, Map<String, String> params);
+    DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params);
 
-    DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params);
-
-    Page<Task> searchTasks(Predicate predicate, Pageable pageable);
+    Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pageable pageable);
 
     Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
 
-    AssignTaskEventOutcome assignTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException;
+    AssignTaskEventOutcome assignTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException;
 
-    CancelTaskEventOutcome cancelTask(String taskId, String userId, String realmId, Map<String, String> params);
+    CancelTaskEventOutcome cancelTask(String taskId, String username, String realmId, HashMap<String, String> params);
 
-    FinishTaskEventOutcome finishTask(String taskId, String userId, String realmId, Map<String, String> params) throws TransitionNotExecutableException;
+    FinishTaskEventOutcome finishTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException;
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
index 2ad39d2f34..874fd64031 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -7,7 +7,6 @@ public enum ActionApiMethods {
     GET_DATA("getData"),
     SET_DATA("setData"),
     SEARCH_CASES("searchCases"),
-    CREATE_CASE("createCase"),
     CREATE_CASE_BY_IDENTIFIER("createCaseByIdentifier"),
     DELETE_CASE("deleteCase"),
     SEARCH_TASKS("searchTasks"),

From 8cb4abc5537967b0b341ee715218b4af586bbb30 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Wed, 15 Oct 2025 13:45:58 +0200
Subject: [PATCH 04/23] Refactor Action API to use AuthPrincipalDto for user
 context

Replaced username and realmId parameters with AuthPrincipalDto to standardize user context handling across Action API methods. Added a helper method to resolve AbstractUser from AuthPrincipalDto, ensuring consistent and concise user lookup logic. This change improves maintainability and aligns with updated authentication patterns.
---
 .../engine/actions/ActionApiImpl.java         | 33 ++++++++++---------
 .../adapter/spring/actions/ActionApi.java     | 14 ++++----
 2 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index dc7019d0e0..5e89f98c3d 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -12,6 +12,7 @@
 import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
 import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
 import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.dto.AuthPrincipalDto;
 import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
 import com.netgrif.application.engine.objects.workflow.domain.Case;
 import com.netgrif.application.engine.objects.workflow.domain.Task;
@@ -93,16 +94,16 @@ public Page<Case> searchCases(String processIdentifier, Predicate predicate, Pag
     }
 
     @Override
-    public Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection) {
+    public Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) {
         List<CaseSearchRequest> caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList();
-        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
         return elasticCaseService.search(caseSearchRequests, loggedUser, pageable, locale, isIntersection);
     }
 
     @Override
-    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, HashMap<String, String> params) {
-        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) {
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
         return workflowService.createCaseByIdentifier(identifier, title, color, loggedUser, locale, params);
     }
@@ -118,34 +119,36 @@ public Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pag
     }
 
     @Override
-    public Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection) {
+    public Page<Task> searchTasks(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) {
         List<ElasticTaskSearchRequest> taskSearchRequests = elasticStringQueries.stream().map(query -> ElasticTaskSearchRequest.builder().query(query).build()).toList();
-        LoggedUser loggedUser = ActorTransformer.toLoggedUser(userService.getLoggedOrSystem());
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
         return elasticTaskService.search(taskSearchRequests, loggedUser, pageable, locale, isIntersection);
     }
 
     @Override
-    public AssignTaskEventOutcome assignTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException {
+    public AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
-        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
-        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
+        AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.assignTask(task, user, params);
     }
 
     @Override
-    public CancelTaskEventOutcome cancelTask(String taskId, String username, String realmId, HashMap<String, String> params) {
+    public CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) {
         Task task = taskService.findOne(taskId);
-        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
-        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
+        AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.cancelTask(task, user, params);
     }
 
     @Override
-    public FinishTaskEventOutcome finishTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException {
+    public FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
-        Optional<AbstractUser> userOptional = userService.findUserByUsername(username, realmId);
-        AbstractUser user = userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(username, realmId)));
+        AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.finishTask(task, user, params);
     }
+
+    private AbstractUser resolveAbstractUser(AuthPrincipalDto authPrincipalDto) {
+        Optional<AbstractUser> userOptional = userService.findUserByUsername(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId());
+        return userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId())));
+    }
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index cfd1131efd..af491663fd 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -1,6 +1,7 @@
 package com.netgrif.application.engine.adapter.spring.actions;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.netgrif.application.engine.objects.auth.dto.AuthPrincipalDto;
 import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
 import com.netgrif.application.engine.objects.workflow.domain.Case;
 import com.netgrif.application.engine.objects.workflow.domain.Task;
@@ -17,7 +18,6 @@
 
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 public interface ActionApi {
 
@@ -27,19 +27,19 @@ public interface ActionApi {
 
     Page<Case> searchCases(String processIdentifier, Predicate predicate, Pageable pageable);
 
-    Page<Case> searchCases(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
+    Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection);
 
-    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, HashMap<String, String> params);
+    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
 
     DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params);
 
     Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pageable pageable);
 
-    Page<Task> searchTasks(List<String> elasticStringQueries, Pageable pageable, Boolean isIntersection);
+    Page<Task> searchTasks(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection);
 
-    AssignTaskEventOutcome assignTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException;
+    AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
 
-    CancelTaskEventOutcome cancelTask(String taskId, String username, String realmId, HashMap<String, String> params);
+    CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
 
-    FinishTaskEventOutcome finishTask(String taskId, String username, String realmId, HashMap<String, String> params) throws TransitionNotExecutableException;
+    FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
 }

From 111827a09c55dbf2ef1dada8fb258e7d36ed6689 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Thu, 16 Oct 2025 13:18:00 +0200
Subject: [PATCH 05/23] Add searchUsers, findCase, and findTask methods to
 Action API

Introduced new methods in ActionApi and implemented them in ActionApiImpl, enabling user, case, and task operations. Updated related services and repositories to support user search by realm with pagination and predicate filtering.
---
 .../engine/actions/ActionApiImpl.java         |  16 +++
 .../petrinet/service/ProcessRoleService.java  |   6 +-
 .../adapter/spring/actions/ActionApi.java     | 125 ++++++++++++++++++
 .../spring/actions/ActionApiMethods.java      |   5 +-
 .../engine/auth/service/UserServiceImpl.java  |  16 +++
 .../engine/auth/service/UserService.java      |  11 ++
 6 files changed, 174 insertions(+), 5 deletions(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index 5e89f98c3d..a3f58fef21 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -12,6 +12,7 @@
 import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
 import com.netgrif.application.engine.objects.auth.domain.ActorTransformer;
 import com.netgrif.application.engine.objects.auth.domain.LoggedUser;
+import com.netgrif.application.engine.objects.auth.domain.User;
 import com.netgrif.application.engine.objects.auth.dto.AuthPrincipalDto;
 import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
 import com.netgrif.application.engine.objects.workflow.domain.Case;
@@ -147,6 +148,21 @@ public FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPri
         return taskService.finishTask(task, user, params);
     }
 
+    @Override
+    public Case findCase(String caseId) {
+        return workflowService.findOne(caseId);
+    }
+
+    @Override
+    public Task findTask(String taskId) {
+        return taskService.findOne(taskId);
+    }
+
+    @Override
+    public Page<User> searchUsers(Predicate predicate, Pageable pageable, String realmId) {
+        return userService.search(predicate, pageable, realmId);
+    }
+
     private AbstractUser resolveAbstractUser(AuthPrincipalDto authPrincipalDto) {
         Optional<AbstractUser> userOptional = userService.findUserByUsername(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId());
         return userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId())));
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java
index 1c94340d3a..1da1afa0b0 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/petrinet/service/ProcessRoleService.java
@@ -15,8 +15,6 @@
 import com.netgrif.application.engine.objects.importer.model.EventPhaseType;
 import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
 import com.netgrif.application.engine.objects.petrinet.domain.dataset.logic.action.Action;
-import com.netgrif.application.engine.objects.workflow.domain.Case;
-import com.netgrif.application.engine.objects.workflow.domain.QCase;
 import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.context.RoleContext;
 import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runner.RoleActionsRunner;
 import com.netgrif.application.engine.objects.petrinet.domain.events.Event;
@@ -102,8 +100,8 @@ public Optional<ProcessRole> get(ProcessResourceId processResourceId) {
     }
 
     @Override
-    public void delete(String s) {
-        Optional<ProcessRole> processRole = processRoleRepository.findByCompositeId(s);
+    public void delete(String roleId) {
+        Optional<ProcessRole> processRole = processRoleRepository.findByCompositeId(roleId);
         processRole.ifPresent(processRoleRepository::delete);
     }
 
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index af491663fd..9de149ced2 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -1,6 +1,7 @@
 package com.netgrif.application.engine.adapter.spring.actions;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.netgrif.application.engine.objects.auth.domain.User;
 import com.netgrif.application.engine.objects.auth.dto.AuthPrincipalDto;
 import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
 import com.netgrif.application.engine.objects.workflow.domain.Case;
@@ -19,27 +20,151 @@
 import java.util.HashMap;
 import java.util.List;
 
+
+/**
+ * ActionApi provides methods for performing operations and actions on workflow-related entities such as cases,
+ * tasks, and users. It facilitates data retrieval, task management, and realm-specific searches within the system.
+ */
 public interface ActionApi {
 
+    /**
+     * Retrieves data associated with a specific task.
+     *
+     * @param taskId the ID of the task for which data is to be retrieved
+     * @param params additional parameters for data retrieval
+     * @return the outcome of the data retrieval operation
+     */
     GetDataEventOutcome getData(String taskId, HashMap<String, String> params);
 
+    /**
+     * Sets or updates data for a specific task.
+     *
+     * @param taskId  the ID of the task to use to update data - task does not have to contain the data that is updated
+     * @param dataSet the data to be set, organized as a map
+     * @param params  additional parameters for the operation
+     * @return the outcome of the set data operation
+     * @throws JsonProcessingException if there is an error processing JSON data
+     */
     SetDataEventOutcome setData(String taskId, HashMap<String, HashMap<String, String>> dataSet, HashMap<String, String> params) throws JsonProcessingException;
 
+    /**
+     * Finds a specific case by its ID.
+     *
+     * @param caseId the ID of the case to find
+     * @return the found case
+     */
+    Case findCase(String caseId);
+
+    /**
+     * Searches for cases matching the given process identifier and predicate.
+     *
+     * @param processIdentifier the identifier of the process
+     * @param predicate         the criteria for filtering cases
+     * @param pageable          the pagination information
+     * @return a page of cases matching the criteria
+     */
     Page<Case> searchCases(String processIdentifier, Predicate predicate, Pageable pageable);
 
+    /**
+     * Searches for cases using elastic search queries.
+     *
+     * @param elasticStringQueries a list of queries for filtering cases
+     * @param authPrincipalDto     the authorization principal used for the search
+     * @param pageable             the pagination information
+     * @param isIntersection       true to intersect results of all queries; false for union
+     * @return a page of cases matching the criteria
+     */
     Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection);
 
+    /**
+     * Creates a new case identified by the given process identifier.
+     *
+     * @param identifier       the process identifier for creating the case
+     * @param title            the title of the new case
+     * @param color            the color associated with the case
+     * @param authPrincipalDto the authorization principal for creating the case
+     * @param params           additional parameters for the operation
+     * @return the outcome of the case creation operation
+     */
     CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
 
+    /**
+     * Deletes a specific case by its ID.
+     *
+     * @param caseId the ID of the case to delete
+     * @param params additional parameters for the operation
+     * @return the outcome of the delete operation
+     */
     DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params);
 
+    /**
+     * Finds a specific task by its ID.
+     *
+     * @param taskId the ID of the task to find
+     * @return the found task
+     */
+    Task findTask(String taskId);
+
+    /**
+     * Searches for tasks matching the given process identifier and predicate.
+     *
+     * @param processIdentifier the identifier of the process
+     * @param predicate         the criteria for filtering tasks
+     * @param pageable          the pagination information
+     * @return a page of tasks matching the criteria
+     */
     Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pageable pageable);
 
+    /**
+     * Searches for tasks using elastic search queries.
+     *
+     * @param elasticStringQueries a list of queries for filtering tasks
+     * @param authPrincipalDto     the authorization principal used for the search
+     * @param pageable             the pagination information
+     * @param isIntersection       true to intersect results of all queries; false for union
+     * @return a page of tasks matching the criteria
+     */
     Page<Task> searchTasks(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection);
 
+    /**
+     * Assigns a specific task to a user.
+     *
+     * @param taskId           the ID of the task to assign
+     * @param authPrincipalDto the authorization principal used for the operation
+     * @param params           additional parameters for the operation
+     * @return the outcome of the task assignment operation
+     * @throws TransitionNotExecutableException if the task's transition cannot be executed
+     */
     AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
 
+    /**
+     * Cancels a specific task.
+     *
+     * @param taskId           the ID of the task to cancel
+     * @param authPrincipalDto the authorization principal used for the operation
+     * @param params           additional parameters for the operation
+     * @return the outcome of the task cancellation operation
+     */
     CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
 
+    /**
+     * Marks a specific task as finished.
+     *
+     * @param taskId           the ID of the task to finish
+     * @param authPrincipalDto the authorization principal used for the operation
+     * @param params           additional parameters for the operation
+     * @return the outcome of the task completion operation
+     * @throws TransitionNotExecutableException if the task's transition cannot be executed
+     */
     FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
+
+    /**
+     * Searches for users in a specific realm based on a predicate.
+     *
+     * @param predicate the criteria for filtering users
+     * @param pageable  the pagination information
+     * @param realmId   the ID of the realm to search
+     * @return a page of users matching the criteria
+     */
+    Page<User> searchUsers(Predicate predicate, Pageable pageable, String realmId);
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
index 874fd64031..10e41d0464 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -6,13 +6,16 @@ public enum ActionApiMethods {
 
     GET_DATA("getData"),
     SET_DATA("setData"),
+    FIND_CASE("findCase"),
     SEARCH_CASES("searchCases"),
     CREATE_CASE_BY_IDENTIFIER("createCaseByIdentifier"),
     DELETE_CASE("deleteCase"),
+    FIND_TASK("findTask"),
     SEARCH_TASKS("searchTasks"),
     ASSIGN_TASK("assignTask"),
     CANCEL_TASK("cancelTask"),
-    FINISH_TASK("finishTask"),;
+    FINISH_TASK("finishTask"),
+    SEARCH_USER("searchUsers");
 
     private String methodName;
 
diff --git a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
index 9820e6296b..217c9e8c33 100644
--- a/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
+++ b/nae-user-ce/src/main/java/com/netgrif/application/engine/auth/service/UserServiceImpl.java
@@ -12,6 +12,7 @@
 import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
 import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
 import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+import com.querydsl.core.types.Predicate;
 import com.querydsl.core.types.dsl.BooleanExpression;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
@@ -588,6 +589,21 @@ public void updateAdminWithRoles(Collection<ProcessRole> roles) {
         log.debug("Admin [{}] now has [{}] process roles", admin.getUsername(), admin.getProcessRoles().size());
     }
 
+
+    /**
+     * Searches for users in the specified realm based on the provided predicate and pagination parameters.
+     *
+     * @param predicate the query conditions to filter users
+     * @param pageable  the pagination parameters for the search results
+     * @param realmId   the name of the realm, used to determine which collection to query
+     * @return a paginated list of users matching the predicate within the specified realm
+     */
+    @Override
+    public Page<User> search(Predicate predicate, Pageable pageable, String realmId) {
+        String collectionName = collectionNameProvider.getCollectionNameForRealm(realmId);
+        return userRepository.findAllByQuery(predicate, pageable, mongoTemplate, collectionName);
+    } 
+
     protected User initializeNewUser(String username, String email, String firstName, String lastName, String password, String realmId) {
         log.trace("Initializing new user [{}] in realm [{}]", username, realmId);
         User user = new User();
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
index 63e0111c82..9490c21308 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
+++ b/nae-user-common/src/main/java/com/netgrif/application/engine/auth/service/UserService.java
@@ -5,6 +5,7 @@
 import com.netgrif.application.engine.objects.petrinet.domain.PetriNet;
 import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole;
 import com.netgrif.application.engine.objects.workflow.domain.ProcessResourceId;
+import com.querydsl.core.types.Predicate;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.mongodb.core.query.Query;
@@ -424,4 +425,14 @@ Page<AbstractUser> searchAllCoMembers(String query, Collection<ProcessResourceId
      * @return the updated user
      */
     AbstractUser changePassword(AbstractUser user, String newPassword, String oldPassword);
+
+    /**
+     * Searches for users in the specified realm based on the provided predicate and pagination parameters.
+     *
+     * @param predicate the query conditions to filter users
+     * @param pageable  the pagination parameters for the search results
+     * @param realmId   the name of the realm, used to determine which collection to query
+     * @return a paginated list of users matching the predicate within the specified realm
+     */
+    Page<User> search(Predicate predicate, Pageable pageable, String realmId);
 }

From 582f418bcf6be9c44f0a2861d95273a796a5c5b8 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Fri, 17 Oct 2025 09:06:06 +0200
Subject: [PATCH 06/23] Refactor Querydsl dependencies and package structure.

Moved Querydsl dependencies and plugin configuration from `nae-user-common` to `nae-spring-core-adapter`. Updated package structure to align with the new module structure, improving separation of concerns and maintainability.
---
 nae-spring-core-adapter/pom.xml               | 34 ++++++++++++++++++
 .../engine/adapter/spring}/package-info.java  |  2 +-
 nae-user-common/pom.xml                       | 35 -------------------
 3 files changed, 35 insertions(+), 36 deletions(-)
 rename {nae-user-common/src/main/java/com/netgrif/application/engine/auth => nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring}/package-info.java (94%)

diff --git a/nae-spring-core-adapter/pom.xml b/nae-spring-core-adapter/pom.xml
index baa4218272..7a8bff888f 100644
--- a/nae-spring-core-adapter/pom.xml
+++ b/nae-spring-core-adapter/pom.xml
@@ -107,6 +107,16 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.querydsl</groupId>
+            <artifactId>querydsl-core</artifactId>
+            <version>${querydsl.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.querydsl</groupId>
+            <artifactId>querydsl-apt</artifactId>
+            <version>${querydsl.version}</version>
+        </dependency>
     </dependencies>
 
     <build>
@@ -131,6 +141,30 @@
                     </execution>
                 </executions>
             </plugin>
+            <plugin>
+                <groupId>com.mysema.maven</groupId>
+                <artifactId>apt-maven-plugin</artifactId>
+                <version>1.1.3</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>process</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>target/generated-sources/java</outputDirectory>
+                            <processors>
+                                <processor>
+                                    com.querydsl.apt.QuerydslAnnotationProcessor
+                                </processor>
+                            </processors>
+                            <options>
+                                <querydsl.excludedClasses>groovy.lang.MetaClass</querydsl.excludedClasses>
+                                <querydsl.unknownAsEmbeddable>true</querydsl.unknownAsEmbeddable>
+                            </options>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 
diff --git a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/package-info.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/package-info.java
similarity index 94%
rename from nae-user-common/src/main/java/com/netgrif/application/engine/auth/package-info.java
rename to nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/package-info.java
index eb189e2a25..742273d634 100644
--- a/nae-user-common/src/main/java/com/netgrif/application/engine/auth/package-info.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/package-info.java
@@ -10,7 +10,7 @@
         Group.class,
         User.class
 })
-package com.netgrif.application.engine.auth;
+package com.netgrif.application.engine.adapter.spring;
 
 import com.netgrif.application.engine.adapter.spring.petrinet.domain.PetriNet;
 import com.netgrif.application.engine.adapter.spring.petrinet.domain.roles.ProcessRole;
diff --git a/nae-user-common/pom.xml b/nae-user-common/pom.xml
index c4e756a301..6c38baf881 100644
--- a/nae-user-common/pom.xml
+++ b/nae-user-common/pom.xml
@@ -117,17 +117,6 @@
             <version>${mapstruct.version}</version>
             <scope>provided</scope>
         </dependency>
-
-        <dependency>
-            <groupId>com.querydsl</groupId>
-            <artifactId>querydsl-core</artifactId>
-            <version>${querydsl.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.querydsl</groupId>
-            <artifactId>querydsl-apt</artifactId>
-            <version>${querydsl.version}</version>
-        </dependency>
         <dependency>
             <groupId>com.querydsl</groupId>
             <artifactId>querydsl-mongodb</artifactId>
@@ -164,30 +153,6 @@
                     </annotationProcessorPaths>
                 </configuration>
             </plugin>
-            <plugin>
-                <groupId>com.mysema.maven</groupId>
-                <artifactId>apt-maven-plugin</artifactId>
-                <version>1.1.3</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>process</goal>
-                        </goals>
-                        <configuration>
-                            <outputDirectory>target/generated-sources/java</outputDirectory>
-                            <processors>
-                                <processor>
-                                    com.querydsl.apt.QuerydslAnnotationProcessor
-                                </processor>
-                            </processors>
-                            <options>
-                                <querydsl.excludedClasses>groovy.lang.MetaClass</querydsl.excludedClasses>
-                                <querydsl.unknownAsEmbeddable>true</querydsl.unknownAsEmbeddable>
-                            </options>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
         </plugins>
     </build>
 

From 95e084d285ca52180f1ad3114d256883e7bc0ef5 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Fri, 17 Oct 2025 10:46:52 +0200
Subject: [PATCH 07/23] Refactor to use Map instead of HashMap and add method
 resolution logic

Replaced HashMap with Map in ActionApi and ActionApiImpl for flexibility and cleaner API design. Introduced method resolution with superclass parameter types in NaeReflectionUtils, along with custom exception handling for ambiguous method calls.
---
 .../engine/actions/ActionApiImpl.java         | 16 ++--
 .../adapter/spring/actions/ActionApi.java     | 17 ++--
 .../spring/utils/NaeReflectionUtils.java      | 79 +++++++++++++++++++
 .../AmbiguousMethodCallException.java         | 12 +++
 4 files changed, 108 insertions(+), 16 deletions(-)
 create mode 100644 nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index a3f58fef21..e9ff90dad1 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -77,13 +77,13 @@ public void setUserService(UserService userService) {
     }
 
     @Override
-    public GetDataEventOutcome getData(String taskId, HashMap<String, String> params) {
+    public GetDataEventOutcome getData(String taskId, Map<String, String> params) {
         return dataService.getData(taskId, params);
     }
 
     @Override
-    public SetDataEventOutcome setData(String taskId, HashMap<String, HashMap<String, String>> dataSet, HashMap<String, String> params) throws JsonProcessingException {
-        ObjectMapper mapper = new ObjectMapper();
+    public SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException {
+        ObjectMapper mapper = new ObjectMapper(); 
         String json = mapper.writeValueAsString(dataSet);
         ObjectNode values = (ObjectNode) mapper.readTree(json);
         return dataService.setData(taskId, values, params);
@@ -103,14 +103,14 @@ public Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDt
     }
 
     @Override
-    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) {
+    public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, Map<String, String> params) {
         LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
         return workflowService.createCaseByIdentifier(identifier, title, color, loggedUser, locale, params);
     }
 
     @Override
-    public DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params) {
+    public DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params) {
         return workflowService.deleteCase(caseId, params);
     }
 
@@ -128,21 +128,21 @@ public Page<Task> searchTasks(List<String> elasticStringQueries, AuthPrincipalDt
     }
 
     @Override
-    public AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException {
+    public AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
         AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.assignTask(task, user, params);
     }
 
     @Override
-    public CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) {
+    public CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params) {
         Task task = taskService.findOne(taskId);
         AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.cancelTask(task, user, params);
     }
 
     @Override
-    public FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException {
+    public FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params) throws TransitionNotExecutableException {
         Task task = taskService.findOne(taskId);
         AbstractUser user = resolveAbstractUser(authPrincipalDto);
         return taskService.finishTask(task, user, params);
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 9de149ced2..73740c91af 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -17,8 +17,9 @@
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 
-import java.util.HashMap;
+import java.util.Map;
 import java.util.List;
+import java.util.Map;
 
 
 /**
@@ -34,7 +35,7 @@ public interface ActionApi {
      * @param params additional parameters for data retrieval
      * @return the outcome of the data retrieval operation
      */
-    GetDataEventOutcome getData(String taskId, HashMap<String, String> params);
+    GetDataEventOutcome getData(String taskId, Map<String, String> params);
 
     /**
      * Sets or updates data for a specific task.
@@ -45,7 +46,7 @@ public interface ActionApi {
      * @return the outcome of the set data operation
      * @throws JsonProcessingException if there is an error processing JSON data
      */
-    SetDataEventOutcome setData(String taskId, HashMap<String, HashMap<String, String>> dataSet, HashMap<String, String> params) throws JsonProcessingException;
+    SetDataEventOutcome setData(String taskId, Map<String, Map<String, String>> dataSet, Map<String, String> params) throws JsonProcessingException;
 
     /**
      * Finds a specific case by its ID.
@@ -86,7 +87,7 @@ public interface ActionApi {
      * @param params           additional parameters for the operation
      * @return the outcome of the case creation operation
      */
-    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
+    CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, Map<String, String> params);
 
     /**
      * Deletes a specific case by its ID.
@@ -95,7 +96,7 @@ public interface ActionApi {
      * @param params additional parameters for the operation
      * @return the outcome of the delete operation
      */
-    DeleteCaseEventOutcome deleteCase(String caseId, HashMap<String, String> params);
+    DeleteCaseEventOutcome deleteCase(String caseId, Map<String, String> params);
 
     /**
      * Finds a specific task by its ID.
@@ -135,7 +136,7 @@ public interface ActionApi {
      * @return the outcome of the task assignment operation
      * @throws TransitionNotExecutableException if the task's transition cannot be executed
      */
-    AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
+    AssignTaskEventOutcome assignTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params) throws TransitionNotExecutableException;
 
     /**
      * Cancels a specific task.
@@ -145,7 +146,7 @@ public interface ActionApi {
      * @param params           additional parameters for the operation
      * @return the outcome of the task cancellation operation
      */
-    CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params);
+    CancelTaskEventOutcome cancelTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params);
 
     /**
      * Marks a specific task as finished.
@@ -156,7 +157,7 @@ public interface ActionApi {
      * @return the outcome of the task completion operation
      * @throws TransitionNotExecutableException if the task's transition cannot be executed
      */
-    FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, HashMap<String, String> params) throws TransitionNotExecutableException;
+    FinishTaskEventOutcome finishTask(String taskId, AuthPrincipalDto authPrincipalDto, Map<String, String> params) throws TransitionNotExecutableException;
 
     /**
      * Searches for users in a specific realm based on a predicate.
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
index dea75bc483..92b6642aa4 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
@@ -1,7 +1,10 @@
 package com.netgrif.application.engine.adapter.spring.utils;
 
+import com.netgrif.application.engine.adapter.spring.utils.exceptions.AmbiguousMethodCallException;
 import org.springframework.aop.framework.AopProxyUtils;
 
+import java.lang.reflect.Method;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -54,4 +57,80 @@ public static <I> int indexOfClass(List<I> list, Class<?> clazz) {
     }
 
 
+    /**
+     * Finds and returns the {@code Method} object for the specified method name and parameter types on the given bean.
+     * This method first attempts to locate the method on the target class of the bean.
+     * If not found, it tries to locate a method using superclasses of the parameter types.
+     *
+     * @param bean              the bean instance on which the method is to be located
+     * @param methodToExecute   the name of the method to be invoked
+     * @param requestParamTypes the types of the parameters expected by the method
+     * @return the {@code Method} object corresponding to the specified name and parameters
+     * @throws NoSuchMethodException        if the method cannot be found
+     * @throws AmbiguousMethodCallException if multiple methods match the specified criteria, resulting in ambiguity
+     */
+    public static Method findMethod(Object bean, String methodToExecute, Class<?>[] requestParamTypes)
+            throws NoSuchMethodException, AmbiguousMethodCallException {
+        try {
+            return NaeReflectionUtils.resolveClass(bean).getMethod(methodToExecute, requestParamTypes);
+        } catch (NoSuchMethodException e) {
+            return findMethodWithSuperClassParams(bean, methodToExecute, requestParamTypes, e);
+        }
+    }
+
+    /**
+     * Attempts to find a method on the target class of the given bean using superclass parameter types when an exact match is not found.
+     * If a method with the specified name is located, and the parameters can be assigned from the provided parameter types,
+     * the method is returned. If multiple methods match the criteria, an {@code AmbiguousMethodCallException} is thrown.
+     *
+     * @param bean              the bean instance on which the method is to be located
+     * @param methodToExecute   the name of the method to be invoked
+     * @param requestParamTypes the types of the parameters expected by the method
+     * @param caughtException   the exception caught from a previous attempt to find the method (used for re-throw if no method is found)
+     * @return the {@code Method} object that matches the specified criteria
+     * @throws NoSuchMethodException        if no suitable method is found
+     * @throws AmbiguousMethodCallException if multiple methods match the specified name and parameters, causing ambiguity
+     */
+    private static Method findMethodWithSuperClassParams(Object bean, String methodToExecute, Class<?>[] requestParamTypes,
+                                                  NoSuchMethodException caughtException)
+            throws NoSuchMethodException, AmbiguousMethodCallException {
+        Class<?> cls = NaeReflectionUtils.resolveClass(bean);
+        Method[] methods = cls.getMethods();
+        Method methodToInvoke = null;
+        outerLoop:
+        for (Method method : methods) {
+            if (!methodToExecute.equals(method.getName())) {
+                continue;
+            }
+
+            Class<?>[] paramTypes = method.getParameterTypes();
+            int requestParamsLen = requestParamTypes.length;
+            int paramsLen = paramTypes.length;
+
+            if (requestParamsLen == 0 && paramsLen == 0) {
+                methodToInvoke = method;
+                break;
+            } else if (paramsLen == 0 || paramsLen != requestParamsLen) {
+                continue;
+            }
+
+            for (int i = 0; i < requestParamTypes.length; ++i) {
+                if (!paramTypes[i].isAssignableFrom(requestParamTypes[i])) {
+                    continue outerLoop;
+                }
+            }
+
+            if (methodToInvoke != null) {
+                throw new AmbiguousMethodCallException(String.format("Method %s is ambiguous for the param types %s",
+                        methodToExecute, Arrays.toString(requestParamTypes)));
+            }
+            methodToInvoke = method;
+        }
+
+        if (methodToInvoke == null) {
+            throw caughtException;
+        } else {
+            return methodToInvoke;
+        }
+    }
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
new file mode 100644
index 0000000000..27e5ddc61b
--- /dev/null
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
@@ -0,0 +1,12 @@
+package com.netgrif.application.engine.adapter.spring.utils.exceptions;
+
+public class AmbiguousMethodCallException extends RuntimeException {
+
+    public AmbiguousMethodCallException(String message) {
+        super(message);
+    }
+
+    public AmbiguousMethodCallException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+}

From cf80649baa924d26bf770087ffb539790174ab45 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:32:47 +0200
Subject: [PATCH 08/23] Refactor ActionApiImpl and enhance exception class.

Refactored `ActionApiImpl` to include `ObjectMapper` and handle `isIntersection` using a safer boolean check. Updated `AmbiguousMethodCallException` to implement `Serializable` and added `serialVersionUID` for better compatibility. These changes improve code clarity, safety, and functionality.
---
 .../engine/actions/ActionApiImpl.java         | 21 +++++++++++++++++--
 .../AmbiguousMethodCallException.java         |  8 ++++++-
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index e9ff90dad1..53ff7d0686 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -51,6 +51,8 @@ public class ActionApiImpl implements ActionApi {
 
     private IElasticTaskService elasticTaskService;
 
+    private ObjectMapper objectMapper;
+
     @Autowired
     public void setDataService(IDataService dataService) {
         this.dataService = dataService;
@@ -76,6 +78,16 @@ public void setUserService(UserService userService) {
         this.userService = userService;
     }
 
+    @Autowired
+    public void setElasticTaskService(IElasticTaskService elasticTaskService) {
+        this.elasticTaskService = elasticTaskService;
+    }
+
+    @Autowired
+    public void setObjectMapper(ObjectMapper objectMapper) {
+        this.objectMapper = objectMapper;
+    }
+
     @Override
     public GetDataEventOutcome getData(String taskId, Map<String, String> params) {
         return dataService.getData(taskId, params);
@@ -96,10 +108,11 @@ public Page<Case> searchCases(String processIdentifier, Predicate predicate, Pag
 
     @Override
     public Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) {
+        boolean intersect = Boolean.TRUE.equals(isIntersection);
         List<CaseSearchRequest> caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList();
         LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
-        return elasticCaseService.search(caseSearchRequests, loggedUser, pageable, locale, isIntersection);
+        return elasticCaseService.search(caseSearchRequests, loggedUser, pageable, locale, intersect);
     }
 
     @Override
@@ -121,10 +134,11 @@ public Page<Task> searchTasks(String processIdentifier, Predicate predicate, Pag
 
     @Override
     public Page<Task> searchTasks(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection) {
+        boolean intersect = Boolean.TRUE.equals(isIntersection);
         List<ElasticTaskSearchRequest> taskSearchRequests = elasticStringQueries.stream().map(query -> ElasticTaskSearchRequest.builder().query(query).build()).toList();
         LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
         Locale locale = LocaleContextHolder.getLocale();
-        return elasticTaskService.search(taskSearchRequests, loggedUser, pageable, locale, isIntersection);
+        return elasticTaskService.search(taskSearchRequests, loggedUser, pageable, locale, intersect);
     }
 
     @Override
@@ -164,6 +178,9 @@ public Page<User> searchUsers(Predicate predicate, Pageable pageable, String rea
     }
 
     private AbstractUser resolveAbstractUser(AuthPrincipalDto authPrincipalDto) {
+        if (authPrincipalDto == null) {
+            throw new IllegalArgumentException("AuthPrincipalDto cannot be null.");
+        }
         Optional<AbstractUser> userOptional = userService.findUserByUsername(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId());
         return userOptional.orElseThrow(() -> new IllegalArgumentException("User with username [%s] and realm ID [%s] not found".formatted(authPrincipalDto.getUsername(), authPrincipalDto.getRealmId())));
     }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
index 27e5ddc61b..594b133b47 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
@@ -1,6 +1,12 @@
 package com.netgrif.application.engine.adapter.spring.utils.exceptions;
 
-public class AmbiguousMethodCallException extends RuntimeException {
+import java.io.Serial;
+import java.io.Serializable;
+
+public final class AmbiguousMethodCallException extends RuntimeException implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
 
     public AmbiguousMethodCallException(String message) {
         super(message);

From 42ec6b42cbff6a5bbfe9d68c2be10b763c557335 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:33:22 +0200
Subject: [PATCH 09/23] Refine ConditionalOnMissingBean annotation for
 ActionApi

Specify ActionApi class in the ConditionalOnMissingBean annotation to ensure proper bean initialization. This prevents unintended behavior when similar beans are present in the context.
---
 .../application/engine/actions/ActionApiConfiguration.java      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
index 4ea84c3976..eed32fcfd8 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiConfiguration.java
@@ -9,7 +9,7 @@
 public class ActionApiConfiguration {
 
     @Bean
-    @ConditionalOnMissingBean
+    @ConditionalOnMissingBean(ActionApi.class)
     public ActionApi actionApi() {
         return new ActionApiImpl();
     }

From a1f164dbf39c0b04a8ee3324b7d172bff232a9c4 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:38:35 +0200
Subject: [PATCH 10/23] Add annotations to exclude sessionId from toString and
 equals

The @ToString.Exclude and @EqualsAndHashCode.Exclude annotations were added to the sessionId field in AuthPrincipalDto. This ensures that the sessionId is not included in toString or equals/hashCode operations, improving security and avoiding unintended leaks of sensitive data.
---
 .../engine/objects/auth/dto/AuthPrincipalDto.java            | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
index bf3d90f923..f5225f1991 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
@@ -1,6 +1,8 @@
 package com.netgrif.application.engine.objects.auth.dto;
 
 import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 import java.io.Serial;
 import java.io.Serializable;
@@ -13,5 +15,8 @@ public class AuthPrincipalDto implements Serializable {
 
     private String username;
     private String realmId;
+
+    @ToString.Exclude
+    @EqualsAndHashCode.Exclude
     private String sessionId;
 }

From 9eacdd08f226646e3b17acdde93bb101822440a2 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:43:27 +0200
Subject: [PATCH 11/23] Fix typo in enum constant name from SEARCH_USER to
 SEARCH_USERS

Corrected the enum constant to accurately reflect the plural form, ensuring consistency with the corresponding method name. This improves code clarity and prevents potential mismatches or confusion.
---
 .../engine/adapter/spring/actions/ActionApiMethods.java         | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
index 10e41d0464..c3d387940e 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -15,7 +15,7 @@ public enum ActionApiMethods {
     ASSIGN_TASK("assignTask"),
     CANCEL_TASK("cancelTask"),
     FINISH_TASK("finishTask"),
-    SEARCH_USER("searchUsers");
+    SEARCH_USERS("searchUsers");
 
     private String methodName;
 

From 6642234883b503214f856dd1275de279761c2457 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:45:02 +0200
Subject: [PATCH 12/23] - removed duplicate dependency

---
 nae-spring-core-adapter/pom.xml | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/nae-spring-core-adapter/pom.xml b/nae-spring-core-adapter/pom.xml
index 7a8bff888f..e3edd06578 100644
--- a/nae-spring-core-adapter/pom.xml
+++ b/nae-spring-core-adapter/pom.xml
@@ -98,11 +98,6 @@
             <artifactId>jackson-module-jsonSchema</artifactId>
             <version>${jackson.version}</version>
         </dependency>
-        <dependency>
-            <groupId>com.querydsl</groupId>
-            <artifactId>querydsl-core</artifactId>
-            <version>${querydsl.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>

From 9e726d1390dda16c486228fd3c5a1293ff912a3f Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:48:42 +0200
Subject: [PATCH 13/23] - removed unused import

---
 .../application/engine/adapter/spring/actions/ActionApi.java     | 1 -
 1 file changed, 1 deletion(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 73740c91af..7f4bf4b669 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -19,7 +19,6 @@
 
 import java.util.Map;
 import java.util.List;
-import java.util.Map;
 
 
 /**

From 905a142b9139307ecc1e6cf2e62c3cc08d66aaf2 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 13:59:15 +0200
Subject: [PATCH 14/23] Remove redundant Serializable implementation in
 exception class

The `Serializable` interface was unnecessary in `AmbiguousMethodCallException` since `RuntimeException` already implements it. This change simplifies the class and avoids redundant code.
---
 .../spring/utils/exceptions/AmbiguousMethodCallException.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
index 594b133b47..c2287972ca 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
@@ -3,7 +3,7 @@
 import java.io.Serial;
 import java.io.Serializable;
 
-public final class AmbiguousMethodCallException extends RuntimeException implements Serializable {
+public final class AmbiguousMethodCallException extends RuntimeException {
 
     @Serial
     private static final long serialVersionUID = 1L;

From c497abaad1733d6006c44790753901406d13c676 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 14:00:16 +0200
Subject: [PATCH 15/23] Remove redundant Serializable implementation in
 exception class

The `Serializable` interface was unnecessary in `AmbiguousMethodCallException` since `RuntimeException` already implements it. This change simplifies the class and avoids redundant code.
---
 .../spring/utils/exceptions/AmbiguousMethodCallException.java    | 1 -
 1 file changed, 1 deletion(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
index c2287972ca..e872386604 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
@@ -1,7 +1,6 @@
 package com.netgrif.application.engine.adapter.spring.utils.exceptions;
 
 import java.io.Serial;
-import java.io.Serializable;
 
 public final class AmbiguousMethodCallException extends RuntimeException {
 

From f5df0dc8d05bd66929dcff40f2efe1873ab2360e Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Mon, 20 Oct 2025 14:11:41 +0200
Subject: [PATCH 16/23] Enhance method handling and enforce non-null
 constraints

Added `@NonNull` annotations to critical fields in `AuthPrincipalDto` to ensure required values are always provided. Refined method retrieval in `NaeReflectionUtils` to filter only bridge and synthetic methods, improving specificity. Expanded `AmbiguousMethodCallException` with detailed Javadoc for better clarity and usage documentation.
---
 .../engine/objects/auth/dto/AuthPrincipalDto.java |  4 ++++
 .../adapter/spring/utils/NaeReflectionUtils.java  |  2 +-
 .../exceptions/AmbiguousMethodCallException.java  | 15 +++++++++++++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
index f5225f1991..c5cf003963 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
@@ -2,6 +2,7 @@
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import lombok.NonNull;
 import lombok.ToString;
 
 import java.io.Serial;
@@ -13,7 +14,10 @@ public class AuthPrincipalDto implements Serializable {
     @Serial
     private static final long serialVersionUID = 6725518942728316525L;
 
+    @NonNull
     private String username;
+
+    @NonNull
     private String realmId;
 
     @ToString.Exclude
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
index 92b6642aa4..77866fb39f 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
@@ -95,7 +95,7 @@ private static Method findMethodWithSuperClassParams(Object bean, String methodT
                                                   NoSuchMethodException caughtException)
             throws NoSuchMethodException, AmbiguousMethodCallException {
         Class<?> cls = NaeReflectionUtils.resolveClass(bean);
-        Method[] methods = cls.getMethods();
+        Method[] methods = Arrays.stream(cls.getMethods()).filter(m -> m.isBridge() || m.isSynthetic()).toArray(Method[]::new);
         Method methodToInvoke = null;
         outerLoop:
         for (Method method : methods) {
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
index e872386604..32ffaf8363 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/exceptions/AmbiguousMethodCallException.java
@@ -2,15 +2,30 @@
 
 import java.io.Serial;
 
+/**
+ * Exception thrown when a method call cannot be resolved unambiguously
+ * due to multiple possible matches.
+ */
 public final class AmbiguousMethodCallException extends RuntimeException {
 
     @Serial
     private static final long serialVersionUID = 1L;
 
+    /**
+     * Constructs a new exception with the specified detail message.
+     *
+     * @param message a description of the ambiguity that caused the exception
+     */
     public AmbiguousMethodCallException(String message) {
         super(message);
     }
 
+    /**
+     * Constructs a new exception with the specified detail message and cause.
+     *
+     * @param message   a description of the ambiguity that caused the exception
+     * @param throwable the cause of the exception
+     */
     public AmbiguousMethodCallException(String message, Throwable throwable) {
         super(message, throwable);
     }

From e1dad6cd2e4924d90789eb1e565fbb53c3a9989b Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Thu, 6 Nov 2025 11:13:08 +0100
Subject: [PATCH 17/23] Remove @NonNull annotations from AuthPrincipalDto
 fields

The @NonNull annotations were removed from the `username` and `realmId` fields in `AuthPrincipalDto` to relax validation constraints. This allows greater flexibility in handling null values for these fields where necessary.
---
 .../application/engine/objects/auth/dto/AuthPrincipalDto.java   | 2 --
 1 file changed, 2 deletions(-)

diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
index c5cf003963..50d6ead9fb 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
@@ -14,10 +14,8 @@ public class AuthPrincipalDto implements Serializable {
     @Serial
     private static final long serialVersionUID = 6725518942728316525L;
 
-    @NonNull
     private String username;
 
-    @NonNull
     private String realmId;
 
     @ToString.Exclude

From 50a4fb99f31f65b4f3131dfde8d3a0d453702636 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Tue, 2 Dec 2025 15:34:37 +0100
Subject: [PATCH 18/23] Improve null handling, performance, and serialization

Added `@JsonIgnore` to prevent `sessionId` serialization. Enhanced null-checking and parameter handling in `NaeReflectionUtils`. Optimized `ActionApiMethods` lookup with a prebuilt map for better performance.
---
 .../engine/objects/auth/dto/AuthPrincipalDto.java      |  3 ++-
 .../engine/adapter/spring/actions/ActionApi.java       |  2 +-
 .../adapter/spring/actions/ActionApiMethods.java       | 10 ++++++----
 .../adapter/spring/utils/NaeReflectionUtils.java       |  9 +++++++--
 4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
index 50d6ead9fb..3333122aae 100644
--- a/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
+++ b/nae-object-library/src/main/java/com/netgrif/application/engine/objects/auth/dto/AuthPrincipalDto.java
@@ -1,8 +1,8 @@
 package com.netgrif.application.engine.objects.auth.dto;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import lombok.NonNull;
 import lombok.ToString;
 
 import java.io.Serial;
@@ -20,5 +20,6 @@ public class AuthPrincipalDto implements Serializable {
 
     @ToString.Exclude
     @EqualsAndHashCode.Exclude
+    @JsonIgnore
     private String sessionId;
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 7f4bf4b669..497a920487 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -51,7 +51,7 @@ public interface ActionApi {
      * Finds a specific case by its ID.
      *
      * @param caseId the ID of the case to find
-     * @return the found case
+     * @return the found case, otherwise returns null
      */
     Case findCase(String caseId);
 
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
index c3d387940e..ed4a19d075 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -1,6 +1,8 @@
 package com.netgrif.application.engine.adapter.spring.actions;
 
 import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 public enum ActionApiMethods {
 
@@ -19,6 +21,8 @@ public enum ActionApiMethods {
 
     private String methodName;
 
+    private static final Map<String, ActionApiMethods> METHODS_BY_NAME_MAP = Arrays.stream(values()).collect(Collectors.toUnmodifiableMap(ActionApiMethods::getMethodName, e -> e));
+
     ActionApiMethods(String methodName) {
         this.methodName = methodName;
     }
@@ -27,10 +31,8 @@ public String getMethodName() {
         return methodName;
     }
 
+
     public static ActionApiMethods fromMethodName(String methodName) {
-        return Arrays.stream(ActionApiMethods.values())
-                .filter(type -> type.methodName.equals(methodName))
-                .findFirst()
-                .orElse(null);
+        return METHODS_BY_NAME_MAP.get(methodName);
     }
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
index 77866fb39f..eadac8c7e9 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/utils/NaeReflectionUtils.java
@@ -71,8 +71,11 @@ public static <I> int indexOfClass(List<I> list, Class<?> clazz) {
      */
     public static Method findMethod(Object bean, String methodToExecute, Class<?>[] requestParamTypes)
             throws NoSuchMethodException, AmbiguousMethodCallException {
+        Objects.requireNonNull(bean, "bean must not be null");
+        Objects.requireNonNull(methodToExecute, "methodToExecute must not be null");
+        final Class<?>[] paramTypes = (requestParamTypes == null) ? new Class<?>[0] : requestParamTypes;
         try {
-            return NaeReflectionUtils.resolveClass(bean).getMethod(methodToExecute, requestParamTypes);
+            return NaeReflectionUtils.resolveClass(bean).getMethod(methodToExecute, paramTypes);
         } catch (NoSuchMethodException e) {
             return findMethodWithSuperClassParams(bean, methodToExecute, requestParamTypes, e);
         }
@@ -95,7 +98,9 @@ private static Method findMethodWithSuperClassParams(Object bean, String methodT
                                                   NoSuchMethodException caughtException)
             throws NoSuchMethodException, AmbiguousMethodCallException {
         Class<?> cls = NaeReflectionUtils.resolveClass(bean);
-        Method[] methods = Arrays.stream(cls.getMethods()).filter(m -> m.isBridge() || m.isSynthetic()).toArray(Method[]::new);
+        Method[] methods = Arrays.stream(cls.getMethods())
+                .filter(m -> !m.isBridge() && !m.isSynthetic())
+                .toArray(Method[]::new);
         Method methodToInvoke = null;
         outerLoop:
         for (Method method : methods) {

From b33499ea7ca7599f7f7ec5d133b7f1b979379fa4 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Wed, 3 Dec 2025 13:21:08 +0100
Subject: [PATCH 19/23] [NAE-2292] Make force delete of petriNets
 non-transactional

- updated docs according to PR
---
 .../engine/adapter/spring/actions/ActionApi.java           | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 497a920487..b0ea0fdd2c 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -56,9 +56,12 @@ public interface ActionApi {
     Case findCase(String caseId);
 
     /**
-     * Searches for cases matching the given process identifier and predicate.
+     * Searches for cases matching the given predicate.
      *
-     * @param processIdentifier the identifier of the process
+     * @param processIdentifier reserved for interface compatibility; this implementation
+     *                          does not filter by process identifier and returns cases
+     *                          from all processes. Use the predicate parameter to filter
+     *                          by specific process(es) if needed.
      * @param predicate         the criteria for filtering cases
      * @param pageable          the pagination information
      * @return a page of cases matching the criteria

From 8d2aa1324041d7566222eceb20ed4b7f9de5789d Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Wed, 3 Dec 2025 13:32:32 +0100
Subject: [PATCH 20/23] - updated javadocs

---
 .../application/engine/adapter/spring/actions/ActionApi.java  | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index b0ea0fdd2c..dc9f5dd5a4 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -51,7 +51,8 @@ public interface ActionApi {
      * Finds a specific case by its ID.
      *
      * @param caseId the ID of the case to find
-     * @return the found case, otherwise returns null
+     * @return the found case
+     * @throws IllegalArgumentException if not found
      */
     Case findCase(String caseId);
 
@@ -105,6 +106,7 @@ public interface ActionApi {
      *
      * @param taskId the ID of the task to find
      * @return the found task
+     * @throws IllegalArgumentException if not found
      */
     Task findTask(String taskId);
 

From 73db147fb21abf6a3b5d93cdb8eaf112bad1107c Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Thu, 4 Dec 2025 11:19:12 +0100
Subject: [PATCH 21/23] - updated javadocs

---
 .../engine/adapter/spring/actions/ActionApi.java           | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index dc9f5dd5a4..3e3c1dc96f 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -111,9 +111,12 @@ public interface ActionApi {
     Task findTask(String taskId);
 
     /**
-     * Searches for tasks matching the given process identifier and predicate.
+     * Searches for tasks matching the given predicate.
      *
-     * @param processIdentifier the identifier of the process
+     * @param processIdentifier reserved for interface compatibility; this implementation
+     *                          does not filter by process identifier and returns tasks
+     *                          from all processes. Use the predicate parameter to filter
+     *                          by specific process(es) if needed.
      * @param predicate         the criteria for filtering tasks
      * @param pageable          the pagination information
      * @return a page of tasks matching the criteria

From 85765f28a95567184cd39ae3d9da01dbf1fa1a91 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Thu, 4 Dec 2025 12:30:21 +0100
Subject: [PATCH 22/23] Add methods for counting cases and retrieving the
 system user

Introduced `countCases` and `getSystemUser` methods in the Action API to expand its functionality. These additions enable case counting based on queries and allow access to the system user, enhancing application flexibility and support.
---
 .../engine/actions/ActionApiImpl.java         | 14 +++++++++++++
 .../adapter/spring/actions/ActionApi.java     | 20 +++++++++++++++++++
 .../spring/actions/ActionApiMethods.java      |  4 +++-
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index 53ff7d0686..c25cfcb0ee 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -115,6 +115,15 @@ public Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDt
         return elasticCaseService.search(caseSearchRequests, loggedUser, pageable, locale, intersect);
     }
 
+    @Override
+    public Long countCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection) {
+        boolean intersect = Boolean.TRUE.equals(isIntersection);
+        List<CaseSearchRequest> caseSearchRequests = elasticStringQueries.stream().map(query -> CaseSearchRequest.builder().query(query).build()).toList();
+        LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
+        Locale locale = LocaleContextHolder.getLocale();
+        return elasticCaseService.count(caseSearchRequests, loggedUser, locale, intersect);
+    }
+
     @Override
     public CreateCaseEventOutcome createCaseByIdentifier(String identifier, String title, String color, AuthPrincipalDto authPrincipalDto, Map<String, String> params) {
         LoggedUser loggedUser = ActorTransformer.toLoggedUser(resolveAbstractUser(authPrincipalDto));
@@ -177,6 +186,11 @@ public Page<User> searchUsers(Predicate predicate, Pageable pageable, String rea
         return userService.search(predicate, pageable, realmId);
     }
 
+    @Override
+    public AbstractUser getSystemUser() {
+        return userService.getSystem();
+    }
+
     private AbstractUser resolveAbstractUser(AuthPrincipalDto authPrincipalDto) {
         if (authPrincipalDto == null) {
             throw new IllegalArgumentException("AuthPrincipalDto cannot be null.");
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
index 3e3c1dc96f..b2e112a6b1 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApi.java
@@ -1,6 +1,7 @@
 package com.netgrif.application.engine.adapter.spring.actions;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.netgrif.application.engine.objects.auth.domain.AbstractUser;
 import com.netgrif.application.engine.objects.auth.domain.User;
 import com.netgrif.application.engine.objects.auth.dto.AuthPrincipalDto;
 import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
@@ -80,6 +81,17 @@ public interface ActionApi {
      */
     Page<Case> searchCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Pageable pageable, Boolean isIntersection);
 
+
+    /**
+     * Counts the number of cases that match the provided elastic search queries.
+     *
+     * @param elasticStringQueries a list of elastic search queries used for filtering cases
+     * @param authPrincipalDto     the authorization principal for the operation
+     * @param isIntersection       true to intersect the results of all queries; false for union
+     * @return the total number of cases matching the criteria
+     */
+    Long countCases(List<String> elasticStringQueries, AuthPrincipalDto authPrincipalDto, Boolean isIntersection);
+
     /**
      * Creates a new case identified by the given process identifier.
      *
@@ -175,4 +187,12 @@ public interface ActionApi {
      * @return a page of users matching the criteria
      */
     Page<User> searchUsers(Predicate predicate, Pageable pageable, String realmId);
+
+
+    /**
+     * Retrieves the system user of the application.
+     *
+     * @return the system user
+     */
+    AbstractUser getSystemUser();
 }
diff --git a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
index ed4a19d075..79b9d673d8 100644
--- a/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
+++ b/nae-spring-core-adapter/src/main/java/com/netgrif/application/engine/adapter/spring/actions/ActionApiMethods.java
@@ -9,6 +9,7 @@ public enum ActionApiMethods {
     GET_DATA("getData"),
     SET_DATA("setData"),
     FIND_CASE("findCase"),
+    COUNT_CASES("countCases"),
     SEARCH_CASES("searchCases"),
     CREATE_CASE_BY_IDENTIFIER("createCaseByIdentifier"),
     DELETE_CASE("deleteCase"),
@@ -17,7 +18,8 @@ public enum ActionApiMethods {
     ASSIGN_TASK("assignTask"),
     CANCEL_TASK("cancelTask"),
     FINISH_TASK("finishTask"),
-    SEARCH_USERS("searchUsers");
+    SEARCH_USERS("searchUsers"),
+    GET_SYSTEM_USER("getSystemUser");
 
     private String methodName;
 

From 40f5423ae918333413a0f4fe8228f4de753a8283 Mon Sep 17 00:00:00 2001
From: renczesstefan <renczes.stefan@gmail.com>
Date: Tue, 9 Dec 2025 19:18:23 +0100
Subject: [PATCH 23/23] Remove unused ObjectMapper from ActionApiImpl

The ObjectMapper field and its associated setter were removed as they were not used in the class. This cleanup reduces unnecessary code, improving maintainability and clarity.
---
 .../netgrif/application/engine/actions/ActionApiImpl.java  | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
index c25cfcb0ee..c54221a285 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/actions/ActionApiImpl.java
@@ -51,8 +51,6 @@ public class ActionApiImpl implements ActionApi {
 
     private IElasticTaskService elasticTaskService;
 
-    private ObjectMapper objectMapper;
-
     @Autowired
     public void setDataService(IDataService dataService) {
         this.dataService = dataService;
@@ -83,11 +81,6 @@ public void setElasticTaskService(IElasticTaskService elasticTaskService) {
         this.elasticTaskService = elasticTaskService;
     }
 
-    @Autowired
-    public void setObjectMapper(ObjectMapper objectMapper) {
-        this.objectMapper = objectMapper;
-    }
-
     @Override
     public GetDataEventOutcome getData(String taskId, Map<String, String> params) {
         return dataService.getData(taskId, params);
