PM_Console/docs/runbooks/sqlite-to-mysql.md

2.4 KiB

SQLite to MySQL controlled migration

Preconditions

  • Work from a dedicated branch and record the source commit.
  • Put the application in a planned write freeze.
  • Keep the source SQLite file outside the web root.
  • Create an immutable copy and verify its SHA-256 hash.
  • Provision an empty MySQL 8 database using utf8mb4 and utf8mb4_unicode_ci.
  • Use a dedicated least-privilege migration account. Do not commit its password.

Dry run

Configure only the MIGRATION_MYSQL_* variables. Keep DB_CONNECTION=sqlite.

php artisan migrate --database=migration_mysql --force
php artisan db:transfer-sqlite-to-mysql

The transfer command does not write unless --execute is supplied.

Transfer

php artisan db:transfer-sqlite-to-mysql --execute --truncate
php artisan db:transfer-sqlite-to-mysql --execute

The second execution proves idempotency. Both runs must finish with identical source and target row counts. Sessions, access tokens, cache, queues, reset tokens, and the migration repository are intentionally excluded; users must authenticate again.

Validation gates

  • All migrations succeed on an empty MySQL database.
  • Every transferred table has equal source and target row counts.
  • Foreign-key validation reports no orphan rows.
  • Unique business keys have no duplicates.
  • JSON columns contain valid JSON.
  • Dates, times, decimals, booleans, Persian text, and emoji round-trip correctly.
  • Backend, frontend build, and browser tests pass with MySQL as the active test database.
  • A manual smoke test covers login, project/task CRUD, sprint, meeting, files, notifications, settings, and reports.

Cutover

  1. Enable maintenance/write-freeze mode.
  2. Take and hash a final SQLite backup.
  3. Re-run the idempotent transfer without --truncate.
  4. Run validation gates.
  5. Change production secrets to DB_CONNECTION=mysql.
  6. Clear configuration cache, restart application and queue workers, then run health and smoke checks.
  7. Retain the SQLite source read-only for the defined rollback period.

Rollback

If any validation or smoke check fails:

  1. Stop writes immediately.
  2. Restore the previous application configuration and DB_CONNECTION=sqlite.
  3. Restore the verified final SQLite copy if the source was touched.
  4. Restart application and workers.
  5. Run /up, authentication, project, task, and file smoke checks.
  6. Preserve MySQL unchanged for incident analysis; never merge partial target data back manually.