1 changed files with 506 additions and 0 deletions
@ -0,0 +1,506 @@ |
|||||
|
# 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: |
||||
|
|
||||
|
```mermaid |
||||
|
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 |
||||
|
|
||||
|
```sql |
||||
|
-- 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 |
||||
|
|
||||
|
```typescript |
||||
|
// 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 |
||||
|
|
||||
|
```typescript |
||||
|
// 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](./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, 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:** |
||||
|
|
||||
|
```vue |
||||
|
<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:** |
||||
|
|
||||
|
```vue |
||||
|
<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:** |
||||
|
|
||||
|
```vue |
||||
|
<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:** |
||||
|
|
||||
|
```vue |
||||
|
<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:** |
||||
|
|
||||
|
```vue |
||||
|
<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:** |
||||
|
|
||||
|
```vue |
||||
|
<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 |
Loading…
Reference in new issue