Players get a fast TTL-backed homepage (local profile / Cloudflare D1) with dense UI polish; login unlocks /home without blocking on every OpenDota refresh. Co-authored-by: Cursor <cursoragent@cursor.com>
115 lines
2.9 KiB
SQL
115 lines
2.9 KiB
SQL
-- Climperor multi-user player data (D1 climperor-users)
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
account_id INTEGER PRIMARY KEY,
|
|
steamid TEXT NOT NULL UNIQUE,
|
|
personaname TEXT,
|
|
avatar TEXT,
|
|
public_share INTEGER NOT NULL DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
last_login_at TEXT
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS player_profiles (
|
|
account_id INTEGER PRIMARY KEY REFERENCES users(account_id),
|
|
rank_tier INTEGER,
|
|
leaderboard_rank INTEGER,
|
|
availability_status TEXT,
|
|
availability_note TEXT,
|
|
availability_complete INTEGER NOT NULL DEFAULT 0,
|
|
source TEXT,
|
|
fetched_at TEXT,
|
|
enriched_at TEXT,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS player_stats (
|
|
account_id INTEGER NOT NULL REFERENCES users(account_id),
|
|
scope TEXT NOT NULL, -- career | recent20 | recent180
|
|
sample INTEGER NOT NULL DEFAULT 0,
|
|
wins INTEGER NOT NULL DEFAULT 0,
|
|
losses INTEGER NOT NULL DEFAULT 0,
|
|
winrate REAL,
|
|
kills INTEGER,
|
|
deaths INTEGER,
|
|
assists INTEGER,
|
|
kda REAL,
|
|
avg_kills REAL,
|
|
avg_deaths REAL,
|
|
avg_assists REAL,
|
|
avg_gpm REAL,
|
|
avg_xpm REAL,
|
|
avg_hero_damage REAL,
|
|
payload_json TEXT,
|
|
updated_at TEXT NOT NULL,
|
|
PRIMARY KEY (account_id, scope)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS player_heroes (
|
|
account_id INTEGER NOT NULL REFERENCES users(account_id),
|
|
hero_id INTEGER NOT NULL,
|
|
hero_key TEXT,
|
|
hero_name_loc TEXT,
|
|
games INTEGER NOT NULL DEFAULT 0,
|
|
wins INTEGER NOT NULL DEFAULT 0,
|
|
winrate REAL,
|
|
last_played INTEGER,
|
|
updated_at TEXT NOT NULL,
|
|
PRIMARY KEY (account_id, hero_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS player_matches (
|
|
account_id INTEGER NOT NULL REFERENCES users(account_id),
|
|
match_id INTEGER NOT NULL,
|
|
start_time INTEGER,
|
|
duration INTEGER,
|
|
won INTEGER,
|
|
hero_id INTEGER,
|
|
hero_key TEXT,
|
|
hero_name_loc TEXT,
|
|
kills INTEGER,
|
|
deaths INTEGER,
|
|
assists INTEGER,
|
|
kda REAL,
|
|
gpm INTEGER,
|
|
xpm INTEGER,
|
|
hero_damage INTEGER,
|
|
game_mode INTEGER,
|
|
lobby_type INTEGER,
|
|
r2_key TEXT,
|
|
updated_at TEXT NOT NULL,
|
|
PRIMARY KEY (account_id, match_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_player_matches_start
|
|
ON player_matches(account_id, start_time DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS player_peers (
|
|
account_id INTEGER NOT NULL REFERENCES users(account_id),
|
|
peer_account_id INTEGER NOT NULL,
|
|
personaname TEXT,
|
|
avatar TEXT,
|
|
games INTEGER NOT NULL DEFAULT 0,
|
|
wins INTEGER NOT NULL DEFAULT 0,
|
|
winrate REAL,
|
|
updated_at TEXT NOT NULL,
|
|
PRIMARY KEY (account_id, peer_account_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS sync_jobs (
|
|
id TEXT PRIMARY KEY,
|
|
account_id INTEGER NOT NULL,
|
|
kind TEXT NOT NULL, -- login_refresh | publish_match | backfill
|
|
match_id INTEGER,
|
|
status TEXT NOT NULL, -- queued | running | done | error
|
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
lease_until TEXT,
|
|
error TEXT,
|
|
next_retry_at TEXT,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sync_jobs_status
|
|
ON sync_jobs(status, next_retry_at);
|