# Customer Data Migration Script ## Overview This script provides a comprehensive solution for migrating data from multiple source customer master accounts to a single destination customer account. It includes robust conflict detection, detailed preview capabilities, transaction safety, and complete migration history tracking. ## Features ✅ **Multiple Source Support** - Migrate from multiple source customer accounts simultaneously ✅ **Conflict Detection** - Automatically detects username conflicts and aborts by default ✅ **Detailed Preview** - Visualizes all changes before execution ✅ **Transaction Safety** - Uses `mongo_enhanced.js` for robust transaction handling ✅ **Admin Conversion** - Optionally convert source customers to admin accounts ✅ **Merge Capability** - Can merge conflicting accounts when explicitly requested ✅ **History Tracking** - Maintains complete migration history in JSON format ✅ **Comprehensive Migration** - Handles all related data including: - Sub-accounts (clients, pilots, vehicles) - Jobs and applications - Products and crops - Invoices and billing data - Costing items ## Usage ### Preview Migration (Recommended First Step) Always run a preview first to see what will be migrated and detect conflicts: ```bash # Using customer usernames (recommended - easier to read) node scripts/migrateCustomerData.js \ --preview \ --sources acme_aviation,regional_ag \ --destination consolidated_ag # Using customer IDs (also supported) node scripts/migrateCustomerData.js \ --preview \ --sources SOURCE_CUSTOMER_ID1,SOURCE_CUSTOMER_ID2 \ --destination DESTINATION_CUSTOMER_ID # Mixed: usernames and IDs can be combined node scripts/migrateCustomerData.js \ --preview \ --sources acme_aviation,507f1f77bcf86cd799439012 \ --destination consolidated_ag # With custom environment file (e.g., production) node scripts/migrateCustomerData.js \ --env ../environment_prod.env \ --preview \ --sources acme_aviation,regional_ag \ --destination consolidated_ag ``` ### Execute Migration After reviewing the preview, execute the migration: ```bash # Using usernames (source customers converted to admin by default) node scripts/migrateCustomerData.js \ --sources acme_aviation,regional_ag \ --destination consolidated_ag # Using IDs node scripts/migrateCustomerData.js \ --sources SOURCE_CUSTOMER_ID1,SOURCE_CUSTOMER_ID2 \ --destination DESTINATION_CUSTOMER_ID # With entity reuse to avoid duplicates node scripts/migrateCustomerData.js \ --sources acme_aviation,regional_ag \ --destination consolidated_ag \ --reuse-existing-entities # With production environment node scripts/migrateCustomerData.js \ --env ../environment_prod.env \ --sources acme_aviation,regional_ag \ --destination consolidated_ag \ --reuse-existing-entities ``` ### Convert Source Customers to Admins Source customers are converted to admin accounts by default. To disable this: ```bash # Deactivate source customers instead of converting to admin node scripts/migrateCustomerData.js \ --sources acme_aviation \ --destination consolidated_ag \ --deactivate-source # Explicit admin conversion (this is the default behavior) node scripts/migrateCustomerData.js \ --sources acme_aviation \ --destination consolidated_ag \ --convert-to-admin ``` ### Reuse Existing Entities To avoid creating duplicate products/crops with the same names: ```bash node scripts/migrateCustomerData.js \ --sources acme_aviation \ --destination consolidated_ag \ --reuse-existing-entities ``` This will: - Compare product/crop names between source and destination - Reuse destination entities when names match - Delete source entities that were matched - Only migrate entities with unique names ## Command-Line Options | Option | Description | Required | Default | |--------|-------------|----------|---------| | `--sources` | Comma-separated list of source customer IDs or usernames | ✅ Yes | - | | `--destination` | Destination customer ID or username | ✅ Yes | - | | `--preview` | Show migration plan without executing | No | false | | `--convert-to-admin` | Convert source customers to admin accounts | No | true | | `--deactivate-source` | Deactivate source customers instead of converting to admin | No | false | | `--reuse-existing-entities` | Reuse destination's products/crops with matching names | No | false | | `--skip-invoices` | Don't migrate invoice references | No | false | | `--output-file` | Custom output file path | No | `./migration_history.json` | | `--env` | Custom environment file path | No | `../environment.env` | | `--help`, `-h` | Show help message | No | - | **Note**: You can use either customer **usernames** (e.g., `acme_aviation`) or **MongoDB ObjectIds** (e.g., `507f1f77bcf86cd799439011`). Usernames are recommended as they're easier to read and remember. ## Migration Process ### 1. Validation Phase The script first validates: - All source customer IDs exist - None of the source customers are already deleted - Destination customer exists and is active - Gathers statistics for all customers ### 2. Conflict Detection Phase The script checks for username conflicts between: - Source clients vs destination clients - Source pilots vs destination pilots - Source vehicles vs destination vehicles **Default Behavior**: If conflicts are found, the migration **ABORTS** immediately. **With `--merge-conflicts`**: Conflicting accounts are merged: - References updated to point to existing accounts - Old accounts marked as deleted - Username changed to prevent future conflicts ### 3. Preview Phase Shows a detailed breakdown of: - Source customer information and statistics - Destination customer information - All conflicts (if any) - Summary of data to be migrated - Actions that will be taken ### 4. Execution Phase (if not preview mode) Within a single MongoDB transaction: 1. **Convert Customer Accounts** (if `--convert-to-admin`) - Creates new admin user from customer data - Marks original customer as migrated 2. **Migrate Sub-Accounts** - Clients, pilots, vehicles - Updates parent references or merges conflicts 3. **Migrate Entities** - Products - Crops - Costing items 4. **Migrate Jobs** - Updates `byPuid` references - All related data (logs, assignments, applications) automatically follow 5. **Migrate Billing Data** - Updates invoice customer references 6. **Deactivate Source Customers** (unless converted to admin) - Marks as deleted - Changes username to prevent conflicts ### 5. History Logging All migrations are logged to a JSON file with: - Timestamp - Source and destination IDs - Complete statistics - Detailed changes list - Conflict information - Success/failure status - Error details (if failed) ## Migration History File The script maintains a complete history of all migrations in `migration_history.json` (or custom path via `--output-file`). ### Structure ```json [ { "timestamp": "2025-10-21T10:30:00.000Z", "sourceCustomerIds": ["507f1f77bcf86cd799439011"], "targetCustomerId": "507f191e810c19729de860ea", "options": { "preview": false, "convertToAdmin": false, "mergeConflicts": false, "updateInvoices": true }, "status": "completed", "completedAt": "2025-10-21T10:30:45.000Z", "stats": { "sourceCustomers": { ... }, "totalJobs": 150, "totalClients": 25, "totalPilots": 10, "totalVehicles": 8, "totalProducts": 45, "totalCrops": 12, "totalApplications": 890, "totalInvoices": 75, "conflicts": [], "skipped": [], "errors": [] }, "details": { "sources": [ ... ], "conflicts": [], "changes": [ ... ] } } ] ``` ## Examples ### Example 1: Simple Migration (Single Source) ```bash # Preview first (using username) node scripts/migrateCustomerData.js \ --preview \ --sources acme_aviation \ --destination consolidated_ag # Execute after reviewing node scripts/migrateCustomerData.js \ --sources acme_aviation \ --destination consolidated_ag # Alternative: Using IDs node scripts/migrateCustomerData.js \ --sources 507f1f77bcf86cd799439011 \ --destination 507f191e810c19729de860ea ``` ### Example 2: Multiple Sources with Admin Conversion ```bash # Using usernames (recommended) node scripts/migrateCustomerData.js \ --sources acme_west,acme_east,acme_south \ --destination acme_corporate \ --convert-to-admin # Using IDs node scripts/migrateCustomerData.js \ --sources 507f1f77bcf86cd799439011,507f1f77bcf86cd799439012,507f1f77bcf86cd799439013 \ --destination 507f191e810c19729de860ea \ --convert-to-admin ``` ### Example 3: Migration with Conflict Merging ```bash # Preview to see conflicts node scripts/migrateCustomerData.js \ --preview \ --sources 507f1f77bcf86cd799439011 \ --destination 507f191e810c19729de860ea # Execute with merge if conflicts are acceptable node scripts/migrateCustomerData.js \ --sources 507f1f77bcf86cd799439011 \ --destination 507f191e810c19729de860ea \ --merge-conflicts ``` ### Example 4: Custom Output File ```bash node scripts/migrateCustomerData.js \ --sources 507f1f77bcf86cd799439011 \ --destination 507f191e810c19729de860ea \ --output-file /path/to/custom/migration_log.json ``` ## Preview Output Example ``` ================================================================================ MIGRATION PREVIEW ================================================================================ Source Customers: • acme_aviation (507f1f77bcf86cd799439011) Email: contact@acme.com Country: US Clients: 25 Pilots: 10 Vehicles: 8 Jobs: 150 Products: 45 Crops: 12 Applications: 890 Invoices: 75 ⚠️ Will be DEACTIVATED after migration Destination Customer: • consolidated_ag (507f191e810c19729de860ea) Email: admin@consolidated.com Country: US Migration Summary: Total Clients: 25 Total Pilots: 10 Total Vehicles: 8 Total Jobs: 150 Total Products: 45 Total Crops: 12 Total Applications: 890 Total Invoices: 75 Preview mode - no changes made Preview saved to: ./migration_history.json ``` ## Conflict Output Example When conflicts are detected: ``` ⚠️ MIGRATION ABORTED - CONFLICTS DETECTED The following conflicts were found: From customer: acme_aviation • Client: john_farmer Source ID: 507f1f77bcf86cd799439015 Conflicts with existing ID: 507f191e810c19729de86100 Email: john@farm.com • Pilot: mike_pilot Source ID: 507f1f77bcf86cd799439016 Conflicts with existing ID: 507f191e810c19729de86101 Email: mike@pilots.com To proceed with merging conflicts, use --merge-conflicts flag WARNING: Merging will link old accounts to existing ones and mark old accounts as deleted ``` ## Safety Features ### 1. Transaction Rollback If any error occurs during migration, the **entire transaction is rolled back**. No partial migrations. ### 2. Validation Before Execution - Verifies all customers exist - Checks for deleted customers - Validates data integrity ### 3. Conflict Detection - Detects username conflicts across all sub-account types - Aborts by default to prevent data loss ### 4. History Tracking - Every migration attempt is logged - Includes success/failure status - Complete audit trail ### 5. Preview Mode - Test migration without making changes - See exactly what will happen - Review conflicts before deciding ## What Gets Migrated ### ✅ Migrated Collections | Collection | Migration Method | Notes | |------------|------------------|-------| | **Clients** | Parent reference updated | Merged if conflicts | | **Pilots** | Parent reference updated | Merged if conflicts | | **Vehicles** | Parent reference updated | Merged if conflicts | | **Jobs** | `byPuid` reference updated | All related data follows | | **Applications** | Via job relationship | No direct update needed | | **App Files** | Via application relationship | No direct update needed | | **App Details** | Via app file relationship | No direct update needed | | **Job Logs** | Via job relationship | No direct update needed | | **Job Assigns** | Via job relationship | Updated if account merge | | **Products** | `byPuid` reference updated | - | | **Crops** | `byPuid` reference updated | - | | **Costing Items** | `byPuid` reference updated | - | | **Invoices** | Customer reference updated | Optional via `--skip-invoices` | ### ❌ Not Migrated - Stripe subscriptions (requires manual handling) - Bill periods - Payment logs - User authentication tokens - Session data ## Troubleshooting ### Issue: Transaction Timeout **Symptom**: Migration fails with transaction timeout error **Solution**: The script uses enhanced transaction handling with 60-second timeout. For very large migrations: - Ensure database connection is stable - Consider migrating in smaller batches (fewer source customers at once) ### Issue: Conflicts Detected **Symptom**: Migration aborted with conflict list **Solutions**: 1. **Recommended**: Manually resolve conflicts by renaming accounts in source or destination 2. Use `--merge-conflicts` flag (USE WITH CAUTION) 3. Migrate source customers without conflicting accounts first ### Issue: Validation Failed **Symptom**: "Source or target customer not found" **Solutions**: - Verify customer IDs are correct - Ensure customers are not already deleted - Check database connection ### Issue: Permission Denied **Symptom**: MongoDB permission errors **Solutions**: - Ensure database user has write permissions - Check that user can create transactions - Verify user has access to all collections ## Best Practices ### 1. Always Preview First ```bash # ALWAYS run preview before execution node scripts/migrateCustomerData.js --preview --sources ... --destination ... ``` ### 2. Backup Database Before running any migration, ensure you have a recent database backup. ### 3. Test on Non-Production First Test the migration process on a development or staging environment first. ### 4. Review Conflicts Carefully If conflicts are detected, review them carefully. Consider manually resolving rather than using `--merge-conflicts`. ### 5. Monitor History File Regularly review `migration_history.json` to track all migrations. ### 6. Plan Stripe Subscriptions Customer subscriptions cannot be automatically migrated and require manual intervention through Stripe. ### 7. Use Custom Environment Files For production migrations, use the `--env` flag to specify the production environment file: ```bash # Production migration node scripts/migrateCustomerData.js \ --env ../environment_prod.env \ --sources acme_aviation \ --destination consolidated_ag \ --preview # Development/testing (default) node scripts/migrateCustomerData.js \ --sources acme_aviation \ --destination consolidated_ag \ --preview ``` ## Rollback Migrations If you need to undo a migration, use the rollback script: ```bash # Rollback the last migration (development environment) node scripts/rollbackMigration.js # Rollback with production environment node scripts/rollbackMigration.js --env ../environment_prod.env ``` ### What Rollback Does - ✅ Restores all migrated entities (`byPuid` references) - ✅ Restores deleted products/crops (if entity reuse was used) - ✅ Restores invoice references - ✅ Restores sub-account parent references - ✅ Restores source customer from admin back to customer - ✅ Reactivates deactivated source customers ### Rollback Limitations - ⚠️ Can only rollback the **last** completed migration - ⚠️ Must be run against the same database as the migration - ⚠️ Cannot rollback if database has been manually modified since migration - ⚠️ Check entities exist before restoring (handles already-rolled-back state) ## Database Schema Impact ### Updated Fields - `User.parent` - Updated for sub-accounts - `Job.byPuid` - Updated to destination customer - `Product.byPuid` - Updated to destination customer - `Crop.byPuid` - Updated to destination customer - `CostingItem.byPuid` - Updated to destination customer - `Invoice.customer` - Updated to destination customer - `Job.client/operator/vehicle` - Updated if account merged ### Marked for Deletion - `Customer.markedDelete` - Source customers (unless converted to admin) - `Customer.username` - Suffixed with timestamp - `User.markedDelete` - Merged sub-accounts - `User.username` - Suffixed with timestamp ## Support and Debugging Enable debug output: ```bash DEBUG=agm:migrate-customer-data node scripts/migrateCustomerData.js ... ``` For detailed transaction debugging: ```bash DEBUG=agm:migrate-customer-data,agm:mongo_enhanced node scripts/migrateCustomerData.js ... ``` ## Related Files - `scripts/migrateCustomerData.js` - Main migration script - `scripts/rollbackMigration.js` - Rollback script for undoing migrations - `helpers/mongo_enhanced.js` - Transaction utilities - `helpers/constants.js` - User types and constants - `model/job.js` - Job model with `byPuid` reference - `migration_history.json` - Migration history log (tracks all migrations and rollbacks) ## License Internal use only - AgMission Customer Data Management