> ## 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 notes 6.1 (pre-alignment)

This page explains the changes required to migrate to the stated version
of Atoti Sign-Off.

## Migrate to 6.1.1

Upgrading from version 6.1.0, see [Atoti Sign-Off 6.1.1 Release Notes](./release-notes-6.1-pre-alignment#611).

Atoti Sign-Off is using Atoti Server 6.1.4, Atoti UI \~5.2.6, and
Sign-Off API
4.2.0
.

For new features and fixes included in these releases, please see:

* [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog)
* [Release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.4/docs/release/changelog/)
* [Release notes for Signoff API](https://docs.activeviam.com/products/modules/signoff-api/4.2/online-help/release/release-notes.)

### Headline announcement

This is a maintenance release that includes bug fixes and performance improvements.

### Configuration properties

#### Files modified

##### [application.yml](../../../user-ref/properties/property-files/application-yml)

Updated properties:

| Property Name                | Comment                                                                                                                                                                                                                                           | New Value | Old Value |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | --------- |
| spring.activiti.historyLevel | Reduces the amount of Atoti Sign-Off entries in the Activiti database by excluding process variable updates from being persisted. You can read more about the different history levels [here](https://www.activiti.org/userguide/#historyConfig). | audit     | full      |

## Migrate to 6.1.0

Upgrading from version 6.0.0, see [Atoti Sign-Off 6.1.0 Release Notes](./release-notes-6.1-pre-alignment#610).

Atoti Sign-Off is using Atoti Server 6.1.4, Atoti UI \~5.2.6, and
Sign-Off API
4.2.0
.

For new features and fixes included in these releases, please see:

* [Atoti UI documentation](https://docs.activeviam.com/products/atoti/ui/5.2/) and [Atoti UI Migration Notes](https://docs.activeviam.com/products/atoti/ui/5.2/docs/changelog)
* [Release notes for Atoti Server](https://docs.activeviam.com/products/atoti/server/6.1.4/docs/release/changelog/)
* [Release notes for Signoff API](https://docs.activeviam.com/products/modules/signoff-api/4.2/online-help/release/release-notes.)

### Headline announcement

* **Starter changes**: Multiple classes have been removed from the starter module. See [Starter changes](#starter-changes) for more details.
* **Package restructure**: The package structure in the `signoff-activeviam` module has been reorganized to improve maintainability. See [Package changes](#package-changes) for more details.
* **Validation error changes**: A new method has been added to the API for validation errors to support accurately reporting indexes. See [Validation error changes](#validation-error-changes) for more details.
* **Workflow Service API changes**: The `ISignOffProcessDefinitionWorkflowService` and `ISignOffProcessInstanceWorkflowService` APIs have been updated and a new method has been added to accommodate workflow file attachments. See [Workflow Service API changes](#workflow-service-api-changes) for more details.
* **Application server communication changes**: Atoti Sign-Off has changed how it communicates with the application server. See [Application server communication changes](#application-server-communication-changes) for more details.
* **Exact location required for adjustments**: Adjustments can only be performed at the exact location defined by the filters in `SupportedAdjustmentDTO`.

#### Exact location required for adjustments

Adjustments can only be made at the specific locations defined by the filters in `SupportedAdjustmentDTO` instances. If a filter is not explicitly specified in the supported adjustment configuration, the corresponding value at that location cannot be adjusted.

If you want to display a hierarchy in the UI during adjustment, even if it isn’t directly related to the adjustment logic, include it as an optional filter.

#### Starter changes

Most of the `signoff-starter` module has been moved into `signoff-activeviam`. The goal of these changes is ultimately to improve the developer experience when
migrating, particularly in the context of client customizations.

The following classes have been migrated from `signoff-starter` to `signoff-activeviam`:

| Class Name                                  | Old Package                                                       | New Package                                               |
| ------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------- |
| `SignOffAdjustmentDefinitionRestService`    | `com.activeviam.signoff.starter.adjustments.definition.rest.impl` | `com.activeviam.signoff.adjustments.rest`                 |
| `SignOffAdjustmentExecutionRestService`     | `com.activeviam.signoff.starter.adjustments.execution.rest.impl`  | `com.activeviam.signoff.adjustments.rest`                 |
| `SignOffAdjustmentStatusRestService`        | `com.activeviam.signoff.starter.adjustments.status.rest.impl`     | `com.activeviam.signoff.adjustments.status.rest`          |
| `ISignOffAdjustmentStatusService`           | `com.activeviam.signoff.starter.adjustments.status.service`       | `com.activeviam.signoff.adjustments.status.service`       |
| `SignOffAdjustmentStatusService`            | `com.activeviam.signoff.starter.adjustments.status.service.impl`  | `com.activeviam.signoff.adjustments.status.service.impl`  |
| `SignOffSupportedAdjustmentsRestService`    | `com.activeviam.signoff.starter.adjustments.support.rest.impl`    | `com.activeviam.signoff.adjustments.support.rest`         |
| `ISignOffSupportedAdjustmentsService`       | `com.activeviam.signoff.starter.adjustments.support.service`      | `com.activeviam.signoff.adjustments.support.service`      |
| `SignOffSupportedAdjustmentsService`        | `com.activeviam.signoff.starter.adjustments.support.service.impl` | `com.activeviam.signoff.adjustments.support.service.impl` |
| `ApplicationStatusConfig`                   | `com.activeviam.signoff.starter.cfg`                              | `com.activeviam.signoff.cfg`                              |
| `DatastoreConfiguratorSetup`                | `com.activeviam.signoff.starter.cfg`                              | `com.activeviam.signoff.cfg`                              |
| `InitialLoad`                               | `com.activeviam.signoff.starter.cfg`                              | `com.activeviam.signoff.cfg`                              |
| `AdjustmentsCubeConfig`                     | `com.activeviam.signoff.starter.cfg.cache.pivot.adjustements`     | `com.activeviam.signoff.cfg.pivot.adjustments`            |
| `AdjustmentsExecutionCubeConfig`            | `com.activeviam.signoff.starter.cfg.cache.pivot.adjustements`     | `com.activeviam.signoff.cfg.pivot.adjustments`            |
| `SignOffProcessDefinitionCubeConfig`        | `com.activeviam.signoff.starter.cfg.cache.pivot.definition`       | `com.activeviam.signoff.cfg.pivot.definition`             |
| `SignOffProcessInstanceCubeConfig`          | `com.activeviam.signoff.starter.cfg.cache.pivot.instance`         | `com.activeviam.signoff.cfg.pivot.instance`               |
| `IObserver`                                 | `com.activeviam.signoff.starter.observable`                       | `com.activeviam.signoff.observable`                       |
| `ApplicationServerAndStatus`                | `com.activeviam.signoff.starter.server`                           | `com.activeviam.signoff.server`                           |
| `ApplicationStatusService`                  | `com.activeviam.signoff.starter.server`                           | `com.activeviam.signoff.server`                           |
| `ApplicationStatusTask`                     | `com.activeviam.signoff.starter.server`                           | `com.activeviam.signoff.server`                           |
| `ProcessNotifyingApplicationStatusObserver` | `com.activeviam.signoff.starter.server`                           | `com.activeviam.signoff.server`                           |
| `SignOffProcessEventHandlers`               | `com.activeviam.signoff.starter.workflow`                         | `com.activeviam.signoff.workflow.service`                 |

The following classes have been migrated from `signoff-starter` to `signoff-activeviam` and renamed to better reflect their purpose:

| Old Package                                                    | New Package                                                    |
| -------------------------------------------------------------- | -------------------------------------------------------------- |
| `com.activeviam.signoff.starter.cfg.RestTemplateConfiguration` | `com.activeviam.signoff.cfg.SignOffBasicAuthRestClientBuilder` |

Any beans exposed by these classes have been annotated with `@ConditionalOnMissingBean` which allows you to define your own implementations to override the
defaults. See the [Getting Started](../../../dev/dev-getting-started#customizing-via-spring-beans) guide for more information.

#### Package changes

The packages in the `signoff-activeviam` module have been reorganized to improve maintainability. The table below lists the classes affected by this change. If
you have custom classes that depend on any of these classes, you will need to update the package imports accordingly.

| Class Name                                              | Old Package                                                          | New Package                                                   |
| ------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------- |
| `AtotiServerWithDatastoreConfig`                        | `com.activeviam.signoff.cache.cube.cfg`                              | `com.activeviam.signoff.cfg.datastore`                        |
| `DatastoreSchemaDescriptionConfig`                      | `com.activeviam.signoff.cache.cube.cfg`                              | `com.activeviam.signoff.cfg.datastore`                        |
| `SignOffSchema`                                         | `com.activeviam.signoff.cache.cube.cfg.store`                        | `com.activeviam.signoff.cfg.datastore`                        |
| `AAdjustmentsDefinitionDatastoreConfig`                 | `com.activeviam.signoff.cache.cube.impl.adjustements.definition`     | `com.activeviam.signoff.cfg.datastore.adjustments.definition` |
| `AdjustmentsDefinitionDatastoreConfig`                  | `com.activeviam.signoff.cache.cube.cfg.store.adjustments.definition` | `com.activeviam.signoff.cfg.datastore.adjustments.definition` |
| `IAdjustmentsDefinitionCacheService`                    | `com.activeviam.signoff.workflow.cache.adjustments.definition`       | `com.activeviam.signoff.cfg.datastore.adjustments.definition` |
| `AdjustmentsDatastoreDefinitionCacheService`            | `com.activeviam.signoff.cache.cube.impl.adjustements.definition`     | `com.activeviam.signoff.cfg.datastore.adjustments.definition` |
| `AAdjustmentsExecutionDatastoreConfig`                  | `com.activeviam.signoff.cache.cube.impl.adjustements.execution`      | `com.activeviam.signoff.cfg.datastore.adjustments.execution`  |
| `IAdjustmentsExecutionCacheService`                     | `com.activeviam.signoff.workflow.cache.adjustments.execution`        | `com.activeviam.signoff.cfg.datastore.adjustments.execution`  |
| `AdjustmentsDatastoreExecutionCacheService`             | `com.activeviam.signoff.cache.cube.impl.adjustements.execution`      | `com.activeviam.signoff.cfg.datastore.adjustments.execution`  |
| `AdjustmentsExecutionDatastoreConfig`                   | `com.activeviam.signoff.cache.cube.cfg.store.adjustments.execution`  | `com.activeviam.signoff.cfg.datastore.adjustments.execution`  |
| `ASignOffProcessDefinitionDatastoreConfig`              | `com.activeviam.signoff.cache.cube.impl.definition`                  | `com.activeviam.signoff.cfg.datastore.definition`             |
| `SignOffProcessDefinitionDatastoreConfig`               | `com.activeviam.signoff.cache.cube.cfg.store.definition`             | `com.activeviam.signoff.cfg.datastore.definition`             |
| `ISignOffProcessDefinitionWorkflowCacheService`         | `com.activeviam.signoff.workflow.cache.definition`                   | `com.activeviam.signoff.cfg.datastore.definition`             |
| `SignOffProcessDefinitionWorkflowDatastoreCacheService` | `com.activeviam.signoff.cache.cube.impl.definition`                  | `com.activeviam.signoff.cfg.datastore.definition`             |
| `ASignOffProcessInstanceDatastoreConfig`                | `com.activeviam.signoff.cache.cube.impl.instance`                    | `com.activeviam.signoff.cfg.datastore.instance`               |
| `SignOffProcessInstanceDatastoreConfig`                 | `com.activeviam.signoff.cache.cube.cfg.store.instance`               | `com.activeviam.signoff.cfg.datastore.instance`               |
| `ISignOffProcessInstanceWorkflowCacheService`           | `com.activeviam.signoff.workflow.cache.instance`                     | `com.activeviam.signoff.cfg.datastore.instance`               |
| `SignOffProcessInstanceWorkflowDatastoreCacheService`   | `com.activeviam.signoff.cache.cube.impl.instance`                    | `com.activeviam.signoff.cfg.datastore.instance`               |
| `ActivePivotCoreConfig`                                 | `com.activeviam.signoff.cache.cube.cfg`                              | `com.activeviam.signoff.cfg.pivot`                            |
| `ISignOffCubeBuilderFunction`                           | `com.activeviam.signoff.cfg.cache.pivot`                             | `com.activeviam.signoff.cfg.pivot`                            |
| `PivotConfig`                                           | `com.activeviam.signoff.cache.cube.cfg.pivot`                        | `com.activeviam.signoff.cfg.pivot`                            |
| `PivotManager`                                          | `com.activeviam.signoff.cache.cube.cfg`                              | `com.activeviam.signoff.cfg.pivot`                            |
| `CubeFormatProperties`                                  | `com.activeviam.signoff.cfg`                                         | `com.activeviam.signoff.cfg.properties`                       |
| `RestApiProperties`                                     | `com.activeviam.signoff.cfg`                                         | `com.activeviam.signoff.cfg.properties`                       |
| `SignOffApplicationConfigurationProperties`             | `com.activeviam.signoff.cfg`                                         | `com.activeviam.signoff.cfg.properties`                       |
| `SignOffServerSettingRestController`                    | `com.activeviam.signoff.server.service.rest`                         | `com.activeviam.signoff.server.settings.rest`                 |
| `SignOffSettingsDTO`                                    | `com.activeviam.signoff.server.service.rest.dto`                     | `com.activeviam.signoff.server.settings.rest.dto`             |
| `SignOffRestConstants`                                  | `com.activeviam.signoff.rest`                                        | `com.activeviam.signoff.util.rest`                            |
| `SignOffRestUtils`                                      | `com.activeviam.signoff.rest`                                        | `com.activeviam.signoff.util.rest`                            |

#### Validation error changes

A new method has been added to `IValidationError` and an existing method was removed.

##### New method added

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
/**
   * Sets the 0-based index of the object in the list of objects processed by the validator.
   *
   * @param index the 0-based index of the object
   */
  void setIndex(Integer index);
```

If you have a custom implementation of `IValidationError`, you will need to implement this method in your custom class. This method allows for the index set on
the errors to be updated after the errors are initially created. This is important because all validation errors in the default validators are initially created
with an index of `0` since the validation is performed on a single object at a time. If the validator is invoked in the context of a list of objects, such as
from the `SignOffDefinitionListConstraintValidator` or `SignOffAdjustmentListConstraintValidator`, the indexes on the resulting errors need to be updated to
reflect the actual index of the object in the list.

##### Removed method

The `getAction()` method has been removed from `IValidationError`. All information about the error, including any recommended resolution steps, should now be
provided in the `getReason()` method. If you have a custom implementation of `IValidationError`, you can safely remove the `getAction()` method.

#### Workflow service API changes

To support file attachments in the Atoti Sign-Off workflows, the methods associated with workflow actions in `ISignOffProcessDefinitionWorkflowService` and
`ISignOffProcessInstanceWorkflowService` have been updated to include a `variables` parameter of type `Map<String, Object>` that is used to store a reference to
the saved file. A new method, `processInstanceHistory`, has also been added in both APIs to support retrieving these workflow variables as part of the workflow
history. If you have a custom implementation of these interfaces, you will need to update the existing method signatures and implement the new
`processInstanceHistory` method to match the updated APIs:

<Accordion title="ISignOffProcessDefinitionWorkflowService">
  ```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
  public interface ISignOffProcessDefinitionWorkflowService
          extends IBitemporalObjectWorkflowService<SignOffProcessDefinitionDTO>
  {

      /**
       * Start the workflow process for creating a new sign-off process definition.
       * <p>
       * Note: this starts a new workflow process instance.  It will be blocked if the object's key is currently involved in another process instance.
       * It will also fail validation if the object already exists in the persistent storage.
       *
       * @param object the sign-off process definition to create
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for starting the process, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException if the object fails the creation validation
       * @see IKeyedObjectWorkflowService#startProcess(String, String, IKeyedObject, String, String, java.util.Map)
       */
      ProcessRecordDTO create(SignOffProcessDefinitionDTO object, String comment, Map<String, Object> variables) throws ValidationException;

      /**
       * Start the workflow process for updating a (published/approved) sign-off process definition.
       * <p>
       * Note: this starts a new workflow process instance.  It will be blocked if the object's key is currently involved in another process instance.
       * It will also fail validation if the object doesn't currently exist in the persistent storage.
       *
       * @param object the sign-off process definition to update
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for starting the process, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException if the object fails the update validation
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      UserTaskRecordDTO update(SignOffProcessDefinitionDTO object, String comment, Map<String, Object> variables) throws ValidationException;

      /**
       * Start the workflow process for archiving a (published/approved) sign-off process definition.
       * <p>
       * Note: this starts a new workflow process instance.  It will be blocked if the object's key is currently involved in another process instance.
       * It will also fail validation if the object doesn't currently exist in the persistent storage.
       *
       * @param key the sign-off process definition to archive
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for starting the process, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException if the object fails the archive validation
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      UserTaskRecordDTO archive(String key, String comment, Map<String, Object> variables) throws ValidationException;

      /**
       * Import a CSV file containing sign-off process definitions.
       * A new ({@link IKeyedObjectService#createOrUpdate(IKeyedObject) create or update}) process instance is started for each row of the file.
       * <p>
       * Note: this starts multiple new workflow process instances.  Each of these may be blocked if the corresponding object's key is currently involved in another process instance.
       *
       * @param csv the CSV file to import
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the list of history records for starting each process, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException if an object fails the archive validation
       * @throws IOException if there is an error reading the CSV file
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      List<AHistoryRecordDTO> upload(Reader csv, String comment, Map<String, Object> variables) throws ValidationException, IOException;

      /**
       * Save a new version of an object as it progresses through the workflow.
       * <p>
       * This performs the "save" action and sets the workflow status to "SAVED"
       *
       * @param key the object's identifying key
       * @param object the new version of the object
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       * @throws ValidationException the request could not be processed on the current state
       */
      default UserTaskRecordDTO save(String key, SignOffProcessDefinitionDTO object, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(key, object, "save", comment, variables);
      }

      /**
       * Publish/approve a new version of an object that has progressed through the workflow.  This ends the workflow process instance for the object.
       * <p>
       * This performs the "publish" action and sets the workflow status to "PUBLISHING"
       *
       * @param key the object's identifying key
       * @param object the (optional) new version of the object
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       * @throws ValidationException the request could not be processed on the current state
       */
      default UserTaskRecordDTO publish(String key, SignOffProcessDefinitionDTO object, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(key, object, "publish", comment, variables);
      }

      /**
       * Delete an object that was progressing through the workflow.  This ends the workflow process instance for the object.
       * <p>
       * This performs the "delete" action and sets the workflow status to {@code null}.
       *
       * @param key the object's identifying key
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       * @throws ValidationException the request could not be processed on the current state
       */
      default UserTaskRecordDTO delete(String key, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(key, null, "delete", comment, variables);
      }

      /**
       * Retrieve a process definition with its key, adding the available actions depending on the process instance's state.
       *
       * @param key of the {@link SignOffProcessDefinitionDTO} to retrieve
       * @return a {@link SignOffProcessDefinitionDTO} with actions
       */
      SignOffProcessDefinitionDTO getSignOffProcessDefinitionWithActions(String key);

      /**
       * Retrieve all process definitions with their key as key of the map, adding the available actions depending on the process instance's state.
       *
       * @return a map of {@link SignOffProcessDefinitionDTO}s with actions
       */
      Map<String, SignOffProcessDefinitionDTO> getSignOffProcessDefinitionsWithActions();

      /**
       * Retrieve the history (audit log) of a {@link SignOffProcessDefinitionDTO} identified by
       * signOffProcessDefinitionKey. This history will include all the process instances that were used to
       * modify the object, as well as all the user tasks involved in those processes. The records match
       * those returned by startProcess() and taskStateTransition()
       *
       * @param signOffProcessDefinitionKey - the key of the {@link SignOffProcessDefinitionDTO}
       * @param includeVariables - if true, then the variables associated with the task ID will be
       *     wrapped in the response
       * @return the history records of the {@link SignOffProcessDefinitionDTO} specified by {@code
       *     signOffProcessDefinitionKey}
       */
      List<AHistoryRecordDTO> processInstanceHistory(
              String signOffProcessDefinitionKey,
              boolean includeVariables);
  }
  ```
</Accordion>

<Accordion title="ISignOffProcessInstanceWorkflowService">
  ```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
  public interface ISignOffProcessInstanceWorkflowService
          extends IVersionedObjectWorkflowService<SignOffProcessInstanceDTO> {

      /**
       * Initiate the workflow process for signing-off on data.
       * The {@link SignOffProcessInstanceDTO object} points to the sign-off process definition, which describes both the workflow process to use and the scope of the data to be signed-off, additionally the object's as-of date specifies the date for which the data is being signed off.
       * <p>
       * Note: this starts a new workflow process instance.  It will be blocked if the object's key is currently involved in another process instance.
       * It will also fail validation if the object already exists in the persistent storage.
       *
       * @param object  the sign-off process instance to initiate
       * @param variables optional variables to pass on initiation
       * @return the history record for starting the process, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException if the initiation fails validation
       * @see IKeyedObjectWorkflowService#startProcess(String, String, IKeyedObject, String, String, java.util.Map)
       */
      AHistoryRecordDTO initiate(SignOffProcessInstanceDTO object, Map<String, Object> variables) throws ValidationException;

      /**
       * Request approval for the sign-off process instance.
       * <p>
       * This performs the {@link Action#REQUEST_APPROVAL} action and sets the workflow status to PENDING
       *
       * @param object  the process instance
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException the request could not be processed on the current state
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      default UserTaskRecordDTO requestApproval(SignOffProcessInstanceDTO object, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(object.getKey(), object, Action.REQUEST_APPROVAL.toString(), comment, variables);
      }

      /**
       * Cancel approval request for the sign-off process instance.
       * <p>
       * This performs the {@link Action#CANCEL_REQUEST} action and sets the workflow status to INITIATED
       *
       * @param object  the process instance
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException the request could not be processed on the current state
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      default UserTaskRecordDTO cancelRequest(SignOffProcessInstanceDTO object, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(object.getKey(), object, Action.CANCEL_REQUEST.toString(), comment, variables);
      }

      /**
       * Approve the sign-off process instance.  This completes the workflow and the process instance object will be persisted.
       * <p>
       * This performs the {@link Action#APPROVE} action and sets the workflow status to APPROVED.
       *
       * @param object  the process instance
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException the request could not be processed on the current state
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      UserTaskRecordDTO approve(SignOffProcessInstanceDTO object, String comment, Map<String, Object> variables) throws ValidationException;

      /**
       * Reject the sign-off process instance.
       * <p>
       * This performs the {@link Action#REJECT} action and sets the workflow status to INITIATED.
       *
       * @param object  the process instance
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException the request could not be processed on the current state
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      UserTaskRecordDTO reject(SignOffProcessInstanceDTO object, String comment, Map<String, Object> variables) throws ValidationException;

      /**
       * Close the sign-off process instance.
       * <p>
       * This performs the {@link Action#CLOSE} action and sets the workflow status to EXPORT_SUCCEEDED.
       * <p>
       * A closed sign-off process is considered done and will not be affected by an update signal.
       *
       * @param object  the process instance
       * @param comment an optional user comment
       * @param variables optional variables to store with the process instance
       * @return the history record for the user task, see {@link IKeyedObjectWorkflowService#processInstanceHistory(String)}
       * @throws ValidationException the request could not be processed on the current state
       * @see IKeyedObjectWorkflowService#taskStateTransition(String, IKeyedObject, String, String, java.util.Map)
       */
      default UserTaskRecordDTO close(SignOffProcessInstanceDTO object, String comment, Map<String, Object> variables) throws ValidationException {
          return taskStateTransition(object.getKey(), object, Action.CLOSE.toString(), comment, variables);
      }

      /**
       * Notify relevant processes that the status of an application server has changed. This allows processes to
       * be moved into a new workflow task whilst the application server is not running, and moved back to the
       * appropriate task when the server resumes.
       * @param serverName the name of the server
       * @param status the new status of the server
       */
      void notifyApplicationStatusChange(String serverName, ApplicationStatus status);

      /**
       * Retrieve a process instance with its key, adding the available actions depending on the process instance's state.
       *
       * @param key of the {@link SignOffProcessInstanceDTO} to retrieve
       * @return a {@link SignOffProcessInstanceDTO} with actions
       */
      SignOffProcessInstanceDTO getSignOffProcessInstanceWithActions(String key);

      /**
       * Retrieve all process instances with their key as the key of the map, adding the available actions depending on the process instance's state.
       *
       * @return a Map of {@link SignOffProcessInstanceDTO}s with actions
       */
      Map<String, SignOffProcessInstanceDTO> getSignOffProcessInstancesWithActions();

      /**
       * Retrieve the history (audit log) of a {@link SignOffProcessInstanceDTO} identified by
       * signOffProcessInstanceKey. This history will include all the process instances that were used to
       * modify the object, as well as all the user tasks involved in those processes. The records match
       * those returned by startProcess() and taskStateTransition()
       *
       * @param signOffProcessInstanceKey - the key of the {@link SignOffProcessInstanceDTO}
       * @param includeVariables - if true, then the variables associated with the task ID will be
       *     wrapped in the response
       * @return the history records of the {@link SignOffProcessInstanceDTO} specified by {@code
       *     signOffProcessInstanceKey}
       */
      List<AHistoryRecordDTO> processInstanceHistory(
              String signOffProcessInstanceKey,
              boolean includeVariables);
  }
  ```
</Accordion>

##### `IWorkflowTaskActionsService` new method

A new method `getWorkflowTaskActions(UserTask task, String activitiProcessId)` has been added to the `IWorkflowTaskActionsService`. This is to support
retrieving the workflow variables associated with a task so that file attachments can be retrieved as part of the history records.

If you have a custom implementation of `IWorkflowTaskActionsService`, you will need to implement the new method:

```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
/**
 * Get the actions of a user task.
 *
 * @param task the user task for which to retrieve actions
 * @param activitiProcessId the ID of the process to apply the action consumer
 * @return a list of {@link WorkflowTaskActionDTO}
 */
List<WorkflowTaskActionDTO> getWorkflowTaskActions(UserTask task, String activitiProcessId);
```

#### Application server communication changes

Previously, Atoti Sign-Off communicated with the application server using a custom `RestTemplate` that was configured to use basic authentication. This was
configured in `RestTemplateConfiguration`. To conform with more modern Spring APIs and to improve extensibility, this has been replaced with a
`RestClient.Builder` bean that is exposed via `ISignOffRestClientBuilder`.

<Accordion title="ISignOffRestClientBuilder">
  ```java theme={"languages":{"custom":["/engine/python-sdk/0.9/languages/pycon.tmLanguage.json"]}}
  /**
   * <b>ISignOffRestClientBuilder</b>
   *
   * <p>Used to provide {@link RestClient.Builder} instances for building and sending authenticated requests to Atoti servers connected to Sign-Off.
   * This allows for the creation of {@link RestClient} instances with specific configurations for each server, for example, to handle URLS, authentication or custom headers.
   *
   * @author ActiveViam
   */
  public interface ISignOffRestClientBuilder {

      /**
       * Get a {@link RestClient.Builder} for the specified server name.
       *
       * @param serverName the name of the server for which to get the {@link RestClient.Builder}
       * @return a {@link RestClient.Builder} configured for the specified server
       */
      RestClient.Builder getRestClientBuilder(String serverName);

  }
  ```
</Accordion>

This interface exposes a `RestClient.Builder` for each server that Atoti Sign-Off connects to, allowing you to build and send authenticated requests to the
Atoti servers. We use a builder pattern to allow for easy configuration of the `RestClient` instances, such as setting the URL, authentication, and custom headers.

By default, the `RestClient.Builder` is configured to use JWT authentication with the credentials defined in the `sign-off.application.rest-apis.*` properties.
You can revert this to use Basic authentication by setting the `sign-off.application.authentication-mode` property to `basic`.

JWT authentication requires that only a username is present, so you can now remove any passwords from your `application.yml` files if you continue to use the
JWT authentication.

### Configuration properties

#### Properties added

##### [signoff-activeviam](../../../user-ref/properties/config-properties/signoff-activeviam)

| Property Name                                      | Comment                                                                                                                                                            | Value                                                                                         |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| `sign-off.application.rest-apis.*`                 | Defines the servers that Atoti Sign-Off connects to.                                                                                                               | None                                                                                          |
| `sign-off.cubes.formatters.integer-format`         | Defines the format for measures of type `INTEGER` in the Sign-Off cubes.                                                                                           | `INT[#,###]`                                                                                  |
| `sign-off.export.timeout-in-milliseconds`          | Defines the time in milliseconds to wait for an export to finish.                                                                                                  | `3600000`                                                                                     |
| `sign-off.workflow.process-definition-key`         | Defines the workflow type used by the Sign-Off Definition workflow.                                                                                                | `sign-off-process-definition`                                                                 |
| `sign-off.workflow.file-attachments-are-read-only` | When set to true, the file attachments in the workflow are set to read-only on the file system. You may disable this if you encounter difficulties uploading file. | `true`                                                                                        |
| `sign-off.workflow.allowed-file-upload-extensions` | The file types allowed to be uploaded as attachments in the workflow.                                                                                              | `pdf`, `jpeg`, `png`, `csv`, `xls`, `xlsx`, `doc`, `docx`, `txt`, `ppt`, `pptx`, `eml`, `msg` |
| `sign-off.workflow.file-storage-path`              | The folder where the workflow attachments are stored. This can be an absolute or relative path.                                                                    | `sign-off/workflow/attachments`                                                               |
| `sign-off.application.emitter-timeout`             | The timeout on each Event Source that a client opens to receive real-time updates on Sign-Off definitions and tasks.                                               | `8h`                                                                                          |

#### Files modified

##### [application.yml](../../../user-ref/properties/property-files/application-yml)

New properties:

| Property Name                      | Comment                                              | Value |
| ---------------------------------- | ---------------------------------------------------- | ----- |
| `sign-off.application.rest-apis.*` | Defines the servers that Atoti Sign-Off connects to. | None  |

Deleted properties:

| Property Name             | Comment                                                        |
| ------------------------- | -------------------------------------------------------------- |
| `application.rest-apis.*` | This property is replaced by `sign-off.application.rest-apis`. |

### Other changes

#### Validation error changes

The structure of validation errors has been streamlined to improve readability and usability. If you have custom validation errors in your project,
you’ll need to migrate them accordingly.

##### `IValidationError` changes

* new method added: `String getFieldName()` - returns the name of the field containing the error.
* method `getLineNumber()` was renamed to `getIndex()`.
* method `getColumnIndex()` was removed and replaced by `getFieldName()`.
* method `getSource()` was removed.

#### Spring configuration changes

The primary configuration class for the `signoff-actieviam` module is now `SignOffCoreAutoConfiguration` which is a [Spring AutoConfiguration](https://docs.spring.io/spring-boot/reference/using/auto-configuration.)
class. Most of the imports from `SignOffAppConfig` in the starter module have been moved to this new autoconfiguration class.

Additionally, many service imports have been removed in favor of exposing the services as Spring beans marked as `@ConditionalOnMissingBean`, making them easier
to override if you want to implement a custom service. To override a default service implementation, create your own implementation of the respective
interface and expose it as a Spring bean. The `@Primary` annotation is no longer required if the bean for the default implementation is marked as
`@ConditionalOnMissingBean`.
