Character Sync System
Real-time synchronization of World of Warcraft characters from Battle.net with WebSocket progress tracking.
Overview
The Character Sync system fetches a user's WoW characters from the Battle.net API and enriches them with profile data (avatars, gear, etc.) using background jobs and real-time progress updates.
Architecture
Components
- SyncCharactersFromBattleNetUseCase - Orchestrates the sync process
- BattleNetAdapter - Anti-corruption layer for Battle.net API
- CharacterEnrichmentProcessor - Background job processor (Bull queue)
- CharacterSyncGateway - WebSocket gateway for real-time updates
- CharacterSyncSession - Tracks sync progress in database
Flow
sequenceDiagram
participant User
participant API
participant UseCase
participant BattleNet
participant Queue
participant Processor
participant WebSocket
participant Frontend
User->>API: POST /characters/sync
API->>UseCase: execute()
UseCase->>BattleNet: getUserCharacters()
BattleNet-->>UseCase: characters[]
UseCase->>UseCase: Create sync session
UseCase->>UseCase: Upsert characters
UseCase->>Queue: Queue enrichment jobs
UseCase-->>API: { sessionId, syncedCount }
API-->>User: { sessionId }
User->>WebSocket: Subscribe to sessionId
loop For each character
Queue->>Processor: Process enrichment job
Processor->>WebSocket: Emit "processing" status
WebSocket->>Frontend: Character update
Processor->>BattleNet: Fetch avatar/profile
BattleNet-->>Processor: Profile data
Processor->>Processor: Update character
Processor->>WebSocket: Emit "completed" status
WebSocket->>Frontend: Character completed
end
Processor->>WebSocket: Emit "sync-complete"
WebSocket->>Frontend: Sync finished
Features
Batch Character Sync
Syncs all characters for a user from Battle.net.
Endpoint: POST /api/v1/characters/sync
Request:
{
"gameVersion": "classic_sod"
}
Response:
{
"message": "Character sync started",
"sessionId": "uuid",
"syncedCharacters": 6
}
Single Character Enrichment
Enriches a single character (avatar fetch).
Endpoint: POST /api/v1/characters/:id/enrich
Response:
{
"message": "Character enrichment queued",
"sessionId": "uuid",
"jobId": 123,
"character": {
"id": "uuid",
"name": "Pallywar",
"realm": "old-blanchy"
}
}
Real-Time Progress Updates
WebSocket events for live progress tracking:
Events
sync-progress - Character-by-character updates
{
"sessionId": "uuid",
"status": "processing",
"totalCharacters": 6,
"processedCharacters": 3,
"failedCharacters": 0,
"progressPercentage": 50,
"currentCharacter": {
"id": "uuid",
"name": "Pallywar",
"realm": "old-blanchy",
"status": "processing"
}
}
sync-complete - Sync finished
{
"sessionId": "uuid",
"status": "completed",
"totalCharacters": 6,
"processedCharacters": 6,
"failedCharacters": 0,
"progressPercentage": 100
}
sync-error - Error occurred
{
"sessionId": "uuid",
"error": "Error message"
}
Frontend Integration
React Hook: useCharacterSync
const {
progress,
error,
isConnected,
isSyncing,
isComplete,
startSync,
joinSession,
reset,
} = useCharacterSync();
// Start a new sync
await startSync('retail');
// Join an existing sync (for single-character enrichment)
joinSession(sessionId);
Progress Component
{
progress && <CharacterSyncProgress progress={progress} />;
}
Shows:
- Overall progress bar
- Current character being processed
- Animated status icons (processing, completed, failed)
- Real-time character name updates
Character Deduplication
Characters are uniquely identified by (battleNetId, realm) to prevent duplicates.
Logic:
- Fetch existing characters for user (including inactive)
- Build map with key:
${battleNetId}-${realm} - Check map before creating new characters
- Update existing, create new, reactivate archived
Game Version Support
Syncs characters from different WoW versions:
retail→ Retail WoWclassic_era→ Classic Era (Vanilla)classic_sod→ Season of Discoveryclassic_anniversary→ Anniversary Serversclassic_progression→ TBC/WotLK/Cata
Maps to CharacterTemplate enum:
retail→wow- Classic variants →
wow_classic
Error Handling
Sync Errors
- Invalid Battle.net token → 409 Conflict
- Active sync in progress → 409 Conflict
- Battle.net API errors → Logged, enrichment skipped
Enrichment Errors
- Avatar fetch failure → Character saved without avatar
- Decryption failure → Job marked as failed
- Rate limits → Retry with exponential backoff (2 attempts)
Database Schema
CharacterSyncSession
model CharacterSyncSession {
id String @id @default(uuid())
userId String
status String @default("pending")
totalCharacters Int @default(0)
processedCharacters Int @default(0)
failedCharacters Int @default(0)
startedAt DateTime @default(now())
completedAt DateTime?
error String?
user User @relation(fields: [userId], references: [id])
@@index([userId])
@@index([status])
}
Performance
- Lightweight sync: Only stores basic character data initially
- Background enrichment: Avatar/profile fetched asynchronously
- Bulk job queuing: All enrichment jobs queued in single batch
- Parallel processing: Bull queue processes multiple jobs concurrently
- Progress caching: Session progress stored in database
Testing
Character sync endpoints and WebSocket events are tested in:
character.controller.spec.ts- Controller testssync-characters-from-battlenet.use-case.spec.ts- Use case testscharacter-enrichment.processor.spec.ts- Processor testscharacter-sync.gateway.spec.ts- WebSocket tests
Future Enhancements
- Character rename detection
- Gear/talent snapshot storage
- Historical character data tracking
- Multi-realm character linking
- Auto-sync scheduling