Tournevia

Upgrade

Move an installation to a new image with one launcher command, check it and go back if needed.

1. Before you start

  1. Verify and build the new kit as in installation. Note the image name it prints: NEW_IMAGE below.

  2. Let current calculations finish and pause new changes.

  3. Make sure the host Python has the packages from backend/requirements.txt: the launcher takes a backup before changing anything.

  4. If a tool on the server deletes unused Docker images, as Coolify's Docker cleanup does, save the current image first, for example docker save -o PRIVATE_PATH/backups/CURRENT_IMAGE.tar CURRENT_IMAGE: after the upgrade it is unused, and you need it to go back. docker load -i restores it.

  5. Read the schema changes the new version brings: some need an action in the application after the upgrade.

Never delete volumes or repeat first-time setup to upgrade. Changing --image alone does not upgrade an existing installation: the image is recorded in its private directory.

2. Upgrade a launcher installation

From the kit of the currently installed version (the backup it takes checks the schema against that kit):

python3 scripts/start_server.py --directory PRIVATE_PATH --upgrade-image NEW_IMAGE

A local installation uses python scripts/start_local.py --directory PRIVATE_PATH --upgrade-image NEW_IMAGE.

The launcher then:

  1. checks that the new image exists and differs from the current one;
  2. writes a backup to PRIVATE_PATH/backups/before-upgrade-<UTC time>.dump; if the backup fails, nothing is changed;
  3. stops the API and worker;
  4. records the new image, and the previous one, in image.json and workspace.json;
  5. starts the installation: setup runs the database migrations before the API and worker start.

On a 2 vCPU / 8 GB VPS shared with Coolify, this took 19 s including the backup; see Install on a VPS, step by step. Use the new version's kit for later maintenance. Later starts of a server installation pass the new image with --image; the launcher refuses values that differ from the recorded installation.

3. If the upgrade does not start

The launcher reports: “Upgrade did not start. If setup failed, API and worker stay stopped and the database is preserved.” It also names the previous image.

Keep that database for diagnosis. Do not reset the volume and do not start the previous image on the migrated database: an older image may not support a newer schema.

4. Go back to the previous version

There is no one-step backout command. With the previous version's kit:

  1. Restore the before-upgrade backup into an isolated database, as in Backup and restore.
  2. Start the recorded previous image (previous_image in workspace.json) against that copy.
  3. Validate sign-in, data and a calculation before reopening access.

5. Upgrade a Compose installation without the launcher

For an installation configured in .env, with any overlays it uses repeated on every Compose command that changes services:

python scripts/database_backup.py backup
docker compose --env-file .env -f deploy/docker-compose.example.yml stop api worker
docker compose --env-file .env -f deploy/docker-compose.example.yml up --build -d

Take the backup with the kit of the installed version. If setup fails, keep the API and worker stopped and correct the reported configuration or schema issue before retrying.

An installation from an earlier version that used the bootstrap database account needs a trusted PostgreSQL backup made with that account first, then the separate runtime and migration credentials of the configuration reference.

6. How migrations run

The setup service runs python -m app.setup_database with the same image as the API. It prepares the managed database roles, runs the migrations as the migration owner and grants the runtime role its permissions. The API waits for setup to succeed; its normal startup never runs migrations or inserts data.

Migrations keep existing identifiers and edits, but some transform data, such as 0012_weekly_hours. Their downgrades are not a backout procedure: go back by restoring a backup, as in step 4.

7. Check the upgraded installation

  1. docker compose ps shows the API, worker and database healthy; GET /api/v1/ready answers.
  2. A named user signs in and keeps their account language.
  3. Existing depot, vehicles, deliveries and saved plans are present.
  4. Planning shows no Calculation service needs attention banner.
  5. A representative calculation produces a reviewable result.
  6. The actions the new migrations need, described below, are done.

Reopen access only after these checks.

8. Migrations 0009 to 0017

An earlier installation receives all of these migrations during the upgrade: setup applies them in order, with no extra command. This version expects the schema revision 0017_safety_margin; GET /api/v1/ready and the backup command check it.

MigrationEffect
0009_address_lookupAdds the company's choice to use IGN's public address service, off for every company. The runtime role may change this column.
0010_order_numbersAdds the delivery number format, absent until an administrator chooses one, and the starting number (1 by default). The runtime role may change these two columns.
0011_depot_addressAdds the depot's postal address, empty for an existing depot.
0012_weekly_hoursReplaces each vehicle's dated availability window with weekly working hours and dated exceptions. A company vehicle's former window becomes an exception on its date, with no weekly hours invented; the vehicles of a sample workspace work their hours every day.
0013_customersAdds the saved customers table.
0014_delete_ordersAdds the function public.delete_orders, through which the runtime role deletes a company's chosen deliveries.
0015_depotsAllows several depots and places per company: each existing depot becomes its company's main depot. Adds the function public.delete_depot.
0016_examplesAdds the example mark to depots, vehicles and deliveries, and the function public.remove_examples, which replaces public.start_company_from_sample. A sample workspace created by first-use setup becomes a company workspace whose vehicles and deliveries are examples; its depot stays the main depot. The legacy local demonstration without accounts (APP_MODE=local_demo) stays a sample.
0017_safety_marginAdds the company's safety margin in minutes, 15 for every company, limited to 0 to 120. The runtime role may change this column.

The three functions belong to the migration role; setup grants the runtime role only the right to execute them.

After the upgrade:

  1. Vehicle hours. After 0012_weekly_hours, a company vehicle works only on the date of its former window: a calculation for any other day refuses it (VEHICLE_OFF_DAY). Set each vehicle's week once in Fleet, or re-import the vehicle file with the new columns.
  2. Former sample workspace. After 0016_examples, the company keeps the fictional Paris depot as its main depot. Before planning real deliveries, replace its address and entrance with your depot's, add your vehicles, then remove the examples in Settings → Example data.
  3. Integrations. The vehicle CSV replaces available_start,available_end with one column per weekday (monday … sunday, for example 07:30-17:00, empty for a day off). POST /api/v1/vehicles/availability and POST /api/v1/workspace/company no longer exist; POST /api/v1/setup refuses workspace_kind and requires depot. See the API reference.
  4. Safety margin. After 0017_safety_margin, new calculations plan every delivery to start at least 15 minutes before its window ends, where they used to plan up to its last minute. A delivery that can only be reached in those last minutes may now stay unassigned. An administrator changes the margin in Settings → Calculation (0 plans up to the window's end). Plans calculated before the upgrade show their margin as None: planned up to the last minute.

The downgrades of 0015_depots and 0016_examples refuse to run while other depots or places, or examples, exist; the downgrade of 0012_weekly_hours restores only one window per vehicle. To go back to the previous version, restore the before-upgrade backup, as in step 4.

On this page