src/main/data/migration/v2/migrators/README-KnowledgeMigrator.md
KnowledgeMigrator migrates legacy knowledge data from Redux + Dexie exports into the new SQLite schema.
| Data | Source | File/Path |
|---|---|---|
| Knowledge bases + lightweight items | Redux knowledge.bases | ReduxStateReader.getCategory('knowledge') |
| Full note content | Dexie knowledge_notes | knowledge_notes.json |
| File metadata fallback | Dexie files | files.json |
| Legacy vector databases | Filesystem | ctx.paths.knowledgeBaseDir/<sanitizedBaseId> (via MigrationPaths) |
Note: The legacy vector DB path comes from
ctx.paths.knowledgeBaseDir, which is pre-computed byMigrationPathsfrom the resolved v1 userData directory. The base id is sanitized withsanitizeFilename(baseId, '_'). Do NOT callapp.getPath('userData')directly — seemigration/v2/README.mdPath Safety section.
knowledge_baseknowledge_itemBase metadata migration
embeddingModelId and rerankModelId.user_model rows.embeddingModelId = null, status = failed, and error = missing_embedding_model.error = missing_embedding_model is the current shared KnowledgeBaseErrorCode member for recoverable base-level embedding model loss.fileProcessorId.Unified item payload migration
content is transformed into the new knowledge_item.data union payload by item type.file, url, note, and directory.sitemap items with valid string content are migrated as ordinary url items.knowledge_item as a flat item list with optional groupId.groupId = null by design.directory is a container/source declaration in knowledge_item; its own container-level vectors are handled by KnowledgeVectorMigrator as non-indexable and are not written to the V2 vector store.Note content source priority
knowledge_notes content.content when note export is missing.Dexie lookup loading strategy
knowledge_notes and files are scanned via streaming readers.Processing status normalization
processingStatus is treated as runtime-only and not trusted for migration.uniqueId:
uniqueId present and non-empty -> completedidleVector dimension dependency
knowledge_base.dimensions value.vectors.vector blob length.KnowledgeVectorMigrator.failed; valid legacy dimensions are kept, otherwise dimensions is null.| Source (Legacy base) | Target (knowledge_base) | Notes |
|---|---|---|
id | id | Direct copy |
name | name | Direct copy |
| no legacy grouping field | groupId | V1 knowledge bases do not carry group metadata; migrate as null |
dimensions | dimensions | Completed bases use legacy vector DB blob length (length(vector)/4); failed bases keep valid legacy dimensions or null |
model | embeddingModelId / status / error | Converted to provider::modelId, then resolved against user_model; missing/dangling references produce a failed recoverable base |
rerankModel | rerankModelId | Optional, converted to provider::modelId, then resolved against user_model; dangling references are cleared |
preprocessProvider.provider.id | fileProcessorId | Optional |
chunkSize | chunkSize | Copied when positive integer; otherwise normalized to the default chunk size |
chunkOverlap | chunkOverlap | Copied when non-negative integer and smaller than chunkSize; otherwise normalized to the default overlap for the resolved chunk size |
threshold | threshold | Copied when within [0, 1]; otherwise cleared |
documentCount | documentCount | Copied when positive; otherwise cleared |
created_at | createdAt | Timestamp conversion |
updated_at | updatedAt | Timestamp conversion |
| Source (Legacy item) | Target (knowledge_item) | Notes |
|---|---|---|
id | id | Direct copy |
base owner id | baseId | From parent base |
| no legacy grouping field | groupId | V1 exports are flat; migrated items are inserted without grouping metadata (null) |
type | type | Supported target types: file/url/note/directory. Legacy sitemap maps to url. |
content + Dexie lookups | data | Type-specific transform |
uniqueId | status | uniqueId non-empty => completed, otherwise idle |
processingError | error | Direct copy |
created_at | createdAt | Timestamp conversion |
updated_at | updatedAt | Timestamp conversion |
video items are skipped.memory items are skipped.prepare.directory items are migrated into knowledge_item as container/source declarations when their legacy payload is valid.sitemap items are migrated into knowledge_item as url items when their legacy payload is valid.knowledge_item ids for every expanded directory child document.directory item are considered container-level vectors and are skipped by KnowledgeVectorMigrator with warnings.sitemap item are migrated as URL vectors because the item now maps to target type url.file, url, or note item id.dimensions is required only for completed bases; failed migrated bases may have dimensions = null.dimensions field is not treated as the migration source of truth.dimensions is resolved from legacy vector DB content by inspecting:
vectors tablelength(vector)/4)preparenull, status is set to failed, and error is set to missing_embedding_model with a warning. That error value is a shared KnowledgeBaseErrorCode, not a free-form string. It does not require legacy vector DB inspection; valid legacy dimensions are preserved and invalid or missing legacy dimensions are stored as null.chunkSize, chunkOverlap, threshold, documentCount) is migrated on a best-effort basis:
chunkSize / chunkOverlap values are replaced with defaultsthreshold / documentCount are clearedknowledge_item flat and uses optional groupId for grouping queries.null.groupId after migration.(baseId, groupId) -> (baseId, id).A common recoverable case is a legacy knowledge base whose embedding model id exists in Redux but not in the V2 user_model table. For example, Redux may contain ollama::dengcao/Qwen3-Embedding-0.6B:Q8_0 while no matching migrated user model row exists.
The migrator handles this as a recoverable failed base:
embeddingModelId = null
status = failed
error = missing_embedding_model
The base and its knowledge_item rows are preserved. KnowledgeVectorMigrator skips vectors for this base because the embedding model contract cannot be verified.
User recovery is handled by runtime restore, not by mutating the failed base in place:
knowledge:restore-base
-> create a new knowledge base with the source base config and selected embedding model
-> copy source root items only
-> run the normal createBase + addItems indexing flow
The original failed base remains available after restore so the UI can let the user confirm success before deleting it.
sourceCounttargetCountskippedCountknowledge_item rows without valid knowledge_base.