Files
stalwart-migrator/docs/status.md
T
jcoffey-dev 6608f3a97f Shorten the README; move the technical detail into docs/
The README keeps what the tool is, how to install it and the first commands,
and points to the guide on docs.ihasmail.org. Everything else moves, whole,
into docs/ and CONTRIBUTING.md, where it is organized for readers who want
the detail. Where the old README disagreed with the code, the code wins.
2026-09-15 12:14:36 -07:00

4.8 KiB

Status and field reports

What works today, what run does, what has been tested against real servers, and the state of each package. For the short version, see the README.

Commands

Command State
stalwart-migrate preflight Works — read-only checks and a migration plan
stalwart-migrate rehearse Works — read-only; converts your settings and reports what won't carry over
stalwart-migrate run Works — performs the migration; --recovery-point-confirmed --yes. Container deployments additionally need --container-path-unproven (see Docker deployments)
stalwart-migrate tenants Works — read-only; who owns which domain, and what would block a migration
stalwart-migrate status <id> Works
stalwart-migrate report <id> Works — prints what validation found for a run

Run stalwart-migrate <command> -h for the current flags of each.

What run does

run performs the migration in this order:

preflight → stage → dump → stop → convert → recovery-mode → cutover → validate

It needs two flags: --yes (intent) and --recovery-point-confirmed (a claim that you have a snapshot or backup you have verified you can restore — this tool cannot undo a migration and will not start without it). Start with rehearse first: it is read-only, needs no maintenance window, and tells you what run will and won't carry over. See rehearsal.md.

An interrupted run resumes from its last completed step with stalwart-migrate run --resume <run-id> and the same flags; status lists run IDs and shows which steps completed.

Validation after cutover

After cutover, run compares the migrated instance against the snapshot preflight took, and fails the command if an account that existed before is missing from it. A domain that no longer appears is reported as a warning rather than a failure: the two versions do not agree on what counts as a domain — principals on one side, Domain objects on the other — and failing a migration over that difference would abort runs that lost nothing.

The service is left running either way. By that point the store has been migrated in place, so stopping it would not undo anything; your recovery point is the way back (see recovery.md). report <run-id> prints the same finding again later. Where preflight had no admin URL to snapshot from, validation reports itself as skipped rather than passed.

Field reports

A production server, 2026-08-25

The tool took a live server — nine domains, six accounts, a 2.4 GB RocksDB store — from 0.15.5 to 0.16.19 with 8 seconds of downtime, every phase green including post-cutover validation, mail flowing before and after. That run was preceded by a full dress rehearsal on a clone of the same server, which is the practice this project most recommends copying: see Rehearse on a clone first.

Three servers, reported in issue #1

@kaya-eu reported three successful 0.15.5 → 0.16.19 migrations on three servers: a testing and a production instance, each 16 domains, 55 accounts and roughly 221 GB of real mail, and an arm64 home server of 1.4 GB across 181 folders.

Read that with two qualifications:

  • They ran a commit predating the automated Docker cutover, so they performed the cutover by hand. What those runs exercised is preflight, the dumps, the settings conversion and the recovery-mode store migration, not the container cutover.
  • They hit things worth knowing about before you follow them:

Code

Roughly 14,600 lines of Go, standard library only, of which about 6,300 are tests. Every phase exists as a package, and run wires them into the migration described above.

Lines are implementation only; each package carries its tests alongside.

Package Lines Tests
internal/stalwartapi 1456 yes
internal/backup 1333 yes
internal/preflight 1035 yes
internal/applyplan 913 yes
internal/cutover 784 yes
internal/recovery 431 yes
internal/checkpoint 406 yes
internal/validate 382 yes
internal/stage 233 yes
internal/service 201 yes
internal/plan 130 yes
internal/config stub