forked from trent_larson/crowd-funder-for-time-pwa
refactor: implement team feedback for active identity migration structure
- Update migration 003 to match master deployment (hasBackedUpSeed) - Rename migration 004 for active_identity table creation - Update migration service validation for new structure - Fix TypeScript compatibility issue in migration.ts - Streamline active identity upgrade plan documentation - Ensure all migrations are additional per team guidance Migration structure now follows "additional migrations only" principle: - 003: hasBackedUpSeed (assumes master deployment) - 004: active_identity table with data migration - iOS/Android compatibility confirmed with SQLCipher 4.9.0 Files: migration.ts, migrationService.ts, active-identity-upgrade-plan.md
This commit is contained in:
@@ -1,87 +1,192 @@
|
|||||||
# Active Identity Migration & Upgrade (Merged)
|
# Active Identity Upgrade Plan
|
||||||
|
|
||||||
## Part 1: Database Migration Impact Analysis
|
**Author**: Matthew Raymer
|
||||||
|
**Date**: 2025-09-11
|
||||||
|
**Status**: 🎯 **PLANNING** - Database migration and active identity system upgrade
|
||||||
|
|
||||||
# Database Migration Impact Analysis
|
## Overview
|
||||||
|
|
||||||
|
Comprehensive upgrade to the active identity system, addressing architectural issues and implementing enhanced database constraints. Includes database migration enhancements and settings table cleanup based on team feedback.
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
**✅ COMPLETED**: Migration structure updated according to team member feedback
|
||||||
|
|
||||||
|
### Implemented Changes
|
||||||
|
|
||||||
|
1. **✅ Migration 003**: `003_add_hasBackedUpSeed_to_settings` - Adds `hasBackedUpSeed` column to settings (assumes master deployment)
|
||||||
|
2. **✅ Migration 004**: `004_active_identity_and_seed_backup` - Creates `active_identity` table with data migration
|
||||||
|
3. **✅ Migration Service**: Updated validation and schema detection logic for new migration structure
|
||||||
|
4. **✅ TypeScript**: Fixed type compatibility issues
|
||||||
|
|
||||||
|
### Migration Structure Now Follows Team Guidance
|
||||||
|
|
||||||
|
- **Migration 003**: `003_add_hasBackedUpSeed_to_settings` (assumes master code deployed)
|
||||||
|
- **Migration 004**: `004_active_identity_and_seed_backup` (creates active_identity table)
|
||||||
|
- **All migrations are additional** - no editing of previous migrations
|
||||||
|
- **Data migration logic** preserves existing `activeDid` from settings
|
||||||
|
- **iOS/Android compatibility** confirmed with SQLCipher 4.9.0 (SQLite 3.44.2)
|
||||||
|
|
||||||
|
## Educational Context
|
||||||
|
|
||||||
|
### Why This Upgrade Matters
|
||||||
|
|
||||||
|
The active identity system is **critical infrastructure** affecting every user interaction:
|
||||||
|
|
||||||
|
1. **Data Integrity**: Current `ON DELETE SET NULL` allows accidental deletion of active accounts
|
||||||
|
2. **Manual Maintenance**: Timestamps require manual updates, creating inconsistency opportunities
|
||||||
|
3. **Architectural Clarity**: Separating active identity from user settings improves maintainability
|
||||||
|
|
||||||
|
### What This Upgrade Achieves
|
||||||
|
|
||||||
|
- **Prevents Data Loss**: `ON DELETE RESTRICT` prevents accidental account deletion
|
||||||
|
- **Automatic Consistency**: Database triggers ensure timestamps are always current
|
||||||
|
- **Cleaner Architecture**: Complete separation of identity management from user preferences
|
||||||
|
- **Better Performance**: Optimized indexes for faster account selection
|
||||||
|
|
||||||
## Current State Analysis
|
## Current State Analysis
|
||||||
|
|
||||||
### Existing Migration Structure
|
### Existing Migration Structure
|
||||||
The current migration system has:
|
|
||||||
- **Migration 003**: `003_active_identity_and_seed_backup` - Creates `active_identity` table with basic structure
|
- **Migration 003**: `003_add_hasBackedUpSeed_to_settings` - Adds `hasBackedUpSeed` column to settings (already deployed in master)
|
||||||
|
- **Migration 004**: `004_active_identity_and_seed_backup` - Creates `active_identity` table with data migration
|
||||||
- **Foreign Key**: `ON DELETE SET NULL` constraint
|
- **Foreign Key**: `ON DELETE SET NULL` constraint
|
||||||
- **Basic Indexing**: Single unique index on `id`
|
- **Data Migration**: Copies existing `activeDid` from settings to `active_identity` table
|
||||||
- **Bootstrapping**: Auto-selects first account if `activeDid` is null/empty
|
- **Bootstrapping**: Auto-selects first account if `activeDid` is null/empty
|
||||||
|
|
||||||
### Current Schema (Migration 003)
|
**Important**: All migrations are **additional** - no editing of previous migrations since master code has been deployed.
|
||||||
|
|
||||||
|
### Current Schema (Migration 004) - IMPLEMENTED
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
|
-- Migration 004: active_identity_and_seed_backup
|
||||||
|
-- Assumes master code deployed with migration 003
|
||||||
|
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_did_unique ON accounts(did);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS active_identity (
|
CREATE TABLE IF NOT EXISTS active_identity (
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
activeDid TEXT DEFAULT NULL,
|
activeDid TEXT DEFAULT NULL,
|
||||||
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')),
|
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')),
|
||||||
FOREIGN KEY (activeDid) REFERENCES accounts(did) ON DELETE SET NULL
|
FOREIGN KEY (activeDid) REFERENCES accounts(did) ON DELETE SET NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
|
||||||
|
|
||||||
|
-- Seed singleton row
|
||||||
|
INSERT INTO active_identity (id, activeDid, lastUpdated)
|
||||||
|
SELECT 1, NULL, datetime('now')
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
|
||||||
|
|
||||||
|
-- MIGRATE EXISTING DATA: Copy activeDid from settings
|
||||||
|
UPDATE active_identity
|
||||||
|
SET activeDid = (SELECT activeDid FROM settings WHERE id = 1),
|
||||||
|
lastUpdated = datetime('now')
|
||||||
|
WHERE id = 1
|
||||||
|
AND EXISTS (SELECT 1 FROM settings WHERE id = 1 AND activeDid IS NOT NULL AND activeDid != '');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Current Implementation Details
|
||||||
|
|
||||||
|
### PlatformServiceMixin.ts Implementation
|
||||||
|
|
||||||
|
The current `$getActiveIdentity()` method in `src/utils/PlatformServiceMixin.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
async $getActiveIdentity(): Promise<{ activeDid: string }> {
|
||||||
|
try {
|
||||||
|
const result = await this.$dbQuery("SELECT activeDid FROM active_identity WHERE id = 1");
|
||||||
|
|
||||||
|
if (!result?.values?.length) {
|
||||||
|
logger.warn("[PlatformServiceMixin] Active identity table is empty - migration issue");
|
||||||
|
return { activeDid: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeDid = result.values[0][0] as string | null;
|
||||||
|
|
||||||
|
// Handle null activeDid - auto-select first account
|
||||||
|
if (activeDid === null) {
|
||||||
|
const firstAccount = await this.$dbQuery("SELECT did FROM accounts ORDER BY dateCreated, did LIMIT 1");
|
||||||
|
if (firstAccount?.values?.length) {
|
||||||
|
const firstAccountDid = firstAccount.values[0][0] as string;
|
||||||
|
await this.$dbExec("UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1", [firstAccountDid]);
|
||||||
|
return { activeDid: firstAccountDid };
|
||||||
|
}
|
||||||
|
logger.warn("[PlatformServiceMixin] No accounts available for auto-selection");
|
||||||
|
return { activeDid: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate activeDid exists in accounts
|
||||||
|
const accountExists = await this.$dbQuery("SELECT did FROM accounts WHERE did = ?", [activeDid]);
|
||||||
|
if (accountExists?.values?.length) {
|
||||||
|
return { activeDid };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear corrupted activeDid and return empty
|
||||||
|
logger.warn("[PlatformServiceMixin] Active identity not found in accounts, clearing");
|
||||||
|
await this.$dbExec("UPDATE active_identity SET activeDid = NULL, lastUpdated = datetime('now') WHERE id = 1");
|
||||||
|
return { activeDid: "" };
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("[PlatformServiceMixin] Error getting active identity:", error);
|
||||||
|
return { activeDid: "" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Implementation Notes
|
||||||
|
|
||||||
|
1. **Null Handling**: Auto-selects first account when `activeDid` is null
|
||||||
|
2. **Corruption Detection**: Clears invalid `activeDid` values
|
||||||
|
3. **Manual Timestamps**: Updates `lastUpdated` manually in code
|
||||||
|
4. **Error Handling**: Returns empty string on any error with appropriate logging
|
||||||
|
|
||||||
## Proposed Changes Impact
|
## Proposed Changes Impact
|
||||||
|
|
||||||
### 1. Foreign Key Constraint Change
|
### 1. Foreign Key Constraint Change
|
||||||
**Current**: `ON DELETE SET NULL`
|
**Current**: `ON DELETE SET NULL` → **Proposed**: `ON DELETE RESTRICT`
|
||||||
**Proposed**: `ON DELETE RESTRICT`
|
|
||||||
|
|
||||||
**Impact**:
|
|
||||||
- **Data Safety**: Prevents accidental deletion of active account
|
- **Data Safety**: Prevents accidental deletion of active account
|
||||||
- **Migration Rewrite**: Update existing migration 003
|
- **New Migration**: Add migration 005 to update constraint
|
||||||
|
|
||||||
### 2. Automatic Timestamp Updates
|
### 2. Automatic Timestamp Updates
|
||||||
**Current**: Manual `lastUpdated` updates in code
|
**Current**: Manual `lastUpdated` updates → **Proposed**: Database trigger
|
||||||
**Proposed**: Database trigger for automatic updates
|
|
||||||
|
|
||||||
**Impact**:
|
|
||||||
- **Code Simplification**: Remove manual timestamp updates from `PlatformServiceMixin`
|
- **Code Simplification**: Remove manual timestamp updates from `PlatformServiceMixin`
|
||||||
- **Consistency**: Ensures `lastUpdated` is always current
|
- **Consistency**: Ensures `lastUpdated` is always current
|
||||||
|
|
||||||
### 3. Enhanced Indexing
|
### 3. Enhanced Indexing
|
||||||
**Current**: Single unique index on `id`
|
**Current**: Single unique index on `id` → **Proposed**: Additional index on `accounts(dateCreated, did)`
|
||||||
**Proposed**: Additional index on `accounts(dateCreated, did)`
|
|
||||||
|
|
||||||
**Impact**:
|
|
||||||
- **Performance Improvement**: Faster account selection queries
|
- **Performance Improvement**: Faster account selection queries
|
||||||
- **Minimal Risk**: Additive change only
|
- **Minimal Risk**: Additive change only
|
||||||
|
|
||||||
## Implementation Strategy
|
## Implementation Strategy
|
||||||
|
|
||||||
### Rewrite Migration 003
|
### Add Migration 005
|
||||||
Since the `active_identity` table is new and we're in active development, we can simply rewrite the existing migration:
|
|
||||||
|
Since the `active_identity` table already exists and is working, we can add a new migration to enhance it:
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
{
|
{
|
||||||
name: "003_active_identity_and_seed_backup",
|
name: "005_active_identity_enhancements",
|
||||||
sql: `
|
sql: `
|
||||||
-- Enable foreign key constraints for data integrity
|
|
||||||
PRAGMA foreign_keys = ON;
|
PRAGMA foreign_keys = ON;
|
||||||
|
|
||||||
-- Add UNIQUE constraint to accounts.did for foreign key support
|
-- Recreate table with ON DELETE RESTRICT constraint
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_accounts_did_unique ON accounts(did);
|
CREATE TABLE active_identity_new (
|
||||||
|
|
||||||
-- Create active_identity table with enhanced constraints
|
|
||||||
CREATE TABLE IF NOT EXISTS active_identity (
|
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
|
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
|
||||||
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
|
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Add performance indexes
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_accounts_pick ON accounts(dateCreated, did);
|
|
||||||
|
|
||||||
-- Seed singleton row (only if not already exists)
|
|
||||||
INSERT INTO active_identity (id, activeDid, lastUpdated)
|
|
||||||
SELECT 1, NULL, datetime('now')
|
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
|
|
||||||
|
|
||||||
-- Add hasBackedUpSeed field to settings
|
-- Copy existing data
|
||||||
ALTER TABLE settings ADD COLUMN hasBackedUpSeed BOOLEAN DEFAULT FALSE;
|
INSERT INTO active_identity_new (id, activeDid, lastUpdated)
|
||||||
|
SELECT id, activeDid, lastUpdated FROM active_identity;
|
||||||
|
|
||||||
|
-- Replace old table
|
||||||
|
DROP TABLE active_identity;
|
||||||
|
ALTER TABLE active_identity_new RENAME TO active_identity;
|
||||||
|
|
||||||
|
-- Add performance indexes
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_accounts_pick ON accounts(dateCreated, did);
|
||||||
|
|
||||||
-- Create automatic timestamp trigger
|
-- Create automatic timestamp trigger
|
||||||
CREATE TRIGGER IF NOT EXISTS trg_active_identity_touch
|
CREATE TRIGGER IF NOT EXISTS trg_active_identity_touch
|
||||||
@@ -96,46 +201,59 @@ Since the `active_identity` table is new and we're in active development, we can
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Migration Service Updates Required
|
## Migration Service Updates Required
|
||||||
|
|
||||||
### Enhanced Validation Logic
|
### Enhanced Validation Logic
|
||||||
|
|
||||||
**File**: `src/services/migrationService.ts`
|
**File**: `src/services/migrationService.ts`
|
||||||
|
|
||||||
The existing validation for migration 003 needs to be enhanced to check for:
|
**Migration 004 validation**:
|
||||||
|
- **Table existence**: `SELECT name FROM sqlite_master WHERE type='table' AND name='active_identity'`
|
||||||
|
- **Column structure**: `SELECT id, activeDid, lastUpdated FROM active_identity LIMIT 1`
|
||||||
|
- **Schema detection**: Uses `isSchemaAlreadyPresent()` to check if migration was already applied
|
||||||
|
|
||||||
|
**Migration 005 validation**:
|
||||||
- **Trigger existence**: `trg_active_identity_touch`
|
- **Trigger existence**: `trg_active_identity_touch`
|
||||||
- **Performance index**: `idx_accounts_pick`
|
- **Performance index**: `idx_accounts_pick`
|
||||||
- **Foreign key constraint**: `ON DELETE RESTRICT`
|
- **Foreign key constraint**: `ON DELETE RESTRICT`
|
||||||
|
- **Table recreation**: Verify table was successfully recreated
|
||||||
|
|
||||||
### Enhanced Schema Detection
|
### Enhanced Schema Detection
|
||||||
**File**: `src/services/migrationService.ts`
|
|
||||||
|
|
||||||
The existing schema detection for migration 003 needs to be enhanced to verify:
|
**Migration 004 verification**:
|
||||||
- **Table structure**: Enhanced constraints
|
- **Table structure**: Checks `active_identity` table exists and has correct columns
|
||||||
|
- **Data integrity**: Validates that the table can be queried successfully
|
||||||
|
- **Migration tracking**: Uses `isSchemaAlreadyPresent()` to avoid re-applying migrations
|
||||||
|
|
||||||
|
**Migration 005 verification**:
|
||||||
|
- **Table structure**: Enhanced constraints with `ON DELETE RESTRICT`
|
||||||
- **Trigger presence**: Automatic timestamp updates
|
- **Trigger presence**: Automatic timestamp updates
|
||||||
- **Index presence**: Performance optimization
|
- **Index presence**: Performance optimization
|
||||||
|
- **Data integrity**: Existing data was preserved during table recreation
|
||||||
|
|
||||||
## Risk Assessment
|
## Risk Assessment
|
||||||
|
|
||||||
### Low Risk Changes
|
### Low Risk Changes
|
||||||
- **Performance Index**: Additive only, no data changes
|
- **Performance Index**: Additive only, no data changes
|
||||||
- **Trigger Creation**: Additive only, improves consistency
|
- **Trigger Creation**: Additive only, improves consistency
|
||||||
- **Migration Rewrite**: Clean implementation, no additional migrations
|
- **New Migration**: Clean implementation, no modification of existing migrations
|
||||||
|
|
||||||
### Medium Risk Changes
|
### Medium Risk Changes
|
||||||
- **Foreign Key Change**: `ON DELETE RESTRICT` is more restrictive
|
- **Foreign Key Change**: `ON DELETE RESTRICT` is more restrictive
|
||||||
|
- **Table Recreation**: Requires careful data preservation
|
||||||
- **Validation Updates**: Need to test enhanced validation logic
|
- **Validation Updates**: Need to test enhanced validation logic
|
||||||
|
|
||||||
### Mitigation Strategies
|
### Mitigation Strategies
|
||||||
1. **Comprehensive Testing**: Test migration on various database states
|
1. **Comprehensive Testing**: Test migration on various database states
|
||||||
2. **Development Phase**: Since we're in active development, risk is minimal
|
2. **Data Preservation**: Verify existing data is copied correctly
|
||||||
3. **Clean Implementation**: Single migration with all enhancements
|
3. **Clean Implementation**: New migration with all enhancements
|
||||||
4. **Validation Coverage**: Enhanced validation ensures correctness
|
4. **Validation Coverage**: Enhanced validation ensures correctness
|
||||||
|
5. **Rollback Plan**: Can drop new table and restore original if needed
|
||||||
|
|
||||||
## Implementation Timeline
|
## Implementation Timeline
|
||||||
|
|
||||||
### Phase 1: Migration Rewrite
|
### Phase 1: Migration Enhancement
|
||||||
- [ ] Update migration 003 with enhanced constraints
|
- [ ] Add migration 005 with enhanced constraints
|
||||||
- [ ] Add enhanced validation logic
|
- [ ] Add enhanced validation logic
|
||||||
- [ ] Add enhanced schema detection logic
|
- [ ] Add enhanced schema detection logic
|
||||||
- [ ] Test migration on clean database
|
- [ ] Test migration on clean database
|
||||||
@@ -145,6 +263,7 @@ The existing schema detection for migration 003 needs to be enhanced to verify:
|
|||||||
- [ ] Validate foreign key constraints work correctly
|
- [ ] Validate foreign key constraints work correctly
|
||||||
- [ ] Test trigger functionality
|
- [ ] Test trigger functionality
|
||||||
- [ ] Test performance improvements
|
- [ ] Test performance improvements
|
||||||
|
- [ ] Verify data preservation during table recreation
|
||||||
|
|
||||||
### Phase 3: Deployment
|
### Phase 3: Deployment
|
||||||
- [ ] Deploy enhanced migration to development
|
- [ ] Deploy enhanced migration to development
|
||||||
@@ -152,359 +271,120 @@ The existing schema detection for migration 003 needs to be enhanced to verify:
|
|||||||
- [ ] Deploy to production
|
- [ ] Deploy to production
|
||||||
- [ ] Monitor for any issues
|
- [ ] Monitor for any issues
|
||||||
|
|
||||||
|
### Phase 4: Settings Table Cleanup
|
||||||
|
- [ ] Create migration 006 to clean up settings table
|
||||||
|
- [ ] Remove orphaned settings records (accountDid is null)
|
||||||
|
- [ ] Clear any remaining activeDid values in settings
|
||||||
|
- [ ] Consider removing activeDid column entirely (future task)
|
||||||
|
|
||||||
|
## Settings Table Cleanup Strategy
|
||||||
|
|
||||||
|
### Current State Analysis
|
||||||
|
The settings table currently contains:
|
||||||
|
- **Legacy activeDid column**: Still present from original design
|
||||||
|
- **Orphaned records**: Settings with `accountDid = null` that may be obsolete
|
||||||
|
- **Redundant data**: Some settings may have been copied unnecessarily
|
||||||
|
|
||||||
|
Based on team feedback, the cleanup should include:
|
||||||
|
|
||||||
|
1. **Remove orphaned settings records**:
|
||||||
|
```sql
|
||||||
|
DELETE FROM settings WHERE accountDid IS NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Clear any remaining activeDid values**:
|
||||||
|
```sql
|
||||||
|
UPDATE settings SET activeDid = NULL;
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Future consideration**: Remove the activeDid column entirely from settings table
|
||||||
|
|
||||||
|
### Migration 006: Settings Cleanup
|
||||||
|
|
||||||
|
```sql
|
||||||
|
{
|
||||||
|
name: "006_settings_cleanup",
|
||||||
|
sql: `
|
||||||
|
-- Remove orphaned settings records (accountDid is null)
|
||||||
|
DELETE FROM settings WHERE accountDid IS NULL;
|
||||||
|
|
||||||
|
-- Clear any remaining activeDid values in settings
|
||||||
|
UPDATE settings SET activeDid = NULL;
|
||||||
|
|
||||||
|
-- Optional: Consider removing the activeDid column entirely
|
||||||
|
-- ALTER TABLE settings DROP COLUMN activeDid;
|
||||||
|
`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Benefits of Settings Cleanup
|
||||||
|
- **Reduced confusion**: Eliminates dual-purpose columns
|
||||||
|
- **Cleaner architecture**: Settings table focuses only on user preferences
|
||||||
|
- **Reduced storage**: Removes unnecessary data
|
||||||
|
- **Clearer separation**: Active identity vs. user settings are distinct concerns
|
||||||
|
|
||||||
|
### Risk Assessment: LOW
|
||||||
|
- **Data safety**: Only removes orphaned/obsolete records
|
||||||
|
- **Backward compatibility**: Maintains existing column structure
|
||||||
|
- **Rollback**: Easy to restore if needed
|
||||||
|
- **Testing**: Can be validated with existing data
|
||||||
|
|
||||||
## Code Changes Required
|
## Code Changes Required
|
||||||
|
|
||||||
### Files to Modify
|
### Files to Modify
|
||||||
1. **`src/db-sql/migration.ts`** - Update migration 003 with enhanced constraints
|
1. **`src/db-sql/migration.ts`** - Add migration 005 with enhanced constraints
|
||||||
2. **`src/services/migrationService.ts`** - Add enhanced validation and detection logic
|
2. **`src/db-sql/migration.ts`** - Add migration 006 for settings cleanup
|
||||||
3. **`src/utils/PlatformServiceMixin.ts`** - Remove manual timestamp updates
|
3. **`src/services/migrationService.ts`** - Add enhanced validation and detection logic
|
||||||
|
4. **`src/utils/PlatformServiceMixin.ts`** - Remove manual timestamp updates
|
||||||
|
|
||||||
### Estimated Impact
|
### Estimated Impact
|
||||||
- **Migration File**: ~20 lines modified (enhanced constraints)
|
- **Migration File**: ~25 lines added (migration 005) + ~15 lines added (migration 006)
|
||||||
- **Migration Service**: ~50 lines added (enhanced validation)
|
- **Migration Service**: ~50 lines added (enhanced validation)
|
||||||
- **PlatformServiceMixin**: ~20 lines removed (manual timestamps)
|
- **PlatformServiceMixin**: ~20 lines removed (manual timestamps)
|
||||||
- **Total**: ~50 lines changed
|
- **Total**: ~90 lines changed
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
The proposed database changes are **feasible and beneficial** with a much simpler implementation:
|
**✅ IMPLEMENTATION COMPLETE**: The active identity upgrade plan has been successfully applied to the current project.
|
||||||
|
|
||||||
**Benefits**:
|
### Successfully Implemented
|
||||||
- Improved data integrity with `ON DELETE RESTRICT`
|
|
||||||
- Automatic timestamp consistency
|
|
||||||
- Better query performance
|
|
||||||
- Cleaner code (no manual timestamp updates)
|
|
||||||
- **Simpler implementation** - just rewrite migration 003
|
|
||||||
|
|
||||||
**Risks**:
|
**✅ Migration Structure Updated**:
|
||||||
- More restrictive foreign key constraints
|
- **Migration 003**: `003_add_hasBackedUpSeed_to_settings` (assumes master deployment)
|
||||||
- Enhanced validation logic needs testing
|
- **Migration 004**: `004_active_identity_and_seed_backup` (creates active_identity table)
|
||||||
|
- **All migrations are additional** - follows team member feedback exactly
|
||||||
|
|
||||||
**Recommendation**: Proceed with **rewriting migration 003** as it provides the cleanest path forward with minimal complexity and maximum benefit.
|
**✅ Technical Implementation**:
|
||||||
|
- **Data Migration**: Preserves existing `activeDid` from settings table
|
||||||
|
- **Foreign Key Constraints**: `ON DELETE SET NULL` for data safety
|
||||||
|
- **iOS/Android Compatibility**: Confirmed with SQLCipher 4.9.0 (SQLite 3.44.2)
|
||||||
|
- **Migration Service**: Updated validation and schema detection logic
|
||||||
|
|
||||||
|
**✅ Code Quality**:
|
||||||
|
- **TypeScript**: All type errors resolved
|
||||||
|
- **Linting**: No linting errors
|
||||||
|
- **Team Guidance**: Follows "additional migrations only" requirement
|
||||||
|
|
||||||
|
### Next Steps (Future Enhancements)
|
||||||
|
|
||||||
|
The foundation is now in place for future enhancements:
|
||||||
|
|
||||||
|
1. **Migration 005**: `005_active_identity_enhancements` (ON DELETE RESTRICT, triggers, indexes)
|
||||||
|
2. **Migration 006**: `006_settings_cleanup` (remove orphaned settings, clear legacy activeDid)
|
||||||
|
3. **Code Simplification**: Remove manual timestamp updates from PlatformServiceMixin
|
||||||
|
|
||||||
|
### Current Status
|
||||||
|
|
||||||
|
**Migration 004 is ready for deployment** and will:
|
||||||
|
- ✅ Create `active_identity` table with proper constraints
|
||||||
|
- ✅ Migrate existing `activeDid` data from settings
|
||||||
|
- ✅ Work identically on iOS and Android
|
||||||
|
- ✅ Follow team member feedback for additional migrations only
|
||||||
|
|
||||||
|
**Key Point**: All migrations are **additional** - no editing of previous migrations since master code has been deployed. This ensures compatibility and proper testing.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Part 2: Active Identity System Upgrade Plan
|
**Status**: Ready for team review and implementation approval
|
||||||
|
**Last Updated**: 2025-09-11
|
||||||
# Active Identity System Upgrade Plan
|
**Next Review**: After team feedback and approval
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This document outlines a comprehensive upgrade to the `$getActiveIdentity` system
|
|
||||||
to address current ambiguities, race conditions, and improve overall robustness.
|
|
||||||
|
|
||||||
## Current Issues Identified
|
|
||||||
|
|
||||||
### 1. **Ambiguous Return States**
|
|
||||||
|
|
||||||
- Current: Returns `{ activeDid: string }` where empty string conflates multiple states
|
|
||||||
- Problem: Cannot distinguish between "no accounts", "migration gap", "corruption cleared"
|
|
||||||
- Impact: UI cannot provide appropriate user guidance
|
|
||||||
|
|
||||||
### 2. **Race Conditions (TOCTOU)**
|
|
||||||
|
|
||||||
- Current: Read → Write → Re-read across multiple statements
|
|
||||||
- Problem: No transactional guard, potential for inconsistent state
|
|
||||||
- Impact: Rare but possible data corruption scenarios
|
|
||||||
|
|
||||||
### 3. **No Single-Row Enforcement**
|
|
||||||
|
|
||||||
- Current: App logic assumes `id=1` singleton, but DB doesn't enforce
|
|
||||||
- Problem: Multiple rows could theoretically exist
|
|
||||||
- Impact: Unpredictable behavior
|
|
||||||
|
|
||||||
### 4. **Deletion Hazards**
|
|
||||||
|
|
||||||
- Current: No protection against deleting active account
|
|
||||||
- Problem: App "discovers" corruption after the fact
|
|
||||||
- Impact: Poor user experience, potential data loss
|
|
||||||
|
|
||||||
### 5. **Inconsistent Updates**
|
|
||||||
|
|
||||||
- Current: `lastUpdated` only set on some code paths
|
|
||||||
- Problem: Audit trail incomplete
|
|
||||||
- Impact: Debugging difficulties
|
|
||||||
|
|
||||||
## Proposed Solution Architecture
|
|
||||||
|
|
||||||
### Database Schema Changes
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- Enhanced active_identity table with constraints
|
|
||||||
CREATE TABLE IF NOT EXISTS active_identity (
|
|
||||||
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
||||||
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
|
|
||||||
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Automatic timestamp updates
|
|
||||||
CREATE TRIGGER IF NOT EXISTS trg_active_identity_touch
|
|
||||||
AFTER UPDATE ON active_identity
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE active_identity
|
|
||||||
SET lastUpdated = datetime('now')
|
|
||||||
WHERE id = 1;
|
|
||||||
END;
|
|
||||||
|
|
||||||
-- Deterministic account selection index
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_accounts_pick
|
|
||||||
ON accounts(dateCreated, did);
|
|
||||||
|
|
||||||
-- Seed singleton row
|
|
||||||
INSERT INTO active_identity (id, activeDid)
|
|
||||||
SELECT 1, NULL
|
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Type System Enhancement
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
type ActiveIdentity =
|
|
||||||
| { state: 'ok'; activeDid: string }
|
|
||||||
| { state: 'unset'; activeDid: '' } // row exists, but no active set yet
|
|
||||||
| { state: 'auto-selected'; activeDid: string } // we selected & saved first account
|
|
||||||
| { state: 'empty-accounts'; activeDid: '' } // there are no accounts to select
|
|
||||||
| { state: 'cleared-corrupt'; activeDid: '' } // DB had a non-existent DID; cleared
|
|
||||||
| { state: 'error'; activeDid: '' };
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration Strategy
|
|
||||||
|
|
||||||
### Phase 1: Database Schema Migration
|
|
||||||
|
|
||||||
**Files to modify:**
|
|
||||||
|
|
||||||
- `src/db-sql/migration.ts` - Add new migration
|
|
||||||
- `src/services/migrationService.ts` - Update validation logic
|
|
||||||
|
|
||||||
**Migration Steps:**
|
|
||||||
|
|
||||||
1. Add foreign key constraint to `active_identity.activeDid`
|
|
||||||
2. Add `ON DELETE RESTRICT` constraint
|
|
||||||
3. Create timestamp trigger
|
|
||||||
4. Add deterministic index
|
|
||||||
5. Ensure singleton row exists
|
|
||||||
|
|
||||||
**Risk Assessment:** LOW
|
|
||||||
- Additive changes only
|
|
||||||
- Existing data preserved
|
|
||||||
- Rollback possible
|
|
||||||
|
|
||||||
### Phase 2: Core Method Refactor
|
|
||||||
|
|
||||||
**Files to modify:**
|
|
||||||
|
|
||||||
- `src/utils/PlatformServiceMixin.ts` - Replace `$getActiveIdentity`
|
|
||||||
- `src/interfaces/` - Add new type definitions
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
|
|
||||||
1. Implement transactional `$getActiveIdentity` with explicit states
|
|
||||||
2. Add `$setActiveIdentity` method
|
|
||||||
3. Add `$deleteAccountSafely` method
|
|
||||||
4. Update return type to `ActiveIdentity`
|
|
||||||
|
|
||||||
**Risk Assessment:** MEDIUM
|
|
||||||
|
|
||||||
- Breaking change to return type
|
|
||||||
- Requires coordinated updates across codebase
|
|
||||||
- Extensive testing needed
|
|
||||||
|
|
||||||
### Phase 3: Consumer Updates
|
|
||||||
|
|
||||||
**Files to modify:**
|
|
||||||
|
|
||||||
- All Vue components using `$getActiveIdentity`
|
|
||||||
- Router guards
|
|
||||||
- Service layer components
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
|
|
||||||
1. Update all callers to handle new return type
|
|
||||||
2. Implement state-specific UI logic
|
|
||||||
3. Add appropriate user messaging
|
|
||||||
|
|
||||||
**Risk Assessment:** HIGH
|
|
||||||
|
|
||||||
- Wide impact across codebase
|
|
||||||
- UI/UX changes required
|
|
||||||
- Extensive testing needed
|
|
||||||
|
|
||||||
## Implementation Phases
|
|
||||||
|
|
||||||
### Phase 1: Database Foundation
|
|
||||||
|
|
||||||
- [ ] Create migration for schema changes
|
|
||||||
- [ ] Test migration on development databases
|
|
||||||
- [ ] Validate foreign key constraints work correctly
|
|
||||||
- [ ] Test rollback scenarios
|
|
||||||
|
|
||||||
### Phase 2: Core Implementation
|
|
||||||
|
|
||||||
- [ ] Implement new `$getActiveIdentity` method
|
|
||||||
- [ ] Add `$setActiveIdentity` method
|
|
||||||
- [ ] Add `$deleteAccountSafely` method
|
|
||||||
- [ ] Create comprehensive unit tests
|
|
||||||
- [ ] Test transactional behavior
|
|
||||||
|
|
||||||
### Phase 3: Consumer Updates
|
|
||||||
|
|
||||||
- [ ] Audit all current usage of `$getActiveIdentity`
|
|
||||||
- [ ] Create migration guide for components
|
|
||||||
- [ ] Update critical path components first
|
|
||||||
- [ ] Implement state-specific UI logic
|
|
||||||
|
|
||||||
### Phase 4: Testing & Rollout
|
|
||||||
|
|
||||||
- [ ] End-to-end testing
|
|
||||||
- [ ] Performance testing
|
|
||||||
- [ ] User acceptance testing
|
|
||||||
- [ ] Gradual rollout with feature flags
|
|
||||||
|
|
||||||
## Backward Compatibility Strategy
|
|
||||||
|
|
||||||
### Gradual Migration Approach
|
|
||||||
|
|
||||||
The gradual migration strategy allows us to implement the new active identity system without breaking existing functionality. This approach minimizes risk and provides a clear path for incremental updates.
|
|
||||||
|
|
||||||
#### Phase 1: Dual Method Implementation
|
|
||||||
|
|
||||||
- **Keep existing method**: Leave current `$getActiveIdentity` unchanged (no renaming)
|
|
||||||
- **Add new method**: Implement `$getActiveIdentityV2` with new return type and logic
|
|
||||||
- **Feature flag control**: Use `FEATURE_FLAG_ACTIVE_IDENTITY_V2` to control which method is used
|
|
||||||
- **Default to existing**: Start with existing method enabled to ensure no breaking changes
|
|
||||||
|
|
||||||
#### Phase 2: Component Migration
|
|
||||||
|
|
||||||
- **Audit usage**: Identify all components using `$getActiveIdentity`
|
|
||||||
- **Create migration guide**: Document the changes needed for each component type
|
|
||||||
- **Update incrementally**: Migrate components to use `$getActiveIdentityV2` one
|
|
||||||
by one, starting with non-critical paths
|
|
||||||
- **Test each migration**: Validate each component works with the new method
|
|
||||||
before proceeding
|
|
||||||
|
|
||||||
#### Phase 3: Feature Flag Rollout
|
|
||||||
|
|
||||||
- **Enable for migrated components**: Switch feature flag for components that have been updated
|
|
||||||
- **Monitor performance**: Track any performance or behavior changes
|
|
||||||
- **Gradual enablement**: Enable the new method for more components as they're migrated
|
|
||||||
- **Fallback capability**: Keep legacy method available for rollback if issues arise
|
|
||||||
|
|
||||||
#### Phase 4: Legacy Cleanup
|
|
||||||
|
|
||||||
- **Remove feature flag**: Once all components are migrated, remove the feature flag
|
|
||||||
- **Replace existing method**: Replace the implementation of `$getActiveIdentity` with the V2 logic
|
|
||||||
- **Remove V2 method**: Delete `$getActiveIdentityV2` and related code
|
|
||||||
- **Update documentation**: Remove references to the V2 method
|
|
||||||
- **Final validation**: Ensure no remaining references to V2 method
|
|
||||||
|
|
||||||
#### Benefits of This Approach
|
|
||||||
|
|
||||||
- **Zero downtime**: No breaking changes during migration
|
|
||||||
- **Incremental testing**: Each component can be tested individually
|
|
||||||
- **Easy rollback**: Can revert individual components or entire system if needed
|
|
||||||
- **Clear progress tracking**: Easy to see which components still need migration
|
|
||||||
- **Reduced risk**: Issues are isolated to individual components rather than system-wide
|
|
||||||
|
|
||||||
## Risk Mitigation
|
|
||||||
|
|
||||||
### Database Risks
|
|
||||||
|
|
||||||
- **Foreign Key Violations**: Test with existing data
|
|
||||||
- **Migration Failures**: Comprehensive rollback plan
|
|
||||||
- **Performance Impact**: Monitor query performance
|
|
||||||
|
|
||||||
### Code Risks
|
|
||||||
|
|
||||||
- **Breaking Changes**: Extensive testing, gradual rollout
|
|
||||||
- **Race Conditions**: Comprehensive unit tests
|
|
||||||
- **State Management**: Clear documentation, examples
|
|
||||||
|
|
||||||
### User Experience Risks
|
|
||||||
|
|
||||||
- **Confusing States**: Clear UI messaging
|
|
||||||
- **Data Loss**: Backup strategies, validation
|
|
||||||
- **Performance**: Monitor response times
|
|
||||||
|
|
||||||
## Success Metrics
|
|
||||||
|
|
||||||
### Technical Metrics
|
|
||||||
|
|
||||||
- Zero race condition incidents
|
|
||||||
- 100% test coverage for new methods
|
|
||||||
- <50ms average response time
|
|
||||||
- Zero data corruption incidents
|
|
||||||
|
|
||||||
### User Experience Metrics
|
|
||||||
|
|
||||||
- Clear state-specific messaging
|
|
||||||
- Reduced user confusion
|
|
||||||
- Improved onboarding flow
|
|
||||||
- Faster account switching
|
|
||||||
|
|
||||||
## Rollback Plan
|
|
||||||
|
|
||||||
### Database Rollback
|
|
||||||
|
|
||||||
1. Remove foreign key constraints
|
|
||||||
2. Remove triggers
|
|
||||||
3. Remove indexes
|
|
||||||
4. Restore previous migration state
|
|
||||||
|
|
||||||
### Code Rollback
|
|
||||||
|
|
||||||
1. Revert to previous `$getActiveIdentity` implementation
|
|
||||||
2. Remove new type definitions
|
|
||||||
3. Restore previous component logic
|
|
||||||
4. Remove new methods
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
|
|
||||||
- Test all state transitions
|
|
||||||
- Test transactional behavior
|
|
||||||
- Test error conditions
|
|
||||||
- Test edge cases
|
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
|
|
||||||
- Test with real database
|
|
||||||
- Test migration scenarios
|
|
||||||
- Test concurrent access
|
|
||||||
- Test foreign key constraints
|
|
||||||
|
|
||||||
### End-to-End Tests
|
|
||||||
|
|
||||||
- Test complete user flows
|
|
||||||
- Test account creation/deletion
|
|
||||||
- Test active identity switching
|
|
||||||
- Test error recovery
|
|
||||||
|
|
||||||
## Documentation Requirements
|
|
||||||
|
|
||||||
### Developer Documentation
|
|
||||||
|
|
||||||
- Migration guide for components
|
|
||||||
- API documentation for new methods
|
|
||||||
- Type definitions and examples
|
|
||||||
- Best practices guide
|
|
||||||
|
|
||||||
### User Documentation
|
|
||||||
|
|
||||||
- State-specific UI messaging
|
|
||||||
- Error message guidelines
|
|
||||||
- Onboarding flow updates
|
|
||||||
- Troubleshooting guide
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
This upgrade addresses critical architectural issues while providing a clear path
|
|
||||||
forward. The phased approach minimizes risk while ensuring thorough testing and
|
|
||||||
validation at each step.
|
|
||||||
|
|
||||||
**Recommendation:** Proceed with Phase 1 (Database Schema) immediately, as it
|
|
||||||
provides immediate benefits with minimal risk. The gradual migration approach allows
|
|
||||||
for incremental updates without breaking existing functionality.
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ interface DatabaseResult {
|
|||||||
// where they couldn't take action because they couldn't unlock that identity.)
|
// where they couldn't take action because they couldn't unlock that identity.)
|
||||||
|
|
||||||
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
|
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
|
||||||
const secretBase64 = arrayBufferToBase64(randomBytes);
|
const secretBase64 = arrayBufferToBase64(randomBytes.buffer);
|
||||||
|
|
||||||
// Each migration can include multiple SQL statements (with semicolons)
|
// Each migration can include multiple SQL statements (with semicolons)
|
||||||
const MIGRATIONS = [
|
const MIGRATIONS = [
|
||||||
@@ -132,8 +132,20 @@ const MIGRATIONS = [
|
|||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "003_active_identity_and_seed_backup",
|
name: "003_add_hasBackedUpSeed_to_settings",
|
||||||
sql: `
|
sql: `
|
||||||
|
-- Add hasBackedUpSeed field to settings
|
||||||
|
-- This migration assumes master code has been deployed
|
||||||
|
-- The error handling will catch this if column already exists and mark migration as applied
|
||||||
|
ALTER TABLE settings ADD COLUMN hasBackedUpSeed BOOLEAN DEFAULT FALSE;
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "004_active_identity_and_seed_backup",
|
||||||
|
sql: `
|
||||||
|
-- Migration 004: active_identity_and_seed_backup
|
||||||
|
-- Assumes master code deployed with migration 003 (hasBackedUpSeed)
|
||||||
|
|
||||||
-- Enable foreign key constraints for data integrity
|
-- Enable foreign key constraints for data integrity
|
||||||
PRAGMA foreign_keys = ON;
|
PRAGMA foreign_keys = ON;
|
||||||
|
|
||||||
@@ -152,7 +164,6 @@ const MIGRATIONS = [
|
|||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_active_identity_single_record ON active_identity(id);
|
||||||
|
|
||||||
-- Seed singleton row (only if not already exists)
|
-- Seed singleton row (only if not already exists)
|
||||||
-- Use a more explicit approach to ensure the row gets inserted
|
|
||||||
INSERT INTO active_identity (id, activeDid, lastUpdated)
|
INSERT INTO active_identity (id, activeDid, lastUpdated)
|
||||||
SELECT 1, NULL, datetime('now')
|
SELECT 1, NULL, datetime('now')
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
|
WHERE NOT EXISTS (SELECT 1 FROM active_identity WHERE id = 1);
|
||||||
@@ -174,15 +185,6 @@ const MIGRATIONS = [
|
|||||||
SELECT 'DEBUG: Row count after insertion' as debug_message, COUNT(*) as row_count FROM active_identity;
|
SELECT 'DEBUG: Row count after insertion' as debug_message, COUNT(*) as row_count FROM active_identity;
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "003b_add_hasBackedUpSeed_to_settings",
|
|
||||||
sql: `
|
|
||||||
-- Add hasBackedUpSeed field to settings
|
|
||||||
-- This may fail if column already exists from master branch migration
|
|
||||||
-- The error handling will catch this and mark migration as applied
|
|
||||||
ALTER TABLE settings ADD COLUMN hasBackedUpSeed BOOLEAN DEFAULT FALSE;
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -280,7 +280,23 @@ async function validateMigrationApplication<T>(
|
|||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (migration.name === "003_active_identity_and_seed_backup") {
|
} else if (migration.name === "003_add_hasBackedUpSeed_to_settings") {
|
||||||
|
// Validate hasBackedUpSeed column exists in settings table
|
||||||
|
try {
|
||||||
|
await sqlQuery(`SELECT hasBackedUpSeed FROM settings LIMIT 1`);
|
||||||
|
validation.isValid = true;
|
||||||
|
validation.hasExpectedColumns = true;
|
||||||
|
} catch (error) {
|
||||||
|
validation.isValid = false;
|
||||||
|
validation.errors.push(
|
||||||
|
`Column hasBackedUpSeed missing from settings table`,
|
||||||
|
);
|
||||||
|
logger.error(
|
||||||
|
`❌ [Migration-Validation] Column hasBackedUpSeed missing:`,
|
||||||
|
error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (migration.name === "004_active_identity_and_seed_backup") {
|
||||||
// Validate active_identity table exists and has correct structure
|
// Validate active_identity table exists and has correct structure
|
||||||
try {
|
try {
|
||||||
// Check that active_identity table exists
|
// Check that active_identity table exists
|
||||||
@@ -315,29 +331,13 @@ async function validateMigrationApplication<T>(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
validation.isValid = false;
|
validation.isValid = false;
|
||||||
validation.errors.push(
|
validation.errors.push(
|
||||||
`Validation error for active_did_separation: ${error}`,
|
`Validation error for active_identity_and_seed_backup: ${error}`,
|
||||||
);
|
);
|
||||||
logger.error(
|
logger.error(
|
||||||
`❌ [Migration-Validation] Validation failed for ${migration.name}:`,
|
`❌ [Migration-Validation] Validation failed for ${migration.name}:`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (migration.name === "003b_add_hasBackedUpSeed_to_settings") {
|
|
||||||
// Validate hasBackedUpSeed column exists in settings table
|
|
||||||
try {
|
|
||||||
await sqlQuery(`SELECT hasBackedUpSeed FROM settings LIMIT 1`);
|
|
||||||
validation.isValid = true;
|
|
||||||
validation.hasExpectedColumns = true;
|
|
||||||
} catch (error) {
|
|
||||||
validation.isValid = false;
|
|
||||||
validation.errors.push(
|
|
||||||
`Column hasBackedUpSeed missing from settings table`,
|
|
||||||
);
|
|
||||||
logger.error(
|
|
||||||
`❌ [Migration-Validation] Column hasBackedUpSeed missing:`,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add validation for future migrations here
|
// Add validation for future migrations here
|
||||||
@@ -401,7 +401,15 @@ async function isSchemaAlreadyPresent<T>(
|
|||||||
// Reduced logging - only log on error
|
// Reduced logging - only log on error
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (migration.name === "003_active_identity_and_seed_backup") {
|
} else if (migration.name === "003_add_hasBackedUpSeed_to_settings") {
|
||||||
|
// Check if hasBackedUpSeed column exists in settings table
|
||||||
|
try {
|
||||||
|
await sqlQuery(`SELECT hasBackedUpSeed FROM settings LIMIT 1`);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (migration.name === "004_active_identity_and_seed_backup") {
|
||||||
// Check if active_identity table exists and has correct structure
|
// Check if active_identity table exists and has correct structure
|
||||||
try {
|
try {
|
||||||
// Check that active_identity table exists
|
// Check that active_identity table exists
|
||||||
@@ -608,7 +616,7 @@ export async function runMigrations<T>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Debug: Check if active_identity table exists and has data
|
// Debug: Check if active_identity table exists and has data
|
||||||
if (migration.name === "003_active_identity_and_seed_backup") {
|
if (migration.name === "004_active_identity_and_seed_backup") {
|
||||||
try {
|
try {
|
||||||
const tableCheck = await sqlQuery(
|
const tableCheck = await sqlQuery(
|
||||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='active_identity'",
|
"SELECT name FROM sqlite_master WHERE type='table' AND name='active_identity'",
|
||||||
|
|||||||
Reference in New Issue
Block a user