# PlatformServiceMixin Completion Plan: 2-Day Sprint ## Overview This document outlines the complete plan to finish PlatformServiceMixin implementation and migrate all 52 remaining files from databaseUtil imports to PlatformServiceMixin usage within 2 days. ## Current Status ### ✅ **PlatformServiceMixin - 95% Complete** - **Core functionality**: ✅ Implemented - **Caching system**: ✅ Implemented - **Database methods**: ✅ Implemented - **Utility methods**: ✅ Implemented - **Type definitions**: ✅ Implemented ### ⚠️ **Remaining Issues** 1. **Single circular dependency**: `memoryLogs` import from databaseUtil 2. **Missing utility functions**: `generateInsertStatement`, `generateUpdateStatement` 3. **52 files** still importing databaseUtil --- ## 🎯 **DAY 1: Complete PlatformServiceMixin (4-6 hours)** ### **Phase 1: Remove Circular Dependency (30 minutes)** #### **Step 1.1: Create Self-Contained memoryLogs** ```typescript // In PlatformServiceMixin.ts - Replace line 50: // Remove: import { memoryLogs } from "@/db/databaseUtil"; // Add self-contained implementation: const _memoryLogs: string[] = []; // Update $memoryLogs computed property: $memoryLogs(): string[] { return _memoryLogs; }, // Add method to append to memory logs: $appendToMemoryLogs(message: string): void { _memoryLogs.push(`${new Date().toISOString()}: ${message}`); // Keep only last 1000 entries to prevent memory leaks if (_memoryLogs.length > 1000) { _memoryLogs.splice(0, _memoryLogs.length - 1000); } }, ``` #### **Step 1.2: Update logger.ts** ```typescript // In logger.ts - Replace memoryLogs usage: // Remove: import { memoryLogs } from "@/db/databaseUtil"; // Add self-contained implementation: const _memoryLogs: string[] = []; export function appendToMemoryLogs(message: string): void { _memoryLogs.push(`${new Date().toISOString()}: ${message}`); if (_memoryLogs.length > 1000) { _memoryLogs.splice(0, _memoryLogs.length - 1000); } } export function getMemoryLogs(): string[] { return [..._memoryLogs]; } ``` ### **Phase 2: Add Missing Utility Functions (1 hour)** #### **Step 2.1: Add generateInsertStatement to PlatformServiceMixin** ```typescript // Add to PlatformServiceMixin methods: _generateInsertStatement( model: Record, tableName: string, ): { sql: string; params: unknown[] } { const columns = Object.keys(model).filter((key) => model[key] !== undefined); const values = Object.values(model) .filter((value) => value !== undefined) .map((value) => { if (value === null || value === undefined) return null; if (typeof value === "object" && value !== null) { return JSON.stringify(value); } if (typeof value === "boolean") return value ? 1 : 0; return value; }); const placeholders = values.map(() => "?").join(", "); const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`; return { sql: insertSql, params: values }; }, ``` #### **Step 2.2: Add generateUpdateStatement to PlatformServiceMixin** ```typescript // Add to PlatformServiceMixin methods: _generateUpdateStatement( model: Record, tableName: string, whereClause: string, whereParams: unknown[] = [], ): { sql: string; params: unknown[] } { const setClauses: string[] = []; const params: unknown[] = []; Object.entries(model).forEach(([key, value]) => { setClauses.push(`${key} = ?`); let convertedValue = value ?? null; if (convertedValue !== null) { if (typeof convertedValue === "object") { convertedValue = JSON.stringify(convertedValue); } else if (typeof convertedValue === "boolean") { convertedValue = convertedValue ? 1 : 0; } } params.push(convertedValue); }); if (setClauses.length === 0) { throw new Error("No valid fields to update"); } const sql = `UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE ${whereClause}`; return { sql, params: [...params, ...whereParams] }; }, ``` #### **Step 2.3: Add Public Wrapper Methods** ```typescript // Add to PlatformServiceMixin methods: $generateInsertStatement( model: Record, tableName: string, ): { sql: string; params: unknown[] } { return this._generateInsertStatement(model, tableName); }, $generateUpdateStatement( model: Record, tableName: string, whereClause: string, whereParams: unknown[] = [], ): { sql: string; params: unknown[] } { return this._generateUpdateStatement(model, tableName, whereClause, whereParams); }, ``` ### **Phase 3: Update Type Definitions (30 minutes)** #### **Step 3.1: Update IPlatformServiceMixin Interface** ```typescript // Add to IPlatformServiceMixin interface: $generateInsertStatement( model: Record, tableName: string, ): { sql: string; params: unknown[] }; $generateUpdateStatement( model: Record, tableName: string, whereClause: string, whereParams?: unknown[], ): { sql: string; params: unknown[] }; $appendToMemoryLogs(message: string): void; ``` #### **Step 3.2: Update ComponentCustomProperties** ```typescript // Add to ComponentCustomProperties interface: $generateInsertStatement( model: Record, tableName: string, ): { sql: string; params: unknown[] }; $generateUpdateStatement( model: Record, tableName: string, whereClause: string, whereParams?: unknown[], ): { sql: string; params: unknown[] }; $appendToMemoryLogs(message: string): void; ``` ### **Phase 4: Test PlatformServiceMixin (1 hour)** #### **Step 4.1: Create Test Component** ```typescript // Create test file: src/test/PlatformServiceMixin.test.ts // Test all methods including new utility functions ``` #### **Step 4.2: Run Linting and Type Checking** ```bash npm run lint npx tsc --noEmit ``` --- ## 🎯 **DAY 2: Migrate All 52 Files (6-8 hours)** ### **Migration Strategy** #### **Priority Order:** 1. **Views** (25 files) - User-facing components 2. **Components** (15 files) - Reusable UI components 3. **Services** (8 files) - Business logic 4. **Utils** (4 files) - Utility functions #### **Migration Pattern for Each File:** **Step 1: Add PlatformServiceMixin** ```typescript // Add to component imports: import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin"; // Add to component definition: export default class ComponentName extends Vue { // Add mixin mixins = [PlatformServiceMixin]; } ``` **Step 2: Replace databaseUtil Imports** ```typescript // Remove: import { generateInsertStatement, generateUpdateStatement, parseJsonField, mapColumnsToValues, logToDb, logConsoleAndDb } from "@/db/databaseUtil"; // Replace with mixin methods: // generateInsertStatement → this.$generateInsertStatement // generateUpdateStatement → this.$generateUpdateStatement // parseJsonField → this._parseJsonField // mapColumnsToValues → this._mapColumnsToValues // logToDb → this.$log // logConsoleAndDb → this.$logAndConsole ``` **Step 3: Update Method Calls** ```typescript // Before: const { sql, params } = generateInsertStatement(contact, 'contacts'); // After: const { sql, params } = this.$generateInsertStatement(contact, 'contacts'); ``` ### **File Migration Checklist** #### **Views (25 files) - Priority 1** - [ ] QuickActionBvcEndView.vue - [ ] ProjectsView.vue - [ ] ClaimReportCertificateView.vue - [ ] NewEditAccountView.vue - [ ] OnboardMeetingSetupView.vue - [ ] SearchAreaView.vue - [ ] TestView.vue - [ ] InviteOneView.vue - [ ] IdentitySwitcherView.vue - [ ] HelpNotificationsView.vue - [ ] StartView.vue - [ ] OfferDetailsView.vue - [ ] ContactEditView.vue - [ ] SharedPhotoView.vue - [ ] ContactQRScanShowView.vue - [ ] ContactGiftingView.vue - [ ] DiscoverView.vue - [ ] ImportAccountView.vue - [ ] ConfirmGiftView.vue - [ ] SeedBackupView.vue - [ ] [5 more view files] #### **Components (15 files) - Priority 2** - [ ] ActivityListItem.vue - [ ] AmountInput.vue - [ ] ChoiceButtonDialog.vue - [ ] ContactNameDialog.vue - [ ] DataExportSection.vue - [ ] EntityGrid.vue - [ ] EntityIcon.vue - [ ] EntitySelectionStep.vue - [ ] EntitySummaryButton.vue - [ ] FeedFilters.vue - [ ] GiftDetailsStep.vue - [ ] GiftedDialog.vue - [ ] GiftedPrompts.vue - [ ] HiddenDidDialog.vue - [ ] IconRenderer.vue #### **Services (8 files) - Priority 3** - [ ] api.ts - [ ] endorserServer.ts - [ ] partnerServer.ts - [ ] [5 more service files] #### **Utils (4 files) - Priority 4** - [ ] LogCollector.ts - [ ] [3 more util files] ### **Migration Tools** #### **Automated Script for Common Patterns** ```bash #!/bin/bash # migration-helper.sh # Find all databaseUtil imports echo "Files with databaseUtil imports:" find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" # Common replacement patterns echo "Common replacement patterns:" echo "generateInsertStatement → this.\$generateInsertStatement" echo "generateUpdateStatement → this.\$generateUpdateStatement" echo "parseJsonField → this._parseJsonField" echo "mapColumnsToValues → this._mapColumnsToValues" echo "logToDb → this.\$log" echo "logConsoleAndDb → this.\$logAndConsole" ``` #### **Validation Script** ```bash #!/bin/bash # validate-migration.sh # Check for remaining databaseUtil imports echo "Checking for remaining databaseUtil imports..." find src -name "*.vue" -o -name "*.ts" | xargs grep -l "import.*databaseUtil" # Run linting echo "Running linting..." npm run lint # Run type checking echo "Running type checking..." npx tsc --noEmit echo "Migration validation complete!" ``` --- ## 🎯 **Success Criteria** ### **Day 1 Success Criteria:** - [ ] PlatformServiceMixin has no circular dependencies - [ ] All utility functions implemented and tested - [ ] Type definitions complete and accurate - [ ] Linting passes with no errors - [ ] TypeScript compilation passes ### **Day 2 Success Criteria:** - [ ] 0 files importing databaseUtil - [ ] All 52 files migrated to PlatformServiceMixin - [ ] No runtime errors in migrated components - [ ] All tests passing - [ ] Performance maintained or improved ### **Overall Success Criteria:** - [ ] Complete elimination of databaseUtil dependency - [ ] PlatformServiceMixin is the single source of truth for database operations - [ ] Migration fence is fully implemented - [ ] Ready for Phase 3: Cleanup and Optimization --- ## 🚀 **Post-Migration Benefits** 1. **80% reduction** in database boilerplate code 2. **Centralized caching** for improved performance 3. **Type-safe** database operations 4. **Eliminated circular dependencies** 5. **Simplified testing** with mockable mixin 6. **Consistent error handling** across all components 7. **Ready for SQLite-only mode** --- ## 📋 **Daily Progress Tracking** ### **Day 1 Progress:** - [ ] Phase 1: Circular dependency resolved - [ ] Phase 2: Utility functions added - [ ] Phase 3: Type definitions updated - [ ] Phase 4: Testing completed ### **Day 2 Progress:** - [ ] Views migrated (0/25) - [ ] Components migrated (0/15) - [ ] Services migrated (0/8) - [ ] Utils migrated (0/4) - [ ] Validation completed --- ## 🆘 **Contingency Plans** ### **If Day 1 Takes Longer:** - Focus on core functionality first - Defer advanced utility functions to Day 2 - Prioritize circular dependency resolution ### **If Day 2 Takes Longer:** - Focus on high-impact views first - Batch similar components together - Use automated scripts for common patterns ### **If Issues Arise:** - Document specific problems - Create targeted fixes - Maintain backward compatibility during transition