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