Skip to main content

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

  1. SyncCharactersFromBattleNetUseCase - Orchestrates the sync process
  2. BattleNetAdapter - Anti-corruption layer for Battle.net API
  3. CharacterEnrichmentProcessor - Background job processor (Bull queue)
  4. CharacterSyncGateway - WebSocket gateway for real-time updates
  5. 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:

  1. Fetch existing characters for user (including inactive)
  2. Build map with key: ${battleNetId}-${realm}
  3. Check map before creating new characters
  4. Update existing, create new, reactivate archived

Game Version Support

Syncs characters from different WoW versions:

  • retail → Retail WoW
  • classic_era → Classic Era (Vanilla)
  • classic_sod → Season of Discovery
  • classic_anniversary → Anniversary Servers
  • classic_progression → TBC/WotLK/Cata

Maps to CharacterTemplate enum:

  • retailwow
  • 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 tests
  • sync-characters-from-battlenet.use-case.spec.ts - Use case tests
  • character-enrichment.processor.spec.ts - Processor tests
  • character-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