# Modules

Every submodule, its role, and what it ships.

## Core — `wow`

Battle.net client + auth, shared enums, base classes, the admin dashboard, and the TTL sweeper. Nothing domain-specific.

Key services:

- `wow.battlenet.auth` — token fetch + refresh
- `wow.battlenet.client` — authenticated HTTP client with rate limiting, retry, conditional requests
- `wow.dashboard_section_provider_manager` — discovers dashboard plugins
- `wow.dashboard_renderer` — owns the dashboard markup (plugins return value objects, never HTML)
- `wow.searchable_data_provider_manager` — discovers search plugins
- `wow.search_orchestrator` — multi-provider search with budget allocation and failure isolation
- `wow.ttl_sweeper` — the 30-day TTL enforcer

Provides:

- The `wow.settings` config (client ID, key ref, default region, cache_icons flag)
- The `/admin/reports/wow` dashboard
- The `/wow/search` and `/wow/search/import` JSON endpoints
- `LookupFormBase` for reusable lookup pages (the actual `/wow/lookup/character` form and route live in `wow_character`)
- `drush wow:sweep-ttl`, `drush wow:test-connection`, `drush wow:status`

## Reference data

All follow the same shape — one taxonomy vocabulary, one Api class, one Sync extending `TaxonomySyncBase`, one Dashboard extending `TaxonomyDashboardProviderBase`.

| Module | Vocabulary | Endpoint | Drush |
|---|---|---|---|
| `wow_realm` | `wow_realm` | `/data/wow/realm/index` + `/connected-realm/index` | `wow:sync-realms` |
| `wow_playable_class` | `wow_playable_class` | `/data/wow/playable-class/index` | `wow:sync-classes` |
| `wow_playable_race` | `wow_playable_race` | `/data/wow/playable-race/index` | `wow:sync-races` |
| `wow_playable_specialization` | `wow_playable_specialization` | `/data/wow/playable-specialization/index` | `wow:sync-specializations` |
| `wow_power_type` | `wow_power_type` | `/data/wow/power-type/index` | `wow:sync-power-types` |
| `wow_reputation` | `wow_reputation_faction` | `/data/wow/reputation-faction/index` | `wow:sync-reputation-factions` |

Every reference vocabulary carries `wow_blizzard_id` and `wow_last_fetched` fields.

## Catalogs

Provide a content entity type plus a `CharacterDataProvider` plugin for the per-character data.

| Module | Catalog entity | Junction entity | Endpoint (catalog) |
|---|---|---|---|
| `wow_achievement` | `wow_achievement` | `wow_achievement_progress` | `/data/wow/achievement/index` |
| `wow_mount` | `wow_mount` | `wow_mount_collection` | `/data/wow/mount/index` |
| `wow_pet` | `wow_pet` | `wow_collected_pet` | `/data/wow/pet/index` |
| `wow_title` | `wow_title` | `wow_title_award` | `/data/wow/title/index` |
| `wow_toy` | `wow_toy` | `wow_toy_collection` | `/data/wow/toy/index` |
| `wow_reputation` | *(uses taxonomy)* | `wow_reputation_standing` | `/data/wow/reputation-faction/index` |
| `wow_item` | `wow_item` | *(none — on-demand lookup only)* | `/data/wow/item-class/index` + `/data/wow/item/{id}` |
| `wow_creature` | `wow_creature` | *(none — on-demand lookup only)* | `/data/wow/creature/{id}` + `/data/wow/creature-type/index` + `/data/wow/creature-family/index` |
| `wow_quest` | `wow_quest` | *(none — batch sync via queue)* | `/data/wow/quest/index` + `/data/wow/quest/{id}` |

`wow_reputation` is hybrid: the factions catalog lives in a taxonomy (shared lookup), per-character standings live in a junction entity.

`wow_item` is distinct: it syncs the item-class taxonomy up front, and items themselves are fetched lazily as referenced by achievements, gear slots, etc. No bulk item catalog. Items have a canonical page at `/wow/item/{blizzard_id}/{name_slug}`.

`wow_creature` follows the same on-demand pattern as items: creature types and families are taxonomy-synced up front, individual creatures are looked up as needed. Canonical page at `/wow/creature/{blizzard_id}/{name_slug}`.

`wow_quest` syncs the full quest catalog via batch queue processing (same pattern as achievements). Quest types are taxonomy-synced. Canonical page at `/wow/quest/{blizzard_id}/{name_slug}`.

## Owners

Project owner references onto junction entities at runtime.

### `wow_character`

The central "who is this player" module. Projects `character` onto every owner-agnostic junction:

```
wow_achievement_progress, wow_collected_pet, wow_mount_collection,
wow_reputation_standing, wow_title_award, wow_toy_collection
```

Also owns the character canonical page at `/wow/character/{region}/{realm}/{name}`, the `CharacterPageRenderer` service for plugin-driven page sections, and the character lookup form at `/wow/lookup/character`.

### `wow_guild`

Analogous for guild-owned data. Projects `guild` onto `wow_achievement_progress`. Owns the guild profile + crest storage.

## Auth and glue

### `wow_battlenet_login`

Pure auth layer. Configures Battle.net as an OpenID Connect client and captures tokens into `user.data` on login. No UI, no routing decisions. Explicitly filters by client plugin ID so non-battlenet logins don't land in its namespace.

### `wow_user`

The Drupal-user ↔ WoW-character bridge. Projects `uid` + `is_main` onto `wow_character`. Owns:

- The character selection UI (`/user/{uid}/characters/select`)
- The post-OIDC redirect that sends players there
- The account-delete / de-link purge cascade

Depends on `wow_character` and `wow_battlenet_login`. Never referenced in the other direction (auth module has no knowledge of glue).

## Editor integration

### `wow_editor`

Optional CKEditor 5 integration. Adds a toolbar button that opens a search modal for inserting styled links to WoW game data. Depends on `wow` + `drupal:ckeditor5`. No routing decisions, no entity storage — purely a UI bridge between CKEditor and the `SearchableDataProvider` plugin system.

## Enable order

All modules work in any order — install-time column projection and runtime `hook_entity_base_field_info` give the same end state regardless. See [lifecycle](lifecycle.md) for the exact mechanics.
