speak-migration-deep-dive
Execute Speak major re-architecture and migration strategies for language learning platforms. Use when migrating to or from Speak, performing major version upgrades, or re-platforming existing language learning integrations. Trigger with phrases like "migrate speak", "speak migration", "switch to speak", "speak replatform", "speak upgrade major". allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(node:*), Bash(kubectl:*) version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>
Allowed Tools
No tools specified
Provided by Plugin
speak-pack
Claude Code skill pack for Speak AI Language Learning Platform (24 skills)
Installation
This skill is included in the speak-pack plugin:
/plugin install speak-pack@claude-code-plugins-plus
Click to copy
Instructions
# Speak Migration Deep Dive
## Overview
Comprehensive guide for migrating to or from Speak, or major version upgrades for language learning platforms.
## Prerequisites
- Current system documentation
- Speak SDK installed
- Feature flag infrastructure
- Rollback strategy tested
- User communication plan
## Migration Types
| Type | Complexity | Duration | Risk |
|------|-----------|----------|------|
| Fresh install | Low | Days | Low |
| From competitor (Duolingo API, etc.) | Medium | Weeks | Medium |
| SDK major version upgrade | Medium | Weeks | Medium |
| Full language platform migration | High | Months | High |
## Pre-Migration Assessment
### Step 1: Current State Analysis
```bash
# Document current language learning implementation
find . -name "*.ts" -o -name "*.py" | xargs grep -l "language\|lesson\|speech" > learning-files.txt
# Count integration points
wc -l learning-files.txt
# Identify dependencies
npm list | grep -i "language\|speech\|duolingo\|babbel"
pip freeze | grep -i "language\|speech"
# Analyze data structures
grep -r "interface.*Lesson\|type.*Lesson" src/ --include="*.ts"
```
### Step 2: Data Inventory
```typescript
interface MigrationInventory {
// User data
userCount: number;
activeUsersLast30Days: number;
// Learning data
lessonRecordsCount: number;
languagesUsed: string[];
averageLessonsPerUser: number;
// Audio data
audioRecordingsCount: number;
totalAudioDurationHours: number;
audioStorageGB: number;
// Progress data
pronunciationScoresCount: number;
vocabularyEntriesCount: number;
streakRecordsCount: number;
// Integration points
apiEndpoints: string[];
webhooksConfigured: string[];
customFeatures: string[];
}
async function assessMigration(): Promise {
const [users, lessons, audio, progress] = await Promise.all([
assessUserData(),
assessLessonData(),
assessAudioData(),
assessProgressData(),
]);
return {
...users,
...lessons,
...audio,
...progress,
apiEndpoints: await findApiEndpoints(),
webhooksConfigured: await findWebhooks(),
customFeatures: await documentCustomFeatures(),
};
}
```
### Step 3: Language Support Mapping
```typescript
// Map your current languages to Speak's supported languages
const LANGUAGE_MAPPING: Record = {
// Current system -> Speak code
'spanish': 'es',
'korean': 'ko',
'japanese': 'ja',
'mandarin': 'zh-CN',
'french': 'fr',
'german': 'de',
'portuguese': 'pt-BR',
'indonesian': 'id',
};
function validateLanguageSupport(
currentLanguages: string[]
): LanguageValidation {
const supported: string[] = [];
const unsupported: string[] = [];
for (const lang of currentLanguages) {
if (LANGUAGE_MAPPING[lang]) {
supported.push(lang);
} else {
unsupported.push(lang);
}
}
return {
supported,
unsupported,
migrationReady: unsupported.length === 0,
recommendation: unsupported.length > 0
? `${unsupported.join(', ')} not supported by Speak. Consider alternatives.`
: 'All languages supported',
};
}
```
## Migration Strategy: Strangler Fig Pattern
```
Phase 1: Parallel Run
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Old Language โ โ Speak โ
โ Platform โ โโโถ โ (Shadow) โ
โ (100%) โ โ (0%) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Phase 2: Feature-by-Feature Migration
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Old Platform โ โ Speak โ
โ (Core only) โ โโโถ โ (New) โ
โ โ โ Features โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Phase 3: Gradual User Migration
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Old Platform โ โ Speak โ
โ (50% users) โ โโโถ โ (50%) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
Phase 4: Complete
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Old Platform โ โ Speak โ
โ (Deprecated) โ โโโถ โ (100%) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
```
## Implementation Plan
### Phase 1: Setup (Week 1-2)
```bash
# Install Speak SDK
npm install @speak/language-sdk
# Configure credentials
cp .env.example .env.speak
# Edit with Speak credentials
# Verify connectivity
npx tsx -e "
const { SpeakClient } = require('@speak/language-sdk');
const client = new SpeakClient({
apiKey: process.env.SPEAK_API_KEY,
appId: process.env.SPEAK_APP_ID,
});
client.health.check().then(console.log);
"
```
### Phase 2: Adapter Layer (Week 3-4)
```typescript
// src/adapters/language-service.ts
interface LanguageServiceAdapter {
// Session management
startLesson(config: LessonConfig): Promise;
endLesson(sessionId: string): Promise;
// Speech processing
recognizeSpeech(audio: ArrayBuffer): Promise;
scorePronunciation(audio: ArrayBuffer, text: string): Promise;
// Progress tracking
getProgress(userId: string): Promise;
updateProgress(userId: string, progress: Partial): Promise;
}
// Old system adapter
class LegacyLanguageAdapter implements LanguageServiceAdapter {
async startLesson(config: LessonConfig): Promise {
return legacyClient.lessons.create(config);
}
// ... implement other methods
}
// New Speak adapter
class SpeakLanguageAdapter implements LanguageServiceAdapter {
private client: SpeakClient;
constructor(client: SpeakClient) {
this.client = client;
}
async startLesson(config: LessonConfig): Promise {
const speakConfig = this.transformConfig(config);
const session = await this.client.tutor.startSession(speakConfig);
return this.transformSession(session);
}
private transformConfig(config: LessonConfig): SpeakLessonConfig {
return {
language: LANGUAGE_MAPPING[config.language],
topic: config.topic,
difficulty: config.level,
duration: config.durationMinutes,
};
}
private transformSession(session: SpeakSession): LessonSession {
return {
id: session.id,
status: session.status,
language: session.language,
// Map other fields
};
}
}
```
### Phase 3: Data Migration (Week 5-8)
```typescript
interface MigrationBatch {
users: UserMigration[];
startedAt: Date;
completedAt?: Date;
errors: MigrationError[];
}
async function migrateUserData(): Promise {
const batchSize = 100;
let processed = 0;
let errors: MigrationError[] = [];
const totalUsers = await db.users.count();
console.log(`Migrating ${totalUsers} users...`);
for await (const batch of iterateUserBatches(batchSize)) {
const results = await Promise.allSettled(
batch.map(user => migrateUser(user))
);
for (let i = 0; i < results.length; i++) {
if (results[i].status === 'rejected') {
errors.push({
userId: batch[i].id,
error: results[i].reason,
timestamp: new Date(),
});
}
}
processed += batch.length;
console.log(`Progress: ${processed}/${totalUsers} (${(processed/totalUsers*100).toFixed(1)}%)`);
// Rate limit protection
await sleep(100);
}
return { processed, errors, successRate: (processed - errors.length) / processed };
}
async function migrateUser(user: LegacyUser): Promise {
// 1. Create user in Speak
const speakUser = await speakClient.users.create({
externalId: user.id,
email: user.email,
preferences: {
nativeLanguage: LANGUAGE_MAPPING[user.nativeLanguage],
targetLanguages: user.learningLanguages.map(l => LANGUAGE_MAPPING[l]),
},
});
// 2. Migrate progress data
const legacyProgress = await legacyDb.progress.findByUser(user.id);
await speakClient.users.updateProgress(speakUser.id, {
vocabularyCount: legacyProgress.vocabularyLearned,
lessonsCompleted: legacyProgress.totalLessons,
streak: legacyProgress.currentStreak,
});
// 3. Store mapping
await db.userMigrations.insert({
legacyId: user.id,
speakId: speakUser.id,
migratedAt: new Date(),
});
}
```
### Phase 4: Traffic Shift (Week 9-12)
```typescript
// Feature flag controlled adapter selection
function getLanguageAdapter(userId: string): LanguageServiceAdapter {
const speakPercentage = getFeatureFlag('speak_migration_percentage');
const userInSpeakCohort = isUserInMigrationCohort(userId, speakPercentage);
if (userInSpeakCohort) {
return new SpeakLanguageAdapter(speakClient);
}
return new LegacyLanguageAdapter();
}
// Gradual rollout controller
async function adjustMigrationPercentage(): Promise {
const metrics = await getMigrationMetrics();
// Auto-rollback if error rate too high
if (metrics.speakErrorRate > 0.05) {
console.error('High error rate detected, reducing Speak traffic');
await setFeatureFlag('speak_migration_percentage', Math.max(0, metrics.currentPercentage - 10));
return;
}
// Increase if stable
if (metrics.speakErrorRate < 0.01 && metrics.latencyOk) {
const newPercentage = Math.min(100, metrics.currentPercentage + 10);
console.log(`Increasing Speak traffic to ${newPercentage}%`);
await setFeatureFlag('speak_migration_percentage', newPercentage);
}
}
```
## Audio Migration
```typescript
// Migrate audio recordings (if needed)
async function migrateAudioRecordings(userId: string): Promise {
const legacyAudioFiles = await legacyStorage.listUserAudio(userId);
for (const file of legacyAudioFiles) {
// Download from legacy storage
const audioData = await legacyStorage.download(file.id);
// Re-encode if necessary (Speak requires specific format)
const optimizedAudio = await optimizeAudioForSpeak(audioData);
// Upload to new storage (Speak-compatible)
await newStorage.upload({
userId: getMigratedUserId(userId),
audioData: optimizedAudio,
metadata: {
legacyId: file.id,
language: file.language,
duration: file.duration,
migratedAt: new Date(),
},
});
}
}
```
## Rollback Plan
```bash
#!/bin/bash
# rollback-speak-migration.sh
echo "=== Speak Migration Rollback ==="
# 1. Route all traffic back to legacy
kubectl set env deployment/language-service SPEAK_MIGRATION_PERCENTAGE=0
# 2. Disable Speak adapter
kubectl set env deployment/language-service SPEAK_ENABLED=false
# 3. Restart to apply
kubectl rollout restart deployment/language-service
kubectl rollout status deployment/language-service
# 4. Verify legacy is working
curl -f https://api.yourapp.com/health | jq '.services.language'
# 5. Notify team
echo "Rollback complete. Legacy language service active."
```
## Post-Migration Validation
```typescript
async function validateMigration(): Promise {
const checks = [
{ name: 'User count match', fn: checkUserCounts },
{ name: 'Progress data intact', fn: checkProgressData },
{ name: 'Audio accessible', fn: checkAudioAccess },
{ name: 'All languages working', fn: checkLanguageSupport },
{ name: 'Speech recognition', fn: checkSpeechRecognition },
{ name: 'Lesson completion flow', fn: checkLessonFlow },
{ name: 'Webhook delivery', fn: checkWebhooks },
{ name: 'Performance baseline', fn: checkPerformance },
];
const results = await Promise.all(
checks.map(async c => ({
name: c.name,
result: await c.fn(),
}))
);
return {
checks: results,
passed: results.every(r => r.result.success),
timestamp: new Date(),
};
}
// User communication after migration
async function notifyMigratedUsers(userIds: string[]): Promise {
for (const userId of userIds) {
await notifications.send(userId, {
type: 'migration_complete',
title: 'Your learning experience just got better!',
body: 'We\'ve upgraded your language learning with improved AI tutoring and speech recognition.',
action: {
label: 'Try a lesson',
url: '/lessons/new',
},
});
}
}
```
## Output
- Migration assessment complete
- Adapter layer implemented
- User data migrated successfully
- Traffic fully shifted to Speak
- Rollback tested and documented
## Error Handling
| Issue | Cause | Solution |
|-------|-------|----------|
| Data mismatch | Transform errors | Validate transforms |
| Performance drop | No caching | Add caching layer |
| User confusion | UI changes | Provide tutorials |
| Audio format error | Incompatible format | Re-encode audio |
## Examples
### Quick Migration Status
```typescript
const status = await validateMigration();
console.log(`Migration ${status.passed ? 'PASSED' : 'FAILED'}`);
status.checks.forEach(c =>
console.log(` ${c.result.success ? 'OK' : 'FAIL'} ${c.name}`)
);
```
## Resources
- [Strangler Fig Pattern](https://martinfowler.com/bliki/StranglerFigApplication.html)
- [Speak Migration Guide](https://developer.speak.com/docs/migration)
- [Data Migration Best Practices](https://developer.speak.com/docs/data-migration)
## Post-Migration
After completing migration, refer back to the standard skills for ongoing operations.