# 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](modules.md) 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` (in `wow_user`) when calling `/profile/user/wow`, which requires the user's own consent. `wow_battlenet_login` captures the token on OIDC login and stores it in `user.data`.

The endpoints-by-auth split is a property of the *call site*, not of `BattleNetClient`. See [data flow](data-flow.md#1-authentication) 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](plugin-system.md) for how owners get their per-owner rows populated, and [lifecycle](lifecycle.md) for how projection lives and dies.

## Where to go next

- [Modules](modules.md) — the full submodule inventory with roles and responsibilities
- [Data flow](data-flow.md) — how bytes move from Blizzard into entities and back out to the UI
- [Plugin system](plugin-system.md) — DashboardSectionProvider and CharacterDataProvider details
- [Lifecycle](lifecycle.md) — install, uninstall, TTL, delete cascades
