15 KiB
Active Identity Upgrade Plan
Author: Matthew Raymer
Date: 2025-09-11
Status: 🎯 PLANNING - Database migration and active identity system upgrade
Overview
Comprehensive upgrade to the active identity system, addressing architectural issues and implementing enhanced database constraints. Includes database migration enhancements and settings table cleanup based on team feedback.
Implementation Status
✅ COMPLETED: Migration structure updated according to team member feedback
Implemented Changes
- ✅ Migration 003:
003_add_hasBackedUpSeed_to_settings
- AddshasBackedUpSeed
column to settings (assumes master deployment) - ✅ Migration 004:
004_active_identity_and_seed_backup
- Createsactive_identity
table with data migration - ✅ Migration Service: Updated validation and schema detection logic for new migration structure
- ✅ TypeScript: Fixed type compatibility issues
Migration Structure Now Follows Team Guidance
- Migration 003:
003_add_hasBackedUpSeed_to_settings
(assumes master code deployed) - Migration 004:
004_active_identity_and_seed_backup
(creates active_identity table) - All migrations are additional - no editing of previous migrations
- Data migration logic preserves existing
activeDid
from settings - iOS/Android compatibility confirmed with SQLCipher 4.9.0 (SQLite 3.44.2)
Educational Context
Why This Upgrade Matters
The active identity system is critical infrastructure affecting every user interaction:
- Data Integrity: Current
ON DELETE SET NULL
allows accidental deletion of active accounts - Manual Maintenance: Timestamps require manual updates, creating inconsistency opportunities
- Architectural Clarity: Separating active identity from user settings improves maintainability
What This Upgrade Achieves
- Prevents Data Loss:
ON DELETE RESTRICT
prevents accidental account deletion - Automatic Consistency: Database triggers ensure timestamps are always current
- Cleaner Architecture: Complete separation of identity management from user preferences
- Better Performance: Optimized indexes for faster account selection
Current State Analysis
Existing Migration Structure
- Migration 003:
003_add_hasBackedUpSeed_to_settings
- AddshasBackedUpSeed
column to settings (already deployed in master) - Migration 004:
004_active_identity_and_seed_backup
- Createsactive_identity
table with data migration - Foreign Key:
ON DELETE SET NULL
constraint - Data Migration: Copies existing
activeDid
from settings toactive_identity
table - Bootstrapping: Auto-selects first account if
activeDid
is null/empty
Important: All migrations are additional - no editing of previous migrations since master code has been deployed.
Current Schema (Migration 004) - IMPLEMENTED
-- Migration 004: active_identity_and_seed_backup
-- Assumes master code deployed with migration 003
PRAGMA foreign_keys = ON;
CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_did_unique ON accounts(did);
CREATE TABLE IF NOT EXISTS active_identity (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT DEFAULT NULL,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (activeDid) REFERENCES accounts(did) ON DELETE SET NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
-- Seed singleton row
INSERT INTO active_identity (id, activeDid, lastUpdated)
SELECT 1, NULL, datetime('now')
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
-- MIGRATE EXISTING DATA: Copy activeDid from settings
UPDATE active_identity
SET activeDid = (SELECT activeDid FROM settings WHERE id = 1),
lastUpdated = datetime('now')
WHERE id = 1
AND EXISTS (SELECT 1 FROM settings WHERE id = 1 AND activeDid IS NOT NULL AND activeDid != '');
Current Implementation Details
PlatformServiceMixin.ts Implementation
The current $getActiveIdentity()
method in src/utils/PlatformServiceMixin.ts
:
async $getActiveIdentity(): Promise<{ activeDid: string }> {
try {
const result = await this.$dbQuery("SELECT activeDid FROM active_identity WHERE id = 1");
if (!result?.values?.length) {
logger.warn("[PlatformServiceMixin] Active identity table is empty - migration issue");
return { activeDid: "" };
}
const activeDid = result.values[0][0] as string | null;
// Handle null activeDid - auto-select first account
if (activeDid === null) {
const firstAccount = await this.$dbQuery("SELECT did FROM accounts ORDER BY dateCreated, did LIMIT 1");
if (firstAccount?.values?.length) {
const firstAccountDid = firstAccount.values[0][0] as string;
await this.$dbExec("UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", [firstAccountDid]);
return { activeDid: firstAccountDid };
}
logger.warn("[PlatformServiceMixin] No accounts available for auto-selection");
return { activeDid: "" };
}
// Validate activeDid exists in accounts
const accountExists = await this.$dbQuery("SELECT did FROM accounts WHERE did = ?", [activeDid]);
if (accountExists?.values?.length) {
return { activeDid };
}
// Clear corrupted activeDid and return empty
logger.warn("[PlatformServiceMixin] Active identity not found in accounts, clearing");
await this.$dbExec("UPDATE active_identity SET activeDid = NULL, lastUpdated = datetime('now') WHERE id = 1");
return { activeDid: "" };
} catch (error) {
logger.error("[PlatformServiceMixin] Error getting active identity:", error);
return { activeDid: "" };
}
}
Key Implementation Notes
- Null Handling: Auto-selects first account when
activeDid
is null - Corruption Detection: Clears invalid
activeDid
values - Manual Timestamps: Updates
lastUpdated
manually in code - Error Handling: Returns empty string on any error with appropriate logging
Proposed Changes Impact
1. Foreign Key Constraint Change
Current: ON DELETE SET NULL
→ Proposed: ON DELETE RESTRICT
- Data Safety: Prevents accidental deletion of active account
- New Migration: Add migration 005 to update constraint
2. Automatic Timestamp Updates
Current: Manual lastUpdated
updates → Proposed: Database trigger
- Code Simplification: Remove manual timestamp updates from
PlatformServiceMixin
- Consistency: Ensures
lastUpdated
is always current
3. Enhanced Indexing
Current: Single unique index on id
→ Proposed: Additional index on accounts(dateCreated, did)
- Performance Improvement: Faster account selection queries
- Minimal Risk: Additive change only
Implementation Strategy
Add Migration 005
Since the active_identity
table already exists and is working, we can add a new migration to enhance it:
{
name: "005_active_identity_enhancements",
sql: `
PRAGMA foreign_keys = ON;
-- Recreate table with ON DELETE RESTRICT constraint
CREATE TABLE active_identity_new (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Copy existing data
INSERT INTO active_identity_new (id, activeDid, lastUpdated)
SELECT id, activeDid, lastUpdated FROM active_identity;
-- Replace old table
DROP TABLE active_identity;
ALTER TABLE active_identity_new RENAME TO active_identity;
-- Add performance indexes
CREATE INDEX IF NOT EXISTS idx_accounts_pick ON accounts(dateCreated, did);
-- Create automatic timestamp trigger
CREATE TRIGGER IF NOT EXISTS trg_active_identity_touch
AFTER UPDATE ON active_identity
FOR EACH ROW
BEGIN
UPDATE active_identity
SET lastUpdated = datetime('now')
WHERE id = 1;
END;
`
}
Migration Service Updates Required
Enhanced Validation Logic
File: src/services/migrationService.ts
Migration 004 validation:
- Table existence:
SELECT name FROM sqlite_master WHERE type='table' AND name='active_identity'
- Column structure:
SELECT id, activeDid, lastUpdated FROM active_identity LIMIT 1
- Schema detection: Uses
isSchemaAlreadyPresent()
to check if migration was already applied
Migration 005 validation:
- Trigger existence:
trg_active_identity_touch
- Performance index:
idx_accounts_pick
- Foreign key constraint:
ON DELETE RESTRICT
- Table recreation: Verify table was successfully recreated
Enhanced Schema Detection
Migration 004 verification:
- Table structure: Checks
active_identity
table exists and has correct columns - Data integrity: Validates that the table can be queried successfully
- Migration tracking: Uses
isSchemaAlreadyPresent()
to avoid re-applying migrations
Migration 005 verification:
- Table structure: Enhanced constraints with
ON DELETE RESTRICT
- Trigger presence: Automatic timestamp updates
- Index presence: Performance optimization
- Data integrity: Existing data was preserved during table recreation
Risk Assessment
Low Risk Changes
- Performance Index: Additive only, no data changes
- Trigger Creation: Additive only, improves consistency
- New Migration: Clean implementation, no modification of existing migrations
Medium Risk Changes
- Foreign Key Change:
ON DELETE RESTRICT
is more restrictive - Table Recreation: Requires careful data preservation
- Validation Updates: Need to test enhanced validation logic
Mitigation Strategies
- Comprehensive Testing: Test migration on various database states
- Data Preservation: Verify existing data is copied correctly
- Clean Implementation: New migration with all enhancements
- Validation Coverage: Enhanced validation ensures correctness
- Rollback Plan: Can drop new table and restore original if needed
Implementation Timeline
Phase 1: Migration Enhancement
- Add migration 005 with enhanced constraints
- Add enhanced validation logic
- Add enhanced schema detection logic
- Test migration on clean database
Phase 2: Testing
- Test migration on existing databases
- Validate foreign key constraints work correctly
- Test trigger functionality
- Test performance improvements
- Verify data preservation during table recreation
Phase 3: Deployment
- Deploy enhanced migration to development
- Monitor migration success rates
- Deploy to production
- Monitor for any issues
Phase 4: Settings Table Cleanup
- Create migration 006 to clean up settings table
- Remove orphaned settings records (accountDid is null)
- Clear any remaining activeDid values in settings
- Consider removing activeDid column entirely (future task)
Settings Table Cleanup Strategy
Current State Analysis
The settings table currently contains:
- Legacy activeDid column: Still present from original design
- Orphaned records: Settings with
accountDid = null
that may be obsolete - Redundant data: Some settings may have been copied unnecessarily
Based on team feedback, the cleanup should include:
-
Remove orphaned settings records:
DELETE FROM settings WHERE accountDid IS NULL;
-
Clear any remaining activeDid values:
UPDATE settings SET activeDid = NULL;
-
Future consideration: Remove the activeDid column entirely from settings table
Migration 006: Settings Cleanup
{
name: "006_settings_cleanup",
sql: `
-- Remove orphaned settings records (accountDid is null)
DELETE FROM settings WHERE accountDid IS NULL;
-- Clear any remaining activeDid values in settings
UPDATE settings SET activeDid = NULL;
-- Optional: Consider removing the activeDid column entirely
-- ALTER TABLE settings DROP COLUMN activeDid;
`
}
Benefits of Settings Cleanup
- Reduced confusion: Eliminates dual-purpose columns
- Cleaner architecture: Settings table focuses only on user preferences
- Reduced storage: Removes unnecessary data
- Clearer separation: Active identity vs. user settings are distinct concerns
Risk Assessment: LOW
- Data safety: Only removes orphaned/obsolete records
- Backward compatibility: Maintains existing column structure
- Rollback: Easy to restore if needed
- Testing: Can be validated with existing data
Code Changes Required
Files to Modify
src/db-sql/migration.ts
- Add migration 005 with enhanced constraintssrc/db-sql/migration.ts
- Add migration 006 for settings cleanupsrc/services/migrationService.ts
- Add enhanced validation and detection logicsrc/utils/PlatformServiceMixin.ts
- Remove manual timestamp updates
Estimated Impact
- Migration File: ~25 lines added (migration 005) + ~15 lines added (migration 006)
- Migration Service: ~50 lines added (enhanced validation)
- PlatformServiceMixin: ~20 lines removed (manual timestamps)
- Total: ~90 lines changed
Conclusion
✅ IMPLEMENTATION COMPLETE: The active identity upgrade plan has been successfully applied to the current project.
Successfully Implemented
✅ Migration Structure Updated:
- Migration 003:
003_add_hasBackedUpSeed_to_settings
(assumes master deployment) - Migration 004:
004_active_identity_and_seed_backup
(creates active_identity table) - All migrations are additional - follows team member feedback exactly
✅ Technical Implementation:
- Data Migration: Preserves existing
activeDid
from settings table - Foreign Key Constraints:
ON DELETE SET NULL
for data safety - iOS/Android Compatibility: Confirmed with SQLCipher 4.9.0 (SQLite 3.44.2)
- Migration Service: Updated validation and schema detection logic
✅ Code Quality:
- TypeScript: All type errors resolved
- Linting: No linting errors
- Team Guidance: Follows "additional migrations only" requirement
Next Steps (Future Enhancements)
The foundation is now in place for future enhancements:
- Migration 005:
005_active_identity_enhancements
(ON DELETE RESTRICT, triggers, indexes) - Migration 006:
006_settings_cleanup
(remove orphaned settings, clear legacy activeDid) - Code Simplification: Remove manual timestamp updates from PlatformServiceMixin
Current Status
Migration 004 is ready for deployment and will:
- ✅ Create
active_identity
table with proper constraints - ✅ Migrate existing
activeDid
data from settings - ✅ Work identically on iOS and Android
- ✅ Follow team member feedback for additional migrations only
Key Point: All migrations are additional - no editing of previous migrations since master code has been deployed. This ensures compatibility and proper testing.
Status: Ready for team review and implementation approval
Last Updated: 2025-09-11
Next Review: After team feedback and approval