142 lines
8.3 KiB
SQL
142 lines
8.3 KiB
SQL
-- Initial embedded Turso schema. Every statement is safe to run repeatedly.
|
|
CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT, discord_id TEXT UNIQUE, role TEXT NOT NULL DEFAULT 'user', created_at TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS builds (id TEXT PRIMARY KEY, owner_id TEXT NOT NULL REFERENCES users(id), title TEXT NOT NULL, slug TEXT NOT NULL UNIQUE, visibility TEXT NOT NULL DEFAULT 'draft', summary TEXT, guide_body TEXT, source_build_id TEXT REFERENCES builds(id), created_at TEXT NOT NULL, updated_at TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS build_items (id TEXT PRIMARY KEY, build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE, slot_id TEXT NOT NULL, item_definition_id TEXT NOT NULL, configuration_json TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS ratings (user_id TEXT NOT NULL REFERENCES users(id), build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE, value INTEGER NOT NULL CHECK(value BETWEEN 1 AND 5), PRIMARY KEY(user_id, build_id));
|
|
CREATE TABLE IF NOT EXISTS comments (id TEXT PRIMARY KEY, build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE, user_id TEXT NOT NULL REFERENCES users(id), body TEXT NOT NULL, created_at TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS favorites (user_id TEXT NOT NULL REFERENCES users(id), build_id TEXT NOT NULL REFERENCES builds(id) ON DELETE CASCADE, created_at TEXT NOT NULL, PRIMARY KEY(user_id, build_id));
|
|
CREATE TABLE IF NOT EXISTS equipment_types (id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, category TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS stat_definitions (id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, value_kind TEXT NOT NULL, min_value REAL, max_value REAL, unit TEXT, active INTEGER NOT NULL DEFAULT 1);
|
|
CREATE TABLE IF NOT EXISTS stat_equipment_types (stat_id TEXT NOT NULL REFERENCES stat_definitions(id), equipment_type_id TEXT NOT NULL REFERENCES equipment_types(id), PRIMARY KEY(stat_id, equipment_type_id));
|
|
CREATE TABLE IF NOT EXISTS audit_log (id TEXT PRIMARY KEY, actor_id TEXT NOT NULL REFERENCES users(id), entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, action TEXT NOT NULL, before_json TEXT, after_json TEXT, created_at TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS sessions (id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash TEXT NOT NULL UNIQUE, expires_at TEXT NOT NULL, created_at TEXT NOT NULL);
|
|
CREATE TABLE IF NOT EXISTS roles (id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, description TEXT);
|
|
CREATE TABLE IF NOT EXISTS permissions (id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, description TEXT);
|
|
CREATE TABLE IF NOT EXISTS user_roles (user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, role_id TEXT NOT NULL REFERENCES roles(id) ON DELETE CASCADE, PRIMARY KEY(user_id, role_id));
|
|
CREATE TABLE IF NOT EXISTS role_permissions (role_id TEXT NOT NULL REFERENCES roles(id) ON DELETE CASCADE, permission_id TEXT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE, scope_json TEXT, PRIMARY KEY(role_id, permission_id));
|
|
CREATE TABLE IF NOT EXISTS oauth_states (state_hash TEXT PRIMARY KEY, provider TEXT NOT NULL, mode TEXT NOT NULL, user_id TEXT REFERENCES users(id) ON DELETE CASCADE, expires_at TEXT NOT NULL, created_at TEXT NOT NULL);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS users_username_nocase_idx ON users(username COLLATE NOCASE);
|
|
CREATE TABLE IF NOT EXISTS stat_attributes (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
type TEXT NOT NULL CHECK(type IN ('Offensive', 'Defensive')),
|
|
category TEXT NOT NULL CHECK(category IN ('Weapon', 'Skill', 'Character')),
|
|
calculation_type TEXT NOT NULL CHECK(calculation_type IN ('Additive', 'Multiplicative')),
|
|
unit TEXT NOT NULL DEFAULT 'flat',
|
|
gear_min REAL,
|
|
gear_max REAL,
|
|
weapon_min REAL,
|
|
weapon_max REAL,
|
|
skill_chip_min REAL,
|
|
skill_chip_max REAL,
|
|
cap_value REAL,
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
CHECK((gear_min IS NULL AND gear_max IS NULL) OR (gear_min IS NOT NULL AND gear_max IS NOT NULL AND gear_min <= gear_max)),
|
|
CHECK((weapon_min IS NULL AND weapon_max IS NULL) OR (weapon_min IS NOT NULL AND weapon_max IS NOT NULL AND weapon_min <= weapon_max)),
|
|
CHECK((skill_chip_min IS NULL AND skill_chip_max IS NULL) OR (skill_chip_min IS NOT NULL AND skill_chip_max IS NOT NULL AND skill_chip_min <= skill_chip_max)),
|
|
CHECK(cap_value IS NULL OR cap_value >= 0)
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS stat_attributes_name_nocase_idx ON stat_attributes(name COLLATE NOCASE);
|
|
CREATE TABLE IF NOT EXISTS talents (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
category TEXT NOT NULL CHECK(category IN ('Weapon', 'Backpack', 'Body Armor', 'Vest')),
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS talents_name_category_nocase_idx ON talents(name COLLATE NOCASE, category);
|
|
CREATE TABLE IF NOT EXISTS talent_tiers (
|
|
id TEXT PRIMARY KEY,
|
|
talent_id TEXT NOT NULL REFERENCES talents(id) ON DELETE CASCADE,
|
|
tier TEXT NOT NULL CHECK(tier IN ('I', 'II')),
|
|
description TEXT NOT NULL,
|
|
trigger_text TEXT NOT NULL,
|
|
effect_text TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(talent_id, tier)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS talent_triggers (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
description TEXT NOT NULL,
|
|
supports_uptime INTEGER NOT NULL DEFAULT 0 CHECK(supports_uptime IN (0, 1)),
|
|
min_uptime REAL,
|
|
max_uptime REAL,
|
|
calculation_script TEXT,
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
CHECK(
|
|
(supports_uptime = 0 AND min_uptime IS NULL AND max_uptime IS NULL)
|
|
OR
|
|
(supports_uptime = 1 AND min_uptime IS NOT NULL AND max_uptime IS NOT NULL
|
|
AND min_uptime >= 0 AND max_uptime <= 100 AND min_uptime <= max_uptime)
|
|
)
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS talent_triggers_name_nocase_idx ON talent_triggers(name COLLATE NOCASE);
|
|
CREATE TABLE IF NOT EXISTS talent_tier_triggers (
|
|
talent_tier_id TEXT NOT NULL REFERENCES talent_tiers(id) ON DELETE CASCADE,
|
|
trigger_id TEXT NOT NULL REFERENCES talent_triggers(id),
|
|
PRIMARY KEY(talent_tier_id, trigger_id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS talent_tier_effects (
|
|
id TEXT PRIMARY KEY,
|
|
talent_tier_id TEXT NOT NULL REFERENCES talent_tiers(id) ON DELETE CASCADE,
|
|
stat_attribute_id TEXT NOT NULL REFERENCES stat_attributes(id),
|
|
value REAL NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
UNIQUE(talent_tier_id, stat_attribute_id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS brand_sets (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0, 1)),
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS brand_sets_name_nocase_idx ON brand_sets(name COLLATE NOCASE);
|
|
CREATE TABLE IF NOT EXISTS brand_set_effects (
|
|
id TEXT PRIMARY KEY,
|
|
brand_set_id TEXT NOT NULL REFERENCES brand_sets(id) ON DELETE CASCADE,
|
|
pieces_required INTEGER NOT NULL CHECK(pieces_required IN (2, 3, 4)),
|
|
stat_attribute_id TEXT NOT NULL REFERENCES stat_attributes(id),
|
|
value REAL NOT NULL CHECK(value >= 0),
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(brand_set_id, pieces_required)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS gear (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
slot TEXT NOT NULL CHECK(slot IN ('Holster', 'Gloves', 'Backpack', 'Knee Pads', 'Body Armor', 'Mask')),
|
|
tier INTEGER NOT NULL CHECK(tier BETWEEN 0 AND 2),
|
|
level INTEGER NOT NULL CHECK(level BETWEEN 1 AND 50),
|
|
base_health_min REAL NOT NULL CHECK(base_health_min >= 0),
|
|
base_health_max REAL NOT NULL CHECK(base_health_max >= base_health_min),
|
|
base_armor_min REAL,
|
|
base_armor_max REAL,
|
|
active INTEGER NOT NULL DEFAULT 1 CHECK(active IN (0, 1)),
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
CHECK(
|
|
(slot IN ('Gloves', 'Knee Pads', 'Body Armor') AND base_armor_min IS NOT NULL AND base_armor_max IS NOT NULL AND base_armor_min >= 0 AND base_armor_max >= base_armor_min)
|
|
OR
|
|
(slot NOT IN ('Gloves', 'Knee Pads', 'Body Armor') AND base_armor_min IS NULL AND base_armor_max IS NULL)
|
|
)
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS gear_name_nocase_idx ON gear(name COLLATE NOCASE);
|
|
CREATE TABLE IF NOT EXISTS gear_brand_sets (
|
|
gear_id TEXT NOT NULL REFERENCES gear(id) ON DELETE CASCADE,
|
|
brand_set_id TEXT NOT NULL REFERENCES brand_sets(id),
|
|
PRIMARY KEY(gear_id, brand_set_id)
|
|
);
|
|
CREATE TABLE IF NOT EXISTS gear_talents (
|
|
gear_id TEXT NOT NULL REFERENCES gear(id) ON DELETE CASCADE,
|
|
talent_id TEXT NOT NULL REFERENCES talents(id),
|
|
PRIMARY KEY(gear_id, talent_id)
|
|
);
|