You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

17 KiB

ActiveDid Migration Plan - Separate Table Architecture

Author: Matthew Raymer Date: 2025-01-27T18:30Z 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.

Result

This document serves as the comprehensive planning and implementation guide for the ActiveDid migration.

Use/Run

Reference this document during implementation to ensure all migration steps are followed correctly and all stakeholders are aligned on the approach.

Context & Scope

  • In scope:
    • Database schema modification for active_identity table
    • Migration of existing activeDid data
    • Updates to all platform services and mixins
    • Type definition updates
    • Testing across all platforms
  • Out of scope:
    • Changes to user interface for identity selection
    • Modifications to identity creation logic
    • Changes to authentication flow

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:

flowchart TD
    A[Current State<br/>activeDid in settings] --> B[Phase 1: Schema Creation<br/>Add active_identity table]
    B --> C[Phase 2: Data Migration<br/>Copy activeDid data]
    C --> D[Phase 3: API Updates<br/>Update all access methods]
    D --> E[Phase 4: Cleanup<br/>Remove activeDid from settings]
    E --> F[Final State<br/>Separate active_identity table]

    G[Rollback Plan<br/>Keep old field until verified] --> H[Data Validation<br/>Verify integrity at each step]
    H --> I[Platform Testing<br/>Test all platforms]
    I --> J[Production Deployment<br/>Gradual rollout]

Interfaces & Contracts

Database Schema Changes

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

API Contract Changes

Method Current Behavior New Behavior Breaking Change
$accountSettings() Returns settings with activeDid Returns settings without activeDid 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

Repro: End-to-End Procedure

Phase 1: Schema Creation

-- Create new active_identity table
CREATE TABLE active_identity (
  id INTEGER PRIMARY KEY CHECK (id = 1),
  activeDid TEXT NOT NULL,
  lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
);

-- Insert default record (will be updated during migration)
INSERT INTO active_identity (id, activeDid) VALUES (1, '');

Phase 2: Data Migration

// Migration script to copy existing activeDid values
async function migrateActiveDidToSeparateTable(): Promise<void> {
  // 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",
      [activeDid]
    );
  }
}

Phase 3: API Updates

// Updated PlatformServiceMixin method
async $accountSettings(did?: string, defaults: Settings = {}): Promise<Settings> {
  // Get settings without activeDid
  const settings = await this._getSettingsWithoutActiveDid();

  // Get activeDid from separate table
  const activeIdentity = await this._getActiveIdentity();

  return { ...settings, activeDid: activeIdentity.activeDid };
}

What Works (Evidence)

  • Current activeDid storage in settings table

    • Time: 2025-01-27T18:30Z
    • 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
    • Evidence: src/utils/PlatformServiceMixin.ts:108 - activeDid tracking
    • Verify at: Component usage across all platforms
  • Database migration infrastructure exists

    • Time: 2025-01-27T18:30Z
    • Evidence: src/db-sql/migration.ts:31 - migration system in place
    • Verify at: Existing migration scripts and database versioning

What Doesn't (Evidence & Hypotheses)

  • No separate active_identity table exists

    • Time: 2025-01-27T18:30Z
    • 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

Risks, Limits, Assumptions

  • Data Loss Risk: Migration failure could lose activeDid values
  • Breaking Changes: API updates required across all platform services
  • 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

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

References

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
  • Teach-back: Explain the four-phase migration approach and why each phase is necessary

Collaboration Hooks

  • Sign-off checklist:
    • Migration script tested on development database
    • All platform services updated and tested
    • Rollback plan 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

Component & View Impact Analysis

