Database
KatanOS is local-first. There is no server database.
Persistence is split into:
services/storage.ts(raw key/value storage adapter)services/db.ts(typed domain API)
Storage Layer (services/storage.ts)
services/storage.ts)Configuration:
IndexedDB database:
katanos_storageobject store:
kvmigration flag:
katanos_idb_migrated_v1
Behavior:
loads all key/value pairs into in-memory cache on init
migrates known keys from localStorage to IndexedDB once
falls back to localStorage when IndexedDB is unavailable
Public API:
initStorage(migrateKeys)storageGetRaw(key)storageSetRaw(key, value)storageRemoveRaw(key)getStorageStatus()
Domain Layer (services/db.ts)
services/db.ts)db namespaces:
autheventstodoscheckliststransactionsfinanceBudgetsfinanceGoalsfinanceDebtsfinanceRecurringcontactshabitsjournalbooksvaultautosavecreateUserBackupPayloadrestore
Canonical Data Keys
Data Schema Reference
The table below is the practical schema index for persistence and restore operations.
chronos_users
User[]
global
user record by id
includes profile/settings/security fields
chronos_current_user
User (single)
runtime-global
active user snapshot
not an array
chronos_events
CalendarEvent[]
shared collection
per-item userId
agenda module
chronos_todos
TodoItem[]
shared collection
per-item userId
sticky todos
chronos_checklists
Checklist[]
shared collection
per-item userId
todo sub-domain
chronos_transactions
Transaction[]
shared collection
per-item userId
finance ledger
chronos_finance_budgets
FinanceBudget[]
shared collection
per-item userId
finance planning
chronos_finance_goals
FinanceGoal[]
shared collection
per-item userId
savings goals
chronos_finance_debts
FinanceDebt[]
shared collection
per-item userId
debt tracker
chronos_finance_recurring
FinanceRecurring[]
shared collection
per-item userId
recurring entries
chronos_contacts
Contact[]
shared collection
per-item userId
contacts module
chronos_habits
Habit[]
shared collection
per-item userId
habits module
chronos_journal
JournalEntry[]
shared collection
per-item userId
journal module
chronos_books
Book[]
shared collection
per-item userId
bookshelf module
chronos_vault
EncryptedVault[]
shared collection
per-item userId
encrypted blobs, special handling in delete/restore
Schema invariants used across modules:
all domain entities except
Userandchronos_current_userare persisted as arraysper-user separation is done by filtering
item.userIdIDs are generated as UUIDs for new records
timestamps are stored as ISO strings
Data Contracts
Primary interfaces are defined in types.ts.
Major entities:
UserCalendarEventTodoItemChecklistTransactionFinanceBudgetFinanceGoalFinanceDebtFinanceRecurringContactHabitJournalEntryBookEncryptedVault
User Isolation Model
Most collections are shared arrays keyed by userId and filtered on read.
Pattern used in list methods:
Authentication and Account Data
Auth behavior (db.auth):
case-insensitive username matching
login/register/update settings
password reset via security question/answer
lock-PIN verification
Hashing parameters in db.ts:
scheme: PBKDF2-SHA256
iterations:
150000salt bytes:
16hash bytes:
32stored format:
pbkdf2$<iterations>$<saltBase64>$<hashBase64>
Compatibility fallback:
if Web Crypto is unavailable, secrets may be stored in plain text (documented limitation)
Vault Persistence Behavior
db.vault stores encrypted vault blobs (EncryptedVault) per user id.
Special handling:
legacy vault entries without
userIdare migrated to current user on readdb.auth.deleteUserDatacurrently removes the entire vault key (chronos_vault), not only one user slice
Backup Payloads (db.ts)
db.ts)db can build backup payloads with:
scope: 'all'via internalbuildBackupPayloadscope: 'user'viacreateUserBackupPayload(userId)
Payload structure includes:
version
timestamp
userId
currentUser
scope
datacollectionsextrasweather location keys
cloud backup keys
app localStorage keys
Backup payload shape (effective contract):
Contributor note:
when adding a new persistent domain, update
DATA_KEYS, backup build/filter logic, and restore branches togetherif restore rules differ between
scope: 'user'andscope: 'all', document both explicitly
Restore Semantics (db.restore)
db.restore)User-scope restore (scope: 'user')
scope: 'user')merges imported records for target user
keeps records for other users
may overwrite vault with incoming
data.vaultcan restore
currentUserand extras
Full-scope restore (non-user scope)
replaces most collection keys directly when present
restores extras
Important implementation detail:
full-scope branch does not currently write
chronos_vaultexplicitly
Autosave and Electron Snapshot Notes
db.set(...) triggers autosave via window.katanos.saveSnapshot(...) when Electron bridge is available.
Electron main process serializes autosave/export folder data using USER_DATA_FILES:
eventstodostransactionscontactshabitsjournal
So Electron-side autosave/export-folder artifacts currently do not include all db domains (for example checklists, finance planning entities, books, vault).
Auxiliary LocalStorage Keys (non-canonical)
Examples used by modules/components:
katanos_weather_loc_<userId>katanos_emoji_recentkatanos_last_login_langkatanos_last_login_themekatanos_login_bgkatanos_pomodoro_<userId>katanos.readingGoal.<userId>chronos_notified_events(sessionStorage)
Failure and Quota Behavior
On quota errors, db.ts dispatches katanos:notify storage warnings.
Storage write/read failures are generally caught with console warnings/errors to keep UI running.
Last updated
Was this helpful?
