-- Generalise the two-slot kit designation (migration 0024) into the full set of -- active club designations. -- -- Ownership still lives ONLY in `owned_cards`; this table records which owned -- INSTANCE currently occupies each club-scoped role. A row here is a pointer, -- never a second ownership authority. -- -- Lifecycle invariants enforced by the schema, not by convention: -- * `PRIMARY KEY (club_id, slot)` — at most one active item per role. -- * `owned_card_id ... UNIQUE` — one owned instance can occupy at most ONE -- slot, so "the same card is both the home and the away kit" is unstorable. -- * `REFERENCES owned_cards(id) ON DELETE CASCADE` — quick-selling/consuming -- the item removes the designation, so a sold item can never be projected -- back to the client as active. -- * the BEFORE UPDATE trigger below — a market transfer moves ownership by -- UPDATE (the row id survives), which no FK action can see, so the -- designation is dropped explicitly before the owner changes. -- -- `squad_managers` (migration 0023) is squad-scoped, not club-scoped, and is -- deliberately NOT folded in here. CREATE TABLE IF NOT EXISTS club_active_items ( club_id TEXT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE, slot TEXT NOT NULL CHECK (slot IN ( 'home_kit', 'away_kit', 'badge', 'ball', 'stadium' )), owned_card_id TEXT NOT NULL UNIQUE REFERENCES owned_cards(id) ON DELETE CASCADE, updated_at TEXT NOT NULL, PRIMARY KEY (club_id, slot) ); CREATE INDEX IF NOT EXISTS idx_club_active_items_owned ON club_active_items(owned_card_id); -- Carry every existing kit designation over: 'home' -> 'home_kit', -- 'away' -> 'away_kit'. No designation is lost and none is invented. INSERT INTO club_active_items (club_id, slot, owned_card_id, updated_at) SELECT club_id, CASE slot WHEN 'home' THEN 'home_kit' ELSE 'away_kit' END, owned_card_id, updated_at FROM club_kit_assignments WHERE slot IN ('home', 'away'); -- 0024's trigger lives ON owned_cards, so DROP TABLE would NOT remove it and -- every subsequent ownership transfer would fail on a missing table. Drop it -- explicitly first, then replace it with the generalised one. DROP TRIGGER IF EXISTS clear_club_kit_assignment_before_transfer; DROP TABLE club_kit_assignments; CREATE TRIGGER IF NOT EXISTS clear_club_active_item_before_transfer BEFORE UPDATE OF club_id ON owned_cards WHEN OLD.club_id <> NEW.club_id BEGIN DELETE FROM club_active_items WHERE owned_card_id = OLD.id; END;