-- Generic owned-content classification on the EXISTING ownership table. -- -- Core owns ONE instance-based ownership model for every kind of owned content. -- There is deliberately no parallel "items" table: a manager, a consumable, a -- kit and a player are all rows in `owned_cards`, differing only by -- `content_kind`. Two copies of one definition remain TWO rows (instance-based -- ownership: `card_id` is the definition, `id` is the instance). -- -- `content_kind` is a game-INDEPENDENT vocabulary. Game adapters translate their -- own taxonomy (e.g. FIFA 17 `cardsubtypeid` / resource ranges) into one of these -- tokens before ownership reaches Core; a game's numeric ids NEVER land here. -- -- BACKFILL: none needed — every pre-existing row is a player card, which is -- exactly the column DEFAULT, so the ALTER backfills all existing ownership as -- 'player' in place. (Verified against a real populated club snapshot: 1986 -- owned rows, all players.) ALTER TABLE owned_cards ADD COLUMN content_kind TEXT NOT NULL DEFAULT 'player' CHECK (content_kind IN ( 'player', 'manager', 'staff', 'consumable', 'kit', 'badge', 'ball', 'stadium', 'misc' )); -- Optional stack count for content that is owned as an instance CARRYING a -- count rather than as a bare instance. -- -- Evidence (real profile, 1995 owned items): consumables are instance-based with -- an OPTIONAL count — some carry a wire `amount` (observed 1,2,4,5,10,15), some -- omit the key entirely, and two copies of one definition exist as two distinct -- instances. So a count is a per-instance ATTRIBUTE, never a replacement for the -- instance: NULL means "not a stack", a positive integer is the stack size. -- Collapsing instances into counts is forbidden by the ownership model above. ALTER TABLE owned_cards ADD COLUMN quantity INTEGER CHECK (quantity IS NULL OR quantity >= 1); -- Every club projection reads one kind at a time (players for the squad, kits -- for the club room, consumables for the item list), so the club+kind pair is -- the hot access path. CREATE INDEX IF NOT EXISTS idx_owned_cards_club_kind ON owned_cards(club_id, content_kind);