Browse Source
Separate activeDid from monolithic settings table into dedicated active_identity table to improve data normalization and reduce cache drift. Implements phased migration with dual-write triggers and fallback support during transition. - Add migrations 003 (create table) and 004 (drop legacy column) - Extend PlatformServiceMixin with new façade methods - Add feature flags for controlled rollout - Include comprehensive validation and error handling - Maintain backward compatibility during transition phase BREAKING CHANGE: Components should use $getActiveDid()/$setActiveDid() instead of direct settings.activeDid accessactivedid_migration
5 changed files with 684 additions and 0 deletions
@ -0,0 +1,298 @@ |
|||||
|
# ActiveDid Table Separation Progress Report |
||||
|
|
||||
|
**Author**: Matthew Raymer |
||||
|
**Date**: 2025-08-21T12:32Z |
||||
|
**Status**: 🔍 **INVESTIGATION COMPLETE** - Ready for implementation planning |
||||
|
|
||||
|
## Executive Summary |
||||
|
|
||||
|
This document tracks the investigation and progress of separating the `activeDid` field |
||||
|
from the `settings` table into a dedicated `active_identity` table. The project aims |
||||
|
to improve data integrity, reduce cache drift, and simplify transaction logic for |
||||
|
identity management in TimeSafari. |
||||
|
|
||||
|
## Investigation Results |
||||
|
|
||||
|
### Reference Audit Findings |
||||
|
|
||||
|
**Total ActiveDid References**: 505 across the codebase |
||||
|
|
||||
|
- **Write Operations**: 100 (20%) |
||||
|
- **Read Operations**: 260 (51%) |
||||
|
- **Other References**: 145 (29%) - includes type definitions, comments, etc. |
||||
|
|
||||
|
**Component Impact**: 15+ Vue components directly access `settings.activeDid` |
||||
|
|
||||
|
### Current Database Schema |
||||
|
|
||||
|
The `settings` table currently contains **30 fields** mixing identity state with user |
||||
|
preferences: |
||||
|
|
||||
|
```sql |
||||
|
CREATE TABLE IF NOT EXISTS settings ( |
||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, |
||||
|
accountDid TEXT, -- Links to identity (null = master) |
||||
|
activeDid TEXT, -- Current active identity (master only) |
||||
|
apiServer TEXT, -- API endpoint |
||||
|
filterFeedByNearby BOOLEAN, |
||||
|
filterFeedByVisible BOOLEAN, |
||||
|
finishedOnboarding BOOLEAN, |
||||
|
firstName TEXT, -- User's name |
||||
|
hideRegisterPromptOnNewContact BOOLEAN, |
||||
|
isRegistered BOOLEAN, |
||||
|
lastName TEXT, -- Deprecated |
||||
|
lastAckedOfferToUserJwtId TEXT, |
||||
|
lastAckedOfferToUserProjectsJwtId TEXT, |
||||
|
lastNotifiedClaimId TEXT, |
||||
|
lastViewedClaimId TEXT, |
||||
|
notifyingNewActivityTime TEXT, |
||||
|
notifyingReminderMessage TEXT, |
||||
|
notifyingReminderTime TEXT, |
||||
|
partnerApiServer TEXT, |
||||
|
passkeyExpirationMinutes INTEGER, |
||||
|
profileImageUrl TEXT, |
||||
|
searchBoxes TEXT, -- JSON string |
||||
|
showContactGivesInline BOOLEAN, |
||||
|
showGeneralAdvanced BOOLEAN, |
||||
|
showShortcutBvc BOOLEAN, |
||||
|
vapid TEXT, |
||||
|
warnIfProdServer BOOLEAN, |
||||
|
warnIfTestServer BOOLEAN, |
||||
|
webPushServer TEXT |
||||
|
); |
||||
|
``` |
||||
|
|
||||
|
### Component State Management |
||||
|
|
||||
|
#### PlatformServiceMixin Cache System |
||||
|
|
||||
|
- **`_currentActiveDid`**: Component-level cache for activeDid |
||||
|
- **`$updateActiveDid()`**: Method to sync cache with database |
||||
|
- **Change Detection**: Watcher triggers component updates on activeDid changes |
||||
|
- **State Synchronization**: Cache updates when `$saveSettings()` changes activeDid |
||||
|
|
||||
|
#### Common Usage Patterns |
||||
|
|
||||
|
```typescript |
||||
|
// Standard pattern across 15+ components |
||||
|
this.activeDid = settings.activeDid || ""; |
||||
|
|
||||
|
// API header generation |
||||
|
const headers = await getHeaders(this.activeDid); |
||||
|
|
||||
|
// Identity validation |
||||
|
if (claim.issuer === this.activeDid) { ... } |
||||
|
``` |
||||
|
|
||||
|
### Migration Infrastructure Status |
||||
|
|
||||
|
#### Existing Capabilities |
||||
|
|
||||
|
- **`migrateSettings()`**: Fully implemented and functional |
||||
|
- **Settings Migration**: Handles 30 fields with proper type conversion |
||||
|
- **Data Integrity**: Includes validation and error handling |
||||
|
- **Rollback Capability**: Migration service has rollback infrastructure |
||||
|
|
||||
|
#### Migration Order |
||||
|
|
||||
|
1. **Accounts** (foundational - contains DIDs) |
||||
|
2. **Settings** (references accountDid, activeDid) |
||||
|
3. **ActiveDid** (depends on accounts and settings) |
||||
|
4. **Contacts** (independent, but migrated after accounts) |
||||
|
|
||||
|
### Testing Infrastructure |
||||
|
|
||||
|
#### Current Coverage |
||||
|
|
||||
|
- **Playwright Tests**: `npm run test:web` and `npm run test:mobile` |
||||
|
- **No Unit Tests**: Found for migration or settings management |
||||
|
- **Integration Tests**: Available through Playwright test suite |
||||
|
- **Platform Coverage**: Web, Mobile (Android/iOS), Desktop (Electron) |
||||
|
|
||||
|
## Risk Assessment |
||||
|
|
||||
|
### High Risk Areas |
||||
|
|
||||
|
1. **Component State Synchronization**: 505 references across codebase |
||||
|
2. **Cache Drift**: `_currentActiveDid` vs database `activeDid` |
||||
|
3. **Cross-Platform Consistency**: Web + Mobile + Desktop |
||||
|
|
||||
|
### Medium Risk Areas |
||||
|
|
||||
|
1. **Foreign Key Constraints**: activeDid → accounts.did relationship |
||||
|
2. **Migration Rollback**: Complex 30-field settings table |
||||
|
3. **API Surface Changes**: Components expect `settings.activeDid` |
||||
|
|
||||
|
### Low Risk Areas |
||||
|
|
||||
|
1. **Migration Infrastructure**: Already exists and functional |
||||
|
2. **Data Integrity**: Current migration handles complex scenarios |
||||
|
3. **Testing Framework**: Playwright tests available for validation |
||||
|
|
||||
|
## Implementation Phases |
||||
|
|
||||
|
### Phase 1: Foundation Analysis ✅ **COMPLETE** |
||||
|
|
||||
|
- [x] **ActiveDid Reference Audit**: 505 references identified and categorized |
||||
|
- [x] **Database Schema Analysis**: 30-field settings table documented |
||||
|
- [x] **Component Usage Mapping**: 15+ components usage patterns documented |
||||
|
- [x] **Migration Infrastructure Assessment**: Existing service validated |
||||
|
|
||||
|
### Phase 2: Design & Implementation (Medium Complexity) |
||||
|
|
||||
|
- [ ] **New Table Schema Design** |
||||
|
- Define `active_identity` table structure |
||||
|
- Plan foreign key relationships to `accounts.did` |
||||
|
- Design migration SQL statements |
||||
|
- Validate against existing data patterns |
||||
|
|
||||
|
- [ ] **Component Update Strategy** |
||||
|
- Map all 505 references for update strategy |
||||
|
- Plan computed property changes |
||||
|
- Design state synchronization approach |
||||
|
- Preserve existing API surface |
||||
|
|
||||
|
- [ ] **Testing Infrastructure Planning** |
||||
|
- Unit tests for new table operations |
||||
|
- Integration tests for identity switching |
||||
|
- Migration rollback validation |
||||
|
- Cross-platform testing strategy |
||||
|
|
||||
|
### Phase 3: Migration & Validation (Complex Complexity) |
||||
|
|
||||
|
- [ ] **Migration Execution Testing** |
||||
|
- Test on development database |
||||
|
- Validate data integrity post-migration |
||||
|
- Measure performance impact |
||||
|
- Test rollback scenarios |
||||
|
|
||||
|
- [ ] **Cross-Platform Validation** |
||||
|
- Web platform functionality |
||||
|
- Mobile platform functionality |
||||
|
- Desktop platform functionality |
||||
|
- Cross-platform consistency |
||||
|
|
||||
|
- [ ] **User Acceptance Testing** |
||||
|
- Identity switching workflows |
||||
|
- Settings persistence |
||||
|
- Error handling scenarios |
||||
|
- Edge case validation |
||||
|
|
||||
|
## Technical Requirements |
||||
|
|
||||
|
### New Table Schema |
||||
|
|
||||
|
```sql |
||||
|
-- Proposed active_identity table |
||||
|
CREATE TABLE IF NOT EXISTS active_identity ( |
||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT, |
||||
|
activeDid TEXT NOT NULL, |
||||
|
lastUpdated TEXT NOT NULL, |
||||
|
FOREIGN KEY (activeDid) REFERENCES accounts(did) |
||||
|
); |
||||
|
|
||||
|
-- Index for performance |
||||
|
CREATE INDEX IF NOT EXISTS idx_active_identity_activeDid ON active_identity(activeDid); |
||||
|
``` |
||||
|
|
||||
|
### Migration Strategy |
||||
|
|
||||
|
1. **Extract activeDid**: Copy from settings table to new table |
||||
|
2. **Update References**: Modify components to use new table |
||||
|
3. **Remove Field**: Drop activeDid from settings table |
||||
|
4. **Validate**: Ensure data integrity and functionality |
||||
|
|
||||
|
### Component Updates Required |
||||
|
|
||||
|
- **PlatformServiceMixin**: Update activeDid management |
||||
|
- **15+ Vue Components**: Modify activeDid access patterns |
||||
|
- **Migration Service**: Add activeDid table migration |
||||
|
- **Database Utilities**: Update settings operations |
||||
|
|
||||
|
## Success Criteria |
||||
|
|
||||
|
### Phase 1 ✅ **ACHIEVED** |
||||
|
|
||||
|
- Complete activeDid usage audit with counts |
||||
|
- Database schema validation with data integrity check |
||||
|
- Migration service health assessment |
||||
|
- Clear dependency map for component updates |
||||
|
|
||||
|
### Phase 2 |
||||
|
|
||||
|
- New table schema designed and validated |
||||
|
- Component update strategy documented |
||||
|
- Testing infrastructure planned |
||||
|
- Migration scripts developed |
||||
|
|
||||
|
### Phase 3 |
||||
|
|
||||
|
- Migration successfully executed |
||||
|
- All platforms functional |
||||
|
- Performance maintained or improved |
||||
|
- Zero data loss |
||||
|
|
||||
|
## Dependencies |
||||
|
|
||||
|
### Technical Dependencies |
||||
|
|
||||
|
- **Existing Migration Infrastructure**: Settings migration service |
||||
|
- **Database Access Patterns**: PlatformServiceMixin methods |
||||
|
- **Component Architecture**: Vue component patterns |
||||
|
|
||||
|
### Platform Dependencies |
||||
|
|
||||
|
- **Cross-Platform Consistency**: Web + Mobile + Desktop |
||||
|
- **Testing Framework**: Playwright test suite |
||||
|
- **Build System**: Vite configuration for all platforms |
||||
|
|
||||
|
### Testing Dependencies |
||||
|
|
||||
|
- **Migration Validation**: Rollback testing |
||||
|
- **Integration Testing**: Cross-platform functionality |
||||
|
- **User Acceptance**: Identity switching workflows |
||||
|
|
||||
|
## Next Steps |
||||
|
|
||||
|
### Immediate Actions (Next Session) |
||||
|
|
||||
|
1. **Create New Table Schema**: Design `active_identity` table structure |
||||
|
2. **Component Update Planning**: Map all 505 references for update strategy |
||||
|
3. **Migration Script Development**: Create activeDid extraction migration |
||||
|
|
||||
|
### Success Metrics |
||||
|
|
||||
|
- **Data Integrity**: 100% activeDid data preserved |
||||
|
- **Performance**: No degradation in identity switching |
||||
|
- **Platform Coverage**: All platforms functional |
||||
|
- **Testing Coverage**: Comprehensive migration validation |
||||
|
|
||||
|
## References |
||||
|
|
||||
|
- **Codebase Analysis**: `src/views/*.vue`, `src/utils/PlatformServiceMixin.ts` |
||||
|
- **Database Schema**: `src/db-sql/migration.ts` |
||||
|
- **Migration Service**: `src/services/indexedDBMigrationService.ts` |
||||
|
- **Settings Types**: `src/db/tables/settings.ts` |
||||
|
|
||||
|
## Competence Hooks |
||||
|
|
||||
|
- **Why this works**: Separation of concerns improves data integrity, reduces |
||||
|
cache drift, simplifies transaction logic |
||||
|
- **Common pitfalls**: Missing component updates, foreign key constraint |
||||
|
violations, migration rollback failures |
||||
|
- **Next skill**: Database schema normalization and migration planning |
||||
|
- **Teach-back**: "How would you ensure zero downtime during the activeDid |
||||
|
table migration?" |
||||
|
|
||||
|
## Collaboration Hooks |
||||
|
|
||||
|
- **Reviewers**: Database team for schema design, Frontend team for component |
||||
|
updates, QA team for testing strategy |
||||
|
- **Sign-off checklist**: Migration tested, rollback verified, performance |
||||
|
validated, component state consistent |
||||
|
|
||||
|
--- |
||||
|
|
||||
|
**Status**: Investigation complete, ready for implementation planning |
||||
|
**Next Review**: 2025-08-28 |
||||
|
**Estimated Complexity**: High (cross-platform refactoring with 505 references) |
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* Feature Flags Configuration |
||||
|
* |
||||
|
* Controls the rollout of new features and migrations |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @date 2025-08-21 |
||||
|
*/ |
||||
|
|
||||
|
export const FLAGS = { |
||||
|
/** |
||||
|
* When true, disallow legacy fallback reads from settings.activeDid |
||||
|
* Set to true after all components are migrated to the new façade |
||||
|
*/ |
||||
|
USE_ACTIVE_IDENTITY_ONLY: false, |
||||
|
|
||||
|
/** |
||||
|
* Controls Phase C column removal from settings table |
||||
|
* Set to true when ready to drop the legacy activeDid column |
||||
|
*/ |
||||
|
DROP_SETTINGS_ACTIVEDID: false, |
||||
|
|
||||
|
/** |
||||
|
* Log warnings when dual-read falls back to legacy settings.activeDid |
||||
|
* Useful for monitoring migration progress |
||||
|
*/ |
||||
|
LOG_ACTIVE_ID_FALLBACK: process.env.NODE_ENV === 'development', |
||||
|
|
||||
|
/** |
||||
|
* Enable the new active_identity table and migration |
||||
|
* Set to true to start the migration process |
||||
|
*/ |
||||
|
ENABLE_ACTIVE_IDENTITY_MIGRATION: true, |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Get feature flag value with type safety |
||||
|
*/ |
||||
|
export function getFlag<K extends keyof typeof FLAGS>(key: K): typeof FLAGS[K] { |
||||
|
return FLAGS[key]; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Check if a feature flag is enabled |
||||
|
*/ |
||||
|
export function isFlagEnabled<K extends keyof typeof FLAGS>(key: K): boolean { |
||||
|
return Boolean(FLAGS[key]); |
||||
|
} |
@ -0,0 +1,64 @@ |
|||||
|
/** |
||||
|
* Active Identity Table Definition |
||||
|
* |
||||
|
* Manages the currently active identity/DID for the application. |
||||
|
* Replaces the activeDid field from the settings table to improve |
||||
|
* data normalization and reduce cache drift. |
||||
|
* |
||||
|
* @author Matthew Raymer |
||||
|
* @date 2025-08-21 |
||||
|
*/ |
||||
|
|
||||
|
/** |
||||
|
* Active Identity record structure |
||||
|
*/ |
||||
|
export interface ActiveIdentity { |
||||
|
/** Primary key */ |
||||
|
id?: number; |
||||
|
|
||||
|
/** Scope identifier for multi-profile support (future) */ |
||||
|
scope: string; |
||||
|
|
||||
|
/** The currently active DID - foreign key to accounts.did */ |
||||
|
active_did: string; |
||||
|
|
||||
|
/** Last update timestamp in ISO format */ |
||||
|
updated_at?: string; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Database schema for the active_identity table |
||||
|
*/ |
||||
|
export const ActiveIdentitySchema = { |
||||
|
active_identity: "++id, &scope, active_did, updated_at", |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Default scope for single-user mode |
||||
|
*/ |
||||
|
export const DEFAULT_SCOPE = "default"; |
||||
|
|
||||
|
/** |
||||
|
* Validation helper to ensure valid DID format |
||||
|
*/ |
||||
|
export function isValidDid(did: string): boolean { |
||||
|
return typeof did === 'string' && did.length > 0 && did.startsWith('did:'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Create a new ActiveIdentity record |
||||
|
*/ |
||||
|
export function createActiveIdentity( |
||||
|
activeDid: string, |
||||
|
scope: string = DEFAULT_SCOPE |
||||
|
): ActiveIdentity { |
||||
|
if (!isValidDid(activeDid)) { |
||||
|
throw new Error(`Invalid DID format: ${activeDid}`); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
scope, |
||||
|
active_did: activeDid, |
||||
|
updated_at: new Date().toISOString(), |
||||
|
}; |
||||
|
} |
Loading…
Reference in new issue