| name | apollo-migration-deep-dive |
| description | Comprehensive Apollo.io migration strategies.
Use when migrating from other CRMs to Apollo, consolidating data sources,
or executing large-scale data migrations.
Trigger with phrases like "apollo migration", "migrate to apollo",
"apollo data import", "crm to apollo", "apollo migration strategy".
|
| allowed-tools | Read, Write, Edit, Bash(kubectl:*), Bash(curl:*) |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Apollo Migration Deep Dive
Overview
Comprehensive guide for migrating to Apollo.io from other CRMs and data sources, including data mapping, validation, and rollback strategies.
Migration Planning
Pre-Migration Assessment
interface MigrationAssessment {
source: {
system: string;
recordCount: number;
dataQuality: DataQualityReport;
fieldMapping: FieldMappingAnalysis;
};
target: {
apolloPlan: string;
creditBudget: number;
apiLimits: APILimits;
};
risk: {
level: 'low' | 'medium' | 'high';
factors: string[];
mitigations: string[];
};
timeline: {
estimatedDuration: string;
phases: Phase[];
};
}
async function assessMigration(sourceConfig: any): Promise<MigrationAssessment> {
const sourceAnalysis = await analyzeSourceData(sourceConfig);
const apolloCapacity = await checkApolloCapacity();
const risks = calculateRisks(sourceAnalysis, apolloCapacity);
const timeline = estimateTimeline(sourceAnalysis, apolloCapacity);
return {
source: sourceAnalysis,
target: apolloCapacity,
risk: risks,
timeline,
};
}
async function analyzeSourceData(config: any): Promise<SourceAnalysis> {
const records = await fetchSourceRecords(config);
return {
system: config.system,
recordCount: records.length,
dataQuality: {
emailValid: records.filter(r => isValidEmail(r.email)).length / records.length,
emailPresent: records.filter(r => r.email).length / records.length,
phonePresent: records.filter(r => r.phone).length / records.length,
companyPresent: records.filter(r => r.company).length / records.length,
duplicates: findDuplicates(records).length,
},
fieldMapping: analyzeFields(records),
};
}
Field Mapping
interface FieldMapping {
sourceField: string;
targetField: string;
transform?: (value: any) => any;
required: boolean;
validation?: (value: any) => boolean;
}
const SALESFORCE_TO_APOLLO: FieldMapping[] = [
{
sourceField: 'Email',
targetField: 'email',
required: true,
validation: isValidEmail,
},
{
sourceField: 'FirstName',
targetField: 'first_name',
required: false,
},
{
sourceField: 'LastName',
targetField: 'last_name',
required: false,
},
{
sourceField: 'Title',
targetField: 'title',
required: false,
transform: normalizeTitle,
},
{
sourceField: 'Phone',
targetField: ,
: ,
: normalizePhone,
},
{
: ,
: ,
: ,
},
{
: ,
: ,
: extractDomain,
: ,
},
{
: ,
: ,
: ,
: isValidLinkedInUrl,
},
];
: [] = [
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : extractDomain, : },
];
(): {
: = {};
: [] = [];
( mapping mappings) {
value = (record, mapping.);
(mapping. && !value) {
errors.();
;
}
(value) {
transformedValue = mapping. ? mapping.(value) : value;
(mapping. && !mapping.(transformedValue)) {
errors.();
;
}
transformed[mapping.] = transformedValue;
}
}
{ : transformed, errors };
}
Migration Execution
Phased Migration Strategy
interface MigrationPhase {
name: string;
percentage: number;
criteria: any;
validation: () => Promise<boolean>;
rollbackPlan: () => Promise<void>;
}
const MIGRATION_PHASES: MigrationPhase[] = [
{
name: 'Pilot',
percentage: 1,
criteria: { createdAt: { gt: '2024-01-01' }, hasEmail: true },
validation: async () => {
const migrated = await getMigratedCount('pilot');
const errors = await getErrorCount('pilot');
return errors / migrated < 0.01;
},
rollbackPlan: async () => {
await deleteApolloContacts({ tag: 'migration-pilot' });
},
},
{
name: 'Early Adopters',
: ,
: { : , : { : } },
: () => {
sample = ();
integrity = (sample);
integrity. > ;
},
: () => {
({ : });
},
},
{
: ,
: ,
: { : },
: () => {
();
},
: () => {
.();
},
},
{
: ,
: ,
: {},
: () => ,
: () => {},
},
];
(): <> {
( phase ) {
.();
records = (phase);
.();
batchSize = ;
( i = ; i < records.; i += batchSize) {
batch = records.(i, i + batchSize);
(batch, phase.);
.();
();
}
isValid = phase.();
(!isValid) {
.();
phase.();
();
}
.();
}
}
Batch Migration Worker
import { Queue, Worker, Job } from 'bullmq';
interface MigrationJob {
records: any[];
phase: string;
batchNumber: number;
}
const migrationQueue = new Queue('apollo-migration');
async function enqueueMigrationBatch(
records: any[],
phase: string,
batchNumber: number
): Promise<void> {
await migrationQueue.add('migrate', {
records,
phase,
batchNumber,
}, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 5000,
},
removeOnComplete: 100,
removeOnFail: false,
});
}
const worker = new Worker('apollo-migration', async (: <>) => {
{ records, phase, batchNumber } = job.;
results = {
: ,
: ,
: [] [],
};
( record records) {
{
transformed = (record, (record.));
(transformed.. > ) {
results.++;
results..({ record, : transformed. });
;
}
apollo.(transformed.);
(record., transformed.., phase);
results.++;
} (: ) {
results.++;
results..({ record, : error. });
}
job.((results. + results.) / records. * );
}
.();
(results.. > ) {
(results., phase, batchNumber);
}
results;
});
Validation & Reconciliation
interface ValidationResult {
totalSource: number;
totalTarget: number;
matched: number;
mismatched: number;
missing: number;
extra: number;
fieldDiscrepancies: FieldDiscrepancy[];
}
interface FieldDiscrepancy {
recordId: string;
field: string;
sourceValue: any;
targetValue: any;
}
async function validateMigration(): Promise<ValidationResult> {
const sourceRecords = await fetchAllSourceRecords();
const sourceMap = new Map(sourceRecords.map(r => [r.email, r]));
const apolloRecords = await fetchAllApolloContacts();
const apolloMap = new Map(apolloRecords.( [r., r]));
: = {
: sourceRecords.,
: apolloRecords.,
: ,
: ,
: ,
: ,
: [],
};
( [email, sourceRecord] sourceMap) {
apolloRecord = apolloMap.(email);
(!apolloRecord) {
result.++;
;
}
discrepancies = (sourceRecord, apolloRecord);
(discrepancies. === ) {
result.++;
} {
result.++;
result..(...discrepancies);
}
}
( [email] apolloMap) {
(!sourceMap.(email)) {
result.++;
}
}
result;
}
(): [] {
: [] = [];
fieldsToCompare = [, , , ];
( field fieldsToCompare) {
sourceValue = (source[field]);
targetValue = (target[field]);
(sourceValue !== targetValue) {
discrepancies.({
: source.,
field,
sourceValue,
targetValue,
});
}
}
discrepancies;
}
Rollback Strategy
interface RollbackPlan {
phase: string;
recordIds: string[];
timestamp: Date;
}
async function createRollbackPlan(phase: string): Promise<RollbackPlan> {
const mappings = await prisma.migrationMapping.findMany({
where: { phase },
});
return {
phase,
recordIds: mappings.map(m => m.apolloId),
timestamp: new Date(),
};
}
async function executeRollback(plan: RollbackPlan): Promise<void> {
console.log(`Rolling back ${plan.recordIds.length} records from phase: ${plan.phase}`);
const batchSize = 50;
for (let i = 0; i < plan.recordIds.length; i += batchSize) {
batch = plan..(i, i + batchSize);
.(
batch.( (id) => {
{
apollo.(id, { : });
} (error) {
.(, error);
}
})
);
.();
();
}
prisma..({
: { : plan. },
: { : , : () },
});
.();
}
Migration Dashboard
router.get('/migration/status', async (req, res) => {
const status = {
phases: await getMigrationPhaseStatus(),
progress: await getOverallProgress(),
errors: await getRecentErrors(50),
queue: await getQueueStatus(),
};
res.json(status);
});
router.post('/migration/pause', async (req, res) => {
await migrationQueue.pause();
res.json({ status: 'paused' });
});
router.post('/migration/resume', async (req, res) => {
await migrationQueue.resume();
res.json({ status: 'resumed' });
});
router.post('/migration/rollback/:phase', async (req, res) => {
const plan = await createRollbackPlan(req.params.phase);
await executeRollback(plan);
res.json({ status: 'rolled back', plan });
});
Output
- Pre-migration assessment framework
- Field mapping configurations
- Phased migration strategy
- Batch processing workers
- Validation and reconciliation
- Rollback procedures
Error Handling
| Issue | Resolution |
|---|
| Field mapping error | Review and fix mapping |
| Batch failure | Retry with smaller batch |
| Validation mismatch | Investigate and re-migrate |
| Rollback needed | Execute phase rollback |
Resources
Completion
This completes the Apollo skill pack. All 24 skills are now available for Claude Code users integrating with Apollo.io.