# Customer Migration Script - Simplified Approach (Updated) ## Date: 2025-01-14 ## Summary of Changes The customer migration script has been updated with a **simplified approach** that eliminates username conflicts by simply updating the parent references of sub-accounts instead of trying to move or merge them. ## Previous Approach (Removed) The old approach attempted to: 1. Move sub-accounts from source to destination customer 2. Detect username conflicts between source and destination sub-accounts 3. Offer a `--merge-conflicts` flag to merge conflicting accounts 4. Mark old accounts as deleted and update all references **Problem**: Since usernames are globally unique in the system, attempting to move accounts between customers created conflicts. ## New Approach (Current) The new simplified approach: 1. **Sub-accounts stay in place** with their original usernames 2. Only the `.parent` field is updated to point to the destination customer 3. **No username conflicts** because accounts aren't moving, just being re-parented 4. Much simpler code with no merging logic needed ### Key Changes #### 1. Conflict Detection Simplified - **Before**: Checked for username conflicts across all sub-account types - **After**: Only checks for circular references (migrating a customer to itself) ```javascript // Old: Complex username conflict checking // New: Simple validation async function detectConflicts(sourceCustomers, targetCustomer, migrationRecord) { const conflicts = []; // Only check for circular reference for (const sourceCustomer of sourceCustomers) { if (sourceCustomer._id.toString() === targetCustomer._id.toString()) { conflicts.push({ type: 'circular_reference', message: `Cannot migrate customer ${sourceCustomer.username} to itself` }); } } return conflicts; } ``` #### 2. Sub-Account Migration Rewritten - **Before**: `migrateSubAccounts()` with conflict map, merging logic, reference updates - **After**: `updateSubAccountsParent()` with simple parent field update ```javascript // Old: ~100 lines of merge/conflict handling // New: ~40 lines of simple parent update async function updateSubAccountsParent(sourceId, targetId, session, migrationRecord) { const subAccounts = await models.User.find({ parent: sourceId, kind: { $in: [UserTypes.CLIENT, UserTypes.PILOT, UserTypes.DEVICE, UserTypes.OFFICER, UserTypes.INSPECTOR] } }).session(session); for (const account of subAccounts) { // Simply update the parent reference account.parent = targetId; await account.save({ session }); // Track in migration record migrationRecord.details.changes.push({ action: 'update_parent_reference', kind: account.kind, username: account.username, accountId: account._id, fromParent: sourceId, toParent: targetId }); } } ``` #### 3. Removed Options - **Removed**: `--merge-conflicts` flag (no longer needed) - **Removed**: All conflict merging logic - **Removed**: Reference update functions for merged accounts #### 4. Documentation Updates - Updated header comments to explain the parent-reference approach - Simplified help text - Removed merge-related warnings and examples ## Migration Behavior ### What Happens During Migration 1. **Source Customer Account**: - If `--convert-to-admin` flag: Converted to an admin (kind='2') under destination - Otherwise: Marked as deleted and inactive 2. **Sub-Accounts (Clients, Pilots, Vehicles, Officers, Inspectors)**: - **Parent field updated** from sourceCustomerId to targetCustomerId - **Usernames remain unchanged** (globally unique) - **All other fields unchanged** 3. **Jobs, Products, Crops**: - `byPuid` field updated from sourceCustomerId to targetCustomerId 4. **Invoices** (if `--update-invoices` flag): - `customer` field updated from sourceCustomerId to targetCustomerId ### Example Before migration: ``` Customer: trungh1@agnav.com (ID: 67ae...) ├─ Client: client1@example.com (parent: 67ae...) ├─ Pilot: pilot1@example.com (parent: 67ae...) └─ Vehicle: vehicle1 (parent: 67ae...) Customer: trungh@agnav.com (ID: 6786...) └─ (existing sub-accounts) ``` After migration: ``` Customer: trungh1@agnav.com (ID: 67ae...) [DELETED] Customer: trungh@agnav.com (ID: 6786...) ├─ Client: client1@example.com (parent: 6786...) ← Updated ├─ Pilot: pilot1@example.com (parent: 6786...) ← Updated ├─ Vehicle: vehicle1 (parent: 6786...) ← Updated └─ (existing sub-accounts) ``` ## Testing Results Successfully tested with: ```bash # Preview mode node scripts/migrateCustomerData.js \ --sources trungh1@agnav.com \ --destination trungh@agnav.com \ --preview # Execution node scripts/migrateCustomerData.js \ --sources trungh1@agnav.com \ --destination trungh@agnav.com ``` **Results**: - ✅ No conflicts detected - ✅ 2 clients migrated (parent updated) - ✅ 1 pilot migrated (parent updated) - ✅ 5 vehicles migrated (parent updated) - ✅ 1 job migrated (byPuid updated) - ✅ 1 product migrated (byPuid updated) - ✅ 1 crop migrated (byPuid updated) - ✅ Transaction completed successfully - ✅ Migration history saved ## Benefits of New Approach 1. **Eliminates Conflicts**: No username conflicts since accounts stay in place 2. **Simpler Code**: Removed ~200 lines of conflict/merge logic 3. **Safer**: No account deletion or reference rewiring 4. **Clearer Intent**: Sub-accounts are "re-parented", not "moved" 5. **Faster Execution**: No conflict checking for thousands of sub-accounts ## Files Modified - `scripts/migrateCustomerData.js`: - Simplified `detectConflicts()` function - Replaced `migrateSubAccounts()` with `updateSubAccountsParent()` - Removed `updateAccountReferences()` function - Removed `--merge-conflicts` option parsing - Updated documentation strings - Added display name sanitization for corrupt data ## Backward Compatibility This is a **breaking change** if anyone was using the `--merge-conflicts` flag. However: - The new approach is the **correct** approach for this data model - Old approach would have caused data inconsistencies - Migration history format remains compatible ## Related Files - `scripts/README_CUSTOMER_MIGRATION.md` - Full documentation (needs minor update) - `scripts/MIGRATION_QUICK_REFERENCE.md` - Quick reference (needs minor update) - `MIGRATION_SUMMARY.md` - Implementation overview (needs minor update) ## Next Steps Consider updating the documentation files to reflect: 1. The simplified conflict detection 2. Removal of merge-conflicts flag 3. Clarification that sub-accounts are "re-parented" not "moved"