Skip to main content

Data Migration from Cloud (cloud → on-prem)

About 7 min

Data Migration from Cloud (cloud → on-prem)

📦 Migrating from the StormBPMN cloud to your own (on-prem) installation? Here is the complete procedure for migrating your team: what to prepare, which permissions to grant, and how to upload the data archive.

When to perform the migration

The migration is initiated within a narrow window: after the initial deployment via Quick Start, but before completing onboarding — that is, before creating the first administrator, team, and users.

The reason is that the import works only on an empty database (see key principles below). Once you create your first user or team, the database will no longer be empty, and the import will require recreating the schema and clearing the data.

The migration works as follows: we export your team from the cloud into a self-contained archive bundle (a file with the .storm extension) on our side, and you upload it to a fresh on-prem installation via the application's REST API. The service will automatically parse the archive, distribute rows across tables, and upload files (avatars, diagram previews, attachments) to your S3 object storage.

Who is involved

The migration typically involves several roles on your side:

  • Server Administrator — performs the steps on the server.
  • DBA / Database Administrator — grants temporary permission for a single privilege (see below).

On the Storm side, your manager oversees the migration: we prepare and transfer the bundle file to you and provide real-time communication support.


Key Principles

  • Migration is a snapshot at the time of export. Once the .storm bundle is downloaded from the cloud, any subsequent changes in the cloud will not migrate to the on-prem environment — there is no continuous synchronization between the cloud and on-prem. Therefore, coordinate the migration window in advance: during the migration, team work in the cloud is paused, the import completion is awaited, and work resumes in the on-prem environment.

  • Import only into an empty database. The import is designed for a fresh database (immediately after the initial Liquibase initialization). If the database already contains users, the import will stop with an error. On a fresh installation, the database is empty by default; however, if the service has already been used, back up all necessary data and settings before resetting the database.

  • Temporary permission for one database privilege is required. During the upload, the application disables foreign key checks (session_replication_role = replica) within its own session, then re-enables them and verifies data integrity after loading. For this, the user with which Storm connects to the database requires the SUPERUSER role or a specific grant of SET ON PARAMETER (PostgreSQL 14+). This permission can be granted for the duration of the migration and revoked immediately afterward — it does not affect anything other than the import session.

  • Migration is a one-pass operation. The import runs in a single transaction: it either completes entirely or rolls back, leaving the database in a clean state. Do not run the import again over already imported data — recreate the schema first.


Readiness Checklist

Go through the list before we start the export from the cloud. The application will automatically re-verify most of the items during import, but it is better to address them in advance — this saves time within the granted access window.

Access and Infrastructure

Time Zone

Why this matters

Some dates in the data are stored without a time zone. We recalculate them to your time zone on export, so inform your manager of your time zone in advance and keep the same value in the application and in Postgres.

Database Permissions

Connect to the database using the application account and run:

SELECT
  current_user AS me,
  rolsuper AS i_am_super,
  has_parameter_privilege(current_user, 'session_replication_role', 'SET') AS can_set,
  current_setting('server_version') AS pg_version
FROM pg_roles
WHERE rolname = current_user;

The import will succeed if at least one of the columns i_am_super or can_set is equal to t (true).

Data Backup (Optional)


Migration Procedure

Step 1. Grant the database privilege

If both checks above i_am_super and can_set are f (false), ask the DBA (under the superuser or provider admin role — rds_superuser, cloudsqlsuperuser, etc.) to execute:

GRANT SET ON PARAMETER session_replication_role TO <db_user>;

where <db_user> is the account from current_user in the check. After this, repeat the verification SELECT and ensure that can_set has become t.

The privilege can be granted at the last minute

If the security team is not ready to keep the grant for a long time — agree on a narrow window. The migration is fast (usually a few minutes), the grant is only needed during the import itself and is revoked immediately after.

Step 2. Reset the database — only if the service has already been used

Skip this step for a fresh installation

After the Quick Start, the database is already empty — proceed directly to Step 3. A reset is required only if the on-prem service has already been used and the database contains users/data (import works only on an empty database).

To return the database to an empty state:

  1. Stop the container stormbpmn.

  2. Reset the schema using the application account:

    DROP SCHEMA public CASCADE;
    CREATE SCHEMA public;
    

