forked from trent_larson/crowd-funder-for-time-pwa
docs: reorganize documentation structure with 7-item folder limits
- Create logical sub-folder classification for all documentation - Organize 91 migration files into component-specific folders - Separate user guides, build system, migration, and development docs - Maintain maximum 7 items per folder for easy navigation - Add comprehensive README and reorganization summary - Ensure all changes tracked in git with proper versioning Structure: - user-guides/ (3 items): user-facing documentation - build-system/ (3 items): core, platforms, automation - migration/ (6 items): assessments, testing, templates - development/ (4 items): tools and standards - architecture/, testing/, examples/ (ready for future docs) Total: 24 folders created, all within 7-item limits
This commit is contained in:
@@ -1,519 +0,0 @@
|
||||
# Complete Migration Checklist - MANDATORY STEPS
|
||||
|
||||
## Overview
|
||||
This checklist ensures NO migration steps are forgotten. **Every component migration MUST complete ALL sections.**
|
||||
|
||||
## 🚨 **CRITICAL: PRE-MIGRATION PLANNING REQUIRED**
|
||||
|
||||
**BEFORE starting any migration, you MUST:**
|
||||
|
||||
1. **Create detailed migration documentation** in `docs/migration-testing/[COMPONENT]_MIGRATION.md`
|
||||
2. **Complete pre-migration analysis** including:
|
||||
- Current state assessment (database, notifications, template complexity)
|
||||
- Migration complexity assessment
|
||||
- Risk assessment
|
||||
- Timeline estimation
|
||||
- Testing requirements
|
||||
3. **Review the plan** and confirm all migration targets are identified
|
||||
4. **Get approval** before proceeding with code changes
|
||||
|
||||
**❌ NO EXCEPTIONS**: Every migration must have a documented plan before implementation begins.
|
||||
|
||||
## Requirements
|
||||
|
||||
**EVERY component migration MUST complete ALL SIX migration types:**
|
||||
|
||||
1. **Database Migration**: Replace databaseUtil calls with PlatformServiceMixin methods
|
||||
2. **SQL Abstraction**: Replace raw SQL queries with service methods
|
||||
2.5. **Contact Method Standardization**: Replace inconsistent contact fetching patterns
|
||||
3. **Notification Migration**: Replace `$notify()` calls with helper methods + centralized constants
|
||||
4. **Template Streamlining**: Extract repeated expressions and complex logic to computed properties
|
||||
5. **Component Extraction**: Extract reusable UI patterns into separate components
|
||||
|
||||
**❌ INCOMPLETE**: Any migration missing one of these steps
|
||||
**✅ COMPLETE**: All five patterns implemented with code quality review
|
||||
|
||||
## ⏱️ **TIME TRACKING REQUIREMENT**: All migrations must be timed and performance recorded
|
||||
|
||||
## 🎯 **USER CONTROL COMMANDS**: For seamless migration workflow
|
||||
|
||||
### **Control Handoff Commands**
|
||||
Use these commands to maintain control between migrations:
|
||||
|
||||
```bash
|
||||
# When ready to continue
|
||||
"move to the next file" - Start next component migration
|
||||
"migrate [ComponentName]" - Target specific component
|
||||
"check migration status" - Run validation script
|
||||
"pause migrations" - Focus on other tasks
|
||||
```
|
||||
|
||||
### **Migration Workflow Commands**
|
||||
```bash
|
||||
# Time tracking
|
||||
./scripts/time-migration.sh [Component] start
|
||||
./scripts/time-migration.sh [Component] end
|
||||
|
||||
# Status checking
|
||||
bash scripts/validate-notification-completeness.sh
|
||||
./scripts/daily-migration-summary.sh
|
||||
|
||||
# Quality assurance
|
||||
npm run lint [file]
|
||||
git add [file] && git commit -m "[message]"
|
||||
```
|
||||
|
||||
### **User Control Flow**
|
||||
1. **Review** completed migrations
|
||||
2. **Test** components manually
|
||||
3. **Review** commit messages before committing
|
||||
4. **Plan** next migration batch
|
||||
5. **Choose** when to continue
|
||||
6. **Maintain** project control
|
||||
|
||||
### **Commit Message Control**
|
||||
**CRITICAL**: User must review and approve all commit messages before committing:
|
||||
|
||||
```bash
|
||||
# AI provides commit message preview for copy/paste
|
||||
git add [files]
|
||||
# AI shows: "Ready to commit with message: [preview]"
|
||||
# User copies, pastes, and modifies as needed
|
||||
git commit -m "[user-approved-message]"
|
||||
```
|
||||
|
||||
**Process**:
|
||||
1. AI stages files: `git add [files]`
|
||||
2. AI provides commit message preview
|
||||
3. User reviews, modifies, and commits manually
|
||||
4. User maintains full control over commit history
|
||||
|
||||
## ⚠️ CRITICAL: Enhanced Triple Migration Pattern
|
||||
|
||||
### 🔑 The Complete Pattern (ALL 5 REQUIRED)
|
||||
1. **Database Migration**: Replace legacy `databaseUtil` calls with `PlatformServiceMixin` methods
|
||||
2. **SQL Abstraction**: Replace raw SQL queries with service methods
|
||||
3. **Notification Migration**: Replace `$notify()` calls with helper methods + centralized constants
|
||||
4. **Template Streamlining**: Extract repeated expressions and complex logic to computed properties
|
||||
5. **Component Extraction**: Extract reusable UI patterns into separate components
|
||||
|
||||
**❌ INCOMPLETE**: Any migration missing one of these steps
|
||||
**✅ COMPLETE**: All five patterns implemented with code quality review
|
||||
|
||||
## Pre-Migration Assessment
|
||||
|
||||
### [ ] 0. Pre-Migration Feature Audit & Planning
|
||||
- [ ] **MANDATORY**: Create detailed feature audit using `docs/migration-templates/PRE_MIGRATION_AUDIT_TEMPLATE.md`
|
||||
- [ ] **MANDATORY**: Create comprehensive migration plan in `docs/migration-testing/[COMPONENT]_MIGRATION.md`
|
||||
- [ ] **MANDATORY**: Complete pre-migration analysis (database, notifications, template complexity)
|
||||
- [ ] **MANDATORY**: Assess migration complexity and estimate timeline
|
||||
- [ ] **MANDATORY**: Identify all migration targets and potential risks
|
||||
- [ ] **MANDATORY**: Review plan and get approval before proceeding with code changes
|
||||
- [ ] Document all database operations with line numbers
|
||||
- [ ] Document all notification patterns with line numbers
|
||||
- [ ] Document all template complexity patterns with line numbers
|
||||
- [ ] Create verification checklist for post-migration testing
|
||||
- [ ] Assess migration complexity and time requirements
|
||||
|
||||
### [ ] 1. Start Time Tracking
|
||||
- [ ] **MANDATORY**: Run `./scripts/time-migration.sh [ComponentName.vue] start`
|
||||
- [ ] Record start time in terminal output
|
||||
- [ ] Keep terminal open for entire migration process
|
||||
|
||||
### [ ] 2. Component Complexity Assessment (REVISED ESTIMATES)
|
||||
- [ ] **Simple** (8-12 min): Dialog components, minimal DB operations, few notifications
|
||||
- [ ] **Medium** (15-25 min): Standard views, moderate DB usage, multiple notifications
|
||||
- [ ] **Complex** (25-35 min): Large views, extensive DB operations, many notifications
|
||||
- [ ] Document complexity level for performance tracking
|
||||
- [ ] **Note**: Estimates revised based on 48% acceleration from actual performance data
|
||||
|
||||
### Date Time Context
|
||||
- [ ] Always use system date command to establish accurate time context
|
||||
- [ ] Use time log to track project progress
|
||||
- [ ] Use historical time durations to improve estimates
|
||||
|
||||
### Acceleration Factors (48% Faster Than Original Estimates)
|
||||
- [ ] **Established Patterns**: Consistent migration workflow reduces decision time
|
||||
- [ ] **Enhanced Tooling**: PlatformServiceMixin eliminates boilerplate
|
||||
- [ ] **Notification Infrastructure**: Centralized constants speed up message extraction
|
||||
- [ ] **Documentation**: Comprehensive templates reduce planning overhead
|
||||
- [ ] **Validation Scripts**: Automated checking catches issues early
|
||||
- [ ] **Experience**: Familiarity with common patterns improves efficiency
|
||||
- [ ] **Mixin Enhancement**: Added utility methods eliminate databaseUtil dependencies
|
||||
|
||||
### [ ] 3. Identify Legacy Patterns
|
||||
- [ ] Count `databaseUtil` imports and calls
|
||||
- [ ] Count raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
|
||||
- [ ] Count `$notify()` calls
|
||||
- [ ] Count `logConsoleAndDb()` calls
|
||||
- [ ] Identify template complexity patterns (repeated expressions, long class strings)
|
||||
- [ ] Document total issues found
|
||||
|
||||
### [ ] 4. Verify PlatformServiceMixin Setup
|
||||
- [ ] Component already imports `PlatformServiceMixin`
|
||||
- [ ] Component already has `mixins: [PlatformServiceMixin]`
|
||||
- [ ] If missing, add mixin first
|
||||
|
||||
## Phase 1: Database Migration
|
||||
|
||||
### [ ] 5. Replace Database Utility Calls
|
||||
- [ ] Remove `import * as databaseUtil from "../db/databaseUtil"`
|
||||
- [ ] Replace `databaseUtil.retrieveSettingsForActiveAccount()` → `this.$accountSettings()`
|
||||
- [ ] Replace `databaseUtil.mapQueryResultToValues()` → `this.$mapQueryResultToValues()`
|
||||
- [ ] Replace other `databaseUtil.*` calls with mixin equivalents
|
||||
|
||||
### [ ] 6. Replace Logging Calls
|
||||
- [ ] Remove `import { logConsoleAndDb } from "../db/index"`
|
||||
- [ ] Replace `logConsoleAndDb()` → `this.$logAndConsole()`
|
||||
|
||||
## Phase 2: SQL Abstraction Migration
|
||||
|
||||
### [ ] 7. Replace Raw Contact Operations
|
||||
- [ ] `SELECT * FROM contacts WHERE did = ?` → `this.$getContact(did)`
|
||||
- [ ] `DELETE FROM contacts WHERE did = ?` → `this.$deleteContact(did)`
|
||||
- [ ] `UPDATE contacts SET x = ? WHERE did = ?` → `this.$updateContact(did, changes)`
|
||||
- [ ] `INSERT INTO contacts` → `this.$insertContact(contact)`
|
||||
|
||||
### [ ] 8. Replace Other Raw SQL
|
||||
- [ ] `SELECT * FROM settings` → `this.$accountSettings()`
|
||||
- [ ] `UPDATE settings` → `this.$saveSettings(changes)`
|
||||
- [ ] Generic queries → appropriate service methods
|
||||
- [ ] **NO RAW SQL ALLOWED**: All database operations through service layer
|
||||
|
||||
## Phase 2.5: Contact Method Standardization
|
||||
|
||||
### [ ] 9. Standardize Contact Fetching Methods
|
||||
- [ ] **CRITICAL**: Replace `this.$getAllContacts()` → `this.$contacts()`
|
||||
- [ ] **REASON**: Eliminate inconsistent contact fetching patterns
|
||||
- [ ] **BENEFIT**: All components use same contact data source
|
||||
- [ ] **VALIDATION**: Search for `$getAllContacts` and replace with `$contacts`
|
||||
- [ ] **CONSISTENCY**: All contact operations use unified approach
|
||||
|
||||
### [ ] 10. Verify Contact Method Consistency
|
||||
- [ ] **NO** `$getAllContacts()` calls remain in component
|
||||
- [ ] **ALL** contact fetching uses `$contacts()` method
|
||||
- [ ] **CONSISTENT** contact data across component lifecycle
|
||||
- [ ] **VALIDATED**: Component uses standardized contact API
|
||||
|
||||
## Phase 3: Notification Migration
|
||||
|
||||
### [ ] 11. Add Notification Infrastructure
|
||||
- [ ] Add import: `import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify"`
|
||||
- [ ] Add property: `notify!: ReturnType<typeof createNotifyHelpers>;`
|
||||
- [ ] Add initialization: `created() { this.notify = createNotifyHelpers(this.$notify); }`
|
||||
|
||||
### [ ] 12. Add Notification Constants to Central File
|
||||
- [ ] **CRITICAL**: Add constants to `src/constants/notifications.ts` (NOT local constants)
|
||||
- [ ] Use naming pattern: `NOTIFY_[COMPONENT]_[ACTION]` (e.g., `NOTIFY_OFFER_SETTINGS_ERROR`)
|
||||
- [ ] Import constants: `import { NOTIFY_X, NOTIFY_Y } from "@/constants/notifications"`
|
||||
- [ ] **NO LOCAL CONSTANTS**: All notification text must be centralized
|
||||
|
||||
### [ ] 13. Replace Notification Calls
|
||||
- [ ] **Warning**: `this.$notify({type: "warning"})` → `this.notify.warning(CONSTANT.message, TIMEOUTS.LONG)`
|
||||
- [ ] **Error**: `this.$notify({type: "danger"})` → `this.notify.error(CONSTANT.message, TIMEOUTS.LONG)`
|
||||
- [ ] **Success**: `this.$notify({type: "success"})` → `this.notify.success(CONSTANT.message, TIMEOUTS.STANDARD)`
|
||||
- [ ] **Toast**: `this.$notify({type: "toast"})` → `this.notify.toast(title, message, TIMEOUTS.SHORT)`
|
||||
- [ ] **Confirm**: `this.$notify({type: "confirm"})` → `this.notify.confirm(message, onYes)`
|
||||
- [ ] **Standard patterns**: Use `this.notify.confirmationSubmitted()`, `this.notify.sent()`, etc.
|
||||
|
||||
### [ ] 13.1. 🚨 CRITICAL: Replace ALL Hardcoded Timeout Values
|
||||
- [ ] **Replace hardcoded timeouts**: `3000`, `5000`, `1000`, `2000` → timeout constants
|
||||
- [ ] **Add timeout constants**: `COMPONENT_TIMEOUT_SHORT = 1000`, `COMPONENT_TIMEOUT_MEDIUM = 2000`, `COMPONENT_TIMEOUT_STANDARD = 3000`, `COMPONENT_TIMEOUT_LONG = 5000`
|
||||
- [ ] **Import timeout constants**: Import from `@/constants/notifications`
|
||||
- [ ] **Validation command**: `grep -n "notify\.[a-z]*(" [file] | grep -E "[0-9]{3,4}"`
|
||||
|
||||
### [ ] 13.2. 🚨 CRITICAL: Remove ALL Unused Notification Imports
|
||||
- [ ] **Check each import**: Verify every imported `NOTIFY_*` constant is actually used
|
||||
- [ ] **Remove unused imports**: Delete any `NOTIFY_*` constants not referenced in component
|
||||
- [ ] **Validation command**: `grep -n "import.*NOTIFY_" [file]` then verify usage
|
||||
- [ ] **Clean imports**: Only import notification constants that are actually used
|
||||
|
||||
### [ ] 13.3. 🚨 CRITICAL: Replace ALL Literal Strings with Constants
|
||||
- [ ] **No literal strings**: All static notification messages must use constants
|
||||
- [ ] **Add constants**: Create `NOTIFY_*` constants for ALL static messages
|
||||
- [ ] **Replace literals**: `"The contact DID is missing."` → `NOTIFY_CONTACT_MISSING_DID.message`
|
||||
- [ ] **Validation command**: `grep -n "notify\.[a-z]*(" [file] | grep -v "NOTIFY_\|message"`
|
||||
|
||||
### [ ] 13.4. 🚨 CRITICAL: Remove Legacy Wrapper Functions
|
||||
- [ ] **Remove legacy functions**: Delete `danger()`, `success()`, `warning()`, `info()` wrapper functions
|
||||
- [ ] **Direct usage**: Use `this.notify.error()` instead of `this.danger()`
|
||||
- [ ] **Why remove**: Maintains consistency with centralized notification system
|
||||
- [ ] **Validation command**: `grep -n "danger\|success\|warning\|info.*(" [file] | grep -v "notify\."`
|
||||
|
||||
### [ ] 14. Constants vs Literal Strings
|
||||
- [ ] **Use constants** for static, reusable messages
|
||||
- [ ] **Use literal strings** for dynamic messages with variables
|
||||
- [ ] **Extract literals from complex modals** - Even raw `$notify` calls should use constants for text
|
||||
- [ ] **Document decision** for each notification call
|
||||
|
||||
## Phase 4: Template Streamlining
|
||||
|
||||
### [ ] 15. Identify Template Complexity Patterns
|
||||
- [ ] **Repeated CSS Classes**: Long Tailwind strings used multiple times
|
||||
- [ ] **Complex Configuration Objects**: Multi-line objects in template
|
||||
- [ ] **Repeated Function Calls**: Same logic executed multiple times
|
||||
- [ ] **Complex Conditional Logic**: Nested ternary or complex boolean expressions
|
||||
|
||||
### [ ] 16. Extract to Computed Properties
|
||||
- [ ] **CSS Class Groups**: Extract repeated styling to computed properties
|
||||
- [ ] **Configuration Objects**: Move router configs, form configs to computed
|
||||
- [ ] **Conditional Logic**: Extract complex `v-if` conditions to computed properties
|
||||
- [ ] **Dynamic Values**: Convert repeated calculations to cached computed properties
|
||||
|
||||
### [ ] 16.1. 🚨 CRITICAL: Extract ALL Long Class Attributes
|
||||
- [ ] **Find long classes**: Search for `class="[^"]{50,}"` (50+ character class strings)
|
||||
- [ ] **Extract to computed**: Replace with `:class="computedPropertyName"`
|
||||
- [ ] **Name descriptively**: Use names like `nameWarningClasses`, `buttonPrimaryClasses`
|
||||
- [ ] **Validation command**: `grep -n "class=\"[^\"]\{50,\}" [file]`
|
||||
- [ ] **Benefits**: Improves readability, enables reusability, makes testing easier
|
||||
|
||||
### [ ] 17. Document Computed Properties
|
||||
- [ ] **JSDoc Comments**: Add comprehensive comments for all computed properties
|
||||
- [ ] **Purpose Documentation**: Explain what template complexity each property solves
|
||||
- [ ] **Organized Sections**: Group related computed properties with section headers
|
||||
- [ ] **Descriptive Names**: Use clear, descriptive names for computed properties
|
||||
|
||||
## Phase 5: Component Extraction
|
||||
|
||||
### [ ] 18. Identify Reusable UI Patterns
|
||||
- [ ] **Repeated Form Elements**: Similar input fields, buttons, or form sections
|
||||
- [ ] **Common Layout Patterns**: Repeated card layouts, list items, or modal structures
|
||||
- [ ] **Shared UI Components**: Elements that appear in multiple places with similar structure
|
||||
- [ ] **Complex Template Sections**: Large template blocks that could be simplified
|
||||
- [ ] **Validation Patterns**: Repeated validation logic or error display patterns
|
||||
|
||||
### [ ] 19. Extract Reusable Components
|
||||
- [ ] **Create New Component Files**: Extract patterns to `src/components/` directory
|
||||
- [ ] **Define Clear Props Interface**: Create TypeScript interfaces for component props
|
||||
- [ ] **Add Event Emissions**: Define events for parent-child communication
|
||||
- [ ] **Include JSDoc Documentation**: Document component purpose and usage
|
||||
- [ ] **Follow Naming Conventions**: Use descriptive, consistent component names
|
||||
|
||||
### [ ] 20. Component Extraction Patterns
|
||||
|
||||
#### 20.1 Form Element Extraction
|
||||
- [ ] **Input Groups**: Extract repeated input field patterns with labels and validation
|
||||
- [ ] **Button Groups**: Extract common button combinations (Save/Cancel, etc.)
|
||||
- [ ] **Form Sections**: Extract logical form groupings (personal info, settings, etc.)
|
||||
|
||||
#### 20.2 Layout Component Extraction
|
||||
- [ ] **Card Components**: Extract repeated card layouts with headers and content
|
||||
- [ ] **List Item Components**: Extract repeated list item patterns
|
||||
- [ ] **Modal Components**: Extract common modal structures and behaviors
|
||||
|
||||
#### 20.3 Validation Component Extraction
|
||||
- [ ] **Error Display Components**: Extract error message display patterns
|
||||
- [ ] **Validation Wrapper Components**: Extract form validation wrapper patterns
|
||||
- [ ] **Status Indicator Components**: Extract loading, success, error status patterns
|
||||
|
||||
### [ ] 21. Update Parent Components
|
||||
- [ ] **Import New Components**: Add imports for extracted components
|
||||
- [ ] **Replace Template Code**: Replace extracted patterns with component usage
|
||||
- [ ] **Pass Required Props**: Provide all necessary data and configuration
|
||||
- [ ] **Handle Events**: Implement event handlers for component interactions
|
||||
- [ ] **Update TypeScript**: Add component types to component registration
|
||||
|
||||
### [ ] 22. Component Quality Standards
|
||||
- [ ] **Single Responsibility**: Each extracted component has one clear purpose
|
||||
- [ ] **Reusability**: Component can be used in multiple contexts
|
||||
- [ ] **Props Interface**: Clear, well-documented props with proper types
|
||||
- [ ] **Event Handling**: Appropriate events for parent communication
|
||||
- [ ] **Documentation**: JSDoc comments explaining usage and examples
|
||||
|
||||
### [ ] 23. Validation of Component Extraction
|
||||
- [ ] **No Template Duplication**: Extracted patterns don't appear elsewhere
|
||||
- [ ] **Proper Component Registration**: All components properly imported and registered
|
||||
- [ ] **Event Handling Works**: Parent components receive and handle events correctly
|
||||
- [ ] **Props Validation**: All required props are provided with correct types
|
||||
- [ ] **Styling Consistency**: Extracted components maintain visual consistency
|
||||
|
||||
## Phase 6: Code Quality Review
|
||||
|
||||
### [ ] 24. Template Quality Assessment
|
||||
- [ ] **Readability**: Template is easy to scan and understand
|
||||
- [ ] **Maintainability**: Styling changes can be made in one place
|
||||
- [ ] **Performance**: Computed properties cache expensive operations
|
||||
- [ ] **Consistency**: Similar patterns use similar solutions
|
||||
|
||||
### [ ] 25. Component Architecture Review
|
||||
- [ ] **Single Responsibility**: Component has clear, focused purpose
|
||||
- [ ] **Props Interface**: Clear, well-documented component props
|
||||
- [ ] **Event Emissions**: Appropriate event handling and emission
|
||||
- [ ] **State Management**: Component state is minimal and well-organized
|
||||
|
||||
### [ ] 26. Code Organization Review
|
||||
- [ ] **Import Organization**: Imports are grouped logically (Vue, constants, services)
|
||||
- [ ] **Method Organization**: Methods are grouped by purpose with section headers
|
||||
- [ ] **Property Organization**: Data properties are documented and organized
|
||||
- [ ] **Comment Quality**: All complex logic has explanatory comments
|
||||
|
||||
## Validation Phase
|
||||
|
||||
### [ ] 27. Run Validation Script
|
||||
- [ ] Execute: `scripts/validate-migration.sh`
|
||||
- [ ] **MUST show**: "Technically Compliant" (not "Mixed Pattern")
|
||||
- [ ] **Zero** legacy patterns detected
|
||||
|
||||
### [ ] 28. Run Linting
|
||||
- [ ] Execute: `npm run lint-fix`
|
||||
- [ ] **Zero errors** introduced
|
||||
- [ ] **TypeScript compiles** without errors
|
||||
|
||||
### [ ] 29. Manual Code Review
|
||||
- [ ] **NO** `databaseUtil` imports or calls
|
||||
- [ ] **NO** raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
|
||||
- [ ] **NO** `$notify()` calls with object syntax
|
||||
- [ ] **NO** `logConsoleAndDb()` calls
|
||||
- [ ] **NO** local notification constants
|
||||
- [ ] **ALL** database operations through service methods
|
||||
- [ ] **ALL** notifications through helper methods with centralized constants
|
||||
- [ ] **ALL** complex template logic extracted to computed properties
|
||||
- [ ] **ALL** reusable UI patterns extracted to components
|
||||
|
||||
### [ ] 29.1. 🚨 CRITICAL: Validate All Omission Fixes
|
||||
- [ ] **NO** hardcoded timeout values (`1000`, `2000`, `3000`, `5000`)
|
||||
- [ ] **NO** unused notification imports (all `NOTIFY_*` imports are used)
|
||||
- [ ] **NO** literal strings in notification calls (all use constants)
|
||||
- [ ] **NO** legacy wrapper functions (`danger()`, `success()`, etc.)
|
||||
- [ ] **NO** long class attributes (50+ characters) in template
|
||||
- [ ] **NO** duplicated template patterns (all extracted to components)
|
||||
- [ ] **ALL** timeout values use constants
|
||||
- [ ] **ALL** notification messages use centralized constants
|
||||
- [ ] **ALL** class styling extracted to computed properties
|
||||
- [ ] **ALL** reusable UI patterns extracted to components
|
||||
|
||||
## ⏱️ Time Tracking & Commit Phase
|
||||
|
||||
### [ ] 30. End Time Tracking
|
||||
- [ ] **MANDATORY**: Run `./scripts/time-migration.sh [ComponentName.vue] end`
|
||||
- [ ] Record total duration from terminal output
|
||||
- [ ] Note any blockers or issues that impacted timing
|
||||
- [ ] **MANDATORY**: Verify all features from pre-migration audit are working
|
||||
|
||||
### [ ] 31. Commit with Time Data
|
||||
- [ ] **MANDATORY**: Include time data in commit message
|
||||
- [ ] Use template: `Complete [ComponentName] Enhanced Triple Migration Pattern (X minutes)`
|
||||
- [ ] Include complexity level and any issues encountered
|
||||
- [ ] Document specific changes made in each phase
|
||||
|
||||
### [ ] 32. Performance Analysis
|
||||
- [ ] Compare actual time vs. revised estimated time for complexity level
|
||||
- [ ] Note if component was faster/slower than expected (target: within 20% of estimate)
|
||||
- [ ] Document any efficiency improvements discovered
|
||||
- [ ] **Revised Baseline**: Simple (8-12 min), Medium (15-25 min), Complex (25-35 min)
|
||||
- [ ] **Acceleration Target**: Maintain 48% improvement over original estimates
|
||||
|
||||
## Documentation Phase
|
||||
|
||||
### [ ] 33. Update Migration Documentation
|
||||
- [ ] Create `docs/migration-testing/[COMPONENT]_MIGRATION.md`
|
||||
- [ ] Document all changes made (database, SQL, notifications, template, component extraction)
|
||||
- [ ] Include before/after examples for template streamlining and component extraction
|
||||
- [ ] Note validation results and timing data
|
||||
- [ ] Provide a guide to finding the components in the user interface
|
||||
- [ ] Include code quality review notes
|
||||
|
||||
### [ ] 34. Update Testing Tracker
|
||||
- [ ] Update `docs/migration-testing/HUMAN_TESTING_TRACKER.md`
|
||||
- [ ] Mark component as "Ready for Testing"
|
||||
- [ ] Include notes about migration completed with template streamlining and component extraction
|
||||
- [ ] Record actual migration time for future estimates
|
||||
|
||||
## Human Testing Phase
|
||||
|
||||
### [ ] 35. Test All Functionality
|
||||
- [ ] **Core functionality** works correctly
|
||||
- [ ] **Database operations** function properly
|
||||
- [ ] **Notifications** display correctly with proper timing
|
||||
- [ ] **Error scenarios** handled gracefully
|
||||
- [ ] **Template rendering** performs smoothly with computed properties
|
||||
- [ ] **Extracted components** work correctly and maintain functionality
|
||||
- [ ] **Cross-platform** compatibility (web/mobile)
|
||||
|
||||
### [ ] 36. Confirm Testing Complete
|
||||
- [ ] User confirms component works correctly
|
||||
- [ ] Update testing tracker with results
|
||||
- [ ] Mark as "Human Tested" in validation script
|
||||
|
||||
## Final Validation
|
||||
|
||||
### [ ] 37. Comprehensive Check
|
||||
- [ ] Component shows as "Technically Compliant" in validation
|
||||
- [ ] All manual testing passed
|
||||
- [ ] Zero legacy patterns remain
|
||||
- [ ] Template streamlining complete
|
||||
- [ ] Component extraction complete
|
||||
- [ ] Code quality review passed
|
||||
- [ ] Documentation complete
|
||||
- [ ] Time tracking data recorded
|
||||
- [ ] Ready for production
|
||||
|
||||
## ⏱️ **Time Tracking Performance Targets**
|
||||
|
||||
### **Expected Durations by Complexity**
|
||||
- **Simple Components**: 15-20 minutes
|
||||
- **Medium Components**: 30-45 minutes
|
||||
- **Complex Components**: 45-60 minutes
|
||||
|
||||
### **Quality Gates**
|
||||
- [ ] Start time logged with script
|
||||
- [ ] End time logged with script
|
||||
- [ ] Duration recorded in commit message
|
||||
- [ ] Performance compared to expected range
|
||||
- [ ] Issues affecting timing documented
|
||||
|
||||
### **Efficiency Tracking**
|
||||
- [ ] Batch similar components for efficiency
|
||||
- [ ] Use proven patterns to reduce time
|
||||
- [ ] Note any new patterns or shortcuts discovered
|
||||
- [ ] Update time estimates based on actual performance
|
||||
|
||||
## Wait for human confirmation before proceeding to next file unless directly overridden.
|
||||
|
||||
## 🚨 FAILURE CONDITIONS
|
||||
|
||||
**❌ INCOMPLETE MIGRATION** if ANY of these remain:
|
||||
- `databaseUtil` imports or calls
|
||||
- Raw SQL queries (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
|
||||
- `$notify()` calls with object syntax
|
||||
- `logConsoleAndDb()` calls
|
||||
- Local notification constants
|
||||
- Complex template logic not extracted to computed properties
|
||||
- **Missing time tracking data in commit**
|
||||
|
||||
**❌ INCOMPLETE TIME TRACKING** if ANY of these are missing:
|
||||
- Start time not logged
|
||||
- End time not logged
|
||||
- Duration not recorded in commit message
|
||||
- Complexity level not assessed
|
||||
- Performance not compared to targets
|
||||
|
||||
## 🎯 **SUCCESS CRITERIA**
|
||||
|
||||
**✅ COMPLETE MIGRATION** requires ALL of these:
|
||||
- All four migration phases completed
|
||||
- Zero legacy patterns detected
|
||||
- All validation scripts pass
|
||||
- Time tracking data recorded
|
||||
- Commit includes performance metrics
|
||||
- Documentation updated
|
||||
- Ready for human testing
|
||||
|
||||
**Expected Project Completion**: 2-3 weeks (69 remaining components × 20 minutes average = 23 hours = 3 days focused work)
|
||||
|
||||
## Templates and References
|
||||
|
||||
- **Migration Template**: `docs/migration-templates/component-migration.md`
|
||||
- **Notification Constants**: `src/constants/notifications.ts`
|
||||
- **PlatformServiceMixin**: `src/utils/PlatformServiceMixin.ts`
|
||||
- **Notification Helpers**: `src/utils/notify.ts`
|
||||
- **Validation Script**: `scripts/validate-migration.sh`
|
||||
|
||||
---
|
||||
|
||||
**⚠️ WARNING**: This checklist exists because steps were previously forgotten. DO NOT skip any items. The enhanced triple migration pattern (Database + SQL + Notifications + Template Streamlining) is MANDATORY for all component migrations.
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2024-07-07
|
||||
**Purpose**: Prevent migration oversight by cementing ALL requirements including template quality
|
||||
**Updated**: Enhanced with template streamlining and code quality review phases
|
||||
@@ -1,159 +0,0 @@
|
||||
# Pre-Migration Feature Audit Template
|
||||
|
||||
## Overview
|
||||
This template provides a systematic approach to audit all features in a component before migration to ensure no functionality is lost and provide a verification checklist.
|
||||
|
||||
## Component Information
|
||||
- **Component Name**: [ComponentName.vue]
|
||||
- **Location**: [src/path/to/Component.vue]
|
||||
- **Total Lines**: [XXX lines]
|
||||
- **Audit Date**: [YYYY-MM-DD]
|
||||
- **Auditor**: Matthew Raymer
|
||||
|
||||
## 📊 Migration Scope Analysis
|
||||
|
||||
### Database Operations Audit
|
||||
- [ ] **Total Database Operations**: [X operations]
|
||||
- [ ] **Legacy databaseUtil imports**: [X imports]
|
||||
- [ ] **PlatformServiceFactory calls**: [X calls]
|
||||
- [ ] **Raw SQL queries**: [X queries]
|
||||
|
||||
### Notification Operations Audit
|
||||
- [ ] **Total Notification Calls**: [X calls]
|
||||
- [ ] **Direct $notify calls**: [X calls]
|
||||
- [ ] **Legacy notification patterns**: [X patterns]
|
||||
|
||||
### Template Complexity Audit
|
||||
- [ ] **Complex template expressions**: [X expressions]
|
||||
- [ ] **Repeated CSS classes**: [X repetitions]
|
||||
- [ ] **Configuration objects**: [X objects]
|
||||
|
||||
## 🔍 Feature-by-Feature Audit
|
||||
|
||||
### 1. Database Features
|
||||
|
||||
#### Feature: [Feature Name]
|
||||
- **Location**: Lines [XXX-XXX]
|
||||
- **Type**: [SELECT/INSERT/UPDATE/DELETE/COUNT/etc.]
|
||||
- **Current Implementation**:
|
||||
```typescript
|
||||
// Current code snippet
|
||||
```
|
||||
- **Migration Target**: `this.$methodName()`
|
||||
- **Verification**: [ ] Functionality preserved after migration
|
||||
|
||||
#### Feature: [Feature Name]
|
||||
- **Location**: Lines [XXX-XXX]
|
||||
- **Type**: [Type]
|
||||
- **Current Implementation**:
|
||||
```typescript
|
||||
// Current code snippet
|
||||
```
|
||||
- **Migration Target**: `this.$methodName()`
|
||||
- **Verification**: [ ] Functionality preserved after migration
|
||||
|
||||
### 2. Notification Features
|
||||
|
||||
#### Feature: [Feature Name]
|
||||
- **Location**: Lines [XXX-XXX]
|
||||
- **Type**: [success/error/warning/info/toast/confirm]
|
||||
- **Current Implementation**:
|
||||
```typescript
|
||||
// Current code snippet
|
||||
```
|
||||
- **Migration Target**: `this.notify.methodName()`
|
||||
- **Verification**: [ ] Functionality preserved after migration
|
||||
|
||||
### 3. Template Features
|
||||
|
||||
#### Feature: [Feature Name]
|
||||
- **Location**: Lines [XXX-XXX]
|
||||
- **Type**: [computed/method/expression/class]
|
||||
- **Current Implementation**:
|
||||
```vue
|
||||
<!-- Current template snippet -->
|
||||
```
|
||||
- **Migration Target**: Extract to computed property/method
|
||||
- **Verification**: [ ] Functionality preserved after migration
|
||||
|
||||
## 🎯 Migration Checklist Totals
|
||||
|
||||
### Database Migration Requirements
|
||||
- [ ] **Replace databaseUtil imports**: [X imports] → PlatformServiceMixin
|
||||
- [ ] **Replace PlatformServiceFactory calls**: [X calls] → mixin methods
|
||||
- [ ] **Replace raw SQL queries**: [X queries] → service methods
|
||||
- [ ] **Update error handling**: [X patterns] → mixin error handling
|
||||
|
||||
### Notification Migration Requirements
|
||||
- [ ] **Add notification helpers**: Import createNotifyHelpers
|
||||
- [ ] **Replace direct $notify calls**: [X calls] → helper methods
|
||||
- [ ] **Add notification constants**: [X constants] → src/constants/notifications.ts
|
||||
- [ ] **Update notification patterns**: [X patterns] → standardized helpers
|
||||
|
||||
### Template Streamlining Requirements
|
||||
- [ ] **Extract repeated classes**: [X repetitions] → computed properties
|
||||
- [ ] **Extract complex expressions**: [X expressions] → computed properties
|
||||
- [ ] **Extract configuration objects**: [X objects] → computed properties
|
||||
- [ ] **Simplify template logic**: [X patterns] → methods/computed
|
||||
|
||||
## 📋 Post-Migration Verification Checklist
|
||||
|
||||
### ✅ Database Functionality Verification
|
||||
- [ ] All database operations work correctly
|
||||
- [ ] Error handling functions properly
|
||||
- [ ] Performance is maintained or improved
|
||||
- [ ] Data integrity is preserved
|
||||
|
||||
### ✅ Notification Functionality Verification
|
||||
- [ ] All notification types display correctly
|
||||
- [ ] Notification timing works as expected
|
||||
- [ ] User feedback is appropriate
|
||||
- [ ] Error notifications are informative
|
||||
|
||||
### ✅ Template Functionality Verification
|
||||
- [ ] All UI elements render correctly
|
||||
- [ ] Interactive elements function properly
|
||||
- [ ] Responsive design is maintained
|
||||
- [ ] Accessibility is preserved
|
||||
|
||||
### ✅ Integration Verification
|
||||
- [ ] Component integrates properly with parent components
|
||||
- [ ] Router navigation works correctly
|
||||
- [ ] Props and events function as expected
|
||||
- [ ] Cross-platform compatibility maintained
|
||||
|
||||
## 🚀 Migration Readiness Assessment
|
||||
|
||||
### Pre-Migration Requirements
|
||||
- [ ] **Feature audit completed**: All features documented with line numbers
|
||||
- [ ] **Migration targets identified**: Each feature has clear migration path
|
||||
- [ ] **Test scenarios planned**: Verification steps documented
|
||||
- [ ] **Backup created**: Original component backed up
|
||||
|
||||
### Complexity Assessment
|
||||
- [ ] **Simple** (15-20 min): Few database operations, minimal notifications
|
||||
- [ ] **Medium** (30-45 min): Multiple database operations, several notifications
|
||||
- [ ] **Complex** (45-60 min): Extensive database usage, many notifications, complex templates
|
||||
|
||||
### Dependencies Assessment
|
||||
- [ ] **No blocking dependencies**: Component can be migrated independently
|
||||
- [ ] **Parent dependencies identified**: Known impacts on parent components
|
||||
- [ ] **Child dependencies identified**: Known impacts on child components
|
||||
|
||||
## 📝 Notes and Special Considerations
|
||||
|
||||
### Special Migration Considerations
|
||||
[Document any unusual patterns, complex logic, or special requirements]
|
||||
|
||||
### Risk Assessment
|
||||
[Document any potential risks or challenges for this migration]
|
||||
|
||||
### Testing Strategy
|
||||
[Document specific testing approach for this component]
|
||||
|
||||
---
|
||||
|
||||
**Template Version**: 1.0
|
||||
**Created**: 2025-01-08
|
||||
**Author**: Matthew Raymer
|
||||
**Status**: Ready for use
|
||||
@@ -1,150 +0,0 @@
|
||||
# TimeSafari Migration Process Overview
|
||||
|
||||
## 🎯 Purpose
|
||||
This document provides a high-level overview of the complete migration process for TimeSafari components, preventing oversight and ensuring systematic completion.
|
||||
|
||||
## 📋 The Complete Migration Pattern
|
||||
|
||||
### Triple Migration Requirement
|
||||
**ALL components must complete ALL three migration types:**
|
||||
|
||||
1. **🗃️ Database Migration**: Replace legacy `databaseUtil` calls
|
||||
2. **🔗 SQL Abstraction**: Replace raw SQL with service methods
|
||||
3. **🔔 Notification Migration**: Replace `$notify()` with helper methods
|
||||
|
||||
### Why All Three Are Required
|
||||
|
||||
| Migration Type | Purpose | Risk of Skipping |
|
||||
|----------------|---------|------------------|
|
||||
| Database | Modern API access | Inconsistent database patterns |
|
||||
| SQL Abstraction | Service layer separation | Exposed SQL in components |
|
||||
| Notification | Consistent UX patterns | Inconsistent user messaging |
|
||||
|
||||
## 🛠️ Tools and Resources
|
||||
|
||||
### Documentation
|
||||
- **Primary Checklist**: `docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md`
|
||||
- **Quick Reference**: `docs/migration-templates/component-migration.md`
|
||||
- **Testing Tracker**: `docs/migration-testing/HUMAN_TESTING_TRACKER.md`
|
||||
|
||||
### Validation Scripts
|
||||
- **Overall Status**: `scripts/validate-migration.sh`
|
||||
- **Notification Completeness**: `scripts/validate-notification-completeness.sh`
|
||||
- **Linting**: `npm run lint-fix`
|
||||
|
||||
### Source References
|
||||
- **PlatformServiceMixin**: `src/utils/PlatformServiceMixin.ts`
|
||||
- **Notification Helpers**: `src/utils/notify.ts`
|
||||
- **Notification Constants**: `src/constants/notifications.ts`
|
||||
|
||||
## 🔄 Standard Workflow
|
||||
|
||||
### 1. Pre-Migration Assessment
|
||||
```bash
|
||||
# Run validation to identify issues
|
||||
scripts/validate-migration.sh
|
||||
scripts/validate-notification-completeness.sh
|
||||
```
|
||||
|
||||
### 2. Execute Triple Migration
|
||||
**Follow `COMPLETE_MIGRATION_CHECKLIST.md` exactly**
|
||||
- Phase 1: Database Migration
|
||||
- Phase 2: SQL Abstraction
|
||||
- Phase 3: Notification Migration
|
||||
|
||||
### 3. Validation Loop
|
||||
```bash
|
||||
# After each phase, validate progress
|
||||
scripts/validate-migration.sh
|
||||
scripts/validate-notification-completeness.sh
|
||||
npm run lint-fix
|
||||
```
|
||||
|
||||
### 4. Human Testing
|
||||
- Component functional testing
|
||||
- Cross-platform validation
|
||||
- Error scenario testing
|
||||
|
||||
### 5. Documentation
|
||||
- Update testing tracker
|
||||
- Create migration documentation
|
||||
- Mark as complete
|
||||
|
||||
## 🚨 Common Oversights
|
||||
|
||||
### ❌ Incomplete Patterns
|
||||
1. **Partial Database Migration**: Mixin imported but legacy calls remain
|
||||
2. **Missing SQL Abstraction**: Database migrated but raw SQL remains
|
||||
3. **Forgotten Notifications**: Database/SQL done but `$notify()` calls remain
|
||||
|
||||
### ✅ Success Indicators
|
||||
1. **Zero Legacy Patterns**: No `databaseUtil`, raw SQL, or `$notify()` calls
|
||||
2. **Validation Clean**: All scripts pass without issues
|
||||
3. **Functional Testing**: All features work correctly
|
||||
4. **Documentation Complete**: Migration recorded and tracked
|
||||
|
||||
## 🎯 Current Status
|
||||
|
||||
### Migration Statistics
|
||||
Run these commands for current status:
|
||||
```bash
|
||||
scripts/validate-migration.sh | grep "Migration percentage"
|
||||
scripts/validate-notification-completeness.sh | grep "Summary"
|
||||
```
|
||||
|
||||
### Priority Focus
|
||||
1. **Mixed Pattern Files**: Components with partial migrations
|
||||
2. **Notification Incomplete**: Components with `$notify()` calls
|
||||
3. **New Components**: Ensure they follow modern patterns
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Component Shows "Mixed Pattern"
|
||||
```bash
|
||||
# Check what patterns remain
|
||||
grep -n "databaseUtil\|logConsoleAndDb\|this\.\$notify" src/path/to/component.vue
|
||||
```
|
||||
|
||||
### Notification Validation Fails
|
||||
```bash
|
||||
# Check notification setup
|
||||
grep -n "createNotifyHelpers\|notify!:\|this\.notify =" src/path/to/component.vue
|
||||
```
|
||||
|
||||
### TypeScript Errors
|
||||
```bash
|
||||
# Check compilation
|
||||
npx tsc --noEmit
|
||||
npm run lint-fix
|
||||
```
|
||||
|
||||
## 📚 Learning From This Process
|
||||
|
||||
### Key Lesson: Systematic Validation
|
||||
The creation of this process was triggered by forgetting notification migration in DIDView.vue, demonstrating that:
|
||||
|
||||
1. **Checklists prevent oversights**
|
||||
2. **Validation scripts catch mistakes**
|
||||
3. **Documentation cements requirements**
|
||||
4. **Multiple validation layers ensure completeness**
|
||||
|
||||
### Prevention Strategy
|
||||
- **Always use the complete checklist**
|
||||
- **Run all validation scripts**
|
||||
- **Document every migration**
|
||||
- **Update tracking systematically**
|
||||
|
||||
## 🚀 Next Steps
|
||||
|
||||
1. **Complete current mixed patterns** using the established process
|
||||
2. **Validate all "technically compliant" components** for notification completeness
|
||||
3. **Establish this as standard process** for all future migrations
|
||||
4. **Create automated CI checks** to prevent regression
|
||||
|
||||
---
|
||||
|
||||
**Remember**: This process exists to prevent the exact oversight that occurred with DIDView.vue notification migration. Follow it completely to ensure systematic migration success.
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2024-01-XX
|
||||
**Purpose**: Prevent migration oversights through systematic process
|
||||
@@ -1,436 +0,0 @@
|
||||
# PlatformServiceMixin Best Practices Guide
|
||||
|
||||
## Overview
|
||||
This guide establishes best practices for using PlatformServiceMixin in TimeSafari components to ensure consistent, maintainable, and secure code.
|
||||
|
||||
## Core Principles
|
||||
|
||||
### 1. **Single Source of Truth**
|
||||
- Always use PlatformServiceMixin for database operations
|
||||
- Never mix legacy patterns with mixin patterns in the same component
|
||||
- Use mixin caching to avoid redundant database queries
|
||||
|
||||
### 2. **Component Context Awareness**
|
||||
- Always include component name in error logging
|
||||
- Use `this.$options.name` for consistent component identification
|
||||
- Implement proper error boundaries with context
|
||||
|
||||
### 3. **Progressive Enhancement**
|
||||
- Start with basic mixin methods (`$db`, `$exec`, `$one`)
|
||||
- Use specialized methods when available (`$getAllContacts`, `$settings`)
|
||||
- Leverage caching for frequently accessed data
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### Database Operations
|
||||
|
||||
#### ✅ **Preferred Pattern: Use Specialized Methods**
|
||||
```typescript
|
||||
// Best: Use high-level specialized methods
|
||||
const contacts = await this.$getAllContacts();
|
||||
const settings = await this.$settings();
|
||||
const userSettings = await this.$accountSettings(did);
|
||||
```
|
||||
|
||||
#### ✅ **Good Pattern: Use Mapped Query Methods**
|
||||
```typescript
|
||||
// Good: Use query methods with automatic mapping
|
||||
const results = await this.$query<Contact>(
|
||||
"SELECT * FROM contacts WHERE registered = ?",
|
||||
[true]
|
||||
);
|
||||
```
|
||||
|
||||
#### ⚠️ **Acceptable Pattern: Use Raw Database Methods**
|
||||
```typescript
|
||||
// Acceptable: Use raw methods when specialized methods don't exist
|
||||
const result = await this.$db("SELECT COUNT(*) as count FROM logs");
|
||||
const count = result?.values?.[0]?.[0] || 0;
|
||||
```
|
||||
|
||||
#### ❌ **Anti-Pattern: Direct Platform Service**
|
||||
```typescript
|
||||
// Anti-pattern: Avoid direct PlatformService usage
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const result = await platformService.dbQuery(sql, params);
|
||||
```
|
||||
|
||||
### Settings Management
|
||||
|
||||
#### ✅ **Best Practice: Use Mixin Methods**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async loadSettings() {
|
||||
// ✅ Use cached settings retrieval
|
||||
const settings = await this.$settings();
|
||||
return settings;
|
||||
}
|
||||
|
||||
async saveUserPreferences(changes: Partial<Settings>) {
|
||||
// ✅ Use specialized save method
|
||||
await this.$saveSettings(changes);
|
||||
await this.$log("User preferences saved");
|
||||
}
|
||||
|
||||
async loadAccountSettings(did: string) {
|
||||
// ✅ Use account-specific settings
|
||||
const accountSettings = await this.$accountSettings(did);
|
||||
return accountSettings;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ❌ **Anti-Pattern: Legacy Settings Access**
|
||||
```typescript
|
||||
// Anti-pattern: Avoid legacy databaseUtil methods
|
||||
import * as databaseUtil from "../db/databaseUtil";
|
||||
|
||||
async loadSettings() {
|
||||
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||
return settings;
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
#### ✅ **Best Practice: Component-Aware Error Handling**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async performOperation() {
|
||||
try {
|
||||
const result = await this.$getAllContacts();
|
||||
await this.$log("Operation completed successfully");
|
||||
return result;
|
||||
} catch (error) {
|
||||
// ✅ Include component context in error logging
|
||||
await this.$logError(`[${this.$options.name}] Operation failed: ${error}`);
|
||||
|
||||
// ✅ Provide user-friendly error handling
|
||||
this.$notify({
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Operation Failed",
|
||||
text: "Unable to load contacts. Please try again.",
|
||||
});
|
||||
|
||||
throw error; // Re-throw for upstream handling
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ❌ **Anti-Pattern: Generic Error Handling**
|
||||
```typescript
|
||||
// Anti-pattern: Generic error handling without context
|
||||
try {
|
||||
// operation
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
throw error;
|
||||
}
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
#### ✅ **Best Practice: Structured Logging**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async performDatabaseOperation() {
|
||||
// ✅ Log operation start with context
|
||||
await this.$log(`[${this.$options.name}] Starting database operation`);
|
||||
|
||||
try {
|
||||
const result = await this.$getAllContacts();
|
||||
|
||||
// ✅ Log successful completion
|
||||
await this.$log(`[${this.$options.name}] Database operation completed, found ${result.length} contacts`);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
// ✅ Log errors with full context
|
||||
await this.$logError(`[${this.$options.name}] Database operation failed: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Use appropriate log levels
|
||||
async validateInput(input: string) {
|
||||
if (!input) {
|
||||
await this.$log(`[${this.$options.name}] Input validation failed: empty input`, 'warn');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caching Strategies
|
||||
|
||||
#### ✅ **Best Practice: Smart Caching Usage**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async loadContactsWithCaching() {
|
||||
// ✅ Use cached contacts (automatically managed by mixin)
|
||||
const contacts = await this.$contacts();
|
||||
|
||||
// ✅ Force refresh when needed
|
||||
if (this.needsFreshData) {
|
||||
const freshContacts = await this.$refreshContacts();
|
||||
return freshContacts;
|
||||
}
|
||||
|
||||
return contacts;
|
||||
}
|
||||
|
||||
async updateContactAndRefresh(did: string, changes: Partial<Contact>) {
|
||||
// ✅ Update contact and invalidate cache
|
||||
await this.$updateContact(did, changes);
|
||||
|
||||
// ✅ Clear cache to ensure fresh data on next access
|
||||
this.$clearAllCaches();
|
||||
|
||||
await this.$log(`[${this.$options.name}] Contact updated and cache cleared`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Input Validation
|
||||
|
||||
#### ✅ **Always Validate Database Inputs**
|
||||
```typescript
|
||||
async saveContact(contact: Partial<Contact>) {
|
||||
// ✅ Validate required fields
|
||||
if (!contact.did || !contact.name) {
|
||||
await this.$logError(`[${this.$options.name}] Invalid contact data: missing required fields`);
|
||||
throw new Error('Contact must have DID and name');
|
||||
}
|
||||
|
||||
// ✅ Sanitize inputs
|
||||
const sanitizedContact = {
|
||||
...contact,
|
||||
name: contact.name.trim(),
|
||||
// Remove any potential XSS vectors
|
||||
notes: contact.notes?.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
||||
};
|
||||
|
||||
return await this.$insertContact(sanitizedContact);
|
||||
}
|
||||
```
|
||||
|
||||
### Error Information Disclosure
|
||||
|
||||
#### ✅ **Safe Error Handling**
|
||||
```typescript
|
||||
async performSensitiveOperation(did: string) {
|
||||
try {
|
||||
// Sensitive operation
|
||||
const result = await this.$accountSettings(did);
|
||||
return result;
|
||||
} catch (error) {
|
||||
// ✅ Log full error for debugging
|
||||
await this.$logError(`[${this.$options.name}] Sensitive operation failed: ${error}`);
|
||||
|
||||
// ✅ Return generic error to user
|
||||
throw new Error('Unable to complete operation. Please try again.');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SQL Injection Prevention
|
||||
|
||||
#### ✅ **Always Use Parameterized Queries**
|
||||
```typescript
|
||||
// ✅ Safe: Parameterized query
|
||||
async findContactsByName(searchTerm: string) {
|
||||
return await this.$query<Contact>(
|
||||
"SELECT * FROM contacts WHERE name LIKE ?",
|
||||
[`%${searchTerm}%`]
|
||||
);
|
||||
}
|
||||
|
||||
// ❌ Dangerous: String concatenation
|
||||
async findContactsByNameUnsafe(searchTerm: string) {
|
||||
return await this.$query<Contact>(
|
||||
`SELECT * FROM contacts WHERE name LIKE '%${searchTerm}%'`
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Database Query Optimization
|
||||
|
||||
#### ✅ **Efficient Query Patterns**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
async loadOptimizedData() {
|
||||
// ✅ Use transactions for multiple operations
|
||||
return await this.$withTransaction(async () => {
|
||||
const contacts = await this.$getAllContacts();
|
||||
const settings = await this.$settings();
|
||||
return { contacts, settings };
|
||||
});
|
||||
}
|
||||
|
||||
async loadDataWithPagination(offset: number, limit: number) {
|
||||
// ✅ Use LIMIT and OFFSET for large datasets
|
||||
return await this.$query<Contact>(
|
||||
"SELECT * FROM contacts ORDER BY name LIMIT ? OFFSET ?",
|
||||
[limit, offset]
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
#### ✅ **Proper Cache Management**
|
||||
```typescript
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
|
||||
beforeDestroy() {
|
||||
// ✅ Clear component caches on destroy
|
||||
this.$clearAllCaches();
|
||||
}
|
||||
|
||||
async handleLargeDataset() {
|
||||
try {
|
||||
// Process large dataset
|
||||
const largeResult = await this.$query("SELECT * FROM large_table");
|
||||
|
||||
// ✅ Process in chunks to avoid memory issues
|
||||
const chunkSize = 100;
|
||||
for (let i = 0; i < largeResult.length; i += chunkSize) {
|
||||
const chunk = largeResult.slice(i, i + chunkSize);
|
||||
await this.processChunk(chunk);
|
||||
}
|
||||
} finally {
|
||||
// ✅ Clear caches after processing large datasets
|
||||
this.$clearAllCaches();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Testing Strategies
|
||||
|
||||
### Unit Testing
|
||||
|
||||
#### ✅ **Mock Mixin Methods**
|
||||
```typescript
|
||||
// test/MyComponent.spec.ts
|
||||
import { mount } from '@vue/test-utils';
|
||||
import MyComponent from '@/components/MyComponent.vue';
|
||||
import { PlatformServiceMixin } from '@/utils/PlatformServiceMixin';
|
||||
|
||||
describe('MyComponent', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
// ✅ Mock mixin methods
|
||||
const mockMixin = {
|
||||
...PlatformServiceMixin,
|
||||
methods: {
|
||||
...PlatformServiceMixin.methods,
|
||||
$getAllContacts: jest.fn().mockResolvedValue([]),
|
||||
$settings: jest.fn().mockResolvedValue({}),
|
||||
$log: jest.fn().mockResolvedValue(undefined),
|
||||
$logError: jest.fn().mockResolvedValue(undefined),
|
||||
}
|
||||
};
|
||||
|
||||
wrapper = mount(MyComponent, {
|
||||
mixins: [mockMixin]
|
||||
});
|
||||
});
|
||||
|
||||
it('should load contacts on mount', async () => {
|
||||
await wrapper.vm.loadContacts();
|
||||
expect(wrapper.vm.$getAllContacts).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Integration Testing
|
||||
|
||||
#### ✅ **Test Real Database Operations**
|
||||
```typescript
|
||||
// test/integration/ContactsView.spec.ts
|
||||
import { createLocalVue, mount } from '@vue/test-utils';
|
||||
import ContactsView from '@/views/ContactsView.vue';
|
||||
import { PlatformServiceMixin } from '@/utils/PlatformServiceMixin';
|
||||
|
||||
describe('ContactsView Integration', () => {
|
||||
it('should perform real database operations', async () => {
|
||||
const wrapper = mount(ContactsView, {
|
||||
mixins: [PlatformServiceMixin]
|
||||
});
|
||||
|
||||
// ✅ Test real mixin functionality
|
||||
const contacts = await wrapper.vm.$getAllContacts();
|
||||
expect(Array.isArray(contacts)).toBe(true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
When migrating components to PlatformServiceMixin:
|
||||
|
||||
### Pre-Migration
|
||||
- [ ] Identify all database operations in the component
|
||||
- [ ] List all logging operations
|
||||
- [ ] Check for error handling patterns
|
||||
- [ ] Note any specialized database queries
|
||||
|
||||
### During Migration
|
||||
- [ ] Add PlatformServiceMixin to mixins array
|
||||
- [ ] Replace all database operations with mixin methods
|
||||
- [ ] Update logging to use mixin logging methods
|
||||
- [ ] Add component context to error messages
|
||||
- [ ] Replace settings operations with mixin methods
|
||||
- [ ] Update error handling to use structured patterns
|
||||
|
||||
### Post-Migration
|
||||
- [ ] Remove all legacy imports (databaseUtil, logConsoleAndDb)
|
||||
- [ ] Test all component functionality
|
||||
- [ ] Verify TypeScript compilation
|
||||
- [ ] Check for any remaining anti-patterns
|
||||
- [ ] Update component tests if needed
|
||||
- [ ] Run migration validation script
|
||||
|
||||
## Troubleshooting Common Issues
|
||||
|
||||
### Issue: TypeScript errors after migration
|
||||
**Solution**: Ensure proper type definitions and mixin interface implementation
|
||||
|
||||
### Issue: Methods not available on `this`
|
||||
**Solution**: Verify PlatformServiceMixin is properly included in mixins array
|
||||
|
||||
### Issue: Caching not working as expected
|
||||
**Solution**: Check cache TTL settings and clear cache when needed
|
||||
|
||||
### Issue: Database operations failing
|
||||
**Solution**: Verify PlatformService is properly initialized and check error logs
|
||||
|
||||
### Issue: Performance degradation
|
||||
**Solution**: Review query efficiency and cache usage patterns
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0** - Initial best practices documentation
|
||||
- **v1.1** - Added security and performance sections
|
||||
- **v1.2** - Enhanced testing strategies and troubleshooting
|
||||
@@ -1,936 +0,0 @@
|
||||
# Component Migration Template
|
||||
|
||||
## Overview
|
||||
This template provides step-by-step instructions for migrating Vue components from legacy patterns to PlatformServiceMixin.
|
||||
|
||||
## Before Migration Checklist
|
||||
|
||||
- [ ] Component uses `import * as databaseUtil`
|
||||
- [ ] Component uses `import { logConsoleAndDb }`
|
||||
- [ ] Component has direct `PlatformServiceFactory.getInstance()` calls
|
||||
- [ ] Component has manual error handling for database operations
|
||||
- [ ] Component has verbose SQL result processing
|
||||
|
||||
## Step-by-Step Migration
|
||||
|
||||
### Step 1: Update Imports
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE - Legacy imports
|
||||
import * as databaseUtil from "../db/databaseUtil";
|
||||
import { logConsoleAndDb } from "../db/databaseUtil";
|
||||
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
|
||||
|
||||
// ✅ AFTER - Clean imports
|
||||
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { Settings } from "@/db/tables/settings";
|
||||
```
|
||||
|
||||
### Step 2: Add Mixin to Component
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE - No mixin
|
||||
@Component({
|
||||
components: { /* ... */ }
|
||||
})
|
||||
export default class MyComponent extends Vue {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ✅ AFTER - With mixin
|
||||
@Component({
|
||||
components: { /* ... */ }
|
||||
})
|
||||
export default class MyComponent extends Vue {
|
||||
mixins: [PlatformServiceMixin],
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Replace Database Operations
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE - Legacy database access
|
||||
async loadContacts() {
|
||||
try {
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const result = await platformService.dbQuery("SELECT * FROM contacts");
|
||||
const contacts = databaseUtil.mapQueryResultToValues(result);
|
||||
await logConsoleAndDb("Contacts loaded successfully");
|
||||
return contacts;
|
||||
} catch (error) {
|
||||
await logConsoleAndDb("Error loading contacts: " + error, true);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ AFTER - Mixin methods
|
||||
async loadContacts() {
|
||||
try {
|
||||
const contacts = await this.$getAllContacts();
|
||||
await this.$log("Contacts loaded successfully");
|
||||
return contacts;
|
||||
} catch (error) {
|
||||
await this.$logError(`[${this.$options.name}] Error loading contacts: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Replace Settings Operations
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE - Legacy settings access
|
||||
async loadSettings() {
|
||||
const settingsRow = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||
const settings = settingsRow || {};
|
||||
return settings;
|
||||
}
|
||||
|
||||
async saveSettings(changes: Partial<Settings>) {
|
||||
await databaseUtil.updateDefaultSettings(changes);
|
||||
await logConsoleAndDb("Settings saved");
|
||||
}
|
||||
|
||||
// ✅ AFTER - Mixin methods
|
||||
async loadSettings() {
|
||||
return await this.$settings();
|
||||
}
|
||||
|
||||
async saveSettings(changes: Partial<Settings>) {
|
||||
await this.$saveSettings(changes);
|
||||
await this.$log("Settings saved");
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5: Replace Logging Operations
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE - Legacy logging
|
||||
try {
|
||||
// operation
|
||||
} catch (error) {
|
||||
console.error("Error occurred:", error);
|
||||
await logConsoleAndDb("Error: " + error, true);
|
||||
}
|
||||
|
||||
// ✅ AFTER - Mixin logging
|
||||
try {
|
||||
// operation
|
||||
} catch (error) {
|
||||
await this.$logError(`[${this.$options.name}] Error: ${error}`);
|
||||
}
|
||||
```
|
||||
|
||||
## Common Migration Patterns
|
||||
|
||||
### Pattern 1: Database Query + Result Processing
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const result = await platformService.dbQuery(sql, params);
|
||||
const processed = databaseUtil.mapQueryResultToValues(result);
|
||||
|
||||
// ✅ AFTER
|
||||
const processed = await this.$query(sql, params);
|
||||
```
|
||||
|
||||
### Pattern 2: Settings Retrieval
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE
|
||||
const settingsRow = await databaseUtil.retrieveSettingsForActiveAccount();
|
||||
const value = settingsRow?.[field] || defaultValue;
|
||||
|
||||
// ✅ AFTER
|
||||
const settings = await this.$settings();
|
||||
const value = settings[field] || defaultValue;
|
||||
```
|
||||
|
||||
### Pattern 3: Contact Operations
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE
|
||||
const platformService = PlatformServiceFactory.getInstance();
|
||||
const contacts = await platformService.dbQuery("SELECT * FROM contacts");
|
||||
const mappedContacts = databaseUtil.mapQueryResultToValues(contacts);
|
||||
|
||||
// ✅ AFTER
|
||||
const contacts = await this.$getAllContacts();
|
||||
```
|
||||
|
||||
### Pattern 4: Error Handling
|
||||
|
||||
```typescript
|
||||
// ❌ BEFORE
|
||||
try {
|
||||
// operation
|
||||
} catch (error) {
|
||||
console.error("[MyComponent] Error:", error);
|
||||
await databaseUtil.logToDb("Error: " + error, "error");
|
||||
}
|
||||
|
||||
// ✅ AFTER
|
||||
try {
|
||||
// operation
|
||||
} catch (error) {
|
||||
await this.$logError(`[${this.$options.name}] Error: ${error}`);
|
||||
}
|
||||
```
|
||||
|
||||
## Notification Migration (Additional Step)
|
||||
|
||||
If component uses `this.$notify()` calls, also migrate to notification helpers:
|
||||
|
||||
### Import and Setup
|
||||
```typescript
|
||||
// Add imports
|
||||
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
||||
import {
|
||||
NOTIFY_CONTACT_LOADING_ISSUE,
|
||||
NOTIFY_FEED_LOADING_ISSUE,
|
||||
// Add other constants as needed
|
||||
} from "@/constants/notifications";
|
||||
|
||||
// Add property
|
||||
notify!: ReturnType<typeof createNotifyHelpers>;
|
||||
|
||||
// Initialize in created()
|
||||
created() {
|
||||
this.notify = createNotifyHelpers(this.$notify);
|
||||
}
|
||||
```
|
||||
|
||||
### Replace Notification Calls
|
||||
```typescript
|
||||
// ❌ BEFORE
|
||||
this.$notify({
|
||||
group: "alert",
|
||||
type: "warning",
|
||||
title: "Warning",
|
||||
text: "Something went wrong"
|
||||
}, 5000);
|
||||
|
||||
// ✅ AFTER - Use constants for reusable messages
|
||||
this.notify.warning(NOTIFY_CONTACT_LOADING_ISSUE.message, TIMEOUTS.LONG);
|
||||
|
||||
// ✅ AFTER - Literal strings for dynamic content
|
||||
this.notify.error(userMessage || "Fallback error message", TIMEOUTS.LONG);
|
||||
```
|
||||
|
||||
### Common Notification Patterns
|
||||
- Warning: `this.notify.warning(NOTIFY_CONSTANT.message, TIMEOUTS.LONG)`
|
||||
- Error: `this.notify.error(NOTIFY_CONSTANT.message, TIMEOUTS.LONG)`
|
||||
- Success: `this.notify.success(NOTIFY_CONSTANT.message, TIMEOUTS.STANDARD)`
|
||||
- Toast: `this.notify.toast(title, message, TIMEOUTS.SHORT)`
|
||||
- Confirm: `this.notify.confirm(message, onYes)`
|
||||
- Standard patterns: `this.notify.confirmationSubmitted()`, `this.notify.sent()`, etc.
|
||||
|
||||
### Notification Constants Guidelines
|
||||
- **Use constants** for static, reusable messages (defined in `src/constants/notifications.ts`)
|
||||
- **Use literal strings** for dynamic messages with variables
|
||||
- **Add new constants** to `notifications.ts` for new reusable messages
|
||||
|
||||
#### Extract Literals from Complex Modals
|
||||
**IMPORTANT**: Even when complex modals must remain as raw `$notify` calls due to advanced features (custom buttons, nested callbacks, `promptToStopAsking`, etc.), **always extract literal strings to constants**:
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Literals in complex modal
|
||||
this.$notify({
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: "Are you nearby with cameras?",
|
||||
text: "If so, we'll use those with QR codes to share.",
|
||||
yesText: "we are nearby with cameras",
|
||||
noText: "we will share another way",
|
||||
onNo: () => { /* complex callback */ }
|
||||
});
|
||||
|
||||
// ✅ GOOD - Constants used even in complex modal
|
||||
export const NOTIFY_CAMERA_SHARE_METHOD = {
|
||||
title: "Are you nearby with cameras?",
|
||||
text: "If so, we'll use those with QR codes to share.",
|
||||
yesText: "we are nearby with cameras",
|
||||
noText: "we will share another way",
|
||||
};
|
||||
|
||||
this.$notify({
|
||||
group: "modal",
|
||||
type: "confirm",
|
||||
title: NOTIFY_CAMERA_SHARE_METHOD.title,
|
||||
text: NOTIFY_CAMERA_SHARE_METHOD.text,
|
||||
yesText: NOTIFY_CAMERA_SHARE_METHOD.yesText,
|
||||
noText: NOTIFY_CAMERA_SHARE_METHOD.noText,
|
||||
onNo: () => { /* complex callback preserved */ }
|
||||
});
|
||||
```
|
||||
|
||||
This approach provides:
|
||||
- **Consistency**: All user-facing text centralized
|
||||
- **Maintainability**: Easy to update messages
|
||||
- **Localization**: Ready for future i18n support
|
||||
- **Testability**: Constants can be imported in tests
|
||||
|
||||
## Critical Migration Omissions to Avoid
|
||||
|
||||
### 1. Remove Unused Notification Imports
|
||||
|
||||
**❌ COMMON MISTAKE**: Importing notification constants that aren't actually used
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Unused imports
|
||||
import {
|
||||
NOTIFY_CONTACT_ADDED, // Not used
|
||||
NOTIFY_CONTACT_ADDED_SUCCESS, // Not used
|
||||
NOTIFY_CONTACT_ERROR, // Actually used
|
||||
NOTIFY_CONTACT_EXISTS, // Actually used
|
||||
} from "@/constants/notifications";
|
||||
|
||||
// ✅ GOOD - Only import what's used
|
||||
import {
|
||||
NOTIFY_CONTACT_ERROR,
|
||||
NOTIFY_CONTACT_EXISTS,
|
||||
} from "@/constants/notifications";
|
||||
```
|
||||
|
||||
**How to check**: Use IDE "Find Usages" or grep to verify each imported constant is actually used in the file.
|
||||
|
||||
### 2. Replace ALL Hardcoded Timeout Values
|
||||
|
||||
**❌ COMMON MISTAKE**: Converting `$notify()` calls but leaving hardcoded timeout values
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Hardcoded timeout values
|
||||
this.notify.error(NOTIFY_CONTACT_ERROR.message, 5000);
|
||||
this.notify.success(NOTIFY_CONTACT_ADDED.message, 3000);
|
||||
this.notify.warning(NOTIFY_CONTACT_EXISTS.message, 5000);
|
||||
this.notify.toast(NOTIFY_URL_COPIED.message, 2000);
|
||||
|
||||
// ✅ GOOD - Use timeout constants
|
||||
this.notify.error(NOTIFY_CONTACT_ERROR.message, QR_TIMEOUT_LONG);
|
||||
this.notify.success(NOTIFY_CONTACT_ADDED.message, QR_TIMEOUT_STANDARD);
|
||||
this.notify.warning(NOTIFY_CONTACT_EXISTS.message, QR_TIMEOUT_LONG);
|
||||
this.notify.toast(NOTIFY_URL_COPIED.message, QR_TIMEOUT_MEDIUM);
|
||||
```
|
||||
|
||||
**Add timeout constants to your constants file**:
|
||||
```typescript
|
||||
// Add to src/constants/notifications.ts
|
||||
export const QR_TIMEOUT_SHORT = 1000; // Short operations
|
||||
export const QR_TIMEOUT_MEDIUM = 2000; // Medium operations
|
||||
export const QR_TIMEOUT_STANDARD = 3000; // Standard success messages
|
||||
export const QR_TIMEOUT_LONG = 5000; // Error messages and warnings
|
||||
```
|
||||
|
||||
### 3. Remove Legacy Wrapper Functions
|
||||
|
||||
**❌ COMMON MISTAKE**: Keeping legacy notification wrapper functions that are inconsistent with the new system
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Legacy wrapper function
|
||||
danger(message: string, title: string = "Error", timeout = 5000) {
|
||||
this.notify.error(message, timeout);
|
||||
}
|
||||
|
||||
// Usage (inconsistent with rest of system)
|
||||
this.danger(result.error as string, "Error Setting Visibility");
|
||||
|
||||
// ✅ GOOD - Direct usage of notification system
|
||||
this.notify.error(result.error as string, QR_TIMEOUT_LONG);
|
||||
```
|
||||
|
||||
**Why remove legacy wrappers**:
|
||||
- Creates inconsistency in the codebase
|
||||
- Adds unnecessary abstraction layer
|
||||
- Often have unused parameters (like `title` above)
|
||||
- Bypasses the centralized notification system benefits
|
||||
|
||||
### 4. Extract Long Class Attributes to Computed Properties
|
||||
|
||||
**❌ COMMON MISTAKE**: Leaving long class strings in template instead of extracting to computed properties
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Long class strings in template
|
||||
<template>
|
||||
<div class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 my-4">
|
||||
<button class="inline-block text-md uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md">
|
||||
Set Name
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// ✅ GOOD - Extract to computed properties
|
||||
<template>
|
||||
<div :class="nameWarningClasses">
|
||||
<button :class="setNameButtonClasses">
|
||||
Set Name
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// Class methods
|
||||
get nameWarningClasses(): string {
|
||||
return "bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 my-4";
|
||||
}
|
||||
|
||||
get setNameButtonClasses(): string {
|
||||
return "inline-block text-md uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md";
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits of extracting long classes**:
|
||||
- Improves template readability
|
||||
- Enables reusability of styles
|
||||
- Makes testing easier
|
||||
- Allows for dynamic class computation
|
||||
|
||||
### 5. Ensure ALL Literal Strings Use Constants
|
||||
|
||||
**❌ COMMON MISTAKE**: Converting `$notify()` calls to helpers but not replacing literal strings with constants
|
||||
|
||||
```typescript
|
||||
// ❌ BAD - Literal strings in notification calls
|
||||
this.notify.error("This QR code does not contain valid contact information.");
|
||||
this.notify.warning("The contact DID is missing.");
|
||||
this.notify.success("Registration submitted...");
|
||||
|
||||
// ✅ GOOD - Use constants for all static messages
|
||||
this.notify.error(NOTIFY_QR_INVALID_QR_CODE.message);
|
||||
this.notify.warning(NOTIFY_QR_MISSING_DID.message);
|
||||
this.notify.success(NOTIFY_QR_REGISTRATION_SUBMITTED.message);
|
||||
```
|
||||
|
||||
**Add constants for ALL static messages**:
|
||||
```typescript
|
||||
// Add to src/constants/notifications.ts
|
||||
export const NOTIFY_QR_INVALID_QR_CODE = {
|
||||
message: "This QR code does not contain valid contact information.",
|
||||
};
|
||||
|
||||
export const NOTIFY_QR_MISSING_DID = {
|
||||
message: "The contact DID is missing.",
|
||||
};
|
||||
|
||||
export const NOTIFY_QR_REGISTRATION_SUBMITTED = {
|
||||
message: "Registration submitted...",
|
||||
};
|
||||
```
|
||||
|
||||
### 6. Validation Checklist for Omissions
|
||||
|
||||
**Before marking migration complete, verify these items**:
|
||||
|
||||
```bash
|
||||
# Check for unused imports
|
||||
grep -n "import.*NOTIFY_" src/views/YourComponent.vue
|
||||
# Then verify each imported constant is actually used in the file
|
||||
|
||||
# Check for hardcoded timeouts
|
||||
grep -n "notify\.[a-z]*(" src/views/YourComponent.vue | grep -E "[0-9]{3,4}"
|
||||
|
||||
# Check for legacy wrapper functions
|
||||
grep -n "danger\|success\|warning\|info.*(" src/views/YourComponent.vue | grep -v "notify\."
|
||||
|
||||
# Check for long class attributes (>50 chars)
|
||||
grep -n "class=\"[^\"]\{50,\}" src/views/YourComponent.vue
|
||||
|
||||
# Check for literal strings in notifications
|
||||
grep -n "notify\.[a-z]*(" src/views/YourComponent.vue | grep -v "NOTIFY_\|message"
|
||||
```
|
||||
|
||||
### 7. Post-Migration Cleanup Commands
|
||||
|
||||
**Run these commands after migration to catch omissions**:
|
||||
|
||||
```bash
|
||||
# Check TypeScript compilation
|
||||
npm run lint-fix
|
||||
|
||||
# Run validation scripts
|
||||
scripts/validate-migration.sh
|
||||
scripts/validate-notification-completeness.sh
|
||||
|
||||
# Check for any remaining databaseUtil references
|
||||
grep -r "databaseUtil" src/views/YourComponent.vue
|
||||
|
||||
# Check for any remaining $notify calls
|
||||
grep -r "\$notify(" src/views/YourComponent.vue
|
||||
```
|
||||
|
||||
## Template Logic Streamlining
|
||||
|
||||
### Move Complex Template Logic to Class
|
||||
|
||||
When migrating components, look for opportunities to simplify template expressions by moving logic into computed properties or methods:
|
||||
|
||||
#### Pattern 1: Repeated Function Calls
|
||||
```typescript
|
||||
// ❌ BEFORE - Template with repeated function calls
|
||||
<template>
|
||||
<div>{{ formatName(user.firstName, user.lastName, user.title) }}</div>
|
||||
<div>{{ formatName(contact.firstName, contact.lastName, contact.title) }}</div>
|
||||
</template>
|
||||
|
||||
// ✅ AFTER - Computed properties for repeated logic
|
||||
<template>
|
||||
<div>{{ userDisplayName }}</div>
|
||||
<div>{{ contactDisplayName }}</div>
|
||||
</template>
|
||||
|
||||
// Class methods
|
||||
get userDisplayName() {
|
||||
return this.formatName(this.user?.firstName, this.user?.lastName, this.user?.title);
|
||||
}
|
||||
|
||||
get contactDisplayName() {
|
||||
return this.formatName(this.contact?.firstName, this.contact?.lastName, this.contact?.title);
|
||||
}
|
||||
```
|
||||
|
||||
#### Pattern 2: Complex Conditional Logic
|
||||
```typescript
|
||||
// ❌ BEFORE - Complex template conditions
|
||||
<template>
|
||||
<div v-if="profile?.locLat && profile?.locLon && profile?.showLocation">
|
||||
<l-map :center="[profile.locLat, profile.locLon]" :zoom="12">
|
||||
<!-- map content -->
|
||||
</l-map>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// ✅ AFTER - Computed properties for clarity
|
||||
<template>
|
||||
<div v-if="shouldShowMap">
|
||||
<l-map :center="mapCenter" :zoom="mapZoom">
|
||||
<!-- map content -->
|
||||
</l-map>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// Class methods
|
||||
get shouldShowMap() {
|
||||
return this.profile?.locLat && this.profile?.locLon && this.profile?.showLocation;
|
||||
}
|
||||
|
||||
get mapCenter() {
|
||||
return [this.profile?.locLat, this.profile?.locLon];
|
||||
}
|
||||
|
||||
get mapZoom() {
|
||||
return 12;
|
||||
}
|
||||
```
|
||||
|
||||
#### Pattern 3: Repeated Configuration Objects
|
||||
```typescript
|
||||
// ❌ BEFORE - Repeated inline objects
|
||||
<template>
|
||||
<l-tile-layer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
layer-type="base"
|
||||
name="OpenStreetMap"
|
||||
/>
|
||||
<l-tile-layer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
layer-type="base"
|
||||
name="OpenStreetMap"
|
||||
/>
|
||||
</template>
|
||||
|
||||
// ✅ AFTER - Computed property for configuration
|
||||
<template>
|
||||
<l-tile-layer
|
||||
:url="tileLayerUrl"
|
||||
layer-type="base"
|
||||
name="OpenStreetMap"
|
||||
/>
|
||||
<l-tile-layer
|
||||
:url="tileLayerUrl"
|
||||
layer-type="base"
|
||||
name="OpenStreetMap"
|
||||
/>
|
||||
</template>
|
||||
|
||||
// Class methods
|
||||
get tileLayerUrl() {
|
||||
return "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
|
||||
}
|
||||
```
|
||||
|
||||
#### Pattern 4: Array/Object Construction in Template
|
||||
```typescript
|
||||
// ❌ BEFORE - Complex array construction in template
|
||||
<template>
|
||||
<component :coords="[item.lat || 0, item.lng || 0]" />
|
||||
</template>
|
||||
|
||||
// ✅ AFTER - Computed property for complex data
|
||||
<template>
|
||||
<component :coords="itemCoordinates" />
|
||||
</template>
|
||||
|
||||
// Class methods
|
||||
get itemCoordinates() {
|
||||
return [this.item?.lat || 0, this.item?.lng || 0];
|
||||
}
|
||||
```
|
||||
|
||||
### Benefits of Logic Streamlining
|
||||
|
||||
1. **Improved Readability**: Template becomes cleaner and easier to understand
|
||||
2. **Better Performance**: Vue caches computed properties, avoiding recalculation
|
||||
3. **Easier Testing**: Logic can be unit tested independently
|
||||
4. **Reduced Duplication**: Common expressions defined once
|
||||
5. **Type Safety**: TypeScript can better validate computed property return types
|
||||
|
||||
### Guidelines for Logic Streamlining
|
||||
|
||||
- **Move to computed properties**: Expressions used multiple times or complex calculations
|
||||
- **Keep in template**: Simple property access (`user.name`) or single-use expressions
|
||||
- **Document computed properties**: Add JSDoc comments explaining purpose and return types
|
||||
- **Use descriptive names**: `userDisplayName` instead of `getName()`
|
||||
|
||||
## Component Extraction Patterns
|
||||
|
||||
### When to Extract Components
|
||||
|
||||
Extract components when you identify:
|
||||
- **Repeated UI patterns** used in multiple places
|
||||
- **Complex template sections** that could be simplified
|
||||
- **Form elements** with similar structure and behavior
|
||||
- **Layout patterns** that appear consistently
|
||||
- **Validation patterns** with repeated logic
|
||||
|
||||
### Component Extraction Examples
|
||||
|
||||
#### Form Input Extraction
|
||||
```typescript
|
||||
// Before: Repeated form input pattern
|
||||
<template>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Name</label>
|
||||
<input class="form-input" v-model="name" />
|
||||
<div class="error-message" v-if="nameError">{{ nameError }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Email</label>
|
||||
<input class="form-input" v-model="email" />
|
||||
<div class="error-message" v-if="emailError">{{ emailError }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// After: Extracted FormInput component
|
||||
<template>
|
||||
<FormInput
|
||||
label="Name"
|
||||
v-model="name"
|
||||
:error="nameError"
|
||||
/>
|
||||
<FormInput
|
||||
label="Email"
|
||||
v-model="email"
|
||||
:error="emailError"
|
||||
/>
|
||||
</template>
|
||||
|
||||
// New FormInput.vue component
|
||||
<template>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ label }}</label>
|
||||
<input
|
||||
class="form-input"
|
||||
:value="value"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
/>
|
||||
<div class="error-message" v-if="error">{{ error }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from "vue-facing-decorator";
|
||||
|
||||
/**
|
||||
* Reusable form input component with label and error handling
|
||||
*/
|
||||
@Component
|
||||
export default class FormInput extends Vue {
|
||||
@Prop({ required: true }) label!: string;
|
||||
@Prop({ required: true }) value!: string;
|
||||
@Prop() error?: string;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Button Group Extraction
|
||||
```typescript
|
||||
// Before: Repeated button patterns
|
||||
<template>
|
||||
<div class="button-group">
|
||||
<button class="btn btn-primary" @click="save">Save</button>
|
||||
<button class="btn btn-secondary" @click="cancel">Cancel</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
// After: Extracted ButtonGroup component
|
||||
<template>
|
||||
<ButtonGroup
|
||||
:primary-action="{ text: 'Save', handler: save }"
|
||||
:secondary-action="{ text: 'Cancel', handler: cancel }"
|
||||
/>
|
||||
</template>
|
||||
|
||||
// New ButtonGroup.vue component
|
||||
<template>
|
||||
<div class="button-group">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
@click="primaryAction.handler"
|
||||
>
|
||||
{{ primaryAction.text }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
@click="secondaryAction.handler"
|
||||
>
|
||||
{{ secondaryAction.text }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from "vue-facing-decorator";
|
||||
|
||||
interface ButtonAction {
|
||||
text: string;
|
||||
handler: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reusable button group component for common action patterns
|
||||
*/
|
||||
@Component
|
||||
export default class ButtonGroup extends Vue {
|
||||
@Prop({ required: true }) primaryAction!: ButtonAction;
|
||||
@Prop({ required: true }) secondaryAction!: ButtonAction;
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Component Quality Standards
|
||||
|
||||
#### Single Responsibility
|
||||
- Each extracted component should have one clear purpose
|
||||
- Component name should clearly indicate its function
|
||||
- Props should be focused and relevant to the component's purpose
|
||||
|
||||
#### Reusability
|
||||
- Component should work in multiple contexts
|
||||
- Props should be flexible enough for different use cases
|
||||
- Events should provide appropriate communication with parent
|
||||
|
||||
#### Type Safety
|
||||
- All props should have proper TypeScript interfaces
|
||||
- Event emissions should be properly typed
|
||||
- Component should compile without type errors
|
||||
|
||||
#### Documentation
|
||||
- JSDoc comments explaining component purpose
|
||||
- Usage examples in comments
|
||||
- Clear prop descriptions and types
|
||||
|
||||
### Validation Checklist
|
||||
|
||||
After component extraction:
|
||||
- [ ] **No template duplication**: Extracted patterns don't appear elsewhere
|
||||
- [ ] **Proper component registration**: All components properly imported and registered
|
||||
- [ ] **Event handling works**: Parent components receive and handle events correctly
|
||||
- [ ] **Props validation**: All required props are provided with correct types
|
||||
- [ ] **Styling consistency**: Extracted components maintain visual consistency
|
||||
- [ ] **Functionality preserved**: All original functionality works with extracted components
|
||||
|
||||
## After Migration Checklist
|
||||
|
||||
⚠️ **CRITICAL**: Use `docs/migration-templates/COMPLETE_MIGRATION_CHECKLIST.md` for comprehensive validation
|
||||
|
||||
### Phase 1: Database Migration
|
||||
- [ ] All `databaseUtil` imports removed
|
||||
- [ ] All `logConsoleAndDb` imports removed
|
||||
- [ ] All direct `PlatformServiceFactory.getInstance()` calls removed
|
||||
- [ ] Component includes `PlatformServiceMixin` in mixins array
|
||||
- [ ] Database operations use mixin methods (`$db`, `$query`, `$getAllContacts`, etc.)
|
||||
- [ ] Settings operations use mixin methods (`$settings`, `$saveSettings`)
|
||||
- [ ] Logging uses mixin methods (`$log`, `$logError`, `$logAndConsole`)
|
||||
|
||||
### Phase 2: SQL Abstraction (if applicable)
|
||||
- [ ] All raw SQL queries replaced with service methods
|
||||
- [ ] Contact operations use `$getContact()`, `$deleteContact()`, `$updateContact()`
|
||||
- [ ] Settings operations use `$accountSettings()`, `$saveSettings()`
|
||||
- [ ] **NO raw SQL queries remain** (`SELECT`, `INSERT`, `UPDATE`, `DELETE`)
|
||||
|
||||
### Phase 3: Notification Migration (if applicable)
|
||||
- [ ] `createNotifyHelpers` imported and initialized
|
||||
- [ ] `notify!` property declared and created in `created()`
|
||||
- [ ] **All `this.$notify()` calls replaced with helper methods**
|
||||
- [ ] **Hardcoded timeouts replaced with `TIMEOUTS` constants**
|
||||
- [ ] **Static messages use notification constants from `@/constants/notifications`**
|
||||
- [ ] **Dynamic messages use literal strings appropriately**
|
||||
- [ ] **Unused notification constants removed from imports but these can mean that notifications have been overlooked**
|
||||
- [ ] **Legacy wrapper functions removed (e.g., `danger()`, `success()`, etc.)**
|
||||
|
||||
### Phase 4: Template Streamlining (if applicable)
|
||||
- [ ] **All long class attributes (50+ characters) extracted to computed properties**
|
||||
- [ ] **Complex conditional logic moved to computed properties**
|
||||
- [ ] **Repeated expressions extracted to computed properties**
|
||||
- [ ] **Configuration objects moved to computed properties**
|
||||
- [ ] **All computed properties have JSDoc documentation**
|
||||
|
||||
### Phase 5: Component Extraction (if applicable)
|
||||
- [ ] **Reusable UI patterns identified and extracted to separate components**
|
||||
- [ ] **Form elements extracted to reusable components**
|
||||
- [ ] **Layout patterns extracted to reusable components**
|
||||
- [ ] **Validation patterns extracted to reusable components**
|
||||
- [ ] **All extracted components have clear props interfaces**
|
||||
- [ ] **All extracted components have proper event handling**
|
||||
- [ ] **All extracted components have JSDoc documentation**
|
||||
- [ ] **Parent components properly import and use extracted components**
|
||||
|
||||
### Final Validation
|
||||
- [ ] Error handling includes component name context
|
||||
- [ ] Component compiles without TypeScript errors
|
||||
- [ ] Component functionality works as expected
|
||||
- [ ] `scripts/validate-migration.sh` shows "Technically Compliant"
|
||||
- [ ] `scripts/validate-notification-completeness.sh` shows as complete
|
||||
|
||||
### Validation Commands
|
||||
```bash
|
||||
# Check overall migration status
|
||||
scripts/validate-migration.sh
|
||||
|
||||
# Check notification migration completeness
|
||||
scripts/validate-notification-completeness.sh
|
||||
|
||||
# Check for compilation errors
|
||||
npm run lint-fix
|
||||
```
|
||||
|
||||
## Testing Migration
|
||||
|
||||
1. **Compile Check**: `npm run build` should complete without errors
|
||||
2. **Runtime Check**: Component should load and function normally
|
||||
3. **Logging Check**: Verify logs appear in console and database
|
||||
4. **Error Handling Check**: Verify errors are properly logged and handled
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Missing Mixin Methods**: Ensure component properly extends PlatformServiceMixin
|
||||
2. **TypeScript Errors**: Check that all types are properly imported
|
||||
3. **Runtime Errors**: Verify all async operations are properly awaited
|
||||
4. **Missing Context**: Add component name to error messages for better debugging
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- Mixin methods include caching for frequently accessed data
|
||||
- Database operations are queued and optimized
|
||||
- Error logging includes proper context and formatting
|
||||
|
||||
## Phase 4: Testing and Validation
|
||||
|
||||
### 4.1 Multi-Platform Testing Requirements
|
||||
|
||||
**ALL MIGRATIONS MUST BE TESTED ON ALL SUPPORTED PLATFORMS:**
|
||||
|
||||
#### Web Platform Testing (Required)
|
||||
- [ ] Test in Chrome/Chromium (primary browser)
|
||||
- [ ] Test in Firefox (secondary browser)
|
||||
- [ ] Test in Safari (if applicable)
|
||||
- [ ] Verify PWA functionality works correctly
|
||||
- [ ] Test responsive design on different screen sizes
|
||||
|
||||
#### Desktop Platform Testing (Required)
|
||||
- [ ] Test Electron app functionality
|
||||
- [ ] Verify desktop-specific features work
|
||||
- [ ] Test file system access (if applicable)
|
||||
- [ ] Verify native desktop integrations
|
||||
|
||||
#### Mobile Platform Testing (Required)
|
||||
- [ ] Test iOS app via Capacitor
|
||||
- [ ] Test Android app via Capacitor
|
||||
- [ ] Verify mobile-specific features (camera, contacts, etc.)
|
||||
- [ ] Test deep linking functionality
|
||||
- [ ] Verify push notifications work
|
||||
|
||||
### 4.2 Functional Testing Per Platform
|
||||
|
||||
For each platform, test these core scenarios:
|
||||
|
||||
#### Database Operations
|
||||
- [ ] Create/Read/Update/Delete operations work
|
||||
- [ ] Data persistence across app restarts
|
||||
- [ ] Database migration handling (if applicable)
|
||||
|
||||
#### Logging and Error Handling
|
||||
- [ ] Errors are logged correctly to console
|
||||
- [ ] Errors are stored in database logs
|
||||
- [ ] Error messages display appropriately to users
|
||||
- [ ] Network errors are handled gracefully
|
||||
|
||||
#### User Interface
|
||||
- [ ] All buttons and interactions work
|
||||
- [ ] Loading states display correctly
|
||||
- [ ] Error states display appropriately
|
||||
- [ ] Responsive design works on platform
|
||||
|
||||
### 4.3 Platform-Specific Testing Notes
|
||||
|
||||
#### Web Platform
|
||||
- Test offline/online scenarios
|
||||
- Verify IndexedDB storage works
|
||||
- Test service worker functionality
|
||||
- Check browser developer tools for errors
|
||||
|
||||
#### Desktop Platform
|
||||
- Test native menu integrations
|
||||
- Verify file system permissions
|
||||
- Test auto-updater functionality
|
||||
- Check Electron developer tools
|
||||
|
||||
#### Mobile Platform
|
||||
- Test device permissions (camera, storage, etc.)
|
||||
- Verify app store compliance
|
||||
- Test background/foreground transitions
|
||||
- Check native debugging tools
|
||||
|
||||
### 4.4 Sign-Off Requirements
|
||||
|
||||
**MIGRATION IS NOT COMPLETE UNTIL ALL PLATFORMS ARE TESTED AND SIGNED OFF:**
|
||||
|
||||
```markdown
|
||||
## Testing Sign-Off Checklist
|
||||
|
||||
### Web Platform ✅/❌
|
||||
- [ ] Chrome: Tested by [Name] on [Date]
|
||||
- [ ] Firefox: Tested by [Name] on [Date]
|
||||
- [ ] Safari: Tested by [Name] on [Date]
|
||||
- [ ] Notes: [Any platform-specific issues or observations]
|
||||
|
||||
### Desktop Platform ✅/❌
|
||||
- [ ] Windows: Tested by [Name] on [Date]
|
||||
- [ ] macOS: Tested by [Name] on [Date]
|
||||
- [ ] Linux: Tested by [Name] on [Date]
|
||||
- [ ] Notes: [Any platform-specific issues or observations]
|
||||
|
||||
### Mobile Platform ✅/❌
|
||||
- [ ] iOS: Tested by [Name] on [Date]
|
||||
- [ ] Android: Tested by [Name] on [Date]
|
||||
- [ ] Notes: [Any platform-specific issues or observations]
|
||||
|
||||
### Final Sign-Off
|
||||
- [ ] All platforms tested and working
|
||||
- [ ] No regressions identified
|
||||
- [ ] Performance is acceptable
|
||||
- [ ] Migration completed by: [Name] on [Date]
|
||||
```
|
||||
@@ -1,307 +0,0 @@
|
||||
# ESLint Rules for PlatformServiceMixin Migration
|
||||
|
||||
## Overview
|
||||
Custom ESLint rules to enforce PlatformServiceMixin patterns and prevent regression to legacy patterns.
|
||||
|
||||
## Rules Configuration
|
||||
|
||||
Add to `.eslintrc.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
// ... existing config
|
||||
rules: {
|
||||
// ... existing rules
|
||||
|
||||
// Custom rules for PlatformServiceMixin migration
|
||||
'timesafari/no-direct-database-util': 'error',
|
||||
'timesafari/no-legacy-logging': 'error',
|
||||
'timesafari/require-mixin-for-database': 'error',
|
||||
'timesafari/no-direct-platform-service': 'warn',
|
||||
'timesafari/prefer-mixin-methods': 'warn',
|
||||
},
|
||||
|
||||
// Custom rules plugin
|
||||
plugins: ['timesafari'],
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Rules Implementation
|
||||
|
||||
Create `eslint-plugin-timesafari/index.js`:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-direct-database-util': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow direct imports from databaseUtil',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source.value.includes('databaseUtil')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Direct databaseUtil imports are deprecated. Use PlatformServiceMixin instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-legacy-logging': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow legacy logging methods',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.specifiers.some(spec => spec.imported?.name === 'logConsoleAndDb')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'logConsoleAndDb is deprecated. Use PlatformServiceMixin $log methods instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (node.callee.name === 'logConsoleAndDb') {
|
||||
context.report({
|
||||
node,
|
||||
message: 'logConsoleAndDb is deprecated. Use this.$logAndConsole() instead.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'require-mixin-for-database': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Require PlatformServiceMixin for components using database operations',
|
||||
category: 'Migration',
|
||||
recommended: true,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
let hasDbOperations = false;
|
||||
let hasMixin = false;
|
||||
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// Check for database operations
|
||||
if (node.callee.property &&
|
||||
['dbQuery', 'dbExec', 'dbGetOneRow'].includes(node.callee.property.name)) {
|
||||
hasDbOperations = true;
|
||||
}
|
||||
},
|
||||
Property(node) {
|
||||
// Check for mixin usage
|
||||
if (node.key.name === 'mixins' &&
|
||||
node.value.elements?.some(el => el.name === 'PlatformServiceMixin')) {
|
||||
hasMixin = true;
|
||||
}
|
||||
},
|
||||
'Program:exit'() {
|
||||
if (hasDbOperations && !hasMixin) {
|
||||
context.report({
|
||||
node: context.getSourceCode().ast,
|
||||
message: 'Components using database operations should include PlatformServiceMixin.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-direct-platform-service': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Discourage direct PlatformServiceFactory usage',
|
||||
category: 'Migration',
|
||||
recommended: false,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (node.callee.object?.name === 'PlatformServiceFactory' &&
|
||||
node.callee.property?.name === 'getInstance') {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using PlatformServiceMixin methods instead of direct PlatformServiceFactory.',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'prefer-mixin-methods': {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Prefer mixin convenience methods over direct database calls',
|
||||
category: 'Migration',
|
||||
recommended: false,
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
// Check for patterns that could use mixin methods
|
||||
if (node.callee.property?.name === 'dbQuery') {
|
||||
const arg = node.arguments[0];
|
||||
if (arg && arg.type === 'Literal') {
|
||||
const sql = arg.value.toLowerCase();
|
||||
if (sql.includes('select * from contacts')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using this.$getAllContacts() instead of direct SQL.',
|
||||
});
|
||||
}
|
||||
if (sql.includes('select * from settings')) {
|
||||
context.report({
|
||||
node,
|
||||
message: 'Consider using this.$settings() instead of direct SQL.',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Pre-commit Hook
|
||||
|
||||
Create `.pre-commit-config.yaml`:
|
||||
|
||||
```yaml
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: eslint-migration-check
|
||||
name: ESLint Migration Check
|
||||
entry: npx eslint --ext .vue --rule 'timesafari/no-direct-database-util: error'
|
||||
language: system
|
||||
files: \.vue$
|
||||
|
||||
- id: no-legacy-logging
|
||||
name: No Legacy Logging
|
||||
entry: bash -c 'if grep -r "logConsoleAndDb" src/ --include="*.vue" --include="*.ts"; then echo "Found legacy logging imports"; exit 1; fi'
|
||||
language: system
|
||||
pass_filenames: false
|
||||
```
|
||||
|
||||
## Migration Validation Script
|
||||
|
||||
Create `scripts/validate-migration.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "🔍 Validating PlatformServiceMixin migration..."
|
||||
|
||||
# Check for legacy patterns
|
||||
echo "Checking for legacy databaseUtil imports..."
|
||||
LEGACY_DB_IMPORTS=$(grep -r "import.*databaseUtil" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $LEGACY_DB_IMPORTS legacy databaseUtil imports"
|
||||
|
||||
echo "Checking for legacy logging imports..."
|
||||
LEGACY_LOG_IMPORTS=$(grep -r "logConsoleAndDb" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $LEGACY_LOG_IMPORTS legacy logging imports"
|
||||
|
||||
# Check for mixin usage
|
||||
echo "Checking for PlatformServiceMixin usage..."
|
||||
MIXIN_USAGE=$(grep -r "PlatformServiceMixin" src/ --include="*.vue" | wc -l)
|
||||
echo "Found $MIXIN_USAGE files using PlatformServiceMixin"
|
||||
|
||||
# Check for direct PlatformService usage
|
||||
echo "Checking for direct PlatformService usage..."
|
||||
DIRECT_PLATFORM=$(grep -r "PlatformServiceFactory.getInstance" src/ --include="*.vue" --include="*.ts" | wc -l)
|
||||
echo "Found $DIRECT_PLATFORM direct PlatformService usages"
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "📊 Migration Status Summary:"
|
||||
echo "- Legacy databaseUtil imports: $LEGACY_DB_IMPORTS (should be 0)"
|
||||
echo "- Legacy logging imports: $LEGACY_LOG_IMPORTS (should be 0)"
|
||||
echo "- Mixin usage: $MIXIN_USAGE (should be high)"
|
||||
echo "- Direct PlatformService usage: $DIRECT_PLATFORM (should be low)"
|
||||
|
||||
# Set exit code based on legacy usage
|
||||
if [ $LEGACY_DB_IMPORTS -gt 0 ] || [ $LEGACY_LOG_IMPORTS -gt 0 ]; then
|
||||
echo "❌ Migration validation failed - legacy patterns found"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Migration validation passed - no legacy patterns found"
|
||||
exit 0
|
||||
fi
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Install ESLint rules**:
|
||||
```bash
|
||||
npm install --save-dev eslint-plugin-timesafari
|
||||
```
|
||||
|
||||
2. **Run validation**:
|
||||
```bash
|
||||
npm run lint
|
||||
./scripts/validate-migration.sh
|
||||
```
|
||||
|
||||
3. **Fix issues automatically**:
|
||||
```bash
|
||||
npm run lint -- --fix
|
||||
```
|
||||
|
||||
## IDE Integration
|
||||
|
||||
### VS Code Settings
|
||||
|
||||
Add to `.vscode/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"vue"
|
||||
],
|
||||
"eslint.options": {
|
||||
"extensions": [".js", ".ts", ".vue"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WebStorm Settings
|
||||
|
||||
1. Go to Settings → Languages & Frameworks → JavaScript → Code Quality Tools → ESLint
|
||||
2. Enable ESLint
|
||||
3. Set configuration file to `.eslintrc.js`
|
||||
4. Add `.vue` to file extensions
|
||||
Reference in New Issue
Block a user