docs/Features/Admin-Panel/Problems/Migrations.md
Status: Implemented · Owner: xet7 · Related:
server/methods/migrateTextDatabase.js, server/lib/repairBoardData.js,
server/lib/systemStatus.js, models/textMigrationStatus.js,
client/components/settings/attachments.js,
client/components/settings/migrationProgress.*.
WeKan can migrate its text data (everything except attachments and avatars,
which stay on the filesystem) between MongoDB and FerretDB v1 (SQLite) in
either direction, from Admin Panel → Attachments. Both databases speak the
MongoDB wire protocol, so the same driver copies collection by collection,
upserting by _id (idempotent — re-running is safe).
After it finishes, point MONGO_URL at the other database (on the snap:
snap set wekan database=ferretdb or =mongodb) and restart.
The migration runs as a background operation on the server. It does not depend on the admin staying on the page — if you close the Attachments page the migration keeps running to completion. The progress you see is just a view of it.
The migration drives the same blue, Product-name-branded progress dashboard as the board repairs (mounted app-wide). The dashboard is fed from the migration status poll, so the two phases above appear as two steps.
The migration and the startup repair persist their progress to the
text_migration_status collection. That means a separate process can see whether a
migration/repair is running:
snap run wekan.problems migrations prints it as text (see Snap.md).This is why an in-memory-only progress object was not enough: a CLI or the Problems page in another session could not read it.
If the ferretdb process is pegged near 200% CPU for a long time (pages take
minutes, All Boards counts stay 0, raw i18n keys appear), the FerretDB v1
(SQLite) backend is saturated under WeKan's poll load. Migrating the text data to
MongoDB and switching to it (snap set wekan database=mongodb) removes that
bottleneck for a heavy instance. First check that a migration/repair is not simply
still running (snap run wekan.problems).
FerretDB v1 has no real replica-set OpLog; WeKan can either poll it
(poll-and-diff) or tail a simulated OpLog. The snap default (since v10.16) is
polling only — it keeps FerretDB CPU low. The ferretdb process pegging ~2
cores for a long time while the WeKan node process is nearly idle is the
signature of an OpLog tail: Meteor holds a tailable cursor on local.oplog.rs
and FerretDB re-scans it server-side. Two guards now prevent this by default:
wekan-control clears MONGO_OPLOG_URL in polling mode, so node never tails.ferretdb-control enables the replica set / OpLog only when
wekan-ferretdb-oplog=true; in the default polling mode FerretDB runs
standalone, so no OpLog is maintained and nothing can spin on tailing it.So if you see the pegged-ferretdb / idle-node pattern, check the setting and
force polling:
snap get wekan wekan-ferretdb-oplog # expect: false
snap set wekan wekan-ferretdb-oplog=false
snap restart wekan.wekan wekan.ferretdb
Admin Panel → Version → Reactivity mode shows which is live (polling vs
oplog). Opting into OpLog (=true) is now also cheaper on the FerretDB side: the
{ts: {$gt}} tail filter is pushed down to SQL and the OpLog's Timestamp is
indexed, so an idle tail is an index range scan instead of a whole-collection
re-decode on every poll.