diff --git a/doc/activeDid-migration-plan.md b/doc/activeDid-migration-plan.md
index 4f5afedd..12407172 100644
--- a/doc/activeDid-migration-plan.md
+++ b/doc/activeDid-migration-plan.md
@@ -1,19 +1,20 @@
# ActiveDid Migration Plan - Separate Table Architecture
**Author**: Matthew Raymer
-**Date**: 2025-01-27T18:30Z
+**Date**: 2025-08-29T07:24Z
**Status**: 🎯 **PLANNING** - Active migration planning phase
## Objective
Move the `activeDid` field from the `settings` table to a dedicated
-`active_identity` table to improve database architecture and separate
-identity selection from user preferences.
+`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.
+guide for the ActiveDid migration with enhanced data integrity and
+rollback capabilities.
## Use/Run
@@ -24,15 +25,17 @@ approach.
## Context & Scope
- **In scope**:
- - Database schema modification for active_identity table
- - Migration of existing activeDid data
- - Updates to all platform services and mixins
+ - 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
@@ -44,19 +47,22 @@ approach.
## Architecture / Process Overview
The migration follows a phased approach to minimize risk and ensure
-data integrity:
+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]
- B --> C[Phase 2: Data Migration
Copy activeDid data]
- C --> D[Phase 3: API Updates
Update all access methods]
+ 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[Rollback Plan
Keep old field until verified] --> H[Data Validation
Verify integrity at each step]
+ 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]
+ 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]
```
## Interfaces & Contracts
@@ -66,66 +72,154 @@ flowchart TD
| 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` | Yes - table creation |
+| `active_identity` | Does not exist | New table with `activeDid TEXT` + constraints | Yes - table creation |
-### API Contract Changes
+### Enhanced API Contract Changes
| Method | Current Behavior | New Behavior | Breaking Change |
|---------|------------------|--------------|-----------------|
-| `$accountSettings()` | Returns settings with activeDid | Returns settings without activeDid | No - backward compatible |
+| `$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 |
## Repro: End-to-End Procedure
-### Phase 1: Schema Creation
+### Phase 1: Enhanced Schema Creation
```sql
--- Create new active_identity table
+-- Create new active_identity table with proper constraints
CREATE TABLE active_identity (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT NOT NULL,
- lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
+ lastUpdated TEXT NOT NULL DEFAULT (datetime('now')),
+ FOREIGN KEY (activeDid) REFERENCES accounts(did) ON DELETE CASCADE
);
+-- Add performance indexes
+CREATE INDEX IF NOT EXISTS idx_active_identity_activeDid ON active_identity(activeDid);
+CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
+
-- Insert default record (will be updated during migration)
-INSERT INTO active_identity (id, activeDid) VALUES (1, '');
+INSERT INTO active_identity (id, activeDid, lastUpdated) VALUES (1, '', datetime('now'));
```
-### Phase 2: Data Migration
+### Phase 2: Enhanced Data Migration with Validation
```typescript
-// Migration script to copy existing activeDid values
-async function migrateActiveDidToSeparateTable(): Promise {
- // Get current activeDid from settings
- const currentSettings = await retrieveSettingsForDefaultAccount();
- const activeDid = currentSettings.activeDid;
-
- if (activeDid) {
- // Insert into new table
- await dbExec(
- "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
+// Enhanced migration script with comprehensive validation
+async function migrateActiveDidToSeparateTable(): Promise {
+ const result: MigrationResult = {
+ success: false,
+ errors: [],
+ warnings: [],
+ dataMigrated: 0
+ };
+
+ try {
+ // 1. Get current activeDid from settings
+ 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]
);
+
+ if (!accountExists?.values?.length) {
+ result.errors.push(`ActiveDid ${activeDid} not found in accounts table - data corruption detected`);
+ return result;
+ }
+
+ // 3. Check if active_identity table already has data
+ const existingActiveIdentity = await dbQuery(
+ "SELECT activeDid FROM active_identity WHERE id = 1"
+ );
+
+ if (existingActiveIdentity?.values?.length) {
+ // Update existing record
+ await dbExec(
+ "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
+ [activeDid]
+ );
+ } else {
+ // Insert new record
+ await dbExec(
+ "INSERT INTO active_identity (id, activeDid, lastUpdated) VALUES (1, ?, datetime('now'))",
+ [activeDid]
+ );
+ }
+
+ result.success = true;
+ result.dataMigrated = 1;
+ result.warnings.push(`Successfully migrated activeDid: ${activeDid}`);
+
+ } catch (error) {
+ result.errors.push(`Migration failed: ${error}`);
+ logger.error("[ActiveDid Migration] Critical error during migration:", error);
}
+
+ return result;
+}
+
+// Migration result interface
+interface MigrationResult {
+ success: boolean;
+ errors: string[];
+ warnings: string[];
+ dataMigrated: number;
}
```
-### Phase 3: API Updates
+### Phase 3: Focused API Updates
```typescript
-// Updated PlatformServiceMixin method
+// Updated PlatformServiceMixin method - maintains backward compatibility
async $accountSettings(did?: string, defaults: Settings = {}): Promise {
- // Get settings without activeDid
- const settings = await this._getSettingsWithoutActiveDid();
+ try {
+ // Get settings without activeDid (unchanged logic)
+ const settings = await this._getSettingsWithoutActiveDid();
+
+ if (!settings) {
+ return defaults;
+ }
+
+ // Get activeDid from new table (new logic)
+ const activeIdentity = await this._getActiveIdentity();
- // Get activeDid from separate table
- const activeIdentity = await this._getActiveIdentity();
+ // Return combined result (maintains backward compatibility)
+ return { ...settings, activeDid: activeIdentity.activeDid };
+ } catch (error) {
+ logger.error("[Settings Trace] ❌ Error in $accountSettings:", error);
+ return defaults;
+ }
+}
- return { ...settings, activeDid: activeIdentity.activeDid };
+// New method for active identity management
+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 };
+ }
}
-// New method to get settings without activeDid
+// Enhanced method to get settings without activeDid
async _getSettingsWithoutActiveDid(): Promise {
const result = await this.$dbQuery(
"SELECT id, accountDid, apiServer, filterFeedByNearby, filterFeedByVisible, " +
@@ -146,17 +240,80 @@ async _getSettingsWithoutActiveDid(): Promise {
return this._mapColumnsToValues(result.columns, result.values)[0] as Settings;
}
-// New method to get active identity
-async _getActiveIdentity(): Promise<{ activeDid: string | null }> {
- const result = await this.$dbQuery(
- "SELECT activeDid FROM active_identity WHERE id = 1"
- );
+// Enhanced save settings method
+async $saveSettings(changes: Partial): Promise {
+ 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 (!result?.values?.length) {
- return { activeDid: null };
+ 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;
}
+}
- return { activeDid: result.values[0][0] as string };
+// Enhanced update activeDid method
+async $updateActiveDid(newDid: string | null): Promise {
+ try {
+ if (newDid === null) {
+ // Clear active identity
+ await this.$dbExec(
+ "UPDATE active_identity SET activeDid = '', lastUpdated = datetime('now') WHERE id = 1"
+ );
+ } else {
+ // Validate DID exists before setting
+ const accountExists = await this.$dbQuery(
+ "SELECT did FROM accounts WHERE did = ?",
+ [newDid]
+ );
+
+ if (!accountExists?.values?.length) {
+ logger.error(`[PlatformServiceMixin] Cannot set activeDid to non-existent DID: ${newDid}`);
+ return false;
+ }
+
+ // Update active identity
+ await this.$dbExec(
+ "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
+ [newDid]
+ );
+ }
+
+ // Update internal tracking
+ await this._updateInternalActiveDid(newDid);
+ return true;
+ } catch (error) {
+ logger.error("[PlatformServiceMixin] Error updating activeDid:", error);
+ return false;
+ }
}
```
@@ -165,15 +322,7 @@ async _getActiveIdentity(): Promise<{ activeDid: string | null }> {
#### **1. Update `retrieveSettingsForDefaultAccount()`**
```typescript
-// Current implementation in src/db/databaseUtil.ts:148
-export async function retrieveSettingsForDefaultAccount(): Promise {
- const platform = PlatformServiceFactory.getInstance();
- const sql = "SELECT * FROM settings WHERE id = ?";
- const result = await platform.dbQuery(sql, [MASTER_SETTINGS_KEY]);
- // ... rest of implementation
-}
-
-// Updated implementation
+// Enhanced implementation with active_identity table integration
export async function retrieveSettingsForDefaultAccount(): Promise {
const platform = PlatformServiceFactory.getInstance();
@@ -205,7 +354,24 @@ export async function retrieveSettingsForDefaultAccount(): Promise {
);
if (activeIdentityResult?.values?.length) {
- settings.activeDid = activeIdentityResult.values[0][0] as string;
+ 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"
+ );
+ }
+ }
}
return settings;
@@ -213,19 +379,10 @@ export async function retrieveSettingsForDefaultAccount(): Promise {
}
```
-
-
#### **2. Update `$getMergedSettings()` Method**
```typescript
-// Current implementation in PlatformServiceMixin.ts:485
-async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallback: Settings = {}): Promise {
- // Get default settings
- const defaultSettings = await this.$getSettings(defaultKey, defaultFallback);
- // ... rest of implementation
-}
-
-// Updated implementation
+// Enhanced implementation with active_identity table integration
async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallback: Settings = {}): Promise {
try {
// Get default settings (now without activeDid)
@@ -240,7 +397,24 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac
);
if (activeIdentityResult?.values?.length) {
- defaultSettings.activeDid = activeIdentityResult.values[0][0] as string;
+ 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;
@@ -257,58 +431,103 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac
## What Works (Evidence)
- ✅ **Current activeDid storage** in settings table
- - **Time**: 2025-01-27T18:30Z
+ - **Time**: 2025-08-29T07:24Z
- **Evidence**: `src/db/tables/settings.ts:25` - activeDid field exists
- **Verify at**: Current database schema and Settings type definition
- ✅ **PlatformServiceMixin integration** with activeDid
- - **Time**: 2025-01-27T18:30Z
+ - **Time**: 2025-08-29T07:24Z
- **Evidence**: `src/utils/PlatformServiceMixin.ts:108` - activeDid tracking
- **Verify at**: Component usage across all platforms
- ✅ **Database migration infrastructure** exists
- - **Time**: 2025-01-27T18:30Z
+ - **Time**: 2025-08-29T07:24Z
- **Evidence**: `src/db-sql/migration.ts:31` - migration system in place
- **Verify at**: Existing migration scripts and database versioning
-- ✅ **Master settings functions architecture** supports migration
- - **Time**: 2025-01-27T18:30Z
- - **Evidence**: Functions use explicit field selection, not `SELECT *`
- - **Verify at**: `src/db/databaseUtil.ts:148` and `src/utils/PlatformServiceMixin.ts:442`
-
## What Doesn't (Evidence & Hypotheses)
- ❌ **No separate active_identity table** exists
- - **Time**: 2025-01-27T18:30Z
+ - **Time**: 2025-08-29T07:24Z
- **Evidence**: Database schema only shows settings table
- **Hypothesis**: Table needs to be created as part of migration
- **Next probe**: Create migration script for new table
-- ❌ **Platform services hardcoded** to settings table
- - **Time**: 2025-01-27T18:30Z
- - **Evidence**: `src/services/platforms/*.ts` - direct settings table access
- - **Hypothesis**: All platform services need updates
- - **Next probe**: Audit all platform service files for activeDid usage
+- ❌ **Data corruption issues** with orphaned activeDid references
+ - **Time**: 2025-08-29T07:24Z
+ - **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
## Risks, Limits, Assumptions
- **Data Loss Risk**: Migration failure could lose activeDid values
-- **Breaking Changes**: API updates required across all platform services
+- **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
+
+## Enhanced Rollback Strategy
+
+### **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**
+```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"
+ );
+
+ 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]
+ );
+
+ return true;
+ }
+
+ return false;
+ } catch (error) {
+ logger.error("[Rollback] Failed to restore activeDid:", error);
+ return false;
+ }
+}
+```
+
+### **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 | Create migration script | Migration script tested and validated | 2025-01-28 |
-| Development Team | Update type definitions | Settings type updated, ActiveIdentity type created | 2025-01-28 |
-| Development Team | Update platform services | All services use new active_identity table | 2025-01-29 |
-| Development Team | Update PlatformServiceMixin | Mixin methods updated and tested | 2025-01-29 |
-| QA Team | Platform testing | All platforms tested and verified | 2025-01-30 |
-| Development Team | Deploy migration | Production deployment successful | 2025-01-31 |
+| Development Team | Create enhanced migration script | Migration script with validation and rollback | 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 |
+| QA Team | Platform testing | All platforms tested and verified | 2025-09-01 |
+| Development Team | Deploy migration | Production deployment successful | 2025-09-02 |
## References
@@ -320,21 +539,23 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac
## Competence Hooks
- *Why this works*: Separates concerns between identity selection and
- user preferences, improves database normalization, enables future
- identity management features
-- *Common pitfalls*: Forgetting to update all platform services, not
- testing rollback scenarios, missing data validation during migration
-- *Next skill unlock*: Advanced database schema design and migration
- planning
+ 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
+ phase is necessary, especially the foreign key constraints
## Collaboration Hooks
- **Sign-off checklist**:
- [ ] Migration script tested on development database
- - [ ] All platform services updated and tested
- - [ ] Rollback plan validated
+ - [ ] Foreign key constraints implemented and tested
+ - [ ] PlatformServiceMixin updated and tested
+ - [ ] Rollback procedures validated
- [ ] Performance impact assessed
- [ ] All stakeholders approve deployment timeline
@@ -345,468 +566,40 @@ async $getMergedSettings(defaultKey: string, accountDid?: string, defaultFallbac
- Migration can be completed without user downtime
- Rollback to previous schema is acceptable if needed
- Performance impact of additional table join is minimal
-
-## Component & View Impact Analysis
-
-### **High Impact Components**
-
-1. **`IdentitySection.vue`** - Receives `activeDid` as prop
- - **Current**: Uses `activeDid` from parent component via prop
- - **Impact**: **NO CHANGES REQUIRED** - Parent component handles migration
- - **Risk**: **LOW** - No direct database access
-
- **Current Implementation:**
-
- ```vue
-
-
-
ID:
-
{{ activeDid }}
-
-
-
-
-
- ```
-
- **Required Changes:**
-
- ```vue
-
- ```
-
- **Key Insight**: This component requires **zero changes** since it receives
- `activeDid` as a prop. The parent component that provides this prop will
- handle the migration automatically through the API layer updates.
-
-2. **`DIDView.vue`** - Heavy activeDid usage
- - **Current**: Initializes `activeDid` in `mounted()` lifecycle
- - **Impact**: Must update initialization logic to use new table
- - **Risk**: **HIGH** - Primary DID viewing component
-
- **Current Implementation:**
-
- ```vue
-
- ```
-
- **Required Changes:**
-
- ```vue
-
- ```
-
-3. **`HomeView.vue`** - ActiveDid change detection
- - **Current**: Has `onActiveDidChanged()` watcher method
- - **Impact**: Watcher logic needs updates for new data source
- - **Risk**: **MEDIUM** - Core navigation component
-
- **Current Implementation:**
-
- ```vue
-
- ```
-
- **Required Changes:**
-
- ```vue
-
- ```
-
- **Key Insight**: HomeView will require minimal changes since it already uses
- the `$accountSettings()` method, which will be updated to handle the new
- table structure transparently.
-
-### **Medium Impact Components**
-
-1. **`InviteOneAcceptView.vue`** - Identity fallback logic
- - **Current**: Creates identity if no `activeDid` exists
- - **Impact**: Fallback logic needs to check new table
- - **Risk**: **MEDIUM** - Invite processing component
-
- **Current Implementation:**
-
- ```vue
-
- ```
-
- **Required Changes:**
-
- ```vue
-
- ```
-
- **Key Insight**: This component will work automatically since it uses
- `$accountSettings()`. The fallback logic doesn't need changes.
-
-2. **`ClaimView.vue`** - Settings retrieval
- - **Current**: Gets `activeDid` from `$accountSettings()`
- - **Impact**: Will automatically work if API is updated
- - **Risk**: **LOW** - Depends on API layer updates
-
- **Current Implementation:**
-
- ```vue
-
- ```
-
- **Required Changes:**
-
- ```vue
-
- ```
-
- **Key Insight**: This component requires zero changes since it already
- uses the proper API method. It's the lowest risk component.
-
-3. **`ContactAmountsView.vue`** - Uses phased-out method
- - **Current**: Uses `$getSettings(MASTER_SETTINGS_KEY)` (being phased out)
- - **Impact**: **NO CHANGES REQUIRED** - Will be updated when migrating to `getMasterSettings`
- - **Risk**: **LOW** - Part of planned refactoring, not migration-specific
-
- **Note**: This component will be updated as part of the broader refactoring to
- replace `$getSettings(MASTER_SETTINGS_KEY)` with `getMasterSettings()`, which
- is separate from the activeDid migration. The migration plan focuses only on
- components that require immediate changes for the active_identity table.
-
-### **Service Layer Impact**
-
-1. **`WebPlatformService.ts`**
- - **Current**: Direct SQL queries to settings table
- - **Impact**: Must add `active_identity` table queries
- - **Risk**: **HIGH** - Core web platform service
-
-2. **`CapacitorPlatformService.ts`**
- - **Current**: Similar direct SQL access
- - **Impact**: Same updates as web service
- - **Risk**: **HIGH** - Mobile platform service
-
-3. **`PlatformServiceMixin.ts`**
- - **Current**: Core methods like `$accountSettings()`, `$saveSettings()`
- - **Impact**: Major refactoring required
- - **Risk**: **CRITICAL** - Used by 50+ components
-
-### **API Contract Changes**
-
-1. **`$saveSettings()` method**
- - **Current**: Updates `settings.activeDid`
- - **New**: Updates `active_identity.activeDid`
- - **Impact**: All components using this method
-
-2. **`$updateActiveDid()` method**
- - **Current**: Internal tracking only
- - **New**: Database persistence required
- - **Impact**: Identity switching logic
-
-### **Master Settings Functions Impact**
-
-1. **`retrieveSettingsForDefaultAccount()` function**
- - **Current**: Returns settings with `activeDid` field from master settings
- - **New**: Returns settings without `activeDid` field
- - **Impact**: **HIGH** - Used by migration scripts and core database utilities
- - **Location**: `src/db/databaseUtil.ts:148`
-
-2. **`$getMergedSettings()` method**
- - **Current**: Merges default and account settings, includes `activeDid` from defaults
- - **New**: Merges settings without `activeDid`, adds from `active_identity` table
- - **Impact**: **HIGH** - Core method used by `$accountSettings()`
- - **Location**: `src/utils/PlatformServiceMixin.ts:485`
-
-**Note**: `$getSettings(MASTER_SETTINGS_KEY)` is being phased out in favor of `getMasterSettings`,
-so it doesn't require updates for this migration.
-
-### **New `getMasterSettings()` Function**
-
-Since we're phasing out `$getSettings(MASTER_SETTINGS_KEY)`, this migration
-provides an opportunity to implement the new `getMasterSettings()` function
-that will handle the active_identity table integration from the start:
-
-```typescript
-// New getMasterSettings function to replace phased-out $getSettings
-async getMasterSettings(): Promise {
- try {
- // Get master settings without activeDid
- 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;
- }
-
- const settings = this._mapColumnsToValues(result.columns, result.values)[0] as Settings;
-
- // Handle JSON field parsing
- if (settings.searchBoxes) {
- settings.searchBoxes = this._parseJsonField(settings.searchBoxes, []);
- }
-
- // Get activeDid from separate table
- const activeIdentityResult = await this.$dbQuery(
- "SELECT activeDid FROM active_identity WHERE id = 1"
- );
-
- if (activeIdentityResult?.values?.length) {
- settings.activeDid = activeIdentityResult.values[0][0] as string;
- }
-
- return settings;
- } catch (error) {
- logger.error(`[Settings Trace] ❌ Failed to get master settings:`, { error });
- return DEFAULT_SETTINGS;
- }
-}
-```
-
-### **Testing Impact**
-
-1. **Unit Tests**
- - All platform service methods
- - PlatformServiceMixin methods
- - Database migration scripts
-
-2. **Integration Tests**
- - Component behavior with new data source
- - Identity switching workflows
- - Settings persistence
-
-3. **Platform Tests**
- - Web, Electron, iOS, Android
- - Cross-platform data consistency
- - Migration success on all platforms
-
-### **Performance Impact**
-
-1. **Additional Table Join**
- - Settings queries now require active_identity table
- - Potential performance impact on frequent operations
- - Need for proper indexing
-
-2. **Caching Considerations**
- - ActiveDid changes trigger cache invalidation
- - Component re-rendering on identity switches
- - Memory usage for additional table data
-
-### **Risk Assessment by Component Type**
-
-- **Critical Risk**: PlatformServiceMixin, Platform Services
-- **High Risk**: Identity-related components, views using `$accountSettings()`
-- **Medium Risk**: Components with direct settings access, identity management
-- **Low Risk**: Components using only basic settings, utility components,
-prop-based components, components using phased-out methods
-
-### **Migration Timeline Impact**
-
-- **Phase 1**: Schema Creation - No component impact
-- **Phase 2**: Data Migration - No component impact
-- **Phase 3**: API Updates - All components affected
-- **Phase 4**: Cleanup - No component impact
-
-### **Update Priority Order**
-
-1. **PlatformServiceMixin** - Core dependency for most components
-2. **Platform Services** - Ensure data access layer works
-3. **Identity Components** - Verify core functionality
-4. **Settings-Dependent Views** - Update in dependency order
-5. **Utility Components** - Final cleanup and testing
-
-## Deferred for depth
-
-- Advanced identity management features enabled by this change
-- Performance optimization strategies for the new table structure
-- Future schema evolution planning
-- Advanced rollback and recovery procedures
+- Foreign key constraints will prevent future corruption
+- API layer updates will handle component compatibility
+
+## What Needs to Change
+
+### **1. Database Schema**
+- Create `active_identity` table with foreign key constraints
+- Add performance indexes
+- Remove `activeDid` field from `settings` table
+
+### **2. PlatformServiceMixin Methods**
+- `$accountSettings()` - integrate with new table
+- `$saveSettings()` - handle activeDid in new table
+- `$updateActiveDid()` - validate and update new table
+- `$getActiveIdentity()` - new method for identity management
+
+### **3. Master Settings Functions**
+- `retrieveSettingsForDefaultAccount()` - integrate with new table
+- `$getMergedSettings()` - integrate with new table
+
+### **4. Migration Scripts**
+- Create migration script with validation
+- Implement rollback procedures
+- Add data corruption detection
+
+### **5. Type Definitions**
+- Update Settings type to remove activeDid
+- Create ActiveIdentity type for new table
+- Update related interfaces
+
+## 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