Skip to content

Storage Schema

NodeWarden's D1 schema has two sources:

  • migrations/0001_init.sql: initial migration file.
  • src/services/storage-schema.ts: runtime automatic initialization and schema completion.

They must stay in sync.

Schema version

src/services/storage.ts contains:

ts
const STORAGE_SCHEMA_VERSION_KEY = 'schema.version';
const STORAGE_SCHEMA_VERSION = '...';

When the Worker initializes, it reads config.schema.version. If the value differs, it runs ensureStorageSchema() and writes the new version.

When adding tables, columns, or indexes, bump STORAGE_SCHEMA_VERSION. Otherwise old instances will not rerun schema initialization.

Main tables

TablePurpose
configRuntime config, schema version, backup config, and run locks.
usersUsers, master password verification hash, encrypted key, role, status, TOTP, API key.
domain_settingsUser domain matching rules.
user_revisionsPer-user vault revision date.
foldersFolders.
ciphersCipher body and encrypted JSON.
attachmentsAttachment metadata.
sendsSend records.
refresh_tokensRefresh token hash and device binding.
invitesInvite codes.
audit_logsAudit logs.
devicesDevices, session stamp, and device encryption key.
trusted_two_factor_device_tokensRemembered-device token hashes.
login_attempts_ipLogin failures and temporary lockouts.
used_attachment_download_tokensOne-time attachment and Send file download token consumption.

Foreign keys and indexes

Vault core tables are isolated by user and have common indexes:

  • idx_ciphers_user_updated
  • idx_ciphers_user_archived
  • idx_ciphers_user_deleted
  • idx_ciphers_user_deleted_updated
  • idx_ciphers_user_folder
  • idx_folders_user_updated
  • idx_attachments_cipher
  • idx_sends_user_updated
  • idx_sends_user_deletion

These indexes directly affect /api/sync, paginated lists, trash, archive, and bulk operation performance.

D1 bind detail

D1 .bind() does not accept undefined. StorageService.safeBind() converts undefined to null, preventing runtime errors when clients submit unknown or omitted fields.

Persistent data checklist

When adding a table or field:

  1. Update migrations/0001_init.sql.
  2. Update src/services/storage-schema.ts.
  3. Bump STORAGE_SCHEMA_VERSION.
  4. Decide whether it belongs in instance backups.
  5. If backed up, update backup-archive.ts, backup-import.ts, and frontend backup types.
  6. Decide whether /api/sync is affected.
  7. Decide whether audit logs or rate limits are needed.

Do not mistake runtime tables for migratable data. refresh_tokens, devices, trusted_two_factor_device_tokens, login_attempts_ip, used_attachment_download_tokens, backup run locks, and audit logs are current-instance runtime state and do not enter instance backups by default.

Released under the LGPL-3.0 License.