15 KiB
Active Identity Migration & Upgrade (Merged)
Part 1: Database Migration Impact Analysis
Database Migration Impact Analysis
Current State Analysis
Existing Migration Structure
The current migration system has:
- Migration 003:
003_active_identity_and_seed_backup
- Createsactive_identity
table with basic structure - Foreign Key:
ON DELETE SET NULL
constraint - Basic Indexing: Single unique index on
id
- Bootstrapping: Auto-selects first account if
activeDid
is null/empty
Current Schema (Migration 003)
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
);
Proposed Changes Impact
1. Foreign Key Constraint Change
Current: ON DELETE SET NULL
Proposed: ON DELETE RESTRICT
Impact:
- Data Safety: Prevents accidental deletion of active account
- Migration Rewrite: Update existing migration 003
2. Automatic Timestamp Updates
Current: Manual lastUpdated
updates in code
Proposed: Database trigger for automatic updates
Impact:
- 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)
Impact:
- Performance Improvement: Faster account selection queries
- Minimal Risk: Additive change only
Implementation Strategy
Rewrite Migration 003
Since the active_identity
table is new and we're in active development, we can simply rewrite the existing migration:
{
name: "003_active_identity_and_seed_backup",
sql: `
-- Enable foreign key constraints for data integrity
PRAGMA foreign_keys = ON;
-- Add UNIQUE constraint to accounts.did for foreign key support
CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_did_unique ON accounts(did);
-- Create active_identity table with enhanced constraints
CREATE TABLE IF NOT EXISTS active_identity (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Add performance indexes
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
CREATE INDEX IF NOT EXISTS idx_accounts_pick ON accounts(dateCreated, did);
-- Seed singleton row (only if not already exists)
INSERT INTO active_identity (id, activeDid, lastUpdated)
SELECT 1, NULL, datetime('now')
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
-- Add hasBackedUpSeed field to settings
ALTER TABLE settings ADD COLUMN hasBackedUpSeed BOOLEAN DEFAULT FALSE;
-- 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
The existing validation for migration 003 needs to be enhanced to check for:
- Trigger existence:
trg_active_identity_touch
- Performance index:
idx_accounts_pick
- Foreign key constraint:
ON DELETE RESTRICT
Enhanced Schema Detection
File: src/services/migrationService.ts
The existing schema detection for migration 003 needs to be enhanced to verify:
- Table structure: Enhanced constraints
- Trigger presence: Automatic timestamp updates
- Index presence: Performance optimization
Risk Assessment
Low Risk Changes
- Performance Index: Additive only, no data changes
- Trigger Creation: Additive only, improves consistency
- Migration Rewrite: Clean implementation, no additional migrations
Medium Risk Changes
- Foreign Key Change:
ON DELETE RESTRICT
is more restrictive - Validation Updates: Need to test enhanced validation logic
Mitigation Strategies
- Comprehensive Testing: Test migration on various database states
- Development Phase: Since we're in active development, risk is minimal
- Clean Implementation: Single migration with all enhancements
- Validation Coverage: Enhanced validation ensures correctness
Implementation Timeline
Phase 1: Migration Rewrite
- Update migration 003 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
Phase 3: Deployment
- Deploy enhanced migration to development
- Monitor migration success rates
- Deploy to production
- Monitor for any issues
Code Changes Required
Files to Modify
src/db-sql/migration.ts
- Update migration 003 with enhanced constraintssrc/services/migrationService.ts
- Add enhanced validation and detection logicsrc/utils/PlatformServiceMixin.ts
- Remove manual timestamp updates
Estimated Impact
- Migration File: ~20 lines modified (enhanced constraints)
- Migration Service: ~50 lines added (enhanced validation)
- PlatformServiceMixin: ~20 lines removed (manual timestamps)
- Total: ~50 lines changed
Conclusion
The proposed database changes are feasible and beneficial with a much simpler implementation:
Benefits:
- Improved data integrity with
ON DELETE RESTRICT
- Automatic timestamp consistency
- Better query performance
- Cleaner code (no manual timestamp updates)
- Simpler implementation - just rewrite migration 003
Risks:
- More restrictive foreign key constraints
- Enhanced validation logic needs testing
Recommendation: Proceed with rewriting migration 003 as it provides the cleanest path forward with minimal complexity and maximum benefit.
Part 2: Active Identity System Upgrade Plan
Active Identity System Upgrade Plan
Overview
This document outlines a comprehensive upgrade to the $getActiveIdentity
system
to address current ambiguities, race conditions, and improve overall robustness.
Current Issues Identified
1. Ambiguous Return States
- Current: Returns
{ activeDid: string }
where empty string conflates multiple states - Problem: Cannot distinguish between "no accounts", "migration gap", "corruption cleared"
- Impact: UI cannot provide appropriate user guidance
2. Race Conditions (TOCTOU)
- Current: Read → Write → Re-read across multiple statements
- Problem: No transactional guard, potential for inconsistent state
- Impact: Rare but possible data corruption scenarios
3. No Single-Row Enforcement
- Current: App logic assumes
id=1
singleton, but DB doesn't enforce - Problem: Multiple rows could theoretically exist
- Impact: Unpredictable behavior
4. Deletion Hazards
- Current: No protection against deleting active account
- Problem: App "discovers" corruption after the fact
- Impact: Poor user experience, potential data loss
5. Inconsistent Updates
- Current:
lastUpdated
only set on some code paths - Problem: Audit trail incomplete
- Impact: Debugging difficulties
Proposed Solution Architecture
Database Schema Changes
-- Enhanced active_identity table with constraints
CREATE TABLE IF NOT EXISTS active_identity (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Automatic timestamp updates
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;
-- Deterministic account selection index
CREATE INDEX IF NOT EXISTS idx_accounts_pick
ON accounts(dateCreated, did);
-- Seed singleton row
INSERT INTO active_identity (id, activeDid)
SELECT 1, NULL
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
Type System Enhancement
type ActiveIdentity =
| { state: 'ok'; activeDid: string }
| { state: 'unset'; activeDid: '' } // row exists, but no active set yet
| { state: 'auto-selected'; activeDid: string } // we selected & saved first account
| { state: 'empty-accounts'; activeDid: '' } // there are no accounts to select
| { state: 'cleared-corrupt'; activeDid: '' } // DB had a non-existent DID; cleared
| { state: 'error'; activeDid: '' };
Migration Strategy
Phase 1: Database Schema Migration
Files to modify:
src/db-sql/migration.ts
- Add new migrationsrc/services/migrationService.ts
- Update validation logic
Migration Steps:
- Add foreign key constraint to
active_identity.activeDid
- Add
ON DELETE RESTRICT
constraint - Create timestamp trigger
- Add deterministic index
- Ensure singleton row exists
Risk Assessment: LOW
- Additive changes only
- Existing data preserved
- Rollback possible
Phase 2: Core Method Refactor
Files to modify:
src/utils/PlatformServiceMixin.ts
- Replace$getActiveIdentity
src/interfaces/
- Add new type definitions
Changes:
- Implement transactional
$getActiveIdentity
with explicit states - Add
$setActiveIdentity
method - Add
$deleteAccountSafely
method - Update return type to
ActiveIdentity
Risk Assessment: MEDIUM
- Breaking change to return type
- Requires coordinated updates across codebase
- Extensive testing needed
Phase 3: Consumer Updates
Files to modify:
- All Vue components using
$getActiveIdentity
- Router guards
- Service layer components
Changes:
- Update all callers to handle new return type
- Implement state-specific UI logic
- Add appropriate user messaging
Risk Assessment: HIGH
- Wide impact across codebase
- UI/UX changes required
- Extensive testing needed
Implementation Phases
Phase 1: Database Foundation
- Create migration for schema changes
- Test migration on development databases
- Validate foreign key constraints work correctly
- Test rollback scenarios
Phase 2: Core Implementation
- Implement new
$getActiveIdentity
method - Add
$setActiveIdentity
method - Add
$deleteAccountSafely
method - Create comprehensive unit tests
- Test transactional behavior
Phase 3: Consumer Updates
- Audit all current usage of
$getActiveIdentity
- Create migration guide for components
- Update critical path components first
- Implement state-specific UI logic
Phase 4: Testing & Rollout
- End-to-end testing
- Performance testing
- User acceptance testing
- Gradual rollout with feature flags
Backward Compatibility Strategy
Gradual Migration Approach
The gradual migration strategy allows us to implement the new active identity system without breaking existing functionality. This approach minimizes risk and provides a clear path for incremental updates.
Phase 1: Dual Method Implementation
- Keep existing method: Leave current
$getActiveIdentity
unchanged (no renaming) - Add new method: Implement
$getActiveIdentityV2
with new return type and logic - Feature flag control: Use
FEATURE_FLAG_ACTIVE_IDENTITY_V2
to control which method is used - Default to existing: Start with existing method enabled to ensure no breaking changes
Phase 2: Component Migration
- Audit usage: Identify all components using
$getActiveIdentity
- Create migration guide: Document the changes needed for each component type
- Update incrementally: Migrate components to use
$getActiveIdentityV2
one by one, starting with non-critical paths - Test each migration: Validate each component works with the new method before proceeding
Phase 3: Feature Flag Rollout
- Enable for migrated components: Switch feature flag for components that have been updated
- Monitor performance: Track any performance or behavior changes
- Gradual enablement: Enable the new method for more components as they're migrated
- Fallback capability: Keep legacy method available for rollback if issues arise
Phase 4: Legacy Cleanup
- Remove feature flag: Once all components are migrated, remove the feature flag
- Replace existing method: Replace the implementation of
$getActiveIdentity
with the V2 logic - Remove V2 method: Delete
$getActiveIdentityV2
and related code - Update documentation: Remove references to the V2 method
- Final validation: Ensure no remaining references to V2 method
Benefits of This Approach
- Zero downtime: No breaking changes during migration
- Incremental testing: Each component can be tested individually
- Easy rollback: Can revert individual components or entire system if needed
- Clear progress tracking: Easy to see which components still need migration
- Reduced risk: Issues are isolated to individual components rather than system-wide
Risk Mitigation
Database Risks
- Foreign Key Violations: Test with existing data
- Migration Failures: Comprehensive rollback plan
- Performance Impact: Monitor query performance
Code Risks
- Breaking Changes: Extensive testing, gradual rollout
- Race Conditions: Comprehensive unit tests
- State Management: Clear documentation, examples
User Experience Risks
- Confusing States: Clear UI messaging
- Data Loss: Backup strategies, validation
- Performance: Monitor response times
Success Metrics
Technical Metrics
- Zero race condition incidents
- 100% test coverage for new methods
- <50ms average response time
- Zero data corruption incidents
User Experience Metrics
- Clear state-specific messaging
- Reduced user confusion
- Improved onboarding flow
- Faster account switching
Rollback Plan
Database Rollback
- Remove foreign key constraints
- Remove triggers
- Remove indexes
- Restore previous migration state
Code Rollback
- Revert to previous
$getActiveIdentity
implementation - Remove new type definitions
- Restore previous component logic
- Remove new methods
Testing Strategy
Unit Tests
- Test all state transitions
- Test transactional behavior
- Test error conditions
- Test edge cases
Integration Tests
- Test with real database
- Test migration scenarios
- Test concurrent access
- Test foreign key constraints
End-to-End Tests
- Test complete user flows
- Test account creation/deletion
- Test active identity switching
- Test error recovery
Documentation Requirements
Developer Documentation
- Migration guide for components
- API documentation for new methods
- Type definitions and examples
- Best practices guide
User Documentation
- State-specific UI messaging
- Error message guidelines
- Onboarding flow updates
- Troubleshooting guide
Conclusion
This upgrade addresses critical architectural issues while providing a clear path forward. The phased approach minimizes risk while ensuring thorough testing and validation at each step.
Recommendation: Proceed with Phase 1 (Database Schema) immediately, as it provides immediate benefits with minimal risk. The gradual migration approach allows for incremental updates without breaking existing functionality.