CREATE TABLE IF NOT EXISTS users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL, username VARCHAR(100) NOT NULL, password_hash VARCHAR(255) NOT NULL, avatar_url VARCHAR(500) DEFAULT NULL, created_at DATETIME DEFAULT NOW(), UNIQUE KEY uq_users_email (email) ); CREATE TABLE IF NOT EXISTS campaigns ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, created_at DATETIME DEFAULT NOW() ); CREATE TABLE IF NOT EXISTS campaign_members ( campaign_id INT UNSIGNED NOT NULL, user_id INT UNSIGNED NOT NULL, role ENUM('dm', 'player') NOT NULL, joined_at DATETIME DEFAULT NOW(), PRIMARY KEY (campaign_id, user_id), FOREIGN KEY (campaign_id) REFERENCES campaigns(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS campaign_invites ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, campaign_id INT UNSIGNED NOT NULL, token VARCHAR(64) NOT NULL, created_by INT UNSIGNED NOT NULL, expires_at DATETIME DEFAULT NULL, created_at DATETIME DEFAULT NOW(), UNIQUE KEY uq_invites_token (token), FOREIGN KEY (campaign_id) REFERENCES campaigns(id) ON DELETE CASCADE, FOREIGN KEY (created_by) REFERENCES users(id) ); CREATE TABLE IF NOT EXISTS characters ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, campaign_id INT UNSIGNED NOT NULL, user_id INT UNSIGNED DEFAULT NULL, name VARCHAR(255) NOT NULL, class VARCHAR(100) NOT NULL DEFAULT 'Fighter', ancestry VARCHAR(100) NOT NULL DEFAULT 'Human', level INT NOT NULL DEFAULT 1, xp INT NOT NULL DEFAULT 0, hp_current INT NOT NULL DEFAULT 0, hp_max INT NOT NULL DEFAULT 0, ac INT NOT NULL DEFAULT 10, alignment VARCHAR(50) NOT NULL DEFAULT 'Neutral', title VARCHAR(255) DEFAULT '', notes TEXT DEFAULT '', background VARCHAR(255) DEFAULT '', deity VARCHAR(255) DEFAULT '', languages VARCHAR(500) DEFAULT '', gp INT NOT NULL DEFAULT 0, sp INT NOT NULL DEFAULT 0, cp INT NOT NULL DEFAULT 0, gear_slots_max INT NOT NULL DEFAULT 10, overrides TEXT DEFAULT '{}', color VARCHAR(100) DEFAULT '', luck_token TINYINT NOT NULL DEFAULT 1, torch_lit_at DATETIME DEFAULT NULL, FOREIGN KEY (campaign_id) REFERENCES campaigns(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL ); CREATE TABLE IF NOT EXISTS character_stats ( character_id INT UNSIGNED NOT NULL, stat_name VARCHAR(10) NOT NULL, value INT NOT NULL DEFAULT 10, PRIMARY KEY (character_id, stat_name), FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS character_gear ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, character_id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL DEFAULT 'gear', slot_count INT NOT NULL DEFAULT 1, properties TEXT DEFAULT '{}', effects TEXT DEFAULT '{}', game_item_id INT UNSIGNED DEFAULT NULL, FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS character_talents ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, character_id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, description TEXT DEFAULT '', effect TEXT DEFAULT '{}', game_talent_id INT UNSIGNED DEFAULT NULL, FOREIGN KEY (character_id) REFERENCES characters(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS game_items ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL, slot_count INT NOT NULL DEFAULT 1, effects TEXT DEFAULT '{}', properties TEXT DEFAULT '{}' ); CREATE TABLE IF NOT EXISTS game_talents ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL, source VARCHAR(255) NOT NULL, description TEXT DEFAULT '', effect TEXT DEFAULT '{}' ); CREATE TABLE IF NOT EXISTS roll_log ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, campaign_id INT UNSIGNED NOT NULL, character_id INT UNSIGNED DEFAULT NULL, character_name VARCHAR(255) NOT NULL DEFAULT 'Roll', type VARCHAR(50) NOT NULL DEFAULT 'custom', label VARCHAR(255) NOT NULL, dice_expression VARCHAR(255) NOT NULL, rolls TEXT NOT NULL DEFAULT '[]', modifier INT NOT NULL DEFAULT 0, total INT NOT NULL DEFAULT 0, advantage TINYINT NOT NULL DEFAULT 0, disadvantage TINYINT NOT NULL DEFAULT 0, nat20 TINYINT NOT NULL DEFAULT 0, character_color VARCHAR(100) DEFAULT '', created_at DATETIME DEFAULT NOW(), FOREIGN KEY (campaign_id) REFERENCES campaigns(id) ON DELETE CASCADE );