> 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".

fetch
$curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/adobe-migration-deep-dive?format=md"
SKILL.mdadobe-migration-deep-dive

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

TypeFromToComplexityDuration
Auth migrationJWT credentialsOAuth Server-to-ServerLow1-2 days
API consolidationSeparate PS/LR endpointsFirefly Services SDKMedium1-2 weeks
Competitor replacementCloudinary/imgix/PDFTronAdobe APIsHigh4-8 weeks
Full replatformCustom pipelineAdobe App BuilderHigh2-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

IssueCauseSolution
Quality differenceDifferent rendering enginesCompare side-by-side; tune parameters
Higher latencyAdobe async APIsUse parallel job submission
Cost increaseDifferent pricing modelImplement caching; optimize batch sizes
Missing featuresNot all features map 1:1Document gaps; find Adobe alternatives

Resources

Next Steps

For advanced troubleshooting, see adobe-advanced-troubleshooting.

┌ stats

installs/wk0
░░░░░░░░░░
github stars1.7K
██████████
first seenMar 23, 2026
└────────────

┌ repo

jeremylongshore/claude-code-plugins-plus-skills
by jeremylongshore
└────────────