# Entity reference

Content entities, taxonomies, and junction entities the suite declares.

## Content entities (catalog)

| Entity type ID | Class | Module | Freshness | Owner-projectable |
|---|---|---|---|---|
| `wow_achievement` | `Drupal\wow_achievement\Entity\Achievement` | `wow_achievement` | `last_fetched` | — |
| `wow_character` | `Drupal\wow_character\Entity\Character` | `wow_character` | `last_fetched` | via `wow_user` (`uid`, `is_main`) |
| `wow_guild` | `Drupal\wow_guild\Entity\Guild` | `wow_guild` | `last_fetched` | — |
| `wow_item` | `Drupal\wow_item\Entity\Item` | `wow_item` | `last_fetched` | — |
| `wow_mount` | `Drupal\wow_mount\Entity\Mount` | `wow_mount` | `last_fetched` | — |
| `wow_pet` | `Drupal\wow_pet\Entity\Pet` | `wow_pet` | `last_fetched` | — |
| `wow_title` | `Drupal\wow_title\Entity\Title` | `wow_title` | `last_fetched` | — |
| `wow_toy` | `Drupal\wow_toy\Entity\Toy` | `wow_toy` | `last_fetched` | — |

## Junction entities (per-owner)

Each is owner-agnostic by design — owner references are projected in by the owner module's `hook_entity_base_field_info()`.

| Entity type ID | Class | Declared by | `character` from | `guild` from |
|---|---|---|---|---|
| `wow_achievement_progress` | `Drupal\wow_achievement\Entity\AchievementProgress` | `wow_achievement` | `wow_character` | `wow_guild` |
| `wow_collected_pet` | `Drupal\wow_pet\Entity\CollectedPet` | `wow_pet` | `wow_character` | — |
| `wow_mount_collection` | `Drupal\wow_mount\Entity\MountCollection` | `wow_mount` | `wow_character` | — |
| `wow_reputation_standing` | `Drupal\wow_reputation\Entity\ReputationStanding` | `wow_reputation` | `wow_character` | — |
| `wow_title_award` | `Drupal\wow_title\Entity\TitleAward` | `wow_title` | `wow_character` | — |
| `wow_toy_collection` | `Drupal\wow_toy\Entity\ToyCollection` | `wow_toy` | `wow_character` | — |

All junctions carry `last_fetched` for TTL sweeping.

## Taxonomies

| Vocabulary ID | Module | Notes |
|---|---|---|
| `wow_realm` | `wow_realm` | Realms + connected realm groups, with region + locale |
| `wow_playable_class` | `wow_playable_class` | Classes + class icons |
| `wow_playable_race` | `wow_playable_race` | Races with faction affiliation |
| `wow_playable_specialization` | `wow_playable_specialization` | Specs with role (Tank/Healer/DPS) |
| `wow_power_type` | `wow_power_type` | Mana, Rage, Energy, Focus, Runic Power, etc. |
| `wow_item_class` | `wow_item` | Weapon / Armor / Container / Quest Item / etc. |
| `wow_char_achi_category` | `wow_achievement` | Character achievement category tree |
| `wow_guild_achi_category` | `wow_achievement` | Guild achievement category tree |
| `wow_reputation_faction` | `wow_reputation` | Reputation factions with parent hierarchy |

Every taxonomy vocabulary carries `wow_blizzard_id` (integer) and `wow_last_fetched` (timestamp) as configurable fields.

## Projected base fields

Fields added to OTHER modules' entities at runtime:

| Projected by | Field | Onto |
|---|---|---|
| `wow_character` | `character` (entity_reference → wow_character) | every owner-agnostic junction |
| `wow_guild` | `guild` (entity_reference → wow_guild) | `wow_achievement_progress` |
| `wow_user` | `uid` (entity_reference → user) | `wow_character` |
| `wow_user` | `is_main` (boolean, default FALSE) | `wow_character` |

Install/uninstall of the projecting module handles column creation and removal. See [architecture/lifecycle.md](../architecture/lifecycle.md#owner-projection).

## Cache tags and lists

All content entities follow Drupal's default cache tag behavior (`{entity_type}:{id}` and `{entity_type}_list`). No custom invalidation is wired — depending on Views or block plugins to invalidate is sufficient.

## Don't rely on surrogate IDs across environments

`id` columns are auto-increment and differ between dev / staging / prod. Always identify entities by `blizzard_id` (content entities and junctions have it as a field or via their `achievement` / `mount` / etc. reference). The Blizzard ID is stable across environments and across the Blizzard upstream.
