Lobby e Catalogo
Riassunto in linguaggio semplice. Qui vivono due idee correlate. Una lobby è un party di giocatori che registrano insieme per un unico tentativo, vincolato a un singolo gioco — è il modo in cui funzionano le registrazioni co-op del "gruppo di N". Il catalogo è l'elenco dei giochi che permettiamo davvero alle persone di registrare, più i dettagli tecnici su come catturare ciascuno di essi. I due si incontrano in un punto: una lobby deve scegliere un gioco dal catalogo.
Mappa
Lobby — il party
lobbies— una riga per party. Unlobby_codeè la chiave di accesso condivisibile e leggibile dalle persone;creator_idè chi l'ha aperta;game_slug(FK versoeligible_games.slug) è il gioco vincolato che ogni membro deve registrare.status ∈ (active [default], closed, expired);max_playersè vincolato a2–16(default 16);expires_atne limita la durata. Una lobby ha vita breve.lobby_participants— la membership corrente, con PK composta(lobby_id, user_id)— è ciò che la rende la roster corrente (una riga viva per utente per lobby). Porta con séjoined_at, il lorosession_iduna volta iniziata la registrazione, eserver_recording_started_at. È qui che una lobby si collega alla spina dorsale della registrazione — ilsession_iddi un partecipante è lo stesso id che compare inrecording_sessions.lobby_join_events— la cronologia completa di join/leave, mai cancellata, guidata da due trigger sulobby_participants: un join fa l'INSERT di una riga (trg_lobby_join_history_insert,sourcedi defaultparticipant_insert); un leave non aggiunge una riga —trg_lobby_join_history_deletefa l'UPDATE delleft_atdella riga aperta più recente. Quindi è prevalentemente in append: una riga per join, marcata come chiusa al leave.
La regola del gioco vincolato è l'invariante importante: la lobby fissa un gioco,
e il trigger di confine-gioco di s3_uploads (vedi
Spina dorsale della registrazione)
rifiuta qualsiasi upload etichettato per la lobby il cui gioco non corrisponde.
La FK game_slug → eligible_games.slug è ON UPDATE CASCADE / ON DELETE RESTRICT:
la rinomina di uno slug si propaga nelle lobby, ma un gioco idoneo che fa da base
a una lobby non può essere cancellato. Vedi Modalità Lobby
per il ciclo di vita completo e la superficie HTTP.
Il catalogo dei giochi
Questo è l'angolo più normalizzato dello schema — quattro tabelle descrivono un gioco a livelli, dal "è consentito" fino a "come catturiamo questo specifico eseguibile".
eligible_games— l'allowlist. Identificata daigdb_id(l'id del database IGDB) con unosluge undisplay_name.enabledè l'interruttore on/off;tokensè un jsonb di token di corrispondenza usati dal rilevamento della libreria giochi per riconoscere un gioco da un titolo scansionato. È la tabella di cui parlano i documenti del Catalogo Giochi, e il confine rispetto a cui ogni upload viene validato.game_store_ids— un gioco può essere venduto su più store, quindi questa mappa unigdb_ida molte coppie(store, store_id).storeè l'unico enum Postgres nello schema:steam | epic | gog | microsoft | riot | rockstar | other. La FKigdb_id → eligible_gamesfa cascade in cancellazione.game_runtime_profiles— la ricetta di cattura per uno specifico eseguibile (exe_name) di una voce store: qualeengineusa, unsettings_override, e un jsonbsettings_enforcement(le impostazioni che forziamo per una cattura pulita;NOT NULL, default{}= "nessuna imposizione"). La FKgame_store_idfa cascade.engine_defaults— ilsettings_specdi base per engine, così che un profilo di runtime debba specificare solo i delta. L'enginedi un profilo è una FK verso qui.
Perché "un gioco" è genuinamente diverse cose: una voce di catalogo (lo consentiamo?), un prodotto acquistabile (quale store, quale id?), e un processo eseguibile (quale exe, quale engine, quali impostazioni di cattura?). Suddividerle ci permette di aggiungere uno store o un eseguibile senza toccare gli altri — e permette di riutilizzare le regole di cattura su ogni gioco con lo stesso engine.
user_game_library — cosa possiede un giocatore
La libreria giochi di ogni giocatore, scansionata da Playnite sulla sua
macchina. La PK surrogata è id; l'unicità è su (user_id, playnite_id) —
non il collegamento al catalogo, quindi due copie store dello stesso gioco IGDB
producono due righe. synced_at guida la re-sincronizzazione con throttling. Ogni
riga (25 colonne) porta con sé il provider / provider_game_id da cui proviene,
il name, i flag di installazione/uso (is_installed, is_hidden,
is_favorite), le statistiche di gioco (playtime_seconds, play_count,
last_played_at), platform / install_size_bytes / release_date, metadati
ricchi (genres, developers, publishers, cover_image_url, executables —
tutti jsonb), e, fondamentalmente, game_registry_igdb_id, una FK di ritorno verso
eligible_games.igdb_id che collega un titolo posseduto da un giocatore al nostro
catalogo.
È così che rispondiamo a "quali giocatori possiedono giochi che vogliamo
registrare?" — facendo il join di user_game_library con eligible_games
sull'id IGDB.
Modello di accesso
La RLS è abilitata su tutte e otto le tabelle presenti qui. Le tabelle del
catalogo (eligible_games, game_store_ids, game_runtime_profiles,
engine_defaults) sono di sola lettura per qualsiasi utente autenticato. lobbies
e lobby_participants hanno scope di partecipante; user_game_library ha scope di
proprietario; lobby_join_events è riservata al solo service-role (la CRM la legge
tramite la service key).
Vedi anche: riferimento completo delle colonne per queste tabelle.