Architecture overview¶
A 60-second mental model for what this suite is and how its parts fit together.
Three layers¶
┌──────────────────────────────────────────────────┐
│ Blizzard Battle.net │
│ - Game Data APIs (global, app-token) │
│ - Profile APIs (per-player — see below) │
└──────────────────────────────────────────────────┘
│
BattleNetClient (auth, rate limit, retry, caching)
│
┌──────────────────────────────────────────────────┐
│ Per-domain submodules │
│ - Api layer wraps endpoints │
│ - Sync layer API → Drupal entities │
│ - Dashboard layer admin UI + actions │
└──────────────────────────────────────────────────┘
│
┌──────────────────────────────────────────────────┐
│ Drupal site │
│ - Taxonomy terms (reference data) │
│ - Content entities (catalogs, characters) │
│ - Junction entities (per-owner rows) │
│ - Views, Twig, your own custom code │
└──────────────────────────────────────────────────┘
Module taxonomy¶
Every module falls into one of four roles. Understanding which role a module plays tells you what it's allowed to depend on and what lifecycle rules it obeys.
| Role | Modules | Depends on | Never depends on |
|---|---|---|---|
| Core | wow |
key, http, state, lock | anything WoW |
| Reference data | wow_realm, wow_playable_class, wow_playable_race, wow_playable_specialization, wow_power_type |
core | anything WoW-specific |
| Catalog + junction | wow_achievement, wow_mount, wow_pet, wow_title, wow_toy, wow_reputation, wow_item, wow_creature, wow_quest |
core, reference data as needed | owners (wow_character, wow_guild) |
| Owner | wow_character, wow_guild |
core + the reference data they project | owners projecting OTHER directions |
| Auth / glue | wow_battlenet_login, wow_user |
OIDC + whichever domains it glues | other auth/glue modules |
The key rule: catalog modules never know about owners. Owner modules inject their reference via hook_entity_base_field_info at runtime. Enabling / disabling either side is always valid.
See modules for the full per-module breakdown.
Two auth modes¶
BattleNetClient::get() accepts an optional access-token argument. If omitted, it falls back to the app-scoped token via BattleNetAuth. That means:
- App token (default) — used for every Game Data call, and today also for the per-character and per-guild Profile endpoints. Blizzard accepts app tokens on those.
- User OAuth token (opt-in) — only passed explicitly by
AccountProfileApi(inwow_user) when calling/profile/user/wow, which requires the user's own consent.wow_battlenet_logincaptures the token on OIDC login and stores it inuser.data.
The endpoints-by-auth split is a property of the call site, not of BattleNetClient. See data flow for the mechanics.
Regions are hardcoded¶
The five Blizzard regions (US, EU, KR, TW, CN) are infrastructure — they define API hosts, OAuth endpoints, and locale sets, and they never change. Rather than syncing from the /data/wow/region/ endpoint, the suite hardcodes them as the Drupal\wow\Enum\Region PHP enum. This keeps region logic available at boot time (before any API call), encapsulates the CN credential separation (globalCases() excludes CN), and avoids a sync dependency on data that is effectively constant.
Three data shapes¶
The suite uses three storage strategies, chosen based on how the data behaves upstream:
Reference data → taxonomy terms¶
Realms, classes, races, specializations, power types, reputation factions. Stable enough that content can reference them via entity_reference, cheap to render inside Views, and Drupal's taxonomy UI is already good enough to browse them.
Catalogs → content entities¶
Achievements, mounts, pets, titles, toys, items. Large sets, structured fields, need custom storage + queue-based sync. Content entities give us last_fetched, translations, direct entity queries.
Per-owner data → owner-agnostic junction entities¶
wow_achievement_progress, wow_mount_collection, wow_collected_pet, wow_title_award, wow_toy_collection, wow_reputation_standing. Each is defined without an owner field. wow_character and wow_guild project their owner references onto junctions at runtime via hook_entity_base_field_info.
This lets a site enable only catalogs without paying the owner-tracking cost, and makes the same junction type work for multiple owners (a single wow_achievement_progress schema serves both character AND guild achievements).
See plugin system for how owners get their per-owner rows populated, and lifecycle for how projection lives and dies.
Where to go next¶
- Modules — the full submodule inventory with roles and responsibilities
- Data flow — how bytes move from Blizzard into entities and back out to the UI
- Plugin system — DashboardSectionProvider and CharacterDataProvider details
- Lifecycle — install, uninstall, TTL, delete cascades