Repository: mycloudnexus/kraken
Pull request #500: feat(sdk): add workflow status to api logs
Author: login: zhiyaoPCCW
Created: 2025-02-26T08:18:06Z | Merged: 2025-03-03T05:21:41Z

<!-- Provide a general summary of your changes in the Title above -->

## Description

<!-- Describe your changes in detail -->
Add workflow status to api logs and show status in control plane
changes: 
Added two build-in tasks to notify success/failure of workflow.
Added new event to update workflow state in control plane.
Trigger workflow state change event and push event to control plane to update workflow state in api activity log.

## Related Issue
https://github.com/mycloudnexus/kraken/issues/444
<!-- This project only accepts pull requests related to open issues. -->
<!-- If suggesting a new feature or change, please discuss it in an issue first. -->
<!-- If fixing a bug, there should be an issue describing it with steps to reproduce. -->
<!-- Please link to the issue here. -->

## Motivation and Context

<!-- Why is this change required? What problem does it solve? -->

## How This Has Been Tested

<!-- Please describe in detail how you tested your changes -->
<!-- Include details of your testing environment, and the tests -->
<!-- you ran to see how your change affects other areas of the code, etc. -->
<!-- This information is helpful for reviewers and QA. -->

## Screenshots (if appropriate)

## Types of changes

<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Refactoring or add test (improvements in base code or adds test coverage to functionality)
- [ ] CI/CD or documentation update (changes to CI/CD pipeline or documentation)

## Self Checklist

<!-- Go over all the following points, and put an `x` in all the boxes that apply -->
<!-- If there are no documentation updates required, mark the item as checked. -->
<!-- Raise up any additional concerns not covered by the checklist. -->

- [x] I ensured that I are not pushing configuration files containing sensitive information such as testing keys.
- [x] I ensured that large PR is avoided,  Consider splitting if there are more than 500 line changes, In addition to line count, also consider the number of files being affected, An ideal amount is less than 10, 25-30 is generally too large with the exception of library upgrades, refactors, etc.
- [x] I ensured that If the PR is inevitably large, a short PR review meeting or discuss with reviewers will be organized.
- [x] I ensured that If the PR is to resolve a blocker, do not make unrelated changes in the same PR e.g. formatting changes, to minimize review time.
- [x] I ensured that PR is focused
- [x] I ensured that context was given in the PR description, Include a clear description of the changes
- [x] I ensured that related github issues are linked, Include screenshots if this will make the context clearer for the reviewer
- [x] I ensured that "work in progress" or "hold" labels are removed
- [x] I ensured that adherence to style guidelines
- [x] I ensured that feature flag is applied if needed
- [x] I ensured that follow secure development practices
- [x] I ensured that no secrets or sensitive data have been committed or logged
- [x] I ensured that no hardcoded values that may change depending on environment (these should be configured dynamically e.g. through environment variables, from the db etc)



Diff:
diff --git a/kraken-app/kraken-app-agent/src/main/resources/application.yaml b/kraken-app/kraken-app-agent/src/main/resources/application.yaml
index 4a0a8b834..f0cc3a712 100644
--- a/kraken-app/kraken-app-agent/src/main/resources/application.yaml
+++ b/kraken-app/kraken-app-agent/src/main/resources/application.yaml
@@ -117,6 +117,7 @@ app:
     push-heartbeat: 0/20 * * * * *
     push-log: 0/20 * * * * *
     push-log-external-system: 0 0/1 * * * *
+    push-workflow-status: 0 0/1 * * * *
     lock:
       at-most-for: 2m
       at-least-for: 10s
