Skip to content

Game platform field: free-text → enum (single value per entry) #26

Description

@mforce

Motivation

Game.Platform is currently a free-text string?. That's bad for filtering, search, normalisation, and IGDB enrichment (which surfaces a canonical platform name we then drop on the floor as a free-text string). Replace it with a curated enum, one platform per entry — multi-platform copies are modelled as separate entries (see "Why one-per-entry" below).

Proposed enum

public enum GamePlatform
{
    Other = 0,
    Pc, Mac, Linux, Mobile,

    // Xbox
    XboxOriginal, Xbox360, XboxOne, XboxSeriesXS,

    // PlayStation
    PS1, PS2, PS3, PS4, PS5, Vita, PSP,

    // Nintendo
    Nes, Snes, N64, GameCube, Wii, WiiU, Switch, Switch2,
    GameBoy, GameBoyColor, GameBoyAdvance, Ds, Ds3,

    // Sega + retro / PC handheld
    Genesis, Saturn, Dreamcast,
    SteamDeck,
}

Display labels live in a GAME_PLATFORMS array on the client (label / value), same shape as the existing MUSIC_FORMATS / MOVIE_FORMAT_FLAGS.

Why one-per-entry (and not a multi-platform field)

A collection tracker tracks releases, which is also IGDB's model. Each release has its own per-platform attributes that don't generalise across platforms:

  • Format (Disc / Digital), digital store, barcode
  • Condition, purchase price / date, location
  • Completion status, hours played, last played
  • Status (Owned / Wishlist / OnOrder / Sold) — "owned on PS5, wishlist on Switch" works trivially with two entries
  • Year + developer can differ per release (e.g. Halo 3 on 360 vs MCC on Series X)

A multi-platform field forces every per-copy field into nested arrays / sub-records, which complicates the schema, every form, and every endpoint. Separate entries keeps the model flat and matches how barcode scanning + IGDB lookup feed data in (one release per scan).

A "duplicate to another platform" button on the edit page covers the convenience case (see follow-up below).

Implementation

Backend

  • Collectify.Domain.Enums.GamePlatform (new file).
  • Game.Platform becomes GamePlatform (non-nullable; Other is the safe default for unknown).
  • EF migration: rename existing Platform to PlatformLegacy (string), add new Platform (int), backfill via case-insensitive match against the enum's display labels (e.g. "PS5" → PS5, "Switch" → Switch, otherwise → Other and the original string is preserved in PlatformLegacy for one release so users can fix manually).
  • IGDB mapping: when IgdbGameProvider.Map extracts the first IGDB platform name, lookup-table it onto GamePlatform. Leave Other for unmapped values.
  • Endpoint tests: roundtrip the enum as a string via JsonStringEnumConverter (already configured globally).

Frontend

  • services/types.ts — add GAME_PLATFORMS: { value: GamePlatform; label: string }[] and the GamePlatform union type.
  • GameForm — swap the <Input> for a <Select> driven by GAME_PLATFORMS.
  • GamesList / list cards — render the label for the stored enum value.
  • IGDB lookup importLookup — use the new platform mapping so picked / scanned games land on a canonical enum.

Migration safety

  • Migration is one-way (string → int with a legacy column kept until a follow-up PR drops it).
  • Document any unmapped values surface as Other; the legacy column lets users see what they'd typed.

Out of scope (follow-ups)

  • "Duplicate to another platform" button on the edit page — pre-fills a new GameForm with the same metadata (title, developer, igdbId, cover, …) and a different Platform. Issue to be filed once this lands.
  • Drop the PlatformLegacy column once the user has had a chance to clean up unmapped values.
  • Multi-platform display badge ("also owned on PS5 / Switch") on the detail page — needs the search/filter index work in Search / filter list pages by per-type attributes #25 to know which entries share an igdbId.

Verification

  • Server tests: endpoint roundtrips the enum, migration backfills sample inputs deterministically.
  • Manual: existing free-text platforms still display, can be re-saved with a real enum value, IGDB-scanned games land on the right platform.
  • Client tests: form submits the right enum value; list card renders the label.

Activity

  1. added a commit that references this issue on May 11, 2026
    7b21f6d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions