> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migration guide

This guide explains how to upgrade Atoti Sign-Off from versions 6.1 to 6.2.

## Recommended migration process

1. Back up your project.
2. Perform a diff between older Atoti Sign-Off release builds and newer release builds.
   * Update your dependencies.
   * Update your code.
3. Confirm successful build and startup.

## Migrate Atoti Sign-Off 6.1.22 to 6.1.23

### `sign-off.workflow.pending-approval-task-statuses` type change

SO-1122: The `sign-off.workflow.pending-approval-task-statuses` property changed type from a flat `List<String>` to a `Map<String, List<String>>` keyed by workflow type.

No action is required if the property was not overridden in your configuration. The new defaults are:

* `simple` → `[INITIATED]`
* `4-eyes` → `[PENDING]`
* `4-eyes-kpi` → `[PENDING]`

If the property was overridden, convert the flat list to the per-workflow-type map form.

Before:

```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
sign-off:
  workflow:
    pending-approval-task-statuses: [PENDING]
```

After:

```yaml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
sign-off:
  workflow:
    pending-approval-task-statuses:
      simple: [INITIATED]
      4-eyes: [PENDING]
      4-eyes-kpi: [PENDING]
```

### `ISignOffWorkflowStatusActionManager::getPendingApprovalTaskStatuses` return type change

SO-1122: The return type of `ISignOffWorkflowStatusActionManager::getPendingApprovalTaskStatuses` changed from a `List<String>` to a `Map<String, List<String>>` keyed by workflow type, mirroring the property change above. The awaiting-approval state is workflow-type dependent (for example `PENDING` for four-eyes workflows, `INITIATED` for the simple workflow), which a single flat list cannot represent.

No action is required if you rely on the default `DefaultSignOffWorkflowStatusActionManager`.

If you implemented your own `ISignOffWorkflowStatusActionManager` to compute pending-approval statuses dynamically, update your implementation to return a map keyed by workflow type.

Before:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Override
public List<String> getPendingApprovalTaskStatuses() {
  return List.of("PENDING");
}
```

After:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
@Override
public Map<String, List<String>> getPendingApprovalTaskStatuses() {
  return Map.of(
      "simple", List.of("INITIATED"),
      "4-eyes", List.of("PENDING"),
      "4-eyes-kpi", List.of("PENDING"));
}
```

## Migrate Atoti Sign-Off 6.1.21 to 6.1.22

This release only shipped bug fixes and performance improvements. It does not require any migration.

## Migrate Atoti Sign-Off 6.1.20 to 6.1.21

This release only shipped bug fixes and performance improvements. It does not require any migration.

## Migrate Atoti Sign-Off 6.2.2 back to 6.1.20

<Warning>
  From version 6.1.20 onwards, Atoti Sign-Off version numbers are aligned with the Atoti Java SDK. Previously, Atoti Sign-Off used its own versioning scheme which had moved ahead of the Atoti Java SDK. The last release under the old scheme was Atoti Sign-Off 6.2.1.

  Although the version number appears to go backwards, this is not a rollback or downgrade. It reflects the realignment with the Atoti Java SDK release track.
</Warning>

Maven dependencies have also changed: update the following group IDs in your `pom.xml`:

* `com.activeviam.solutions` → `com.activeviam.modules`
* `com.activeviam.solutions.services` → `com.activeviam.modules.services`
* `com.activeviam.solutions.signoff-api` → `com.activeviam.modules.signoff-api`

### Export status poller default delay

SO-1082: The default value of `sign-off.export.initial-delay-in-milliseconds` changed from `500` to `0`, so export status polling now starts immediately. No action is required: the poller no longer depends on this delay to avoid the export status race condition. If you relied on the previous default, you can restore it explicitly in your configuration.

## Migrate Atoti Sign-Off 6.2.0 to Atoti Sign-Off 6.2.1

### Sign-Off repository change

The Atoti Sign-Off codebase now lives within the Atoti Server codebase, which streamlines dependency management. This means that the Atoti Sign-Off pom now inherits from

```xml theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
<parent>
    <groupId>com.activeviam.modules</groupId>
    <artifactId>workflows</artifactId>
</parent>
```

where the version is aligned with the version of Atoti Server used by Atoti Sign-Off, which for this release is 6.1.19.

**Please update your pom parent to this artifact.**

The pom file no longer requires the `common-parent-pom`, `common-dependencies-bom` or `common-spring-services-bom`, so you can remove these.

## Migrate Atoti Sign-Off 6.1.1 to Atoti Sign-Off 6.2.0

Migrate from Atoti Sign-Off 6.1.1 to Atoti Sign-Off 6.2.0. This migration
guide focuses on breaking changes. Consult the Atoti Sign-Off 6.2.0 [release notes](./release-notes)
and [changelog](./changelog) for a complete view of changes.

### Upgrade dependencies

The following dependency changes are required for upgrading Atoti Sign-Off 6.1.1 to
Atoti Sign-Off 6.2.0.

#### Updated

