-- Encrypt existing plaintext Account tokens -- This migration adds an encryption_version column and marks existing records for encryption -- The actual encryption happens via Prisma middleware on first read/write -- Add encryption_version column to track encryption state -- NULL = not encrypted (legacy plaintext) -- 'aes' = AES-256-GCM encrypted -- 'vault' = OpenBao Transit encrypted (Phase 2) ALTER TABLE accounts ADD COLUMN IF NOT EXISTS encryption_version VARCHAR(20); -- Create index for efficient queries filtering by encryption status -- This index is also declared in Prisma schema (@@index([encryptionVersion])) -- Using CREATE INDEX IF NOT EXISTS for idempotency CREATE INDEX IF NOT EXISTS "accounts_encryption_version_idx" ON accounts(encryption_version); -- Verify index was created successfully by running: -- SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'accounts' AND indexname = 'accounts_encryption_version_idx'; -- Update statistics for query planner ANALYZE accounts; -- Migration Note: -- This migration does NOT encrypt data in-place to avoid downtime and data corruption risks. -- Instead, the Prisma middleware (account-encryption.middleware.ts) handles encryption: -- -- 1. On READ: Detects format (plaintext vs encrypted) and decrypts if needed -- 2. On WRITE: Encrypts tokens and sets encryption_version = 'aes' -- 3. Backward compatible: Plaintext tokens (encryption_version = NULL) are passed through unchanged -- -- To actively encrypt existing tokens, run the companion script: -- node scripts/encrypt-account-tokens.js -- -- This approach ensures: -- - Zero downtime migration -- - No risk of corrupting tokens during bulk encryption -- - Progressive encryption as tokens are accessed/refreshed -- - Easy rollback (middleware is idempotent)