diff --git a/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/handler/ClientWorkflowStateChangeEventHandler.java b/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/handler/ClientWorkflowStateChangeEventHandler.java
new file mode 100644
index 000000000..8f6c49494
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-controller/src/main/java/com/consoleconnect/kraken/operator/controller/handler/ClientWorkflowStateChangeEventHandler.java
@@ -0,0 +1,45 @@
+package com.consoleconnect.kraken.operator.controller.handler;
+
+import com.consoleconnect.kraken.operator.core.client.ClientEvent;
+import com.consoleconnect.kraken.operator.core.client.ClientEventTypeEnum;
+import com.consoleconnect.kraken.operator.core.client.ClientWorkflowTerminate;
+import com.consoleconnect.kraken.operator.core.model.HttpResponse;
+import com.consoleconnect.kraken.operator.core.repo.ApiActivityLogRepository;
+import com.consoleconnect.kraken.operator.core.toolkit.JsonToolkit;
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+@Slf4j
+public class ClientWorkflowStateChangeEventHandler extends ClientEventHandler {
+  private final ApiActivityLogRepository apiActivityLogRepository;
+
+  @Override
+  public ClientEventTypeEnum getEventType() {
+    return ClientEventTypeEnum.CLIENT_TERMINATE_WORKFLOW;
+  }
+
+  @Override
+  public HttpResponse<Void> onEvent(String envId, String userId, ClientEvent event) {
+    List<ClientWorkflowTerminate> requestList =
+        JsonToolkit.fromJson(event.getEventPayload(), new TypeReference<>() {});
+    requestList.stream()
+        .forEach(
+            clientWorkflowTerminate ->
+                apiActivityLogRepository
+                    .findByRequestIdAndCallSeq(clientWorkflowTerminate.getRequestId(), 0)
+                    .ifPresent(
+                        entity -> {
+                          entity.setErrorMsg(clientWorkflowTerminate.getErrorMessage());
+                          entity.setWorkflowInstanceId(
+                              clientWorkflowTerminate.getWorkflowInstanceId());
+                          entity.setWorkflowStatus(clientWorkflowTerminate.getStatus());
+                          apiActivityLogRepository.save(entity);
+                        }));
+    return HttpResponse.ok(null);
+  }
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-controller/src/test/java/com/consoleconnect/kraken/operator/controller/v2/ClientPubSubControllerTest.java b/kraken-java-sdk/kraken-java-sdk-controller/src/test/java/com/consoleconnect/kraken/operator/controller/v2/ClientPubSubControllerTest.java
index 103cfabeb..c5ec2fe8a 100644
--- a/kraken-java-sdk/kraken-java-sdk-controller/src/test/java/com/consoleconnect/kraken/operator/controller/v2/ClientPubSubControllerTest.java
+++ b/kraken-java-sdk/kraken-java-sdk-controller/src/test/java/com/consoleconnect/kraken/operator/controller/v2/ClientPubSubControllerTest.java
@@ -1,11 +1,16 @@
 package com.consoleconnect.kraken.operator.controller.v2;
 
+import static org.mockito.ArgumentMatchers.*;
+
 import com.consoleconnect.kraken.operator.config.TestApplication;
 import com.consoleconnect.kraken.operator.controller.APITokenCreator;
 import com.consoleconnect.kraken.operator.controller.WebTestClientHelper;
 import com.consoleconnect.kraken.operator.controller.service.APITokenService;
 import com.consoleconnect.kraken.operator.core.client.*;
 import com.consoleconnect.kraken.operator.core.dto.ApiActivityLog;
+import com.consoleconnect.kraken.operator.core.entity.ApiActivityLogEntity;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
+import com.consoleconnect.kraken.operator.core.repo.ApiActivityLogRepository;
 import com.consoleconnect.kraken.operator.core.request.LogSearchRequest;
 import com.consoleconnect.kraken.operator.core.service.ApiActivityLogService;
 import com.consoleconnect.kraken.operator.core.toolkit.DateTime;
@@ -16,7 +21,9 @@
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.*;
+import org.mockito.Mockito;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.SpyBean;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
@@ -32,6 +39,7 @@
 class ClientPubSubControllerTest extends AbstractIntegrationTest implements APITokenCreator {
   @Getter @Autowired APITokenService apiTokenService;
   @Autowired ApiActivityLogService apiActivityLogService;
+  @SpyBean ApiActivityLogRepository apiActivityLogRepository;
 
   public static final String PRODUCT_ID = "mef.sonata";
   public static final String CLIENT_EVENT_ENDPOINT = "/client/events";
@@ -180,4 +188,30 @@ void givenClientServerAPIEvent_whenUploadEvent_thenResponseOK() {
         event,
         Assertions::assertNotNull);
   }
+
+  @Test
+  void givenClientWorkflowStatusEvent_whenTriggerEvent_thenResponseOK() {
+    ClientWorkflowTerminate terminate = new ClientWorkflowTerminate();
+    terminate.setErrorMessage("unexpected error");
+    terminate.setStatus(WorkflowStatusEnum.FAILED.name());
+    terminate.setRequestId(UUID.randomUUID().toString());
+    ClientEvent clientEvent =
+        ClientEvent.of(
+            UUID.randomUUID().toString(),
+            ClientEventTypeEnum.CLIENT_TERMINATE_WORKFLOW,
+            List.of(terminate));
+    Mockito.doReturn(Optional.of(new ApiActivityLogEntity()))
+        .when(apiActivityLogRepository)
+        .findByRequestIdAndCallSeq(anyString(), anyInt());
+    Mockito.doReturn(new ApiActivityLogEntity()).when(apiActivityLogRepository).save(any());
+    Map<String, String> headers = new HashMap<>();
+    headers.put("Authorization", accessToken);
+    webTestClientHelper.requestAndVerify(
+        HttpMethod.POST,
+        uriBuilder -> uriBuilder.path(CLIENT_EVENT_ENDPOINT).build(),
+        headers,
+        HttpStatus.OK.value(),
+        clientEvent,
+        Assertions::assertNotNull);
+  }
 }
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientEventTypeEnum.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientEventTypeEnum.java
index a61497bcd..d16bc252b 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientEventTypeEnum.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientEventTypeEnum.java
@@ -9,5 +9,6 @@ public enum ClientEventTypeEnum {
   CLIENT_SYSTEM_INFO,
   CLIENT_MAPPER_VERSION,
   CLIENT_APP_VERSION_UPGRADE_RESULT,
-  CLIENT_PUSH_API_ACTIVITY_LOG
+  CLIENT_PUSH_API_ACTIVITY_LOG,
+  CLIENT_TERMINATE_WORKFLOW;
 }
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientWorkflowTerminate.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientWorkflowTerminate.java
new file mode 100644
index 000000000..0230eebcc
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/client/ClientWorkflowTerminate.java
@@ -0,0 +1,11 @@
+package com.consoleconnect.kraken.operator.core.client;
+
+import lombok.Data;
+
+@Data
+public class ClientWorkflowTerminate {
+  private String requestId;
+  private String workflowInstanceId;
+  private String status;
+  private String errorMessage;
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/dto/ApiActivityLog.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/dto/ApiActivityLog.java
index 75aabec86..06e144f28 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/dto/ApiActivityLog.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/dto/ApiActivityLog.java
@@ -27,4 +27,6 @@ public class ApiActivityLog extends AbstractHttpModel {
   private String buyerId;
   private String buyerName;
   private String productType;
+  private String workflowStatus;
+  private String errorMsg;
 }
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/ApiActivityLogEntity.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/ApiActivityLogEntity.java
index 9eb1464a7..4865cca1c 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/ApiActivityLogEntity.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/ApiActivityLogEntity.java
@@ -54,6 +54,15 @@ public class ApiActivityLogEntity extends AbstractHttpEntity {
   @Column(name = "product_type", nullable = true, unique = false)
   private String productType;
 
+  @Column(name = "workflow_instance_id", nullable = true, unique = false)
+  private String workflowInstanceId;
+
+  @Column(name = "workflow_status", nullable = true, unique = false)
+  private String workflowStatus;
+
+  @Column(name = "error_msg", nullable = true, unique = false)
+  private String errorMsg;
+
   @OneToOne
   @JoinColumn(name = "api_log_body_id")
   private ApiActivityLogBodyEntity apiLogBodyEntity;
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/WorkflowInstanceEntity.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/WorkflowInstanceEntity.java
new file mode 100644
index 000000000..69f102e49
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/entity/WorkflowInstanceEntity.java
@@ -0,0 +1,34 @@
+package com.consoleconnect.kraken.operator.core.entity;
+
+import io.hypersistence.utils.hibernate.type.json.JsonType;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+import lombok.Getter;
+import lombok.Setter;
+import org.hibernate.annotations.Type;
+
+@Entity
+@Getter
+@Setter
+@Table(name = "kraken_workflow_instance")
+public class WorkflowInstanceEntity extends AbstractEntity {
+  @Column(name = "workflow_instance_id", nullable = false)
+  private String workflowInstanceId;
+
+  @Column(name = "status", nullable = false)
+  private String status;
+
+  @Column(name = "error_msg", nullable = true)
+  private String errorMsg;
+
+  @Column(name = "request_id", nullable = false)
+  private String requestId;
+
+  @Column(name = "synced", nullable = false)
+  private boolean synced;
+
+  @Type(JsonType.class)
+  @Column(name = "payload", columnDefinition = "jsonb")
+  private Object payload;
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/enums/WorkflowStatusEnum.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/enums/WorkflowStatusEnum.java
new file mode 100644
index 000000000..916f4f4c7
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/enums/WorkflowStatusEnum.java
@@ -0,0 +1,7 @@
+package com.consoleconnect.kraken.operator.core.enums;
+
+public enum WorkflowStatusEnum {
+  IN_PROGRESS,
+  SUCCESS,
+  FAILED
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/model/HttpTask.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/model/HttpTask.java
index 4c16c06fd..1668af20e 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/model/HttpTask.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/model/HttpTask.java
@@ -2,6 +2,7 @@
 
 import com.consoleconnect.kraken.operator.core.enums.JoinOperatorEnum;
 import com.consoleconnect.kraken.operator.core.model.facet.ComponentAPITargetFacets;
+import java.util.ArrayList;
 import java.util.List;
 import lombok.Data;
 import lombok.Getter;
@@ -11,13 +12,14 @@
 @Setter
 public class HttpTask extends AbstractTask {
   private ComponentAPITargetFacets.Endpoint endpoint;
-  private ConditionCheck conditionCheck;
+  private ConditionCheck conditionCheck = new ConditionCheck();
   private String notificationUrl;
 
   @Data
   public static class ConditionCheck {
     private JoinOperatorEnum join;
-    private List<ConditionItem> conditionItems;
+    private List<ConditionItem> conditionItems = new ArrayList<>();
     private String buildInTask;
+    private String errorMsg;
   }
 }
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/repo/WorkflowInstanceRepository.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/repo/WorkflowInstanceRepository.java
new file mode 100644
index 000000000..b401e66d9
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/repo/WorkflowInstanceRepository.java
@@ -0,0 +1,18 @@
+package com.consoleconnect.kraken.operator.core.repo;
+
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import java.util.List;
+import java.util.UUID;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+public interface WorkflowInstanceRepository
+    extends PagingAndSortingRepository<WorkflowInstanceEntity, UUID>,
+        JpaRepository<WorkflowInstanceEntity, UUID>,
+        JpaSpecificationExecutor<WorkflowInstanceEntity> {
+
+  List<WorkflowInstanceEntity> findAllBySynced(boolean synced);
+
+  WorkflowInstanceEntity findByRequestId(String requestId);
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java
index bb6ef3580..945ab8a46 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/main/java/com/consoleconnect/kraken/operator/core/toolkit/Constants.java
@@ -23,6 +23,8 @@ private Constants() {}
   public static final String LOG_PAYLOAD_TASK = "log_payload_task";
   public static final String PROCESS_ORDER_TASK = "process_order_task";
   public static final String PERSIST_RESPONSE_TASK = "persist_response_task";
+  public static final String WORKFLOW_FAILED_TASK = "workflow_failed_task";
+  public static final String WORKFLOW_SUCCESS_TASK = "workflow_success_task";
   public static final String NOTIFY_TASK = "notify_task";
   public static final String WORKFLOW_PARAM_PREFIX = "${workflow.input.%s}";
   public static final String COMMA_SPACE_EXPRESSION = "[\\s,]+";
diff --git a/kraken-java-sdk/kraken-java-sdk-core/src/test/java/com/consoleconnect/kraken/operator/core/StringUtilsTest.java b/kraken-java-sdk/kraken-java-sdk-core/src/test/java/com/consoleconnect/kraken/operator/core/StringUtilsTest.java
index 8df683240..81fc4d708 100644
--- a/kraken-java-sdk/kraken-java-sdk-core/src/test/java/com/consoleconnect/kraken/operator/core/StringUtilsTest.java
+++ b/kraken-java-sdk/kraken-java-sdk-core/src/test/java/com/consoleconnect/kraken/operator/core/StringUtilsTest.java
@@ -3,6 +3,7 @@
 import com.consoleconnect.kraken.operator.core.enums.RegisterActionTypeEnum;
 import com.consoleconnect.kraken.operator.core.enums.TaskEnum;
 import com.consoleconnect.kraken.operator.core.enums.WorkflowStageEnum;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
 import com.consoleconnect.kraken.operator.core.exception.ErrorResponse;
 import com.consoleconnect.kraken.operator.core.toolkit.StringUtils;
 import java.util.UUID;
@@ -29,6 +30,9 @@ void testEnum() {
     Assertions.assertNotNull(WorkflowStageEnum.VALIDATION_STAGE);
     Assertions.assertNotNull(TaskEnum.HTTP);
     Assertions.assertNotNull(TaskEnum.SWITCH);
+    Assertions.assertNotNull(WorkflowStatusEnum.FAILED);
+    Assertions.assertNotNull(WorkflowStatusEnum.IN_PROGRESS);
+    Assertions.assertNotNull(WorkflowStatusEnum.SUCCESS);
     Assertions.assertEquals(8, shortId.length());
   }
 
diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/filter/WorkflowActionFilterFactory.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/filter/WorkflowActionFilterFactory.java
index e729704e1..f366110d5 100644
--- a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/filter/WorkflowActionFilterFactory.java
+++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/filter/WorkflowActionFilterFactory.java
@@ -1,10 +1,13 @@
 package com.consoleconnect.kraken.operator.gateway.filter;
 
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
 import com.consoleconnect.kraken.operator.core.exception.KrakenException;
 import com.consoleconnect.kraken.operator.core.model.AppProperty;
 import com.consoleconnect.kraken.operator.core.model.HttpTask;
 import com.consoleconnect.kraken.operator.core.model.facet.ComponentAPIFacets;
 import com.consoleconnect.kraken.operator.core.model.facet.ComponentWorkflowFacets;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
 import com.consoleconnect.kraken.operator.core.toolkit.JsonToolkit;
 import com.consoleconnect.kraken.operator.gateway.model.WorkflowPayload;
 import com.consoleconnect.kraken.operator.gateway.runner.AbstractActionRunner;
@@ -34,6 +37,8 @@
 public class WorkflowActionFilterFactory
     extends AbstractGatewayFilterFactory<WorkflowActionFilterFactory.Config> {
 
+  private final WorkflowInstanceRepository workflowInstanceRepository;
+
   public static final String VAR_SYNCHRONOUS = "synchronous";
   public static final String VAR_WORKFLOW_ENABLED = "enabled";
   public static final String VAR_WORKFLOW_CONFIG = "workflow-config";
@@ -41,8 +46,9 @@ public class WorkflowActionFilterFactory
   public static final String VAR_REQUEST_ID = "log-request-id";
   public static final String VAR_BASE_URL = "url";
 
-  public WorkflowActionFilterFactory() {
+  public WorkflowActionFilterFactory(WorkflowInstanceRepository workflowInstanceRepository) {
     super(Config.class);
+    this.workflowInstanceRepository = workflowInstanceRepository;
   }
 
   @Override
@@ -64,6 +70,8 @@ public GatewayFilter apply(Config config) {
         // start workflow
         log.info("start workflow: {}", JsonToolkit.toJson(request));
         String workflowId = config.getWorkflowClient().startWorkflow(request);
+        // record workflow instance
+        recordWorkflowInstance(request, inputs, workflowId);
         // if async process, then return empty response
         if (!synchronousProcess) {
           return wrapperResponse(exchange, Map.of(), config);
@@ -80,6 +88,17 @@ public GatewayFilter apply(Config config) {
     };
   }
 
+  private void recordWorkflowInstance(
+      StartWorkflowRequest request, Map<String, Object> inputs, String workflowId) {
+    WorkflowInstanceEntity entity = new WorkflowInstanceEntity();
+    entity.setStatus(WorkflowStatusEnum.IN_PROGRESS.name());
+    entity.setPayload(request);
+    entity.setRequestId((String) inputs.get(VAR_REQUEST_ID));
+    entity.setWorkflowInstanceId(workflowId);
+    entity.setSynced(false);
+    workflowInstanceRepository.save(entity);
+  }
+
   public static boolean getBool(Map<String, Object> inputs, String param) {
     if (inputs.containsKey(param) && inputs.get(param) instanceof Boolean boolVar) {
       return boolVar;
diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/func/KrakenGatewayFilterSpecFunc.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/func/KrakenGatewayFilterSpecFunc.java
index 832c20678..497afbe5e 100644
--- a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/func/KrakenGatewayFilterSpecFunc.java
+++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/func/KrakenGatewayFilterSpecFunc.java
@@ -7,6 +7,7 @@
 import com.consoleconnect.kraken.operator.core.enums.ActionTypeEnum;
 import com.consoleconnect.kraken.operator.core.model.AppProperty;
 import com.consoleconnect.kraken.operator.core.model.facet.ComponentAPIFacets;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
 import com.consoleconnect.kraken.operator.gateway.filter.*;
 import com.consoleconnect.kraken.operator.gateway.repo.HttpRequestRepository;
 import com.consoleconnect.kraken.operator.gateway.runner.*;
@@ -38,6 +39,7 @@ public class KrakenGatewayFilterSpecFunc implements Function<GatewayFilterSpec,
   private final FilterHeaderService filterHeaderService;
   private final OrkesWorkflowClient workflowClient;
   private final OrkesMetadataClient metaDataClient;
+  private final WorkflowInstanceRepository workflowInstanceRepository;
 
   @Override
   public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
@@ -108,7 +110,7 @@ public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
           config.setBaseUri(mapping.getUri());
           config.setAppProperty(appProperty);
           gatewayFilterSpec.filter(
-              new WorkflowActionFilterFactory().apply(config),
+              new WorkflowActionFilterFactory(workflowInstanceRepository).apply(config),
               RouteToRequestUrlFilter.ROUTE_TO_URL_FILTER_ORDER + 1);
         }
         default -> gatewayFilterSpec.filter(
diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/KrakenAPIRouteLocatorImpl.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/KrakenAPIRouteLocatorImpl.java
index c6a991394..c9a9dc1b9 100644
--- a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/KrakenAPIRouteLocatorImpl.java
+++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/KrakenAPIRouteLocatorImpl.java
@@ -4,6 +4,7 @@
 import com.consoleconnect.kraken.operator.core.enums.AssetKindEnum;
 import com.consoleconnect.kraken.operator.core.model.AppProperty;
 import com.consoleconnect.kraken.operator.core.model.facet.ComponentAPIFacets;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
 import com.consoleconnect.kraken.operator.core.service.UnifiedAssetService;
 import com.consoleconnect.kraken.operator.core.toolkit.JsonToolkit;
 import com.consoleconnect.kraken.operator.gateway.func.KrakenGatewayFilterSpecFunc;
@@ -37,6 +38,7 @@ public class KrakenAPIRouteLocatorImpl implements RouteLocator {
   private final FilterHeaderService filterHeaderService;
   private final OrkesWorkflowClient workflowClient;
   private final OrkesMetadataClient metadataClient;
+  private final WorkflowInstanceRepository workflowInstanceRepository;
 
   private List<UnifiedAssetDto> listProducts() {
     return service
@@ -78,7 +80,8 @@ private void loadComponentMapping(
                                 appProperty,
                                 filterHeaderService,
                                 workflowClient,
-                                metadataClient)
+                                metadataClient,
+                                workflowInstanceRepository)
                             .apply(f))
                 .uri("no://op");
           });
diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/WorkflowTaskConfig.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/WorkflowTaskConfig.java
index c0efcd699..3ca01afd1 100644
--- a/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/WorkflowTaskConfig.java
+++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/main/java/com/consoleconnect/kraken/operator/gateway/service/WorkflowTaskConfig.java
@@ -3,9 +3,13 @@
 import static com.consoleconnect.kraken.operator.core.toolkit.Constants.*;
 
 import com.consoleconnect.kraken.operator.core.entity.ApiActivityLogEntity;
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
 import com.consoleconnect.kraken.operator.core.exception.KrakenException;
 import com.consoleconnect.kraken.operator.core.model.ApiActivityRequestLog;
 import com.consoleconnect.kraken.operator.core.model.ApiActivityResponseLog;
+import com.consoleconnect.kraken.operator.core.repo.ApiActivityLogRepository;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
 import com.consoleconnect.kraken.operator.core.toolkit.ConstructExpressionUtil;
 import com.consoleconnect.kraken.operator.core.toolkit.JsonToolkit;
 import com.consoleconnect.kraken.operator.gateway.entity.HttpRequestEntity;
@@ -34,6 +38,8 @@ public class WorkflowTaskConfig implements WorkflowTaskRegister {
   private final HttpRequestRepository repository;
 
   private final BackendApiActivityLogService backendApiActivityLogService;
+  private final WorkflowInstanceRepository workflowInstanceRepository;
+  private final ApiActivityLogRepository apiActivityLogRepository;
 
   @WorkerTask(NOTIFY_TASK)
   public void notify(
@@ -144,6 +150,44 @@ public void persistResponse(@InputParam("id") String id, @InputParam("payload")
     }
   }
 
+  @WorkerTask(WORKFLOW_SUCCESS_TASK)
+  public void workflowSuccessTask(@InputParam("id") String id) {
+    workflowStateChange(id, WorkflowStatusEnum.SUCCESS.name(), null);
+  }
+
+  @WorkerTask(WORKFLOW_FAILED_TASK)
+  public void workflowFailedTask(
+      @InputParam("id") String id, @InputParam("errorMsg") String errorMsg) {
+    workflowStateChange(id, WorkflowStatusEnum.FAILED.name(), errorMsg);
+  }
+
+  private void workflowStateChange(
+      @InputParam("id") String id,
+      @InputParam("status") String status,
+      @InputParam("errorMsg") String errorMsg) {
+    log.info("workflow {} terminate with: status = {}, errorMsg = {}", id, status, errorMsg);
+    if (StringUtils.isBlank(id)) {
+      log.warn("id is null");
+      return;
+    }
+    WorkflowInstanceEntity entity = workflowInstanceRepository.findByRequestId(id);
+    if (entity != null) {
+      entity.setStatus(status);
+      entity.setErrorMsg(errorMsg);
+      workflowInstanceRepository.save(entity);
+
+      apiActivityLogRepository
+          .findByRequestIdAndCallSeq(id, 0)
+          .ifPresent(
+              apiActivityLogEntity -> {
+                apiActivityLogEntity.setWorkflowStatus(status);
+                apiActivityLogEntity.setWorkflowInstanceId(entity.getWorkflowInstanceId());
+                apiActivityLogEntity.setErrorMsg(errorMsg);
+                apiActivityLogRepository.save(apiActivityLogEntity);
+              });
+    }
+  }
+
   private void setOrderState(String id, String state) {
     Optional<HttpRequestEntity> optional = repository.findById(UUID.fromString(id));
     optional.ifPresent(
diff --git a/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/workflow/WorkflowTaskConfigTest.java b/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/workflow/WorkflowTaskConfigTest.java
index ed0e0bfaa..afa781115 100644
--- a/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/workflow/WorkflowTaskConfigTest.java
+++ b/kraken-java-sdk/kraken-java-sdk-gateway/src/test/java/com/consoleconnect/kraken/operator/gateway/service/workflow/WorkflowTaskConfigTest.java
@@ -1,11 +1,14 @@
 package com.consoleconnect.kraken.operator.gateway.service.workflow;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.doReturn;
 
 import com.consoleconnect.kraken.operator.core.entity.ApiActivityLogEntity;
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
 import com.consoleconnect.kraken.operator.core.repo.ApiActivityLogRepository;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
 import com.consoleconnect.kraken.operator.gateway.CustomConfig;
 import com.consoleconnect.kraken.operator.gateway.entity.HttpRequestEntity;
 import com.consoleconnect.kraken.operator.gateway.repo.HttpRequestRepository;
@@ -28,8 +31,9 @@
 @ContextConfiguration(classes = CustomConfig.class)
 class WorkflowTaskConfigTest extends AbstractIntegrationTest {
   @SpyBean HttpRequestRepository httpRequestRepository;
-  @Autowired ApiActivityLogRepository apiActivityLogRepository;
+  @SpyBean ApiActivityLogRepository apiActivityLogRepository;
   @Autowired WorkflowTaskConfig workflowTaskConfig;
+  @Autowired WorkflowInstanceRepository workflowInstanceRepository;
 
   @Test
   void givenUrlAndId_whenNotify_thenSuccess() {
@@ -41,6 +45,19 @@ void givenUrlAndId_whenNotify_thenSuccess() {
   @Test
   void givenId_whenFailAndRejectOrder_thenSuccess() {
     String id = UUID.randomUUID().toString();
+    WorkflowInstanceEntity workflowInstanceEntity = new WorkflowInstanceEntity();
+    workflowInstanceEntity.setStatus(WorkflowStatusEnum.FAILED.name());
+    workflowInstanceEntity.setErrorMsg("error");
+    workflowInstanceEntity.setRequestId(id);
+    workflowInstanceEntity.setSynced(false);
+    workflowInstanceEntity.setWorkflowInstanceId(UUID.randomUUID().toString());
+    workflowInstanceRepository.save(workflowInstanceEntity);
+
+    doReturn(Optional.of(new ApiActivityLogEntity()))
+        .when(apiActivityLogRepository)
+        .findByRequestIdAndCallSeq(anyString(), anyInt());
+    doReturn(new ApiActivityLogEntity()).when(apiActivityLogRepository).save(any());
+
     HttpRequestEntity entity = new HttpRequestEntity();
     entity.setRenderedResponse(Map.of("state", "active"));
     doReturn(Optional.of(entity)).when(httpRequestRepository).findById(any());
@@ -55,6 +72,8 @@ void givenId_whenFailAndRejectOrder_thenSuccess() {
     assertDoesNotThrow(() -> workflowTaskConfig.processOrder(id));
     assertDoesNotThrow(() -> workflowTaskConfig.doNothing());
     assertDoesNotThrow(() -> workflowTaskConfig.persistResponse(null, entity));
+    assertDoesNotThrow(() -> workflowTaskConfig.workflowFailedTask(id, "unexpected error"));
+    assertDoesNotThrow(() -> workflowTaskConfig.workflowSuccessTask(id));
     assertDoesNotThrow(
         () -> workflowTaskConfig.evaluateTask(Map.of("entity", entity), "", "${entity1}"));
     assertDoesNotThrow(() -> workflowTaskConfig.rejectOrder(id));
diff --git a/kraken-java-sdk/kraken-java-sdk-sync/src/main/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateService.java b/kraken-java-sdk/kraken-java-sdk-sync/src/main/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateService.java
new file mode 100644
index 000000000..893bbbe9d
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-sync/src/main/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateService.java
@@ -0,0 +1,70 @@
+package com.consoleconnect.kraken.operator.sync.service;
+
+import com.consoleconnect.kraken.operator.core.client.ClientEvent;
+import com.consoleconnect.kraken.operator.core.client.ClientEventTypeEnum;
+import com.consoleconnect.kraken.operator.core.client.ClientWorkflowTerminate;
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.model.HttpResponse;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
+import com.consoleconnect.kraken.operator.sync.model.SyncProperty;
+import com.consoleconnect.kraken.operator.sync.service.security.ExternalSystemTokenProvider;
+import java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
+import org.springframework.http.HttpStatus;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Service
+@Slf4j
+public class PushWorkflowStateService extends KrakenServerConnector {
+  private final WorkflowInstanceRepository workflowInstanceRepository;
+
+  public PushWorkflowStateService(
+      SyncProperty appProperty,
+      WebClient webClient,
+      ExternalSystemTokenProvider externalSystemTokenProvider,
+      WorkflowInstanceRepository workflowInstanceRepository) {
+    super(appProperty, webClient, externalSystemTokenProvider);
+    this.workflowInstanceRepository = workflowInstanceRepository;
+  }
+
+  @Transactional
+  @SchedulerLock(
+      name = "pushWorkflowStatusLock",
+      lockAtMostFor = "${app.cron-job.lock.at-most-for}",
+      lockAtLeastFor = "${app.cron-job.lock.at-least-for}")
+  @Scheduled(cron = "${app.cron-job.push-workflow-status:-}")
+  public void runIt() {
+    List<WorkflowInstanceEntity> workflowInstanceEntities =
+        workflowInstanceRepository.findAllBySynced(false);
+    List<ClientWorkflowTerminate> list =
+        workflowInstanceEntities.stream()
+            .map(
+                entity -> {
+                  ClientWorkflowTerminate workflowTerminate = new ClientWorkflowTerminate();
+                  workflowTerminate.setWorkflowInstanceId(entity.getWorkflowInstanceId());
+                  workflowTerminate.setStatus(entity.getStatus());
+                  workflowTerminate.setRequestId(entity.getRequestId());
+                  workflowTerminate.setErrorMessage(entity.getErrorMsg());
+                  return workflowTerminate;
+                })
+            .toList();
+    ClientEvent event =
+        ClientEvent.of(CLIENT_ID, ClientEventTypeEnum.CLIENT_TERMINATE_WORKFLOW, list);
+
+    HttpResponse<Void> res = pushEvent(event);
+    if (res.getCode() == HttpStatus.OK.value()) {
+      workflowInstanceRepository.saveAll(
+          workflowInstanceEntities.stream()
+              .map(
+                  entity -> {
+                    entity.setSynced(true);
+                    return entity;
+                  })
+              .toList());
+    }
+  }
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-sync/src/test/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateServiceTest.java b/kraken-java-sdk/kraken-java-sdk-sync/src/test/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateServiceTest.java
new file mode 100644
index 000000000..a40820f55
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-sync/src/test/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateServiceTest.java
@@ -0,0 +1,43 @@
+package com.consoleconnect.kraken.operator.sync.service;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.enums.WorkflowStatusEnum;
+import com.consoleconnect.kraken.operator.core.model.HttpResponse;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
+import com.consoleconnect.kraken.operator.sync.CustomConfig;
+import com.consoleconnect.kraken.operator.test.AbstractIntegrationTest;
+import com.consoleconnect.kraken.operator.test.MockIntegrationTest;
+import java.util.UUID;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.test.context.ContextConfiguration;
+
+@MockIntegrationTest
+@ContextConfiguration(classes = {CustomConfig.class})
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class PushWorkflowStateServiceTest extends AbstractIntegrationTest {
+  @SpyBean PushWorkflowStateService pushWorkflowStateService;
+  @Autowired WorkflowInstanceRepository workflowInstanceRepository;
+
+  @Test
+  void givenWorkflowChangeEvent_whenRun_thenResponseOK() {
+    doReturn(HttpResponse.ok(null)).when(pushWorkflowStateService).pushEvent(any());
+    WorkflowInstanceEntity workflowInstanceEntity = new WorkflowInstanceEntity();
+    String requestId = UUID.randomUUID().toString();
+    workflowInstanceEntity.setWorkflowInstanceId(UUID.randomUUID().toString());
+    workflowInstanceEntity.setErrorMsg("error");
+    workflowInstanceEntity.setSynced(false);
+    workflowInstanceEntity.setStatus(WorkflowStatusEnum.FAILED.name());
+    workflowInstanceEntity.setRequestId(requestId);
+    workflowInstanceRepository.save(workflowInstanceEntity);
+    pushWorkflowStateService.runIt();
+    Assertions.assertTrue(workflowInstanceRepository.findByRequestId(requestId).isSynced());
+  }
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/model/WorkflowTerminateEvent.java b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/model/WorkflowTerminateEvent.java
new file mode 100644
index 000000000..97a627b64
--- /dev/null
+++ b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/model/WorkflowTerminateEvent.java
@@ -0,0 +1,10 @@
+package com.consoleconnect.kraken.operator.workflow.model;
+
+import lombok.Data;
+
+@Data
+public class WorkflowTerminateEvent {
+  private String id;
+  private String status;
+  private String errorMsg;
+}
diff --git a/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTaskRegister.java b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTaskRegister.java
index 74eb2ac83..303c95ec9 100644
--- a/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTaskRegister.java
+++ b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTaskRegister.java
@@ -40,4 +40,10 @@ EvaluateResult evaluateTask(
   @WorkerTask(value = EVALUATE_EXPRESSION_TASK, pollingInterval = 10)
   EvaluateResult evaluateExpressionTask(
       @InputParam("value") Map<String, Object> value, @InputParam("expression") String expression);
+
+  @WorkerTask(WORKFLOW_SUCCESS_TASK)
+  void workflowSuccessTask(@InputParam("id") String id);
+
+  @WorkerTask(WORKFLOW_FAILED_TASK)
+  void workflowFailedTask(@InputParam("id") String id, @InputParam("errorMsg") String errorMsg);
 }
diff --git a/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTemplateTransformer.java b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTemplateTransformer.java
index 6d7acd3ae..4198fa44c 100644
--- a/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTemplateTransformer.java
+++ b/kraken-java-sdk/kraken-java-sdk-workflow/src/main/java/com/consoleconnect/kraken/operator/workflow/service/WorkflowTemplateTransformer.java
@@ -19,6 +19,7 @@
 import com.consoleconnect.kraken.operator.workflow.model.EvaluateObject;
 import com.consoleconnect.kraken.operator.workflow.model.HttpExtend;
 import com.consoleconnect.kraken.operator.workflow.model.LogTaskRequest;
+import com.consoleconnect.kraken.operator.workflow.model.WorkflowTerminateEvent;
 import com.google.common.collect.Streams;
 import com.netflix.conductor.common.metadata.tasks.TaskDef;
 import com.netflix.conductor.common.metadata.workflow.WorkflowDef;
@@ -55,7 +56,6 @@ public class WorkflowTemplateTransformer {
   private static final String OUT_PUT = "output";
   private static final String REQUEST_ID = "requestId";
   private static final String PAYLOAD = "payload";
-
   private static final int RETRY_COUNT = 3;
   private static final String SWITCH_HTTP_CHECK_NAME_PREFIX = "switch_http_check_%s";
   private static final String SWITCH_CUSTOMIZED_CHECK_PREFIX = "switch_%s";
@@ -108,7 +108,7 @@ private void buildWorkflowByStage(
                 tasks.addAll(
                     constructSimpleTask(LOG_PAYLOAD_TASK, task, httpTasks).getWorkflowDefTasks());
                 // add check http status task for each http task
-                tasks.addAll(constructHttpCheckSwitchTask(task.getTaskName(), stage));
+                tasks.addAll(constructHttpCheckSwitchTask(task, stage));
                 if (task.getConditionCheck() != null
                     && CollectionUtils.isNotEmpty(task.getConditionCheck().getConditionItems())) {
                   tasks.addAll(
@@ -132,15 +132,17 @@ private void buildAfterEachStageTask(
       workflowDef
           .getTasks()
           .addAll(constructSimpleTask(PERSIST_RESPONSE_TASK, httpTask, null).getWorkflowDefTasks());
+      workflowDef
+          .getTasks()
+          .addAll(constructSimpleTask(WORKFLOW_SUCCESS_TASK, httpTask, null).getWorkflowDefTasks());
     }
   }
 
-  private List<WorkflowTask> constructHttpCheckSwitchTask(
-      String taskName, WorkflowStageEnum stage) {
+  private List<WorkflowTask> constructHttpCheckSwitchTask(HttpTask task, WorkflowStageEnum stage) {
     Switch switchTask =
         new Switch(
-            String.format(SWITCH_HTTP_CHECK_NAME_PREFIX, taskName),
-            String.format(HTTP_STATUS_SWITCH_CASE_EXPRESSION, taskName));
+            String.format(SWITCH_HTTP_CHECK_NAME_PREFIX, task.getTaskName()),
+            String.format(HTTP_STATUS_SWITCH_CASE_EXPRESSION, task.getTaskName()));
     Map<String, List<Task<?>>> branches = new HashMap<>();
     branches.put(
         String.valueOf(HttpStatus.OK.value()),
@@ -148,6 +150,7 @@ private List<WorkflowTask> constructHttpCheckSwitchTask(
     switchTask.decisionCases(branches);
     switchTask.defaultCase(
         constructSimpleTask(stage == EXECUTION_STAGE ? NOTIFY_TASK : FAIL_ORDER_TASK, null, null),
+        constructSimpleTask(WORKFLOW_FAILED_TASK, task, null),
         new Terminate(getUniqueTaskRef(TERMINATE_TASK), Workflow.WorkflowStatus.COMPLETED, null));
     return switchTask.getWorkflowDefTasks();
   }
@@ -162,8 +165,11 @@ private List<WorkflowTask> constructCustomizedSwitchTask(HttpTask task) {
         Boolean.FALSE.toString(),
         List.of(
             constructSimpleTask(task.getConditionCheck().getBuildInTask(), null, null),
+            constructSimpleTask(WORKFLOW_FAILED_TASK, task, null),
             new Terminate(
-                getUniqueTaskRef(TERMINATE_TASK), Workflow.WorkflowStatus.COMPLETED, null)));
+                getUniqueTaskRef(TERMINATE_TASK),
+                Workflow.WorkflowStatus.COMPLETED,
+                task.getConditionCheck().getErrorMsg())));
     switchTask.decisionCases(branches);
     switchTask.setOptional(true);
     return switchTask.getWorkflowDefTasks();
@@ -227,6 +233,13 @@ private SimpleTask buildSimpleTask(
             .getInput()
             .putAll(JsonToolkit.fromJson(JsonToolkit.toJson(evaluateObject), Map.class));
       }
+      case WORKFLOW_FAILED_TASK, WORKFLOW_SUCCESS_TASK -> {
+        HttpTask.ConditionCheck conditionCheck = httpTask.getConditionCheck();
+        WorkflowTerminateEvent payload = new WorkflowTerminateEvent();
+        payload.setErrorMsg(conditionCheck.getErrorMsg());
+        payload.setId(String.format(WORKFLOW_PARAM_PREFIX, REQUEST_ID));
+        simpleTask.getInput().putAll(JsonToolkit.fromJson(JsonToolkit.toJson(payload), Map.class));
+      }
       default -> simpleTask.getInput().putAll(input);
     }
     simpleTask.setOptional(true);
diff --git a/kraken-java-sdk/kraken-java-sdk-workflow/src/test/resources/mockData/api-workflow.order.eline.delete.yaml b/kraken-java-sdk/kraken-java-sdk-workflow/src/test/resources/mockData/api-workflow.order.eline.delete.yaml
index 268d39849..2f81cf8c1 100644
--- a/kraken-java-sdk/kraken-java-sdk-workflow/src/test/resources/mockData/api-workflow.order.eline.delete.yaml
+++ b/kraken-java-sdk/kraken-java-sdk-workflow/src/test/resources/mockData/api-workflow.order.eline.delete.yaml
@@ -44,6 +44,7 @@ spec:
             value: 1
             expression: status_checking_task.count
         buildInTask: reject_order_task
+        errorMsg: "unexpected error"
   preparationStage:
     - taskName: disable_order_task
       taskType: http


Reviews:
user: login: xuelianhan007
body: GOOD
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-02-27T01:57:30Z
user: login: michaeltangpub2
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T03:13:07Z
user: login: michaeltangpub2
body: Good to me
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T03:19:43Z
user: login: zhiyaoPCCW
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T05:20:21Z
user: login: michaeltangpub2
body: Good to me
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T05:20:32Z
user: login: xuelianhan007
body: GOOD
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T05:21:30Z

Review comments:
diff_hunk: @@ -0,0 +1,68 @@
+package com.consoleconnect.kraken.operator.sync.service;
+
+import com.consoleconnect.kraken.operator.core.client.ClientEvent;
+import com.consoleconnect.kraken.operator.core.client.ClientEventTypeEnum;
+import com.consoleconnect.kraken.operator.core.client.ClientWorkflowTerminate;
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.model.HttpResponse;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
+import com.consoleconnect.kraken.operator.sync.model.SyncProperty;
+import com.consoleconnect.kraken.operator.sync.service.security.ExternalSystemTokenProvider;
+import java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
+import org.springframework.http.HttpStatus;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Service
+@Slf4j
+public class PushWorkflowStateService extends KrakenServerConnector {
+  private final WorkflowInstanceRepository workflowInstanceRepository;
+
+  public PushWorkflowStateService(
+      SyncProperty appProperty,
+      WebClient webClient,
+      ExternalSystemTokenProvider externalSystemTokenProvider,
+      WorkflowInstanceRepository workflowInstanceRepository) {
+    super(appProperty, webClient, externalSystemTokenProvider);
+    this.workflowInstanceRepository = workflowInstanceRepository;
+  }
+
+  @Transactional
+  @SchedulerLock(
+      name = "pushWorkflowStatusLock",
+      lockAtMostFor = "${app.cron-job.lock.at-most-for}",
+      lockAtLeastFor = "${app.cron-job.lock.at-least-for}")
+  @Scheduled(cron = "${app.cron-job.push-workflow-status:-}")
+  public void runIt() {
+    List<WorkflowInstanceEntity> workflowInstanceEntities =
+        workflowInstanceRepository.findAllBySynced(false);
+    List<ClientWorkflowTerminate> list =
+        workflowInstanceEntities.stream()
+            .map(
+                entity -> {
+                  ClientWorkflowTerminate workflowTerminate = new ClientWorkflowTerminate();
+                  workflowTerminate.setWorkflowInstanceId(entity.getWorkflowInstanceId());
+                  workflowTerminate.setStatus(entity.getStatus());
+                  workflowTerminate.setRequestId(entity.getRequestId());
+                  workflowTerminate.setErrorMessage(entity.getErrorMsg());
+                  return workflowTerminate;
+                })
+            .toList();
+    ClientEvent event =
+        ClientEvent.of(CLIENT_ID, ClientEventTypeEnum.CLIENT_TERMINATE_WORKFLOW, list);
+
+    HttpResponse<Void> res = pushEvent(event);
+    if (res.getCode() == HttpStatus.OK.value()) {
+      workflowInstanceEntities.stream()
+          .forEach(
+              entity -> {
+                entity.setSynced(true);
+                workflowInstanceRepository.save(entity);
path: kraken-java-sdk/kraken-java-sdk-sync/src/main/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateService.java
user: login: michaeltangpub2
body: Use repository saveAll instead of save wuold be better? however here is not performance bottom-neck
created_at: 2025-03-03T03:12:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,68 @@
+package com.consoleconnect.kraken.operator.sync.service;
+
+import com.consoleconnect.kraken.operator.core.client.ClientEvent;
+import com.consoleconnect.kraken.operator.core.client.ClientEventTypeEnum;
+import com.consoleconnect.kraken.operator.core.client.ClientWorkflowTerminate;
+import com.consoleconnect.kraken.operator.core.entity.WorkflowInstanceEntity;
+import com.consoleconnect.kraken.operator.core.model.HttpResponse;
+import com.consoleconnect.kraken.operator.core.repo.WorkflowInstanceRepository;
+import com.consoleconnect.kraken.operator.sync.model.SyncProperty;
+import com.consoleconnect.kraken.operator.sync.service.security.ExternalSystemTokenProvider;
+import java.util.List;
+import lombok.extern.slf4j.Slf4j;
+import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
+import org.springframework.http.HttpStatus;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.reactive.function.client.WebClient;
+
+@Service
+@Slf4j
+public class PushWorkflowStateService extends KrakenServerConnector {
+  private final WorkflowInstanceRepository workflowInstanceRepository;
+
+  public PushWorkflowStateService(
+      SyncProperty appProperty,
+      WebClient webClient,
+      ExternalSystemTokenProvider externalSystemTokenProvider,
+      WorkflowInstanceRepository workflowInstanceRepository) {
+    super(appProperty, webClient, externalSystemTokenProvider);
+    this.workflowInstanceRepository = workflowInstanceRepository;
+  }
+
+  @Transactional
+  @SchedulerLock(
+      name = "pushWorkflowStatusLock",
+      lockAtMostFor = "${app.cron-job.lock.at-most-for}",
+      lockAtLeastFor = "${app.cron-job.lock.at-least-for}")
+  @Scheduled(cron = "${app.cron-job.push-workflow-status:-}")
+  public void runIt() {
+    List<WorkflowInstanceEntity> workflowInstanceEntities =
+        workflowInstanceRepository.findAllBySynced(false);
+    List<ClientWorkflowTerminate> list =
+        workflowInstanceEntities.stream()
+            .map(
+                entity -> {
+                  ClientWorkflowTerminate workflowTerminate = new ClientWorkflowTerminate();
+                  workflowTerminate.setWorkflowInstanceId(entity.getWorkflowInstanceId());
+                  workflowTerminate.setStatus(entity.getStatus());
+                  workflowTerminate.setRequestId(entity.getRequestId());
+                  workflowTerminate.setErrorMessage(entity.getErrorMsg());
+                  return workflowTerminate;
+                })
+            .toList();
+    ClientEvent event =
+        ClientEvent.of(CLIENT_ID, ClientEventTypeEnum.CLIENT_TERMINATE_WORKFLOW, list);
+
+    HttpResponse<Void> res = pushEvent(event);
+    if (res.getCode() == HttpStatus.OK.value()) {
+      workflowInstanceEntities.stream()
+          .forEach(
+              entity -> {
+                entity.setSynced(true);
+                workflowInstanceRepository.save(entity);
path: kraken-java-sdk/kraken-java-sdk-sync/src/main/java/com/consoleconnect/kraken/operator/sync/service/PushWorkflowStateService.java
user: login: zhiyaoPCCW
body: fixed
created_at: 2025-03-03T05:20:21Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-02-26T08:18:34Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-26T08:18:58Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-26T09:07:13Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-26T09:17:27Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-02-26T09:17:47Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-03T02:35:32Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-03T03:22:33Z
body: ### Library Vulnerability scan results
The following vulnerabilities have been found in libraries included in the repository (some might be dependencies of dependencies).

**Critical** :red_circle: and **High** :yellow_circle: severity vulnerabilities **must** be fixed before the PR can be merged, even if they are dependencies of dependencies.

| Library | Vulnerable version | Severity | Fix version | Vulnerability ID |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| dompurify | 3.1.7 | Medium | 3.2.4 | [GHSA-vhxf-7vqr-mrjg](https://github.com/advisories/GHSA-vhxf-7vqr-mrjg) |
| esbuild | 0.24.0 | Medium | 0.25.0 | [GHSA-67mh-4wv8-2f99](https://github.com/advisories/GHSA-67mh-4wv8-2f99) |
| nanoid | 3.3.7 | Medium | 3.3.8 | [GHSA-mwcw-c2x4-8c55](https://github.com/advisories/GHSA-mwcw-c2x4-8c55) |
| vite | 5.4.9 | Medium | 5.4.12 | [GHSA-vg6x-rcgg-rjx6](https://github.com/advisories/GHSA-vg6x-rcgg-rjx6) |

author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-03-03T03:25:14Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=mycloudnexus_kraken_nodejs&pullRequest=500) **Quality Gate passed for 'kraken_nodejs'**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=mycloudnexus_kraken_nodejs&pullRequest=500&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=mycloudnexus_kraken_nodejs&pullRequest=500&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=mycloudnexus_kraken_nodejs&pullRequest=500&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=mycloudnexus_kraken_nodejs&pullRequest=500&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=mycloudnexus_kraken_nodejs&pullRequest=500&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=mycloudnexus_kraken_nodejs&pullRequest=500)


author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-03T03:30:02Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=mycloudnexus_kraken_java&pullRequest=500) **Quality Gate passed for 'kraken_java'**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=mycloudnexus_kraken_java&pullRequest=500&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=mycloudnexus_kraken_java&pullRequest=500&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=mycloudnexus_kraken_java&pullRequest=500&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [84.9% Coverage on New Code](https://sonarcloud.io/component_measures?id=mycloudnexus_kraken_java&pullRequest=500&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=mycloudnexus_kraken_java&pullRequest=500&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=mycloudnexus_kraken_java&pullRequest=500)


author_association: NONE