| Dependency                 | Atoti Sign-Off 6.1.1 | Atoti Sign-Off 6.2.0 |
| -------------------------- | -------------------- | -------------------- |
| Atoti Server               | `6.1.4`              | `6.1.15`             |
| Atoti UI                   | `5.2.6`              | `5.2.16`             |
| UI Components              | `5.2.10`             | `5.2.16`             |
| Sign-Off API               | `4.2.0`              | `4.2.1`              |
| Adjustments Services       | `4.1.2`              | `4.1.3`              |
| Workflow Core              | `2.5.1`              | `2.5.3`              |
| Common Parent POM          | `2.2.1`              | `2.4.0`              |
| Common Dependencies BOM    | `2.2.1`              | `2.4.0`              |
| Common Spring Services BOM | `1.0.1`              | `1.0.2`              |

#### Rebuild modules

After applying the changes to the pom.xml, run `mvn clean install -DskipTests`. This produces a list of
classes that you need to modify. Use the [Migrate Code](#migrate-code) section to make the necessary code changes and
iterate until successful rebuild and application startup.

## Migrating the project

For a list of all breaking changes, refer to the Atoti Sign-Off [changelog](./changelog) under changed and
removed.

<Info>
  All information mentioned below is applicable for migrating from Atoti Sign-Off 6.1.1 to
  6.2.0 regardless of implementation perspective. We have organized the information to
  help our users.
</Info>

### Low-code/no-code

If you are using Atoti Sign-Off 6.1.1 in a low code/no-code setup and upgrading to
Atoti Sign-Off 6.2.0, be aware of configuration/property, data model, and dashboard changes.

#### Type of change

##### Added properties for statuses used in `DefaultSignOffWorkflowStatusActionManager`

If you have custom workflows with statuses and actions different to our defaults, then you should remove any custom implementations of the
`ISignOffWorkflowStatusActionManager` bean. Instead, you should specify the statuses under the under `sign-off.workflow` properties.

### Code-first

If you are using Atoti Sign-Off 6.1.1 in a code-first setup and upgrading to Atoti Sign-Off
6.2.0, be aware of all changes, including but not limited to configuration/property, data model, and API
changes.

##### `ISignOffWorkflowStatusActionManager`

If you are using custom statuses for completed tasks, you will need to provide your values in the `sign-off.workflow.completed-task-statuses` property so these
statuses can be communicated to the UI. If you already specified these values in a custom implementation of
`ISignOffWorkflowStatusActionManager::getCompletedTaskStatuses`, you may now replace the implementation with the properties.

The method `getUninitiatedTaskStatuses` has been removed as it was not being used.
The method `getInitiatedTaskStatus` has been added so that the status used for initiated tasks can be customised.

#### API improvements for bulk adjustment execution

We have added methods to some of our APIs to improve the performance of bulk adjustment execution. **If you have customized** any of these APIs, you will need
to update your code to implement the new methods. You can view our default implementations for examples of how we have implemented these new methods.

##### New method in `ISignOffAdjustmentExecutionService`

We have added a new method `ISignOffAdjustmentExecutionService::requestAdjustmentExecutionsAndPersistDefinitions` to request adjustment executions in bulk. The
signature of this method is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
List<AdjustmentExecutionDTO> requestAdjustmentExecutionsAndPersistDefinitions(List<AuditableAdjustmentDefinitionDTO> auditableAdjustmentDefinitionDTOs)
        throws ValidationException;
```

The default implementation can be found in `SignOffAdjustmentExecutionService`.

##### New method in `IAdjustmentsDefinitionCacheService`

We have added a new method `IAdjustmentsDefinitionCacheService::saveAll` to save adjustment definitions in bulk to the datastore cache. The signature of this
method is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
void saveAll(Map<String, T> adjustmentDefinitionsById);
```

The default implementation can be found in `AdjustmentsDatastoreDefinitionCacheService`.

##### New method in `IAdjustmentsExecutionCacheService`

We have added a new method `IAdjustmentsExecutionCacheService::saveAll` to save adjustment executions in bulk to the datastore cache. The signature of this
method is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
void saveAll(List<T> adjustmentExecutions);
```

The default implementation can be found in `AdjustmentsDatastoreExecutionCacheService`.

##### New method in `IAdjustmentExecutionService`

We have added a new method `IAdjustmentExecutionService::bulkExecute` to execute adjustments in bulk on the **application server**. The signature of this method is
as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
List<ExecutionIdAdjustmentRequestDTO> bulkExecute(List<AdjustmentRequestDTO> requests);
```

where `ExecutionIdAdjustmentRequestDTO` is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
/**
 * <b>ExecutionIdAdjustmentRequestDTO</b>
 * <p>
 * DTO containing an execution id and the corresponding adjustment request for the execution id.
 *
 * @param executionId the execution id
 * @param adjustmentRequestDTO the adjustment request
 *
 * @author ActiveViam
 */
public record ExecutionIdAdjustmentRequestDTO(String executionId, AdjustmentRequestDTO adjustmentRequestDTO) {
}
```

The default implementation can be found in `AdjustmentExecutionService`. Note that this method needs to be implemented in the application server, not on the
Atoti Sign-Off server, and the code exists in the `adjustments-services` package.

##### New methods in `ISignOffAdjustmentValidator`

We have added two new methods `ISignOffAdjustmentValidator::validateSignOffAdjustmentsCreation` and `ISignOffAdjustmentValidator::validateSignOffAdjustmentsUpdate`
to validate adjustments in bulk when they’re created or updated. The signatures of these methods are as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
List<IValidationError> validateSignOffAdjustmentsCreation(List<IAdjustment> adjustmentsToCreate);

List<IValidationError> validateSignOffAdjustmentsUpdate(List<IAdjustment> adjustmentsToUpdate);
```

##### New methods in `IAuditLogService`

We have added two new methods `IAuditLogService::saveUserTaskRecords` and `IAuditLogService::saveProcessRecords`
to save historic records in bulk. The signatures of these methods are as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
void saveUserTaskRecords(List<UserTaskRecordDTO> userTasks);

void saveProcessRecords(List<ProcessRecordDTO> processRecords);
```

Default implementations can be found in `AAdjustmentsAwareAuditLogService` and `WorkflowAuditLogService`. This code exists in the `workflow-core` package.

##### New method in `IKeyedObjectService`

We have added a new method `IKeyedObjectService::createAll` to create persistent objects in bulk. The signature of this method is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
List<T> createAll(List<T> objects) throws ValidationException;
```

The default implementation can be found in `AVersionedObjectJpaService`. This code exists in the `workflow-core` package.

##### New `BulkAdjustmentExecutor` in the application server

We have added a new `BulkAdjustmentExecutor` in the application server for processing adjustment executions in bulk. If you wish to avail of the full performance
enhancements for bulk adjustment execution, you will need to add implementations of these interfaces in your **application server**. The interface is as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
public interface BulkAdjustmentExecutor extends Consumer<List<ExecutionIdAdjustmentRequestDTO>>{}
```

and expects a list of `ExecutionIdAdjustmentRequestDTO` objects as defined above.

Note that you do not have to implement this interface if you do not wish to avail of the performance improvements for bulk adjustment execution. If no
`BulkAdjustmentExecutor`s are defined, the default behavior is to fall back to sequential execution of adjustments. This is only a part of the entire adjustment
execution process, so you will still avail of performance improvements from the other API changes even if you do not implement this interface.

#### Server-sent events (SSE) subscription filtering by object types

We have added the ability to filter Server-Sent Events (SSE) subscriptions by object types. **If you have customized** any of the following SSE-related APIs or
have custom requests to the SSE subscription endpoints you will need to update your code to implement the new functionality. You can view our default
implementations for examples of how we have implemented these changes.

##### New API methods in `ISignOffTask`

We have added new methods in `ISignOffTasks` to allow for retrieving definition information associated with the task. These are required in order for this
information to be sent with the tasks to the UI when they are retrieved independently of the definitions. The signatures of these methods are as follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
void setSignOffDefinition(ISignOffDefinition definition);

ISignOffDefinition getSignOffDefinition();

String getSignOffDefinitionCubeName();

String getSignOffDefinitionServerName();

Map<String, List<String>> getSignOffDefinitionScopeValues();

String getSignOffDefinitionName();

String getSignOffDefinitionLinkedDashboardId();
```

The default implementations can be found in `SignOffTask`.

##### New API method in `ISignOffTaskService`

We have added a new method `ISignOffTaskService::getFilteredTasks` to retrieve tasks that match specified field conditions. The signature of this method is as
follows:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
List<ISignOffTask> getFilteredTasks(Map<String, Object> filters);
```

Where `filters` is a map of field names to possible values.

The default implementation can be found in `SignOffTaskService` and supports filtering by the following fields:

* `taskId` - the value should be a list of Long values
* `definitionId` - the value should be a list of String values
* `asOfDate` - the value should be a list of String values in `yyyy-MM-dd` format
* `workflowStatus` - the value should be a list of String values
* `taskWorkflowKey` - the value should be a list of String values
* `definitionCube` - the value should be a list of String values
* `definitionServer` - the value should be a list of String values
* `definitionScopeValues` - the value should be a map of String keys (level names) to lists of String values (member names)
* `definitionName` - the value should be a list of String values

##### Updated SSE subscription endpoint paths

We have updated the endpoints to subscribe and unsubscribe to Server-Sent Events (SSE) to remove `/definition/` from the URL path. The updated paths are as
follows:

* **Subscribe to SSE events:** `/sign-off/rest/v2/sse/subscribe`
* **Unsubscribe from SSE events:** `/sign-off/rest/v2/sse/unsubscribe`

##### Renamed classes and methods

We have renamed some classes and methods related to Server-Sent Events (SSE) to better reflect their purpose:

**Class renames:**

* `SignOffDefinitionSseController` is now `SignOffSseController`.
* `SseDefinitionEmitter` is now `SignOffSseEmitter`.

**Method renames in `ISseEmitterService`:**

* `subscribeToDefinitions` is now `subscribe`.
* `unsubscribeToDefinitions` is now `unsubscribe`.
