forked from trent_larson/crowd-funder-for-time-pwa
chore: add plan
This commit is contained in:
506
doc/activeDid-migration-plan.md
Normal file
506
doc/activeDid-migration-plan.md
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user