High Impact Components

  1. IdentitySection.vue - Direct dependency on activeDid

    • Current: Uses activeDid from component data
    • Impact: Will need to update data binding and refresh logic
    • Risk: HIGH - Core identity display component

    Current Implementation:

    <template>
      <div class="text-sm text-slate-500">
        <div class="font-bold">ID:&nbsp;</div>
        <code class="truncate">{{ activeDid }}</code>
        <!-- ... rest of template -->
      </div>
    </template>
    
    <script lang="ts">
    export default class IdentitySection extends Vue {
      activeDid = ""; // Direct component data
    
      async mounted() {
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
      }
    }
    </script>
    

    Required Changes:

    <script lang="ts">
    export default class IdentitySection extends Vue {
      activeDid = ""; // Still needed for template binding
    
      async mounted() {
        // This will automatically work if $accountSettings() is updated
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
      }
    
      // Add watcher for activeDid changes
      async onActiveDidChanged(newDid: string | null) {
        if (newDid) {
          this.activeDid = newDid;
        }
      }
    }
    </script>
    
  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:

    <script lang="ts">
    export default class DIDView extends Vue {
      activeDid = ""; // Component data
    
      async mounted() {
        await this.initializeSettings();
        await this.determineDIDToDisplay();
        // ... rest of initialization
      }
    
      private async initializeSettings() {
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
        this.apiServer = settings.apiServer || "";
      }
    
      private async determineDIDToDisplay() {
        const pathParam = window.location.pathname.substring("/did/".length);
        let showDid = pathParam;
    
        if (!showDid) {
          // No DID provided in URL, use active DID
          showDid = this.activeDid; // Uses component data
          this.notifyDefaultToActiveDID();
        }
        // ... rest of logic
      }
    }
    </script>
    

    Required Changes:

    <script lang="ts">
    export default class DIDView extends Vue {
      activeDid = ""; // Component data still needed
    
      async mounted() {
        await this.initializeSettings();
        await this.determineDIDToDisplay();
        // ... rest of initialization
      }
    
      private async initializeSettings() {
        // This will automatically work if $accountSettings() is updated
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
        this.apiServer = settings.apiServer || "";
      }
    
      // Add watcher for activeDid changes
      async onActiveDidChanged(newDid: string | null) {
        if (newDid && newDid !== this.activeDid) {
          this.activeDid = newDid;
          // Re-initialize if needed
          await this.determineDIDToDisplay();
        }
      }
    }
    </script>
    
  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:

    <script lang="ts">
    export default class HomeView extends Vue {
      async onActiveDidChanged(newDid: string | null, oldDid: string | null) {
        if (newDid !== oldDid) {
          // Re-initialize identity with new settings (loads settings internally)
          await this.initializeIdentity();
        } else {
          logger.debug(
            "[HomeView Settings Trace] 📍 DID unchanged, skipping re-initialization",
          );
        }
      }
    
      private async initializeIdentity() {
        // ... identity initialization logic
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
        // ... rest of initialization
      }
    }
    </script>
    

    Required Changes:

    <script lang="ts">
    export default class HomeView extends Vue {
      async onActiveDidChanged(newDid: string | null, oldDid: string | null) {
        if (newDid !== oldDid) {
          // This will automatically work if $accountSettings() is updated
          await this.initializeIdentity();
        } else {
          logger.debug(
            "[HomeView Settings Trace] 📍 DID unchanged, skipping re-initialization",
          );
        }
      }
    
      private async initializeIdentity() {
        // ... identity initialization logic
        // This will automatically work if $accountSettings() is updated
        const settings = await this.$accountSettings();
        this.activeDid = settings.activeDid || "";
        // ... rest of initialization
      }
    }
    </script>
    

    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
  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
  3. ContactAmountsView.vue - Direct settings access

    • Current: Accesses activeDid directly from settings
    • Impact: Must update to use new API methods
    • Risk: MEDIUM - Financial display component

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

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

Migration Timeline Impact

  • Phase 1: Schema Creation (1-2 days) - No component impact
  • Phase 2: Data Migration (1 day) - No component impact
  • Phase 3: API Updates (3-5 days) - All components affected
  • Phase 4: Cleanup (1-2 days) - 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