> adobe-migration-deep-dive
Execute major Adobe re-architecture: migrating from legacy Adobe APIs to Firefly Services, consolidating Creative Cloud integrations, and strangler-fig migration from competitor document/image APIs to Adobe. Trigger with phrases like "migrate adobe", "adobe migration", "switch to adobe", "adobe replatform", "replace with adobe".
curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/adobe-migration-deep-dive?format=md"Adobe Migration Deep Dive
Overview
Comprehensive guide for three major migration scenarios: (1) legacy Adobe API consolidation into Firefly Services, (2) migrating from competitor document/image APIs to Adobe, and (3) JWT credential migration to OAuth Server-to-Server.
Prerequisites
- Current system documentation with API inventory
- Adobe Developer Console project with target APIs
- Feature flag infrastructure
- Rollback strategy tested in staging
Instructions
Migration Type Assessment
| Type | From | To | Complexity | Duration |
|---|---|---|---|---|
| Auth migration | JWT credentials | OAuth Server-to-Server | Low | 1-2 days |
| API consolidation | Separate PS/LR endpoints | Firefly Services SDK | Medium | 1-2 weeks |
| Competitor replacement | Cloudinary/imgix/PDFTron | Adobe APIs | High | 4-8 weeks |
| Full replatform | Custom pipeline | Adobe App Builder | High | 2-3 months |
Scenario 1: Consolidate to Firefly Services SDK
The Photoshop and Lightroom APIs were previously separate. They are now part of Firefly Services with a unified SDK:
// BEFORE: Separate clients for each API
import { PhotoshopAPI } from 'some-old-photoshop-client';
import { LightroomAPI } from 'some-old-lightroom-client';
// AFTER: Unified Firefly Services SDK
import { PhotoshopClient } from '@adobe/photoshop-apis';
import { LightroomClient } from '@adobe/lightroom-apis';
import { FireflyClient } from '@adobe/firefly-apis';
// All use the same OAuth credentials
const config = {
clientId: process.env.ADOBE_CLIENT_ID!,
accessToken: await getAccessToken(),
};
const photoshop = new PhotoshopClient(config);
const lightroom = new LightroomClient(config);
const firefly = new FireflyClient(config);
Scenario 2: Migrate from Competitor to Adobe PDF Services
// src/adapters/document-adapter.ts
// Adapter pattern for gradual migration from PDFTron/other to Adobe
interface DocumentAdapter {
extractText(pdfPath: string): Promise<string>;
createPdf(htmlContent: string): Promise<Buffer>;
mergePdfs(pdfPaths: string[]): Promise<Buffer>;
}
// Old implementation
class PdfTronAdapter implements DocumentAdapter {
async extractText(pdfPath: string): Promise<string> {
// ... existing PDFTron code
}
// ...
}
// New Adobe implementation
class AdobePdfAdapter implements DocumentAdapter {
private pdfServices: PDFServices;
constructor() {
const credentials = new ServicePrincipalCredentials({
clientId: process.env.ADOBE_CLIENT_ID!,
clientSecret: process.env.ADOBE_CLIENT_SECRET!,
});
this.pdfServices = new PDFServices({ credentials });
}
async extractText(pdfPath: string): Promise<string> {
const inputStream = fs.createReadStream(pdfPath);
const inputAsset = await this.pdfServices.upload({
readStream: inputStream,
mimeType: MimeType.PDF,
});
const params = new ExtractPDFParams({
elementsToExtract: [ExtractElementType.TEXT],
});
const job = new ExtractPDFJob({ inputAsset, params });
const pollingURL = await this.pdfServices.submit({ job });
const result = await this.pdfServices.getJobResult({
pollingURL,
resultType: ExtractPDFResult,
});
// Parse structuredData.json from result ZIP
const streamAsset = await this.pdfServices.getContent({
asset: result.result!.resource,
});
// ... extract text from ZIP
return extractedText;
}
// ... implement createPdf, mergePdfs
}
// Feature-flag controlled routing
function getDocumentAdapter(): DocumentAdapter {
const adobePercentage = getFeatureFlag('adobe_pdf_migration_pct');
if (Math.random() * 100 < adobePercentage) {
return new AdobePdfAdapter();
}
return new PdfTronAdapter();
}
Scenario 3: Image API Migration (Cloudinary to Firefly/Photoshop)
// src/adapters/image-adapter.ts
interface ImageAdapter {
removeBackground(inputUrl: string): Promise<string>;
resize(inputUrl: string, width: number, height: number): Promise<string>;
generateImage(prompt: string): Promise<string>;
}
class CloudinaryAdapter implements ImageAdapter {
async removeBackground(inputUrl: string): Promise<string> {
// ... existing Cloudinary code
return cloudinary.url(publicId, { effect: 'background_removal' });
}
// ...
}
class AdobeImageAdapter implements ImageAdapter {
async removeBackground(inputUrl: string): Promise<string> {
const token = await getAccessToken();
const outputUrl = await generatePresignedUploadUrl();
const response = await fetch('https://image.adobe.io/v2/remove-background', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'x-api-key': process.env.ADOBE_CLIENT_ID!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: { href: inputUrl, storage: 'external' },
output: { href: outputUrl, storage: 'external', type: 'image/png' },
}),
});
const job = await response.json();
const result = await pollAdobeJob(job._links.self.href);
return outputUrl;
}
async generateImage(prompt: string): Promise<string> {
const token = await getAccessToken();
const response = await fetch('https://firefly-api.adobe.io/v3/images/generate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'x-api-key': process.env.ADOBE_CLIENT_ID!,
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt, n: 1, size: { width: 1024, height: 1024 } }),
});
const result = await response.json();
return result.outputs[0].image.url;
}
// ...
}
Phase-Based Migration Plan
Week 1-2: Setup
├── Create Adobe Developer Console project
├── Install SDKs and implement adapter layer
├── Write integration tests for both old and new
└── Deploy adapter with 0% traffic to Adobe
Week 3-4: Validation
├── Route 5% traffic to Adobe adapter
├── Compare results (output quality, latency, error rate)
├── Fix edge cases discovered in production traffic
└── Increase to 25% if metrics are acceptable
Week 5-6: Gradual Migration
├── Increase to 50% traffic
├── Monitor cost impact (Adobe vs old provider)
├── Address any performance regressions
└── Increase to 100% if all metrics pass
Week 7-8: Cleanup
├── Remove old adapter code
├── Delete old provider credentials
├── Update documentation
└── Run postmortem on migration
Post-Migration Validation
async function validateMigration(): Promise<{ passed: boolean; checks: any[] }> {
const checks = [
{ name: 'Auth working', fn: async () => !!(await getAccessToken()) },
{ name: 'PDF extract works', fn: async () => {
const result = await adobeAdapter.extractText('./test/fixture.pdf');
return result.length > 0;
}},
{ name: 'Image generation works', fn: async () => {
const url = await adobeAdapter.generateImage('test blue square');
return url.startsWith('https://');
}},
{ name: 'Error rate < 1%', fn: async () => {
const metrics = await getErrorRate('adobe', '1h');
return metrics < 0.01;
}},
];
const results = await Promise.all(
checks.map(async c => ({ name: c.name, passed: await c.fn() }))
);
return { passed: results.every(r => r.passed), checks: results };
}
Output
- Adapter layer abstracting old and new implementations
- Feature-flag controlled traffic split
- Phase-based migration with rollback at each stage
- Validation suite confirming migration success
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Quality difference | Different rendering engines | Compare side-by-side; tune parameters |
| Higher latency | Adobe async APIs | Use parallel job submission |
| Cost increase | Different pricing model | Implement caching; optimize batch sizes |
| Missing features | Not all features map 1:1 | Document gaps; find Adobe alternatives |
Resources
Next Steps
For advanced troubleshooting, see adobe-advanced-troubleshooting.
> related_skills --same-repo
> fathom-cost-tuning
Optimize Fathom API usage and plan selection. Trigger with phrases like "fathom cost", "fathom pricing", "fathom plan".
> fathom-core-workflow-b
Sync Fathom meeting data to CRM and build automated follow-up workflows. Use when integrating Fathom with Salesforce, HubSpot, or custom CRMs, or creating automated post-meeting email summaries. Trigger with phrases like "fathom crm sync", "fathom salesforce", "fathom follow-up", "fathom post-meeting workflow".
> fathom-core-workflow-a
Build a meeting analytics pipeline with Fathom transcripts and summaries. Use when extracting insights from meetings, building CRM sync, or creating automated meeting follow-up workflows. Trigger with phrases like "fathom analytics", "fathom meeting pipeline", "fathom transcript analysis", "fathom action items sync".
> fathom-common-errors
Diagnose and fix Fathom API errors including auth failures and missing data. Use when API calls fail, transcripts are empty, or webhooks are not firing. Trigger with phrases like "fathom error", "fathom not working", "fathom api failure", "fix fathom".