Files
OpenFUT-Core/migrations/0023_squad_managers.sql
T
funman300 9036f5f411 feat(club): ownership-backed squad manager assignment
Add a generic, durable squad->manager assignment (migration 0023
squad_managers) so a manager persists across squad save, reload, and
server restart, backed by authoritative Core owned_cards.

- squad_managers(squad_id PK, owned_card_id, updated_at) with ON DELETE
  CASCADE on both FKs: quick-selling the manager auto-clears the
  assignment (no resurrection); one manager per squad (no duplicates).
- club::{get,set,clear}_squad_manager validate club ownership of both the
  squad and the card, and re-check ownership on read (defends against a
  stale row left by a market transfer).
- GET/PUT /club/manager routes expose the assignment; FIFA wire meaning
  stays in the adapter.

Tests: persistence across reload+restart (headline), reassignment
replace/no-duplicate, clear/no-resurrection, cascade on quick-sell,
foreign-card rejection.
2026-08-20 16:43:28 +00:00

26 lines
1.4 KiB
SQL

-- Squad manager assignment: an owned item assigned as a squad's manager.
--
-- Generic, game-neutral canonical state. Core does not know what a "manager"
-- means to any game; it only records that one owned item (`owned_card_id`) is
-- assigned to a squad in the manager role. The FIFA 17 adapter owns the wire
-- meaning (itemType "manager", contract, chemistry) exactly as it owns player
-- item shaping — Core just persists the ownership-backed assignment durably and
-- atomically, so a manager survives squad save / reload / server restart.
--
-- One manager per squad: `squad_id` is the primary key, so a re-assignment
-- REPLACEs rather than accumulating (no duplicate-manager rows).
--
-- `owned_card_id` references `owned_cards(id)` with ON DELETE CASCADE: quick
-- selling / discarding the manager card (a DELETE on owned_cards) removes the
-- assignment automatically, so a sold manager is never resurrected on the next
-- squad read. Reads additionally re-check the manager still belongs to the club
-- (see `club::get_squad_manager`), defending against a stale row left by a
-- market transfer (which UPDATEs owner rather than deleting).
CREATE TABLE IF NOT EXISTS squad_managers (
squad_id TEXT PRIMARY KEY NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
owned_card_id TEXT NOT NULL REFERENCES owned_cards(id) ON DELETE CASCADE,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_squad_managers_owned ON squad_managers(owned_card_id);