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)
| Field | Description |
|---|---|
id | Blizzard expansion ID |
syncedAt | Last sync timestamp |
JournalInstance (structural)
| Field | Description |
|---|---|
id | Blizzard journal-instance ID |
category | raid or dungeon |
imageUrl | Cached instance image from Blizzard |
expansionId | Parent expansion |
syncedAt | Last sync timestamp |
JournalEncounter (structural)
| Field | Description |
|---|---|
id | Blizzard encounter ID |
journalInstanceId | Parent instance |
orderIndex | Boss order within instance |
imageUrl | Boss image |
syncedAt | Last 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.
| Table | Key | Text 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.
| Field | Description |
|---|---|
id | Session UUID |
status | running, completed, failed |
progress | JSON with step-level progress |
startedAt | When sync began |
completedAt | When 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:
expansions— Fetching expansion listinstances— Fetching instances per expansionencounters— Fetching encounters per instancemedia— Fetching instance images
The frontend admin panel shows a real-time progress bar using these events.
API Endpoints
Game Data (Public)
| Method | Path | Query Params | Description |
|---|---|---|---|
| GET | /game-data/expansions | locale? | List all synced expansions |
| GET | /game-data/instances | category?, locale? | List instances (filter by category) |
| GET | /game-data/encounters | journalInstanceId?, 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
| Method | Path | Description |
|---|---|---|
| POST | /admin/sync/journal | Trigger full journal sync |
| GET | /admin/sync/journal/status | Get current sync session |
Usage in Event Creation
When creating an event, the frontend uses game data to:
- Show a dropdown of raid/dungeon instances (from
JournalInstance) - Auto-populate the event image from the instance's
imageUrl - 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 Locale | Blizzard Locale |
|---|---|
en | en_US |
de | de_DE |
es | es_ES |
fr | fr_FR |
pt | pt_BR |
zh-CN | zh_CN |