From a2e6ae5c28fb885bf6a2c0f0da4830b9bb4185f5 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Sat, 30 Aug 2025 04:28:15 +0000 Subject: [PATCH] docs(migration): restructure activeDid migration plan for implementation Transform verbose planning document into actionable implementation guide: - Replace theoretical sections with specific code changes required - Add missing $getActiveIdentity() method implementation - List 35+ components requiring activeDid pattern updates - Include exact code patterns to replace in components - Add implementation checklist with clear phases - Remove redundant architecture diagrams and explanations Focuses on practical implementation steps rather than planning theory. --- doc/activeDid-migration-plan.md | 616 ++++++++++++-------------------- 1 file changed, 229 insertions(+), 387 deletions(-) diff --git a/doc/activeDid-migration-plan.md b/doc/activeDid-migration-plan.md index 9329a6f5..0b954e99 100644 --- a/doc/activeDid-migration-plan.md +++ b/doc/activeDid-migration-plan.md @@ -1,91 +1,50 @@ -# ActiveDid Migration Plan - Separate Table Architecture +# ActiveDid Migration Plan - Implementation Guide **Author**: Matthew Raymer **Date**: 2025-08-29T08:03Z -**Status**: 🎯 **PLANNING** - Active migration planning phase +**Status**: 🎯 **IMPLEMENTATION** - Ready for development ## Objective -Move the `activeDid` field from the `settings` table to a dedicated -`active_identity` table to improve database architecture, prevent data corruption, -and separate identity selection from user preferences. +Move the `activeDid` field from the `settings` table to a dedicated `active_identity` table to improve database architecture, prevent data corruption, and separate identity selection from user preferences. ## Result -This document serves as the comprehensive planning and implementation -guide for the ActiveDid migration with enhanced data integrity and -rollback capabilities. +This document provides the specific implementation steps required to complete the ActiveDid migration with all necessary code changes. ## Use/Run -Reference this document during implementation to ensure all migration -steps are followed correctly and all stakeholders are aligned on the -approach. +Follow this implementation checklist step-by-step to complete the migration. ## Context & Scope -- **In scope**: - - Database schema modification for active_identity table with proper constraints - - Migration of existing activeDid data with validation - - Updates to PlatformServiceMixin API layer - - Type definition updates - - Testing across all platforms - - Comprehensive rollback procedures -- **Out of scope**: - - Changes to user interface for identity selection - - Modifications to identity creation logic - - Changes to authentication flow - - Updates to individual components (handled by API layer) - -## Environment & Preconditions - -- **OS/Runtime**: All platforms (Web, Electron, iOS, Android) -- **Versions/Builds**: Current development branch, SQLite database -- **Services/Endpoints**: Local database, PlatformServiceMixin -- **Auth mode**: Existing authentication system unchanged - -## Architecture / Process Overview - -The migration follows a phased approach to minimize risk and ensure -data integrity with enhanced validation and rollback capabilities: - -```mermaid -flowchart TD - A[Current State
activeDid in settings] --> B[Phase 1: Schema Creation
Add active_identity table with constraints] - B --> C[Phase 2: Data Migration
Copy activeDid data with validation] - C --> D[Phase 3: API Updates
Update PlatformServiceMixin methods] - D --> E[Phase 4: Cleanup
Remove activeDid from settings] - E --> F[Final State
Separate active_identity table] - - G[Enhanced Rollback Plan
Schema and data rollback] --> H[Data Validation
Verify integrity at each step] - H --> I[Platform Testing
Test all platforms] - I --> J[Production Deployment
Gradual rollout with monitoring] - - K[Foreign Key Constraints
Prevent future corruption] --> L[Performance Optimization
Proper indexing] - L --> M[Error Recovery
Graceful failure handling] -``` +- **In scope**: Database migration, API updates, component updates, testing +- **Out of scope**: UI changes, authentication flow changes, MASTER_SETTINGS_KEY elimination (future improvement) -## Interfaces & Contracts +## Implementation Checklist -### Database Schema Changes +### Phase 1: Database Migration ✅ +- [x] Add migration to MIGRATIONS array +- [x] Create active_identity table with constraints -| Table | Current Schema | New Schema | Migration Required | -|-------|----------------|------------|-------------------| -| `settings` | `activeDid TEXT` | Field removed | Yes - data migration | -| `active_identity` | Does not exist | New table with `activeDid TEXT` + constraints | Yes - table creation | +### Phase 2: API Layer Updates ❌ +- [ ] Implement `$getActiveIdentity()` method +- [ ] Update `$accountSettings()` to use new table +- [ ] Update `$updateActiveDid()` with dual-write pattern -### Enhanced API Contract Changes +### Phase 3: Component Updates ❌ +- [ ] Update 35+ components to use `$getActiveIdentity()` +- [ ] Replace `this.activeDid = settings.activeDid` pattern +- [ ] Test each component individually -| Method | Current Behavior | New Behavior | Breaking Change | -|---------|------------------|--------------|-----------------| -| `$accountSettings()` | Returns settings with activeDid | Returns settings with activeDid from new table | No - backward compatible | -| `$saveSettings()` | Updates settings.activeDid | Updates active_identity.activeDid | Yes - requires updates | -| `$updateActiveDid()` | Updates internal tracking | Updates active_identity table | Yes - requires updates | -| `$getActiveIdentity()` | Does not exist | New method for active identity management | No - new functionality | +### Phase 4: Testing ❌ +- [ ] Test all platforms (Web, Electron, iOS, Android) +- [ ] Test migration rollback scenarios +- [ ] Test data corruption recovery -## Repro: End-to-End Procedure +## Required Code Changes -### Phase 1: Enhanced Schema Creation via migration.ts +### 1. Database Migration ```typescript // Add to MIGRATIONS array in src/db-sql/migration.ts @@ -110,68 +69,50 @@ flowchart TD }, ``` -### Phase 2: Enhanced Data Migration with Validation +### 2. Missing API Method Implementation ```typescript -// Enhanced migration function with comprehensive validation -async function migrateActiveDidToSeparateTable(): Promise { - const result: MigrationResult = { - success: false, - errors: [], - warnings: [], - dataMigrated: 0 - }; - +// Add to PlatformServiceMixin.ts +async $getActiveIdentity(): Promise<{ activeDid: string }> { try { - // 1. Get current activeDid from settings (legacy approach) - const currentSettings = await retrieveSettingsForDefaultAccount(); - const activeDid = currentSettings.activeDid; - - if (!activeDid) { - result.warnings.push("No activeDid found in current settings"); - return result; - } - - // 2. Validate activeDid exists in accounts table - const accountExists = await dbQuery( - "SELECT did FROM accounts WHERE did = ?", - [activeDid] + const result = await this.$dbQuery( + "SELECT activeDid FROM active_identity WHERE id = 1" ); - - if (!accountExists?.values?.length) { - result.errors.push(`ActiveDid ${activeDid} not found in accounts table - data corruption detected`); - return result; + + if (result?.values?.length) { + const activeDid = result.values[0][0] as string; + + // Validate activeDid exists in accounts + if (activeDid) { + const accountExists = await this.$dbQuery( + "SELECT did FROM accounts WHERE did = ?", + [activeDid] + ); + + if (accountExists?.values?.length) { + return { activeDid }; + } else { + // Clear corrupted activeDid + await this.$dbExec( + "UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" + ); + return { activeDid: "" }; + } + } } - - // 3. Update active_identity table (new system) - await dbExec( - "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", - [activeDid] - ); - - // 4. Ensure legacy settings.activeDid stays in sync (backward compatibility) - // This maintains compatibility with IndexedDB migration service - await dbExec( - "UPDATE settings SET activeDid = ? WHERE id = ?", - [activeDid, MASTER_SETTINGS_KEY] - ); - - dataMigrated = 1; - result.warnings.push(`Successfully migrated activeDid: ${activeDid}`); + return { activeDid: "" }; } catch (error) { - result.errors.push(`Migration failed: ${error}`); - logger.error("[ActiveDid Migration] Critical error during migration:", error); + logger.error("[PlatformServiceMixin] Error getting active identity:", error); + return { activeDid: "" }; } - - return result; } ``` -### Phase 3: Focused API Updates with Dual-Write Pattern +### 3. Updated $accountSettings Method ```typescript -// Updated PlatformServiceMixin method - maintains backward compatibility +// Update in PlatformServiceMixin.ts async $accountSettings(did?: string, defaults: Settings = {}): Promise { try { // Get settings without activeDid (unchanged logic) @@ -182,7 +123,7 @@ async $accountSettings(did?: string, defaults: Settings = {}): Promise } // Get activeDid from new table (new logic) - const activeIdentity = await this._getActiveIdentity(); + const activeIdentity = await this.$getActiveIdentity(); // Return combined result (maintains backward compatibility) return { ...settings, activeDid: activeIdentity.activeDid }; @@ -191,164 +132,161 @@ async $accountSettings(did?: string, defaults: Settings = {}): Promise return defaults; } } +``` -// Enhanced update activeDid method with dual-write pattern -async $updateActiveDid(newDid: string | null): Promise { - try { - if (newDid === null) { - // Clear active identity in both tables - await this.$dbExec( - "UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" - ); - - // Keep legacy field in sync (backward compatibility) - await this.$dbExec( - "UPDATE settings SET activeDid = '' WHERE id = ?", - [MASTER_SETTINGS_KEY] - ); - } else { - // Validate DID exists before setting - const accountExists = await this.$dbQuery( - "SELECT did FROM accounts WHERE did = ?", - [newDid] - ); +### 4. Component Updates Required - if (!accountExists?.values?.length) { - logger.error(`[PlatformServiceMixin] Cannot set activeDid to non-existent DID: ${newDid}`); - return false; - } +**35+ components need this pattern change:** - // Update active identity in new table - await this.$dbExec( - "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", - [newDid] - ); - - // Keep legacy field in sync (backward compatibility) - await this.$dbExec( - "UPDATE settings SET activeDid = ? WHERE id = ?", - [newDid, MASTER_SETTINGS_KEY] - ); - } +```typescript +// CURRENT PATTERN (replace in all components): +this.activeDid = settings.activeDid || ""; - // Update internal tracking - await this._updateInternalActiveDid(newDid); - return true; - } catch (error) { - logger.error("[PlatformServiceMixin] Error updating activeDid:", error); - return false; - } -} +// NEW PATTERN (use in all components): +const activeIdentity = await this.$getActiveIdentity(); +this.activeDid = activeIdentity.activeDid || ""; ``` -### **Master Settings Functions Implementation Strategy** - -#### **1. Update `retrieveSettingsForDefaultAccount()`** +**Components requiring updates:** + +#### Views (25 components) +- `src/views/DIDView.vue` (line 378) +- `src/views/TestView.vue` (line 654) +- `src/views/ContactAmountsView.vue` (line 226) +- `src/views/HomeView.vue` (line 517) +- `src/views/UserProfileView.vue` (line 185) +- `src/views/ClaimView.vue` (line 730) +- `src/views/OfferDetailsView.vue` (line 435) +- `src/views/QuickActionBvcEndView.vue` (line 229) +- `src/views/SharedPhotoView.vue` (line 178) +- `src/views/ClaimReportCertificateView.vue` (line 56) +- `src/views/ProjectsView.vue` (line 393) +- `src/views/ClaimAddRawView.vue` (line 114) +- `src/views/ContactQRScanShowView.vue` (line 288) +- `src/views/InviteOneAcceptView.vue` (line 122) +- `src/views/RecentOffersToUserView.vue` (line 118) +- `src/views/NewEditProjectView.vue` (line 380) +- `src/views/GiftedDetailsView.vue` (line 443) +- `src/views/ProjectViewView.vue` (line 782) +- `src/views/ContactsView.vue` (line 296) +- `src/views/ContactQRScanFullView.vue` (line 267) +- `src/views/NewActivityView.vue` (line 204) +- `src/views/ClaimCertificateView.vue` (line 42) +- `src/views/ContactGiftingView.vue` (line 166) +- `src/views/RecentOffersToUserProjectsView.vue` (line 126) +- `src/views/InviteOneView.vue` (line 285) +- `src/views/IdentitySwitcherView.vue` (line 202) +- `src/views/AccountViewView.vue` (line 1052) +- `src/views/ConfirmGiftView.vue` (line 549) +- `src/views/ContactImportView.vue` (line 342) + +#### Components (10 components) +- `src/components/OfferDialog.vue` (line 177) +- `src/components/PhotoDialog.vue` (line 270) +- `src/components/GiftedDialog.vue` (line 223) +- `src/components/MembersList.vue` (line 234) +- `src/components/OnboardingDialog.vue` (line 272) +- `src/components/ImageMethodDialog.vue` (line 502) +- `src/components/FeedFilters.vue` (line 89) + +**Implementation Strategy:** + +1. **Systematic Replacement**: Use grep search to find all instances +2. **Pattern Matching**: Replace `this.activeDid = settings.activeDid` with new pattern +3. **Error Handling**: Ensure proper error handling in each component +4. **Testing**: Test each component individually after update + +**Example Component Update:** ```typescript -// Enhanced implementation with active_identity table integration -export async function retrieveSettingsForDefaultAccount(): Promise { - const platform = PlatformServiceFactory.getInstance(); - - // Get settings without activeDid - const sql = "SELECT id, accountDid, apiServer, filterFeedByNearby, filterFeedByVisible, " + - "finishedOnboarding, firstName, hideRegisterPromptOnNewContact, isRegistered, " + - "lastName, lastAckedOfferToUserJwtId, lastAckedOfferToUserProjectsJwtId, " + - "lastNotifiedClaimId, lastViewedClaimId, notifyingNewActivityTime, " + - "notifyingReminderMessage, notifyingReminderTime, partnerApiServer, " + - "passkeyExpirationMinutes, profileImageUrl, searchBoxes, showContactGivesInline, " + - "showGeneralAdvanced, showShortcutBvc, vapid, warnIfProdServer, warnIfTestServer, " + - "webPushServer FROM settings WHERE id = ?"; - - const result = await platform.dbQuery(sql, [MASTER_SETTINGS_KEY]); - - if (!result) { - return DEFAULT_SETTINGS; - } else { - const settings = mapColumnsToValues(result.columns, result.values)[0] as Settings; - - // Handle JSON parsing - if (settings.searchBoxes) { - settings.searchBoxes = JSON.parse(settings.searchBoxes); - } +// BEFORE (in any component): +private async initializeSettings() { + const settings = await this.$accountSettings(); + this.activeDid = settings.activeDid || ""; + this.apiServer = settings.apiServer || ""; +} - // Get activeDid from separate table - const activeIdentityResult = await platform.dbQuery( - "SELECT activeDid FROM active_identity WHERE id = 1" - ); +// AFTER (in any component): +private async initializeSettings() { + const settings = await this.$accountSettings(); + const activeIdentity = await this.$getActiveIdentity(); + this.activeDid = activeIdentity.activeDid || ""; + this.apiServer = settings.apiServer || ""; +} +``` - if (activeIdentityResult?.values?.length) { - const activeDid = activeIdentityResult.values[0][0] as string; - if (activeDid) { - // Validate activeDid exists in accounts - const accountExists = await platform.dbQuery( - "SELECT did FROM accounts WHERE did = ?", - [activeDid] - ); - - if (accountExists?.values?.length) { - settings.activeDid = activeDid; - } else { - logger.warn(`[databaseUtil] ActiveDid ${activeDid} not found in accounts, clearing`); - // Clear corrupted activeDid - await platform.dbExec( - "UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" - ); - } - } - } +**Alternative Pattern (if settings still needed):** - return settings; - } +```typescript +// If component needs both settings and activeDid: +private async initializeSettings() { + const settings = await this.$accountSettings(); + const activeIdentity = await this.$getActiveIdentity(); + + // Use activeDid from new table + this.activeDid = activeIdentity.activeDid || ""; + + // Use other settings from settings table + this.apiServer = settings.apiServer || ""; + this.partnerApiServer = settings.partnerApiServer || ""; + // ... other settings } ``` -#### **2. Update `$getMergedSettings()` Method** +### 5. Data Migration Function ```typescript -// Enhanced implementation with active_identity table integration -async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallback: Settings = {}): Promise { +// Add to migration.ts +async function migrateActiveDidToSeparateTable(): Promise { + const result: MigrationResult = { + success: false, + errors: [], + warnings: [], + dataMigrated: 0 + }; + try { - // Get default settings (now without activeDid) - const defaultSettings = await this.$getSettings(defaultKey, defaultFallback); - - // If no account DID, return defaults with activeDid from separate table - if (!accountDid) { - if (defaultSettings) { - // Get activeDid from separate table - const activeIdentityResult = await this.$dbQuery( - "SELECT activeDid FROM active_identity WHERE id = 1" - ); + // 1. Get current activeDid from settings (legacy approach) + const currentSettings = await retrieveSettingsForDefaultAccount(); + const activeDid = currentSettings.activeDid; - if (activeIdentityResult?.values?.length) { - const activeDid = activeIdentityResult.values[0][0] as string; - if (activeDid) { - // Validate activeDid exists in accounts - const accountExists = await this.$dbQuery( - "SELECT did FROM accounts WHERE did = ?", - [activeDid] - ); - - if (accountExists?.values?.length) { - defaultSettings.activeDid = activeDid; - } else { - logger.warn(`[Settings Trace] ActiveDid ${activeDid} not found in accounts, clearing`); - // Clear corrupted activeDid - await this.$dbExec( - "UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" - ); - } - } - } - } - return defaultSettings || defaultFallback; + if (!activeDid) { + result.warnings.push("No activeDid found in current settings"); + return result; } - // ... rest of existing implementation for account-specific settings + // 2. Validate activeDid exists in accounts table + const accountExists = await dbQuery( + "SELECT did FROM accounts WHERE did = ?", + [activeDid] + ); + + if (!accountExists?.values?.length) { + result.errors.push(`ActiveDid ${activeDid} not found in accounts table - data corruption detected`); + return result; + } + + // 3. Update active_identity table (new system) + await dbExec( + "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", + [activeDid] + ); + + // 4. Ensure legacy settings.activeDid stays in sync (backward compatibility) + await dbExec( + "UPDATE settings SET activeDid = ? WHERE id = ?", + [activeDid, MASTER_SETTINGS_KEY] + ); + + result.dataMigrated = 1; + result.warnings.push(`Successfully migrated activeDid: ${activeDid}`); + } catch (error) { - logger.error(`[Settings Trace] ❌ Failed to get merged settings:`, { defaultKey, accountDid, error }); - return defaultFallback; + result.errors.push(`Migration failed: ${error}`); + logger.error("[ActiveDid Migration] Critical error during migration:", error); } + + return result; } ``` @@ -377,40 +315,38 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac - **Hypothesis**: Table needs to be created as part of migration - **Next probe**: Add migration to existing MIGRATIONS array -- ❌ **Data corruption issues** with orphaned activeDid references +- ❌ **Missing $getActiveIdentity() method** in PlatformServiceMixin + - **Time**: 2025-08-29T08:03Z + - **Evidence**: Method referenced in plan but not implemented + - **Hypothesis**: Method needs to be added to PlatformServiceMixin + - **Next probe**: Implement method with proper error handling + +- ❌ **35+ components need updates** to use new API - **Time**: 2025-08-29T08:03Z - - **Evidence**: `IdentitySwitcherView.vue:175` - `hasCorruptedIdentity` detection - - **Hypothesis**: Current schema allows activeDid to point to non-existent accounts - - **Next probe**: Implement foreign key constraints in new table + - **Evidence**: Grep search found 35+ instances of `this.activeDid = settings.activeDid` + - **Hypothesis**: All components need to be updated to use `$getActiveIdentity()` + - **Next probe**: Update each component individually and test ## Risks, Limits, Assumptions - **Data Loss Risk**: Migration failure could lose activeDid values - **Breaking Changes**: API updates required in PlatformServiceMixin -- **Rollback Complexity**: Schema changes make rollback difficult - **Testing Overhead**: All platforms must be tested with new structure -- **Performance Impact**: Additional table join for activeDid retrieval -- **Migration Timing**: Must be coordinated with other database changes -- **Data Corruption**: Current system has documented corruption issues -- **Foreign Key Constraints**: New constraints may prevent some operations +- **Component Updates**: 35+ components need individual updates and testing -## Enhanced Rollback Strategy +## Rollback Strategy -### **Schema Rollback** +### Schema Rollback ```sql -- If migration fails, restore original schema DROP TABLE IF EXISTS active_identity; - --- Restore activeDid field to settings table if needed -ALTER TABLE settings ADD COLUMN activeDid TEXT; ``` -### **Data Rollback** +### Data Rollback ```typescript // Rollback function to restore activeDid to settings table async function rollbackActiveDidMigration(): Promise { try { - // Get activeDid from active_identity table const activeIdentityResult = await dbQuery( "SELECT activeDid FROM active_identity WHERE id = 1" ); @@ -418,7 +354,6 @@ async function rollbackActiveDidMigration(): Promise { if (activeIdentityResult?.values?.length) { const activeDid = activeIdentityResult.values[0][0] as string; - // Restore to settings table await dbExec( "UPDATE settings SET activeDid = ? WHERE id = ?", [activeDid, MASTER_SETTINGS_KEY] @@ -435,142 +370,49 @@ async function rollbackActiveDidMigration(): Promise { } ``` -### **Rollback Triggers** -- Migration validation fails -- Data integrity checks fail -- Performance regression detected -- User reports data loss -- Cross-platform inconsistencies found - ## Next Steps | Owner | Task | Exit Criteria | Target Date (UTC) | |-------|------|---------------|-------------------| -| Development Team | Add migration to existing MIGRATIONS array | Migration script integrated with existing system | 2025-08-30 | -| Development Team | Update type definitions | Settings type updated, ActiveIdentity type created | 2025-08-30 | -| Development Team | Update PlatformServiceMixin | Core methods updated and tested | 2025-08-31 | -| Development Team | Implement foreign key constraints | Schema validation prevents corruption | 2025-08-31 | +| Development Team | Add migration to MIGRATIONS array | Migration script integrated | 2025-08-30 | +| Development Team | Implement $getActiveIdentity() method | Method added to PlatformServiceMixin | 2025-08-30 | +| Development Team | Update $accountSettings method | Method updated and tested | 2025-08-30 | +| Development Team | Update 35+ components | All components use new API | 2025-08-31 | | QA Team | Platform testing | All platforms tested and verified | 2025-09-01 | | Development Team | Deploy migration | Production deployment successful | 2025-09-02 | +## Future Improvement: MASTER_SETTINGS_KEY Elimination + +**Not critical for this task** but logged for future improvement: + +```typescript +// Current: WHERE id = "1" +// Future: WHERE accountDid IS NULL + +// This eliminates the confusing concept of "master" settings +// and uses a cleaner pattern for default settings +``` + ## References - [Database Migration Guide](./database-migration-guide.md) - [Dexie to SQLite Mapping](./dexie-to-sqlite-mapping.md) - [PlatformServiceMixin Documentation](./component-communication-guide.md) -- [Migration Templates](./migration-templates/) ## Competence Hooks -- *Why this works*: Separates concerns between identity selection and - user preferences, prevents data corruption with foreign key constraints, - centralizes identity management through API layer -- *Common pitfalls*: Forgetting to implement foreign key constraints, not - testing rollback scenarios, missing data validation during migration, - over-engineering component updates when API layer handles everything -- *Next skill unlock*: Advanced database schema design with constraints, - migration planning with rollback strategies -- *Teach-back*: Explain the four-phase migration approach and why each - phase is necessary, especially the foreign key constraints +- *Why this works*: Separates concerns between identity selection and user preferences, prevents data corruption with foreign key constraints +- *Common pitfalls*: Forgetting to update all 35+ components, not implementing $getActiveIdentity() method, missing data validation during migration +- *Next skill unlock*: Systematic component updates with grep search and testing +- *Teach-back*: Explain why all components need updates and how to systematically find and replace the pattern ## Collaboration Hooks +- **Reviewers**: Database team, PlatformServiceMixin maintainers, QA team - **Sign-off checklist**: - [ ] Migration script integrated with existing MIGRATIONS array - - [ ] Foreign key constraints implemented and tested - - [ ] PlatformServiceMixin updated and tested + - [ ] $getActiveIdentity() method implemented and tested + - [ ] All 35+ components updated to use new API - [ ] Rollback procedures validated - - [ ] Performance impact assessed - - [ ] All stakeholders approve deployment timeline - -## Assumptions & Limits - -- Current activeDid values are valid and should be preserved -- All platforms can handle the additional database table -- Migration can be completed without user downtime -- Rollback to previous schema is acceptable if needed -- Performance impact of additional table join is minimal -- Foreign key constraints will prevent future corruption -- API layer updates will handle component compatibility - -## What Needs to Change - -### **1. Database Schema via migration.ts** -- Add migration to existing MIGRATIONS array in `src/db-sql/migration.ts` -- Create `active_identity` table with foreign key constraints -- Add performance indexes -- **Keep `activeDid` field in `settings` table temporarily** for backward compatibility -- **Preserve `MASTER_SETTINGS_KEY = "1"`** for legacy migration support - -### **2. PlatformServiceMixin Methods** -- `$accountSettings()` - integrate with new table while maintaining backward compatibility -- `$saveSettings()` - handle activeDid in new table, sync with legacy field -- `$updateActiveDid()` - validate and update new table, sync with legacy field -- `$getActiveIdentity()` - new method for identity management - -### **3. Master Settings Functions** -- `retrieveSettingsForDefaultAccount()` - integrate with new table while preserving legacy support -- `$getMergedSettings()` - integrate with new table while preserving legacy support - -### **4. Type Definitions** -- **Keep `activeDid` in Settings type temporarily** for backward compatibility -- Create ActiveIdentity type for new table -- Update related interfaces - -### **5. Legacy Compatibility** -- **Preserve `MASTER_SETTINGS_KEY = "1"`** for IndexedDB migration service -- **Maintain dual-write pattern** during transition period -- **Ensure legacy clients can still migrate** from Dexie to SQLite - -## What Doesn't Need to Change - -- **All Vue components** - API layer handles migration transparently -- **Platform services** - Use PlatformServiceMixin, no direct access -- **User interface** - No changes to identity selection UI -- **Authentication flow** - Existing system unchanged -- **Component logic** - All activeDid handling through API methods -- **Migration system** - Use existing migration.ts approach, not separate files -- **IndexedDB migration service** - Must continue working for legacy clients - -## Enhanced Architecture: Dual-Write Pattern - -### **Phase 1: Add New Table (Current)** -```typescript -// Create active_identity table -// Keep existing settings.activeDid for backward compatibility -// Use dual-write pattern during transition -``` - -### **Phase 2: Dual-Write Pattern** -```typescript -// When updating activeDid: -// 1. Update active_identity table (new system) -// 2. Update settings.activeDid (legacy compatibility) -// 3. Ensure both stay in sync -``` - -### **Phase 3: Future Cleanup (Not in Current Scope)** -```typescript -// Eventually: -// 1. Remove activeDid from settings table -// 2. Deprecate MASTER_SETTINGS_KEY -// 3. Use pure accountDid IS NULL pattern -// 4. Update IndexedDB migration service -``` - -## Backward Compatibility Requirements - -### **Critical: IndexedDB Migration Service** -- **Must continue working** for users migrating from Dexie -- **Must recognize `id = "1"`** as master settings -- **Must preserve existing migration paths** - -### **Important: Legacy Database Operations** -- **Must continue working** for existing SQLite databases -- **Must handle both old and new patterns** -- **Must not break existing queries** - -### **Desired: Cleaner Architecture** -- **New operations** use `accountDid IS NULL` pattern -- **Legacy operations** continue using `MASTER_SETTINGS_KEY` -- **Gradual migration** toward cleaner patterns \ No newline at end of file + - [ ] All platforms tested + - [ ] All stakeholders approve deployment timeline \ No newline at end of file