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
- Database Migration Guide
- Dexie to SQLite Mapping
- PlatformServiceMixin Documentation
- Migration Templates
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
-
IdentitySection.vue
- Direct dependency onactiveDid
- 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: </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>
- Current: Uses
-
DIDView.vue
- Heavy activeDid usage- Current: Initializes
activeDid
inmounted()
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>
- Current: Initializes
-
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. - Current: Has
Medium Impact Components
-
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: Creates identity if no
-
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: Gets
-
ContactAmountsView.vue
- Direct settings access- Current: Accesses
activeDid
directly from settings - Impact: Must update to use new API methods
- Risk: MEDIUM - Financial display component
- Current: Accesses
Service Layer Impact
-
WebPlatformService.ts
- Current: Direct SQL queries to settings table
- Impact: Must add
active_identity
table queries - Risk: HIGH - Core web platform service
-
CapacitorPlatformService.ts
- Current: Similar direct SQL access
- Impact: Same updates as web service
- Risk: HIGH - Mobile platform service
-
PlatformServiceMixin.ts
- Current: Core methods like
$accountSettings()
,$saveSettings()
- Impact: Major refactoring required
- Risk: CRITICAL - Used by 50+ components
- Current: Core methods like
API Contract Changes
-
$saveSettings()
method- Current: Updates
settings.activeDid
- New: Updates
active_identity.activeDid
- Impact: All components using this method
- Current: Updates
-
$updateActiveDid()
method- Current: Internal tracking only
- New: Database persistence required
- Impact: Identity switching logic
Testing Impact
-
Unit Tests
- All platform service methods
- PlatformServiceMixin methods
- Database migration scripts
-
Integration Tests
- Component behavior with new data source
- Identity switching workflows
- Settings persistence
-
Platform Tests
- Web, Electron, iOS, Android
- Cross-platform data consistency
- Migration success on all platforms
Performance Impact
-
Additional Table Join
- Settings queries now require active_identity table
- Potential performance impact on frequent operations
- Need for proper indexing
-
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
- PlatformServiceMixin - Core dependency for most components
- Platform Services - Ensure data access layer works
- Identity Components - Verify core functionality
- Settings-Dependent Views - Update in dependency order
- 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