|
@ -1,7 +1,7 @@ |
|
|
# ActiveDid Migration Plan - Separate Table Architecture |
|
|
# ActiveDid Migration Plan - Separate Table Architecture |
|
|
|
|
|
|
|
|
**Author**: Matthew Raymer |
|
|
**Author**: Matthew Raymer |
|
|
**Date**: 2025-08-29T07:24Z |
|
|
**Date**: 2025-08-29T08:03Z |
|
|
**Status**: 🎯 **PLANNING** - Active migration planning phase |
|
|
**Status**: 🎯 **PLANNING** - Active migration planning phase |
|
|
|
|
|
|
|
|
## Objective |
|
|
## Objective |
|
@ -85,11 +85,15 @@ flowchart TD |
|
|
|
|
|
|
|
|
## Repro: End-to-End Procedure |
|
|
## Repro: End-to-End Procedure |
|
|
|
|
|
|
|
|
### Phase 1: Enhanced Schema Creation |
|
|
### Phase 1: Enhanced Schema Creation via migration.ts |
|
|
|
|
|
|
|
|
```sql |
|
|
```typescript |
|
|
|
|
|
// Add to MIGRATIONS array in src/db-sql/migration.ts |
|
|
|
|
|
{ |
|
|
|
|
|
name: "003_active_did_separate_table", |
|
|
|
|
|
sql: ` |
|
|
-- Create new active_identity table with proper constraints |
|
|
-- Create new active_identity table with proper constraints |
|
|
CREATE TABLE active_identity ( |
|
|
CREATE TABLE IF NOT EXISTS active_identity ( |
|
|
id INTEGER PRIMARY KEY CHECK (id = 1), |
|
|
id INTEGER PRIMARY KEY CHECK (id = 1), |
|
|
activeDid TEXT NOT NULL, |
|
|
activeDid TEXT NOT NULL, |
|
|
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')), |
|
|
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')), |
|
@ -101,13 +105,15 @@ CREATE INDEX IF NOT EXISTS idx_active_identity_activeDid ON active_identity(acti |
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id); |
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id); |
|
|
|
|
|
|
|
|
-- Insert default record (will be updated during migration) |
|
|
-- Insert default record (will be updated during migration) |
|
|
INSERT INTO active_identity (id, activeDid, lastUpdated) VALUES (1, '', datetime('now')); |
|
|
INSERT OR IGNORE INTO active_identity (id, activeDid, lastUpdated) VALUES (1, '', datetime('now')); |
|
|
|
|
|
`, |
|
|
|
|
|
}, |
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
### Phase 2: Enhanced Data Migration with Validation |
|
|
### Phase 2: Enhanced Data Migration with Validation |
|
|
|
|
|
|
|
|
```typescript |
|
|
```typescript |
|
|
// Enhanced migration script with comprehensive validation |
|
|
// Enhanced migration function with comprehensive validation |
|
|
async function migrateActiveDidToSeparateTable(): Promise<MigrationResult> { |
|
|
async function migrateActiveDidToSeparateTable(): Promise<MigrationResult> { |
|
|
const result: MigrationResult = { |
|
|
const result: MigrationResult = { |
|
|
success: false, |
|
|
success: false, |
|
@ -117,7 +123,7 @@ async function migrateActiveDidToSeparateTable(): Promise<MigrationResult> { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
// 1. Get current activeDid from settings |
|
|
// 1. Get current activeDid from settings (legacy approach) |
|
|
const currentSettings = await retrieveSettingsForDefaultAccount(); |
|
|
const currentSettings = await retrieveSettingsForDefaultAccount(); |
|
|
const activeDid = currentSettings.activeDid; |
|
|
const activeDid = currentSettings.activeDid; |
|
|
|
|
|
|
|
@ -137,27 +143,20 @@ async function migrateActiveDidToSeparateTable(): Promise<MigrationResult> { |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 3. Check if active_identity table already has data |
|
|
// 3. Update active_identity table (new system) |
|
|
const existingActiveIdentity = await dbQuery( |
|
|
|
|
|
"SELECT activeDid FROM active_identity WHERE id = 1" |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (existingActiveIdentity?.values?.length) { |
|
|
|
|
|
// Update existing record |
|
|
|
|
|
await dbExec( |
|
|
await dbExec( |
|
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
|
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
|
|
[activeDid] |
|
|
[activeDid] |
|
|
); |
|
|
); |
|
|
} else { |
|
|
|
|
|
// Insert new record |
|
|
// 4. Ensure legacy settings.activeDid stays in sync (backward compatibility) |
|
|
|
|
|
// This maintains compatibility with IndexedDB migration service |
|
|
await dbExec( |
|
|
await dbExec( |
|
|
"INSERT INTO active_identity (id, activeDid, lastUpdated) VALUES (1, ?, datetime('now'))", |
|
|
"UPDATE settings SET activeDid = ? WHERE id = ?", |
|
|
[activeDid] |
|
|
[activeDid, MASTER_SETTINGS_KEY] |
|
|
); |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
result.success = true; |
|
|
dataMigrated = 1; |
|
|
result.dataMigrated = 1; |
|
|
|
|
|
result.warnings.push(`Successfully migrated activeDid: ${activeDid}`); |
|
|
result.warnings.push(`Successfully migrated activeDid: ${activeDid}`); |
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
} catch (error) { |
|
@ -167,17 +166,9 @@ async function migrateActiveDidToSeparateTable(): Promise<MigrationResult> { |
|
|
|
|
|
|
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Migration result interface |
|
|
|
|
|
interface MigrationResult { |
|
|
|
|
|
success: boolean; |
|
|
|
|
|
errors: string[]; |
|
|
|
|
|
warnings: string[]; |
|
|
|
|
|
dataMigrated: number; |
|
|
|
|
|
} |
|
|
|
|
|
``` |
|
|
``` |
|
|
|
|
|
|
|
|
### Phase 3: Focused API Updates |
|
|
### Phase 3: Focused API Updates with Dual-Write Pattern |
|
|
|
|
|
|
|
|
```typescript |
|
|
```typescript |
|
|
// Updated PlatformServiceMixin method - maintains backward compatibility |
|
|
// Updated PlatformServiceMixin method - maintains backward compatibility |
|
@ -201,93 +192,20 @@ async $accountSettings(did?: string, defaults: Settings = {}): Promise<Settings> |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// New method for active identity management |
|
|
// Enhanced update activeDid method with dual-write pattern |
|
|
async $getActiveIdentity(): Promise<{ activeDid: string | null }> { |
|
|
|
|
|
try { |
|
|
|
|
|
const result = await this.$dbQuery( |
|
|
|
|
|
"SELECT activeDid FROM active_identity WHERE id = 1" |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (!result?.values?.length) { |
|
|
|
|
|
return { activeDid: null }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { activeDid: result.values[0][0] as string }; |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
logger.error("[Settings Trace] ❌ Failed to get active identity:", error); |
|
|
|
|
|
return { activeDid: null }; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Enhanced method to get settings without activeDid |
|
|
|
|
|
async _getSettingsWithoutActiveDid(): Promise<Settings> { |
|
|
|
|
|
const result = await this.$dbQuery( |
|
|
|
|
|
"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 = ?", |
|
|
|
|
|
[MASTER_SETTINGS_KEY] |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if (!result?.values?.length) { |
|
|
|
|
|
return DEFAULT_SETTINGS; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return this._mapColumnsToValues(result.columns, result.values)[0] as Settings; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Enhanced save settings method |
|
|
|
|
|
async $saveSettings(changes: Partial<Settings>): Promise<boolean> { |
|
|
|
|
|
try { |
|
|
|
|
|
// Remove fields that shouldn't be updated |
|
|
|
|
|
const { accountDid, id, activeDid, ...safeChanges } = changes; |
|
|
|
|
|
|
|
|
|
|
|
if (Object.keys(safeChanges).length > 0) { |
|
|
|
|
|
// Convert settings for database storage |
|
|
|
|
|
const convertedChanges = this._convertSettingsForStorage(safeChanges); |
|
|
|
|
|
const setParts: string[] = []; |
|
|
|
|
|
const params: unknown[] = []; |
|
|
|
|
|
|
|
|
|
|
|
Object.entries(convertedChanges).forEach(([key, value]) => { |
|
|
|
|
|
if (value !== undefined) { |
|
|
|
|
|
setParts.push(`${key} = ?`); |
|
|
|
|
|
params.push(value); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (setParts.length > 0) { |
|
|
|
|
|
params.push(MASTER_SETTINGS_KEY); |
|
|
|
|
|
await this.$dbExec( |
|
|
|
|
|
`UPDATE settings SET ${setParts.join(", ")} WHERE id = ?`, |
|
|
|
|
|
params, |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Handle activeDid separately in new table |
|
|
|
|
|
if (changes.activeDid !== undefined) { |
|
|
|
|
|
await this.$updateActiveDid(changes.activeDid); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
logger.error("[PlatformServiceMixin] Error saving settings:", error); |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Enhanced update activeDid method |
|
|
|
|
|
async $updateActiveDid(newDid: string | null): Promise<boolean> { |
|
|
async $updateActiveDid(newDid: string | null): Promise<boolean> { |
|
|
try { |
|
|
try { |
|
|
if (newDid === null) { |
|
|
if (newDid === null) { |
|
|
// Clear active identity |
|
|
// Clear active identity in both tables |
|
|
await this.$dbExec( |
|
|
await this.$dbExec( |
|
|
"UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1" |
|
|
"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 { |
|
|
} else { |
|
|
// Validate DID exists before setting |
|
|
// Validate DID exists before setting |
|
|
const accountExists = await this.$dbQuery( |
|
|
const accountExists = await this.$dbQuery( |
|
@ -300,11 +218,17 @@ async $updateActiveDid(newDid: string | null): Promise<boolean> { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Update active identity |
|
|
// Update active identity in new table |
|
|
await this.$dbExec( |
|
|
await this.$dbExec( |
|
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
|
|
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", |
|
|
[newDid] |
|
|
[newDid] |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Keep legacy field in sync (backward compatibility) |
|
|
|
|
|
await this.$dbExec( |
|
|
|
|
|
"UPDATE settings SET activeDid = ? WHERE id = ?", |
|
|
|
|
|
[newDid, MASTER_SETTINGS_KEY] |
|
|
|
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Update internal tracking |
|
|
// Update internal tracking |
|
@ -431,30 +355,30 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac |
|
|
## What Works (Evidence) |
|
|
## What Works (Evidence) |
|
|
|
|
|
|
|
|
- ✅ **Current activeDid storage** in settings table |
|
|
- ✅ **Current activeDid storage** in settings table |
|
|
- **Time**: 2025-08-29T07:24Z |
|
|
- **Time**: 2025-08-29T08:03Z |
|
|
- **Evidence**: `src/db/tables/settings.ts:25` - activeDid field exists |
|
|
- **Evidence**: `src/db-sql/migration.ts:67` - activeDid field exists in initial migration |
|
|
- **Verify at**: Current database schema and Settings type definition |
|
|
- **Verify at**: Current database schema and Settings type definition |
|
|
|
|
|
|
|
|
- ✅ **PlatformServiceMixin integration** with activeDid |
|
|
- ✅ **PlatformServiceMixin integration** with activeDid |
|
|
- **Time**: 2025-08-29T07:24Z |
|
|
- **Time**: 2025-08-29T08:03Z |
|
|
- **Evidence**: `src/utils/PlatformServiceMixin.ts:108` - activeDid tracking |
|
|
- **Evidence**: `src/utils/PlatformServiceMixin.ts:108` - activeDid tracking |
|
|
- **Verify at**: Component usage across all platforms |
|
|
- **Verify at**: Component usage across all platforms |
|
|
|
|
|
|
|
|
- ✅ **Database migration infrastructure** exists |
|
|
- ✅ **Database migration infrastructure** exists |
|
|
- **Time**: 2025-08-29T07:24Z |
|
|
- **Time**: 2025-08-29T08:03Z |
|
|
- **Evidence**: `src/db-sql/migration.ts:31` - migration system in place |
|
|
- **Evidence**: `src/db-sql/migration.ts:31` - migration system in place |
|
|
- **Verify at**: Existing migration scripts and database versioning |
|
|
- **Verify at**: Existing migration scripts and database versioning |
|
|
|
|
|
|
|
|
## What Doesn't (Evidence & Hypotheses) |
|
|
## What Doesn't (Evidence & Hypotheses) |
|
|
|
|
|
|
|
|
- ❌ **No separate active_identity table** exists |
|
|
- ❌ **No separate active_identity table** exists |
|
|
- **Time**: 2025-08-29T07:24Z |
|
|
- **Time**: 2025-08-29T08:03Z |
|
|
- **Evidence**: Database schema only shows settings table |
|
|
- **Evidence**: Database schema only shows settings table |
|
|
- **Hypothesis**: Table needs to be created as part of migration |
|
|
- **Hypothesis**: Table needs to be created as part of migration |
|
|
- **Next probe**: Create migration script for new table |
|
|
- **Next probe**: Add migration to existing MIGRATIONS array |
|
|
|
|
|
|
|
|
- ❌ **Data corruption issues** with orphaned activeDid references |
|
|
- ❌ **Data corruption issues** with orphaned activeDid references |
|
|
- **Time**: 2025-08-29T07:24Z |
|
|
- **Time**: 2025-08-29T08:03Z |
|
|
- **Evidence**: `IdentitySwitcherView.vue:175` - `hasCorruptedIdentity` detection |
|
|
- **Evidence**: `IdentitySwitcherView.vue:175` - `hasCorruptedIdentity` detection |
|
|
- **Hypothesis**: Current schema allows activeDid to point to non-existent accounts |
|
|
- **Hypothesis**: Current schema allows activeDid to point to non-existent accounts |
|
|
- **Next probe**: Implement foreign key constraints in new table |
|
|
- **Next probe**: Implement foreign key constraints in new table |
|
@ -522,7 +446,7 @@ async function rollbackActiveDidMigration(): Promise<boolean> { |
|
|
|
|
|
|
|
|
| Owner | Task | Exit Criteria | Target Date (UTC) | |
|
|
| Owner | Task | Exit Criteria | Target Date (UTC) | |
|
|
|-------|------|---------------|-------------------| |
|
|
|-------|------|---------------|-------------------| |
|
|
| Development Team | Create enhanced migration script | Migration script with validation and rollback | 2025-08-30 | |
|
|
| 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 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 | 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 | Implement foreign key constraints | Schema validation prevents corruption | 2025-08-31 | |
|
@ -552,7 +476,7 @@ async function rollbackActiveDidMigration(): Promise<boolean> { |
|
|
## Collaboration Hooks |
|
|
## Collaboration Hooks |
|
|
|
|
|
|
|
|
- **Sign-off checklist**: |
|
|
- **Sign-off checklist**: |
|
|
- [ ] Migration script tested on development database |
|
|
- [ ] Migration script integrated with existing MIGRATIONS array |
|
|
- [ ] Foreign key constraints implemented and tested |
|
|
- [ ] Foreign key constraints implemented and tested |
|
|
- [ ] PlatformServiceMixin updated and tested |
|
|
- [ ] PlatformServiceMixin updated and tested |
|
|
- [ ] Rollback procedures validated |
|
|
- [ ] Rollback procedures validated |
|
@ -571,31 +495,33 @@ async function rollbackActiveDidMigration(): Promise<boolean> { |
|
|
|
|
|
|
|
|
## What Needs to Change |
|
|
## What Needs to Change |
|
|
|
|
|
|
|
|
### **1. Database Schema** |
|
|
### **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 |
|
|
- Create `active_identity` table with foreign key constraints |
|
|
- Add performance indexes |
|
|
- Add performance indexes |
|
|
- Remove `activeDid` field from `settings` table |
|
|
- **Keep `activeDid` field in `settings` table temporarily** for backward compatibility |
|
|
|
|
|
- **Preserve `MASTER_SETTINGS_KEY = "1"`** for legacy migration support |
|
|
|
|
|
|
|
|
### **2. PlatformServiceMixin Methods** |
|
|
### **2. PlatformServiceMixin Methods** |
|
|
- `$accountSettings()` - integrate with new table |
|
|
- `$accountSettings()` - integrate with new table while maintaining backward compatibility |
|
|
- `$saveSettings()` - handle activeDid in new table |
|
|
- `$saveSettings()` - handle activeDid in new table, sync with legacy field |
|
|
- `$updateActiveDid()` - validate and update new table |
|
|
- `$updateActiveDid()` - validate and update new table, sync with legacy field |
|
|
- `$getActiveIdentity()` - new method for identity management |
|
|
- `$getActiveIdentity()` - new method for identity management |
|
|
|
|
|
|
|
|
### **3. Master Settings Functions** |
|
|
### **3. Master Settings Functions** |
|
|
- `retrieveSettingsForDefaultAccount()` - integrate with new table |
|
|
- `retrieveSettingsForDefaultAccount()` - integrate with new table while preserving legacy support |
|
|
- `$getMergedSettings()` - integrate with new table |
|
|
- `$getMergedSettings()` - integrate with new table while preserving legacy support |
|
|
|
|
|
|
|
|
### **4. Migration Scripts** |
|
|
### **4. Type Definitions** |
|
|
- Create migration script with validation |
|
|
- **Keep `activeDid` in Settings type temporarily** for backward compatibility |
|
|
- Implement rollback procedures |
|
|
|
|
|
- Add data corruption detection |
|
|
|
|
|
|
|
|
|
|
|
### **5. Type Definitions** |
|
|
|
|
|
- Update Settings type to remove activeDid |
|
|
|
|
|
- Create ActiveIdentity type for new table |
|
|
- Create ActiveIdentity type for new table |
|
|
- Update related interfaces |
|
|
- 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 |
|
|
## What Doesn't Need to Change |
|
|
|
|
|
|
|
|
- **All Vue components** - API layer handles migration transparently |
|
|
- **All Vue components** - API layer handles migration transparently |
|
@ -603,3 +529,48 @@ async function rollbackActiveDidMigration(): Promise<boolean> { |
|
|
- **User interface** - No changes to identity selection UI |
|
|
- **User interface** - No changes to identity selection UI |
|
|
- **Authentication flow** - Existing system unchanged |
|
|
- **Authentication flow** - Existing system unchanged |
|
|
- **Component logic** - All activeDid handling through API methods |
|
|
- **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 |