Step 3. Update the image, enable the import profile, and deploy

Update the image version to the latest one (see Changelog) and set/verify the environment variables.

VariableValue
S3_BUCKET_UPLOADSstorm-prod-uploads
S3_BUCKET_USERSstorm-prod-users
S3_BUCKET_IMPORTSstorm-prod-imports
S3_SINGLE_USERS_BUCKETtrue
SPRING_PROFILES_ACTIVEprod,handover-import

Bucket names must match the archive

The archive transfers files while preserving the original bucket names. If the names in S3_BUCKET_* do not match those hardcoded in the bundle, the import will stop and indicate the expected name. Use exactly the values we provide.

Apply the changes and wait for the string Started BackendApplicationKt in … seconds in the logs.

Step 4. Wait for the file and grant, verify availability

  1. Wait for the bundle file (*.storm) from the Storm manager.

  2. Ensure that the privilege grant has been issued (repeat SELECT, can_set = t).

  3. Log in to the server via SSH and verify that the service responds locally:

    curl http://localhost:8080/api/health/liveness
    # ожидаемый ответ: {"status":"UP"}
    

Without the grant, the handler will reject the request

Import begins with a permissions check. If the grant has not yet been issued, the application will return an error without loading the data. Therefore, wait for confirmation from the DBA before sending the file.

Step 5. Upload the archive

Copy the received .storm file to the server (for example, via scp):

scp Команда-20260429-101020.storm <user>@<STORM_HOST>:/tmp/

Then, from the server itself, send the file to the locally started service.

curl -# -X POST \
  -F "bundle=@/tmp/Команда-20260429-101020.storm" \
  http://localhost:8080/api/v1/handover/import

After the file is uploaded, the service takes a few more minutes to unpack the data and write files to S3 — you can monitor this in the container logs.

A successful response is 200 OK with a JSON summary: how many rows were loaded for each table, how many files were uploaded to S3, and how long the import took. Save the sourceTeamId from the response — it will be needed in Step 8.

{
    "ok": true,
    "errors": [],
    "sourceTeamId": "7d8fc07d-ced8-4615-9d33-a83364e42ae5",
    "sourceTeamName": "Команда ...",
    "blobsDeclared": 282,
    "blobsUploaded": 282,
    "blobsFailed": 0,
    "userSetSize": 20,
    "durationMs": 34294
}

If the response comes with "ok": false or with an HTTP status of 422 — see the errors section below: in the errors field, the application provides detailed information about what is wrong and how to fix it.

Step 6. Complete onboarding and verify data

Open Storm in your browser at your installation address. Complete the onboarding following the standard scenario, during which you will create a team and a server administrator account.

Using this account, open the Administration section and verify the following:

Step 7. Complete the migration (revert temporary settings)

After colleagues confirm that the data is in place:

  1. Ask the DBA to revoke the grant on the privilege, if it was necessary to issue it.
  2. Remove handover-import from SPRING_PROFILES_ACTIVE (leave only prod) and restart the container.

Step 8. Post-configuration

Under the administrator account in Administration → Application Settings:

Data has been migrated

Next, bring the installation to a production state following the Production installation instructions — SSL/HTTPS, SSO, monitoring, backup and other infrastructure.


Troubleshooting

Error regarding permissions for session_replication_role

The grant is missing or has been issued to the wrong account. Repeat the verification SELECT using the application account and ensure that i_am_super = t or can_set = t. On managed Postgres, the grant is issued by the provider's admin role.

"N users already exist in the on-prem environment"

The database is not empty — import works only on a fresh schema. Perform DROP SCHEMA public CASCADE; CREATE SCHEMA public;, restart the container (Liquibase will reapply the schema), and retry the import.

Error regarding S3 bucket names

The names in S3_BUCKET_UPLOADS / S3_BUCKET_USERS / S3_BUCKET_IMPORTS do not match those hardcoded in the archive. The error message specifies the expected name — set it in the corresponding variable and restart the import.

ok=false and a list of "orphan-FK relations"

After loading, the application detected integrity violations and rolled back the entire import — the database remained clean. This indicates that the archive contained inconsistent data or that the cloud and on-prem schemas diverged. Send the service response with the error list to the Storm manager — we will resolve it on our side.