Skip to content

feat: resolve detected games through IGDB on game mappings - #118

Merged
enimaloc merged 9 commits into
devfrom
feat/game-mapping-igdb
Nov 13, 2026
Merged

enimaloc merged 9 commits into
devfrom
feat/game-mapping-igdb

Conversation

@enimaloc

Copy link
Copy Markdown
Owner

Summary

Detected games can now be resolved through an IGDB game pinned on their game mapping. Battle.net needed it: IGDB has no Battle.net source, and the name search picked the wrong game (World of Warcraft → World of Warcraft: Forever, no Twitch category → INCOMPLETE).

  • game_mapping.igdb_id (V110) for every source; the migration seeds the nine Blizzard titles (WoW, WTCG, Pro, Fen, D3, OSI, S2, Hero, W3) with their IGDB game and Twitch category, without overwriting an existing mapping.
  • One resolution entry point (IgdbService.resolveDetected): a mapping's IGDB game wins; a Battle.net game is never searched by name (unmapped → stays INCOMPLETE and listed under "games without a mapping"); other sources keep platform id then name.
  • Admin Game mappings tab: an "IGDB game" picker (search by name); the Twitch category becomes optional when an IGDB game is picked and is deduced from IGDB (400 with a clear message when it can't be, unless the game is ignored by default). Clearing or changing the IGDB game never reuses the previous game's suggestions.

Modules to restart

catapult-api and catapult-web, together (shared DTOs gained igdbId; an older web saving a mapping would clear its IGDB game).

After deploy

  • INCOMPLETE Battle.net bindings resolve on their own (next detection or the incomplete-bindings refresh).
  • Bindings already resolved by name before this change (possibly the wrong game) keep it until an admin opens their mapping and saves it with apply live.

Tests

catapult-common 411, catapult-api 4418, catapult-web 2909 and 1194 vitest: green except the Docker/Testcontainers/Redis classes the local sandbox cannot run (CI runs them, incl. the new access-matrix row for GET /api/internal/admin/game-mappings/igdb-games).

Follow-ups (not in this PR)

  • Short negative cache when IGDB is down for a mapped game's name.
  • A deduced category stores the IGDB game name rather than the Twitch category name (display only).
  • Upper bound on the numeric IGDB id length.
  • Pre-existing: the IGDB app-token request logs an exception message whose URI can carry client_secret.

IgdbService.resolveDetected is the single entry point turning a detected
game into its IGDB game: the game mapping's IGDB id first, nothing for an
unmapped Battle.net game (never searched by name), else the platform id
then the name. The binding, game context, game info, dashboard and DTDD
resolutions all go through it.
An admin mapping can name an IGDB game. With no Twitch category typed, the category is
deduced from that game (400 when none, unless the mapping is ignored by default). The
suggestions applied in the same write now come from the request's IGDB game. Adds the
admin IGDB game search endpoint.
Add an IGDB game picker to the game mappings form (search as you type,
clearable, emptying the Twitch category it deduces), an IGDB column in the
list, the igdb-games proxy route, and the Blizzard presets in the mock.
Suggestions were resolved before the write through the stored mapping row, so an update
clearing the IGDB game still applied the old game's CCLs/TWs, and a mapping moved to another
game re-resolved the old game's bindings through its IGDB game. Both now resolve the game with
its mapping left aside (IgdbService#resolveUnmapped): nothing for Battle.net, else platform id
then name.
IGDB ids are parsed as numbers: a non-numeric one made a save with a typed category fail with
a 500, and an ignored mapping holding one failed on every detection. It is now refused with a
400 before anything is stored.
The category and 400 errors only mentioned picking a Twitch category: they now also say an
IGDB game can be picked instead, its category deduced, and that one must be entered when it
has none.
…data

The budget fixture's game was never resolved before: IgdbService is mocked and
the assembler called methods the mock did not stub, so these routes were
measured without their IGDB details and DTDD data. Resolving through
resolveDetected now runs those reads.
@enimaloc
enimaloc merged commit 1bdbc94 into dev Nov 13, 2026
5 checks passed
@enimaloc
enimaloc deleted the feat/game-mapping-igdb branch November 13, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant