Skip to main content

Journal & Game Data Sync

The journal sync system fetches raid and dungeon metadata from the Blizzard Game Data API and stores it locally for event creation. This provides the instance list, boss encounters, and images used when creating events.

Data Model

Each journal entity is split into a structural table (IDs, relationships, media) and a locale table (all user-facing text). The en_US locale row is the mandatory default -- there are no text fields on the structural tables.

JournalExpansion (structural)

FieldDescription
idBlizzard expansion ID
syncedAtLast sync timestamp

JournalInstance (structural)

FieldDescription
idBlizzard journal-instance ID
categoryraid or dungeon
imageUrlCached instance image from Blizzard
expansionIdParent expansion
syncedAtLast sync timestamp

JournalEncounter (structural)

FieldDescription
idBlizzard encounter ID
journalInstanceIdParent instance
orderIndexBoss order within instance
imageUrlBoss image
syncedAtLast sync timestamp

Locale Tables (text -- single source of truth)

All user-facing text lives exclusively in locale tables, keyed by (entityId, locale). The en_US row is always present and serves as the default.

TableKeyText Fields
JournalExpansionLocale(expansionId, locale)name
JournalInstanceLocale(instanceId, locale)name, description, location
JournalEncounterLocale(encounterId, locale)name, description

The API always joins with locale tables. When the caller provides a ?locale= parameter, that locale is used; otherwise en_US is the default.

JournalSyncSession

Tracks platform-wide sync progress.

FieldDescription
idSession UUID
statusrunning, completed, failed
progressJSON with step-level progress
startedAtWhen sync began
completedAtWhen sync finished

Sync Workflow

Full Sync (Admin-Triggered)

flowchart TD
A[Admin triggers sync] --> B[Create JournalSyncSession]
B --> C["Fetch expansions (en_US)"]
C --> D["Fetch instances with images (en_US)"]
D --> E["Fetch encounters with images (en_US)"]
E --> F["Fetch 5 remaining locales (parallel)"]
F --> G["Transaction: delete all → insert structural → insert locales"]
G --> H[Mark session completed]

All 5 non-English locales are fetched in parallel (Promise.all) to keep the locale phase under ~70 seconds. The entire sync runs inside a single Prisma transaction — if any step fails, no data is written.

Progress Reporting

The sync job emits WebSocket events during execution:

journal-sync:progress → { sessionId, step, current, total, message }

Steps:

  1. expansions — Fetching expansion list
  2. instances — Fetching instances per expansion
  3. encounters — Fetching encounters per instance
  4. media — Fetching instance images

The frontend admin panel shows a real-time progress bar using these events.

API Endpoints

Game Data (Public)

MethodPathQuery ParamsDescription
GET/game-data/expansionslocale?List all synced expansions
GET/game-data/instancescategory?, locale?List instances (filter by category)
GET/game-data/encountersjournalInstanceId?, locale?List encounters (filter by instance)

These endpoints are marked @AllowAnonymous() — no authentication required. They serve cached data from the local database, not live Blizzard API calls.

The optional locale parameter accepts a Blizzard locale code (e.g. de_DE, fr_FR). The API always joins with locale tables — when no locale is provided, en_US is the default. Cache keys include the locale for correct per-language caching.

Admin Sync

MethodPathDescription
POST/admin/sync/journalTrigger full journal sync
GET/admin/sync/journal/statusGet current sync session

Usage in Event Creation

When creating an event, the frontend uses game data to:

  1. Show a dropdown of raid/dungeon instances (from JournalInstance)
  2. Auto-populate the event image from the instance's imageUrl
  3. List encounters for the selected instance (future: phase-aware attendance)

Blizzard API Integration

  • Uses the Game Data API (/data/wow/journal-expansion/index, etc.)
  • Requires a Blizzard API client credential (not user-scoped)
  • Rate-limited: sync runs as a background job with delays between requests
  • Images are stored via StorageService (S3 or local filesystem)
  • Locale translations fetched for all 6 Blizzard locales (en_US, de_DE, es_ES, fr_FR, pt_BR, zh_CN)
  • Data is relatively stable — a weekly sync is sufficient for most guilds

Frontend Locale Integration

The frontend maps the user's i18next language to the corresponding Blizzard locale using useBlizzardLocale() hook, then passes it as a query parameter to RTK Query endpoints:

const locale = useBlizzardLocale(); // e.g. "de_DE" for German
const { data } = useGetInstancesQuery({ locale });
App LocaleBlizzard Locale
enen_US
dede_DE
eses_ES
frfr_FR
ptpt_BR
zh-CNzh_CN