Files
crowd-funder-from-jason/doc/active-identity-upgrade-plan.md
Matthew Raymer 31f66909fa 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
2025-09-11 13:08:37 +00:00

391 lines
15 KiB
Markdown

# Active Identity Upgrade Plan
**Author**: Matthew Raymer
**Date**: 2025-09-11
**Status**: 🎯 **PLANNING** - Database migration and active identity system upgrade
## 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
### Existing Migration 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
- **Data Migration**: Copies existing `activeDid` from settings to `active_identity` table
- **Bootstrapping**: Auto-selects first account if `activeDid` is null/empty
**Important**: All migrations are **additional** - no editing of previous migrations since master code has been deployed.
### Current Schema (Migration 004) - IMPLEMENTED
```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 (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT DEFAULT NULL,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now')),
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
### 1. Foreign Key Constraint Change
**Current**: `ON DELETE SET NULL`**Proposed**: `ON DELETE RESTRICT`
- **Data Safety**: Prevents accidental deletion of active account
- **New Migration**: Add migration 005 to update constraint
### 2. Automatic Timestamp Updates
**Current**: Manual `lastUpdated` updates → **Proposed**: Database trigger
- **Code Simplification**: Remove manual timestamp updates from `PlatformServiceMixin`
- **Consistency**: Ensures `lastUpdated` is always current
### 3. Enhanced Indexing
**Current**: Single unique index on `id`**Proposed**: Additional index on `accounts(dateCreated, did)`
- **Performance Improvement**: Faster account selection queries
- **Minimal Risk**: Additive change only
## Implementation Strategy
### Add Migration 005
Since the `active_identity` table already exists and is working, we can add a new migration to enhance it:
```sql
{
name: "005_active_identity_enhancements",
sql: `
PRAGMA foreign_keys = ON;
-- Recreate table with ON DELETE RESTRICT constraint
CREATE TABLE active_identity_new (
id INTEGER PRIMARY KEY CHECK (id = 1),
activeDid TEXT REFERENCES accounts(did) ON DELETE RESTRICT,
lastUpdated TEXT NOT NULL DEFAULT (datetime('now'))
);
-- Copy existing data
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 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;
`
}
```
## Migration Service Updates Required
### Enhanced Validation Logic
**File**: `src/services/migrationService.ts`
**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`
- **Performance index**: `idx_accounts_pick`
- **Foreign key constraint**: `ON DELETE RESTRICT`
- **Table recreation**: Verify table was successfully recreated
### Enhanced Schema Detection
**Migration 004 verification**:
- **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
- **Index presence**: Performance optimization
- **Data integrity**: Existing data was preserved during table recreation
## Risk Assessment
### Low Risk Changes
- **Performance Index**: Additive only, no data changes
- **Trigger Creation**: Additive only, improves consistency
- **New Migration**: Clean implementation, no modification of existing migrations
### Medium Risk Changes
- **Foreign Key Change**: `ON DELETE RESTRICT` is more restrictive
- **Table Recreation**: Requires careful data preservation
- **Validation Updates**: Need to test enhanced validation logic
### Mitigation Strategies
1. **Comprehensive Testing**: Test migration on various database states
2. **Data Preservation**: Verify existing data is copied correctly
3. **Clean Implementation**: New migration with all enhancements
4. **Validation Coverage**: Enhanced validation ensures correctness
5. **Rollback Plan**: Can drop new table and restore original if needed
## Implementation Timeline
### Phase 1: Migration Enhancement
- [ ] Add migration 005 with enhanced constraints
- [ ] Add enhanced validation logic
- [ ] Add enhanced schema detection logic
- [ ] Test migration on clean database
### Phase 2: Testing
- [ ] Test migration on existing databases
- [ ] Validate foreign key constraints work correctly
- [ ] Test trigger functionality
- [ ] Test performance improvements
- [ ] Verify data preservation during table recreation
### Phase 3: Deployment
- [ ] Deploy enhanced migration to development
- [ ] Monitor migration success rates
- [ ] Deploy to production
- [ ] 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
### Files to Modify
1. **`src/db-sql/migration.ts`** - Add migration 005 with enhanced constraints
2. **`src/db-sql/migration.ts`** - Add migration 006 for settings cleanup
3. **`src/services/migrationService.ts`** - Add enhanced validation and detection logic
4. **`src/utils/PlatformServiceMixin.ts`** - Remove manual timestamp updates
### Estimated Impact
- **Migration File**: ~25 lines added (migration 005) + ~15 lines added (migration 006)
- **Migration Service**: ~50 lines added (enhanced validation)
- **PlatformServiceMixin**: ~20 lines removed (manual timestamps)
- **Total**: ~90 lines changed
## Conclusion
**✅ IMPLEMENTATION COMPLETE**: The active identity upgrade plan has been successfully applied to the current project.
### Successfully Implemented
**✅ Migration Structure Updated**:
- **Migration 003**: `003_add_hasBackedUpSeed_to_settings` (assumes master deployment)
- **Migration 004**: `004_active_identity_and_seed_backup` (creates active_identity table)
- **All migrations are additional** - follows team member feedback exactly
**✅ 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.
---
**Status**: Ready for team review and implementation approval
**Last Updated**: 2025-09-11
**Next Review**: After team feedback and approval