mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-19 05:47:02 +00:00
266 lines
10 KiB
SQL
266 lines
10 KiB
SQL
-- 20260717000000_schema.sql — Consolidated schema for x0gp catalog, races, and drivers.
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Tracks & Waypoints
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS tracks (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
author_id TEXT NOT NULL DEFAULT 'system',
|
|
visibility TEXT NOT NULL DEFAULT 'system' CHECK (visibility IN ('system', 'public', 'private')),
|
|
scale INT NOT NULL DEFAULT 27,
|
|
length_m DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
width_m DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
lane_width_m DOUBLE PRECISION NOT NULL DEFAULT 0.20,
|
|
surface TEXT NOT NULL DEFAULT 'carpet' CHECK (surface IN ('carpet', 'tile', 'wood', 'paper', 'mixed')),
|
|
best_lap_ms BIGINT NOT NULL DEFAULT 0,
|
|
best_lap_holder TEXT NOT NULL DEFAULT '',
|
|
bounds_min_x DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
bounds_min_y DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
bounds_max_x DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
bounds_max_y DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
created_ms BIGINT NOT NULL,
|
|
updated_ms BIGINT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS tracks_visibility_idx ON tracks (visibility);
|
|
CREATE INDEX IF NOT EXISTS tracks_author_idx ON tracks (author_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS track_waypoints (
|
|
track_id TEXT NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
|
|
seq INT NOT NULL,
|
|
x DOUBLE PRECISION NOT NULL,
|
|
y DOUBLE PRECISION NOT NULL,
|
|
heading_rad DOUBLE PRECISION NOT NULL,
|
|
speed_ms DOUBLE PRECISION NOT NULL,
|
|
curvature DOUBLE PRECISION NOT NULL,
|
|
PRIMARY KEY (track_id, seq)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS track_tags (
|
|
track_id TEXT NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
|
|
tag TEXT NOT NULL,
|
|
PRIMARY KEY (track_id, tag)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS track_tags_tag_idx ON track_tags (tag);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Cars
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS cars (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
owner_id TEXT NOT NULL DEFAULT 'system',
|
|
visibility TEXT NOT NULL DEFAULT 'system' CHECK (visibility IN ('system', 'public', 'private')),
|
|
scale INT NOT NULL DEFAULT 27,
|
|
|
|
length_mm DOUBLE PRECISION NOT NULL,
|
|
width_mm DOUBLE PRECISION NOT NULL,
|
|
height_mm DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
weight_g DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
|
|
chassis_model TEXT NOT NULL DEFAULT '',
|
|
chassis_material TEXT NOT NULL DEFAULT '',
|
|
chassis_printed BOOLEAN NOT NULL DEFAULT FALSE,
|
|
chassis_wheelbase_mm DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
chassis_track_mm DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
|
|
motor_kind TEXT NOT NULL DEFAULT 'brushed',
|
|
motor_class TEXT NOT NULL DEFAULT '',
|
|
motor_kv INT NOT NULL DEFAULT 0,
|
|
motor_power_w DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
|
|
battery_voltage_v DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
battery_capacity_mah INT NOT NULL DEFAULT 0,
|
|
battery_cells INT NOT NULL DEFAULT 0,
|
|
battery_chemistry TEXT NOT NULL DEFAULT 'li-po',
|
|
|
|
drive TEXT NOT NULL DEFAULT '2WD' CHECK (drive IN ('2WD', '4WD')),
|
|
|
|
top_speed_ms DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
color_hex TEXT NOT NULL DEFAULT '#ff6b1a',
|
|
avatar_url TEXT NOT NULL DEFAULT '',
|
|
active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
|
|
total_distance_m DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
total_races INT NOT NULL DEFAULT 0,
|
|
total_laps INT NOT NULL DEFAULT 0,
|
|
best_lap_ms BIGINT NOT NULL DEFAULT 0,
|
|
|
|
created_ms BIGINT NOT NULL,
|
|
updated_ms BIGINT NOT NULL,
|
|
device_id INT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS cars_visibility_idx ON cars (visibility);
|
|
CREATE INDEX IF NOT EXISTS cars_owner_idx ON cars (owner_id);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Clans & Drivers
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS clans (
|
|
id TEXT PRIMARY KEY,
|
|
tag TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
avatar_url TEXT NOT NULL DEFAULT '',
|
|
created_ms BIGINT NOT NULL,
|
|
updated_ms BIGINT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS clans_tag_idx ON clans (tag);
|
|
|
|
CREATE TABLE IF NOT EXISTS drivers (
|
|
id TEXT PRIMARY KEY,
|
|
nickname TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
avatar_url TEXT NOT NULL DEFAULT '',
|
|
clan_id TEXT REFERENCES clans(id) ON DELETE SET NULL,
|
|
created_ms BIGINT NOT NULL,
|
|
updated_ms BIGINT NOT NULL
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS drivers_nickname_idx ON drivers (nickname);
|
|
CREATE INDEX IF NOT EXISTS drivers_clan_idx ON drivers (clan_id);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Races & Race Drivers
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS races (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
track_id TEXT NOT NULL DEFAULT '',
|
|
max_cars INT NOT NULL,
|
|
laps INT NOT NULL,
|
|
time_limit_s INT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'lobby' CHECK (status IN ('lobby', 'countdown', 'racing', 'finished', 'cancelled')),
|
|
created_ms BIGINT NOT NULL,
|
|
started_ms BIGINT NOT NULL DEFAULT 0,
|
|
finished_ms BIGINT NOT NULL DEFAULT 0,
|
|
duration_ms BIGINT NOT NULL DEFAULT 0,
|
|
total_laps INT NOT NULL DEFAULT 0,
|
|
total_drivers INT NOT NULL DEFAULT 0,
|
|
updated_ms BIGINT NOT NULL DEFAULT 0
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS races_status_finished_idx ON races (status, finished_ms DESC, id DESC);
|
|
CREATE INDEX IF NOT EXISTS races_started_idx ON races (status, started_ms DESC, id DESC);
|
|
CREATE INDEX IF NOT EXISTS races_track_idx ON races (track_id);
|
|
CREATE INDEX IF NOT EXISTS races_status_idx ON races (status);
|
|
|
|
CREATE TABLE IF NOT EXISTS race_drivers (
|
|
race_id TEXT NOT NULL REFERENCES races(id) ON DELETE CASCADE,
|
|
driver_id TEXT NOT NULL,
|
|
slot INT NOT NULL DEFAULT 0,
|
|
joined_ms BIGINT NOT NULL,
|
|
total_time_ms BIGINT NOT NULL DEFAULT 0,
|
|
best_lap_ms BIGINT NOT NULL DEFAULT 0,
|
|
position INT,
|
|
PRIMARY KEY (race_id, driver_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS race_drivers_driver_idx ON race_drivers (driver_id);
|
|
CREATE INDEX IF NOT EXISTS race_drivers_podium_idx ON race_drivers (race_id, total_time_ms ASC, position ASC) WHERE total_time_ms > 0;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Race Plans & Queue
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS race_plans (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
track_id TEXT NOT NULL DEFAULT 'default',
|
|
max_cars INT NOT NULL,
|
|
laps INT NOT NULL DEFAULT 0,
|
|
time_limit_s INT NOT NULL DEFAULT 0,
|
|
start_at_ms BIGINT NOT NULL,
|
|
interval_s INT NOT NULL DEFAULT 0, -- 0 = single-shot
|
|
count INT NOT NULL DEFAULT 0, -- 0 = repeat forever
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
created_ms BIGINT NOT NULL,
|
|
updated_ms BIGINT NOT NULL,
|
|
next_fire_ms BIGINT NOT NULL, -- last materialised fire time
|
|
fires_done INT NOT NULL DEFAULT 0
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS race_plans_start_idx ON race_plans (start_at_ms ASC, id ASC);
|
|
CREATE INDEX IF NOT EXISTS race_plans_enabled_idx ON race_plans (enabled, next_fire_ms);
|
|
|
|
CREATE TABLE IF NOT EXISTS race_queue (
|
|
driver_id TEXT NOT NULL,
|
|
race_id TEXT NOT NULL,
|
|
plan_id TEXT NOT NULL DEFAULT '',
|
|
enqueued_ms BIGINT NOT NULL,
|
|
PRIMARY KEY (driver_id, race_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS race_queue_race_idx ON race_queue (race_id);
|
|
CREATE INDEX IF NOT EXISTS race_queue_driver_idx ON race_queue (driver_id, enqueued_ms);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Lobby Drivers
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS lobby_drivers (
|
|
driver_id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL DEFAULT '',
|
|
nickname TEXT NOT NULL DEFAULT '',
|
|
avatar_url TEXT NOT NULL DEFAULT '',
|
|
clan_id TEXT NOT NULL DEFAULT '',
|
|
clan_tag TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'idle' CHECK (status IN ('idle', 'racing', 'offline')),
|
|
current_race_id TEXT NOT NULL DEFAULT '',
|
|
connected_ms BIGINT NOT NULL,
|
|
last_seen_ms BIGINT NOT NULL,
|
|
car_id TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS lobby_drivers_status_idx ON lobby_drivers (status);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Track Calendar
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS track_calendar (
|
|
id SERIAL PRIMARY KEY,
|
|
track_id TEXT NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
|
|
start_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
end_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
CHECK (start_at < end_at)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS track_calendar_dates_idx ON track_calendar (start_at, end_at);
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Go Migration Metadata (Bridges Go server startup migrations and Supabase)
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version TEXT PRIMARY KEY,
|
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
INSERT INTO schema_migrations (version) VALUES
|
|
('001_init.sql'),
|
|
('002_seed.sql'),
|
|
('003_f1_seed.sql'),
|
|
('004_monaco_rescale.sql'),
|
|
('005_races.sql'),
|
|
('006_drop_host.sql'),
|
|
('007_podium.sql'),
|
|
('008_drivers_clans.sql'),
|
|
('009_live_persistence.sql'),
|
|
('010_unify_races.sql'),
|
|
('011_drop_driver_ids.sql'),
|
|
('012_normalize_race_results.sql'),
|
|
('013_driver_device.sql'),
|
|
('014_track_calendar.sql'),
|
|
('015_driver_car_id.sql')
|
|
ON CONFLICT (version) DO NOTHING;
|
|
|