The pre-migration backup was a redundant safety net: the migration engine
never deletes v1 data (it stays on disk, so a failed run is retryable), and
StartMigration never required or verified a backup. Removing it shortens the
wizard to introduction -> migration -> completion/error (progress rail 3 steps).
- shared: drop the backup_required/progress/confirmed stages, the
backupInfo/isCompressing fields, MigrationBackupInfo, and the 5 backup IPC
channels; delete the dead DataMigrate_* IpcChannel enum block (superseded by
MigrationIpcChannels, zero consumers)
- main: remove the backup handlers, LegacyBackupManager wiring, progress
bridge, and single-flight guards from MigrationIpcHandler; simplify
updateProgress; Retry now returns to the introduction stage
- main: flip to the protected `migration` stage before running the engine so
the destructive verifyAndClearNewTables() runs under the close-confirm /
write-deferral guard instead of the unprotected introduction stage
- renderer: the introduction Start button now runs the migration directly
(with a loading state; Skip is disabled while exporting); drop the backup
stages, choice UI, and completed-screen backup path; remove the now-dead
ProgressBar indeterminate branch and its keyframe
- i18n, docs, and tests updated accordingly
LegacyBackupManager and IpcChannel.BackupProgress are retained -- still used by
the in-app backup/restore feature.
Pagination docs were scattered across api-types.md (types + cursor
semantics), data-api-in-renderer.md (hooks), data-api-in-main.md (offset
example + keyset note), api-design-guidelines.md (query params), and
data-ordering-guide.md (cache shapes + determinism), with no single
discoverable home for the offset-vs-cursor model.
Add docs/references/data/data-pagination-guide.md as the canonical hub
(mirrors data-ordering-guide.md): two modes, four-layer quickstart, wire
contract, server impl (offset + keyset cursor + multi-band caveat),
renderer consumption, FTS pagination, gotchas, and a see-also map. Other
docs keep their authoritative slice and link to the guide; the migrated
conceptual prose is removed from api-types.md to avoid duplication.
Also fix two pre-existing broken anchors found while verifying links
(database-patterns withWriteTx; ordering guide section number).
Apply the naming-conventions §6.1 acronym-casing rule (MCP -> Mcp) to the
MCP* PascalCase identifier family across the codebase (McpServer, McpTool,
McpToolResponse, BuiltinMcpServerNames, McpService, etc.) plus the local
identifiers boundMcp/enableMcp/disableMcp and the didiMcp registry key.
Regenerate the OpenAPI spec from the renamed schemas.
Deliberately left unchanged (not naming-convention identifiers): persisted
field keys read by migrators (enabledMCPs), v1 Redux selectors (selectMCP),
string values (ExaMCP, logger labels), and UPPER_SNAKE constants (MCP_*).
Also fix naming issues in the data reference docs that prompted this:
- JSONStreamReader -> JsonStreamReader (match the real class name)
- rowToMCPServer -> rowToMcpServer (match the real function name)
- replace the TopicService getInstance() skeleton with a direct singleton
- sync stale MCPServer/MCPTool/McpService references in affected docs
The V2 migration disabled foreign keys ad-hoc in each migrator, which was fragile (a
one-shot PRAGMA is lost at @libsql/client's post-transaction connection swap) and produced
recurring FK constraint bugs.
Register foreign_keys = OFF once via the patched setPragma() in MigrationDbService so it
replays on every connection, and remove the scattered per-migrator PRAGMA toggling. Each
migrator now self-checks its own fully-resolved tables via the new
BaseMigrator.assertOwnedForeignKeys() (scoped PRAGMA foreign_key_check per table), with the
engine's final verifyForeignKeys() as the cross-domain backstop.
- BaseMigrator: add assertOwnedForeignKeys() helper + real-DB tests
- MigrationDbService: db.run(PRAGMA OFF) -> client.setPragma(PRAGMA OFF)
- Assistant/Chat/Agents/Knowledge migrators: drop FK toggling, add scoped self-checks
- remapAgentPrefixIds: drop FK toggling + whole-db check; keep manual tx (ATTACH window);
export AGENT_TABLES for AgentsMigrator self-check
- pragmaReplay: add foreign_keys replay tests
- docs: update v2-migration-guide + migration README FK conventions
Enforce a linear upgrade path (v1.last → v2.0.0 → v2.x) before
allowing data migration to proceed. Users who manually install v2
bypassing the auto-updater are now blocked at startup if their
previous version is incompatible.
- Add versionPolicy.ts with pure check function and version.log reader
- Add versionLogFile to MigrationPaths (uses resolved userData path)
- Wire version check into v2MigrationGate after needsMigration()
- Block on: no version.log, v1 too old (<1.9.0), v2.0.0 gateway skipped
- Treat v2.0.0 pre-releases as "before v2.0.0" per semver ordering
- Update migration docs with version upgrade requirements
Signed-off-by: fullex <0xfullex@gmail.com>
v1 users who configured a custom userData directory via
~/.cherrystudio/config/config.json had their data silently skipped
during v2 migration, because resolveUserDataLocation() reads only
boot-config.json (empty on first v2 launch) and the migration
pipeline ran at the wrong default path.
Introduce MigrationPaths — a frozen, pre-computed path object
resolved once at the migration gate entry. All 10 scattered
app.getPath('userData') and path.join calls in migration/v2 are
replaced with centralized constants. Legacy config.json detection
runs before engine initialization, redirecting both the internal
paths and Chromium-level storage (via app.setPath) so the migration
window's renderer can access the correct Dexie/localStorage data.
When the detected custom path is inaccessible (e.g. unmounted
external drive), a dialog prompts the user instead of silently
falling back to an empty default directory.
Signed-off-by: fullex <0xfullex@gmail.com>