-- Description: SQLite database schema for Lemontropia Suite -- Implements the Data Principle: Every session is a Project -- Schema version: 2.0.0 - Added comprehensive hunting session tracking -- Created: 2026-02-08 -- Updated: 2026-02-09 -- Enable foreign key support PRAGMA foreign_keys = ON; -- ============================================================================ -- PROJECT MANAGEMENT (Data Principle Core) -- ============================================================================ CREATE TABLE IF NOT EXISTS projects ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, type TEXT NOT NULL CHECK (type IN ('hunt', 'mine', 'craft', 'inventory')), status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'paused', 'completed', 'archived')), created_at TEXT, -- ISO format datetime (TEXT to avoid auto-conversion issues) updated_at TEXT, archived_at TEXT, metadata TEXT -- JSON blob for extensible project data ); CREATE INDEX IF NOT EXISTS idx_projects_type ON projects(type); CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status); CREATE INDEX IF NOT EXISTS idx_projects_created ON projects(created_at); -- ============================================================================ -- SESSIONS (Active gameplay instances) -- ============================================================================ CREATE TABLE IF NOT EXISTS sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, project_id INTEGER NOT NULL, started_at TEXT, -- ISO format datetime ended_at TEXT, status TEXT DEFAULT 'running' CHECK (status IN ('running', 'paused', 'completed', 'stopped')), duration_seconds INTEGER DEFAULT 0, total_spent_ped REAL DEFAULT 0.0, -- Decimal stored as REAL, handled in code total_return_ped REAL DEFAULT 0.0, net_profit_ped REAL DEFAULT 0.0, notes TEXT, FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id); CREATE INDEX IF NOT EXISTS idx_sessions_started ON sessions(started_at); -- ============================================================================ -- LOADOUTS (Complete gear configurations) -- ============================================================================ CREATE TABLE IF NOT EXISTS loadouts ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, description TEXT, created_at TEXT, -- ISO format datetime updated_at TEXT, -- Weapon weapon_name TEXT, weapon_damage REAL DEFAULT 0.0, weapon_decay_pec REAL DEFAULT 0.0, weapon_ammo_pec REAL DEFAULT 0.0, weapon_dpp REAL DEFAULT 0.0, weapon_efficiency REAL DEFAULT 0.0, -- Weapon attachments amplifier_name TEXT, amplifier_decay_pec REAL DEFAULT 0.0, scope_name TEXT, scope_decay_pec REAL DEFAULT 0.0, absorber_name TEXT, absorber_decay_pec REAL DEFAULT 0.0, -- Armor armor_name TEXT, armor_decay_per_hp REAL DEFAULT 0.05, -- Plates (JSON: {"head": "Plate Name", "torso": ...}) plates_json TEXT, -- Healing healing_tool_name TEXT, healing_decay_pec REAL DEFAULT 0.0, healing_amount REAL DEFAULT 0.0, -- Mindforce mindforce_implant_name TEXT, mindforce_decay_pec REAL DEFAULT 0.0, -- Accessories (JSON) left_ring TEXT, right_ring TEXT, pet_name TEXT, accessories_json TEXT, -- Enhancers (JSON: {"1": {"name": "...", "decay": 0.01}, ...}) enhancers_json TEXT, -- Per-action costs (pre-calculated) cost_per_shot_ped REAL DEFAULT 0.0, cost_per_hit_ped REAL DEFAULT 0.0, cost_per_heal_ped REAL DEFAULT 0.0, -- Metadata is_active BOOLEAN DEFAULT 0, metadata TEXT -- JSON for extensibility ); CREATE INDEX IF NOT EXISTS idx_loadouts_name ON loadouts(name); CREATE INDEX IF NOT EXISTS idx_loadouts_active ON loadouts(is_active); -- ============================================================================ -- HUNTING SESSIONS (Extended tracking for hunting activities) -- ============================================================================ CREATE TABLE IF NOT EXISTS hunting_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL UNIQUE, loadout_id INTEGER, -- Links to loadouts table started_at TEXT, -- ISO format datetime ended_at TEXT, -- Loot breakdown total_loot_ped REAL DEFAULT 0.0, total_shrapnel_ped REAL DEFAULT 0.0, total_universal_ammo_ped REAL DEFAULT 0.0, total_other_loot_ped REAL DEFAULT 0.0, -- Marketable loot excluding shrapnel/UA -- Cost breakdown (tracked from loadout + actual events) weapon_cost_ped REAL DEFAULT 0.0, armor_cost_ped REAL DEFAULT 0.0, healing_cost_ped REAL DEFAULT 0.0, plates_cost_ped REAL DEFAULT 0.0, enhancer_cost_ped REAL DEFAULT 0.0, mindforce_cost_ped REAL DEFAULT 0.0, total_cost_ped REAL DEFAULT 0.0, -- Combat statistics damage_dealt REAL DEFAULT 0.0, damage_taken REAL DEFAULT 0.0, healing_done REAL DEFAULT 0.0, shots_fired INTEGER DEFAULT 0, shots_missed INTEGER DEFAULT 0, evades INTEGER DEFAULT 0, kills INTEGER DEFAULT 0, hits_taken INTEGER DEFAULT 0, -- Number of times hit by mobs heals_used INTEGER DEFAULT 0, -- Number of heals performed -- Special events globals_count INTEGER DEFAULT 0, hofs_count INTEGER DEFAULT 0, -- Equipment used (snapshot from loadout) weapon_name TEXT, weapon_dpp REAL DEFAULT 0.0, armor_name TEXT, fap_name TEXT, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE, FOREIGN KEY (loadout_id) REFERENCES loadouts(id) ON DELETE SET NULL ); CREATE INDEX IF NOT EXISTS idx_hunting_sessions_session ON hunting_sessions(session_id); CREATE INDEX IF NOT EXISTS idx_hunting_sessions_loadout ON hunting_sessions(loadout_id); CREATE INDEX IF NOT EXISTS idx_hunting_sessions_weapon ON hunting_sessions(weapon_name); -- ============================================================================ -- HUNTING GLOBALS/HoFs (Record of notable loot events) -- ============================================================================ CREATE TABLE IF NOT EXISTS hunting_globals ( id INTEGER PRIMARY KEY AUTOINCREMENT, hunting_session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime creature_name TEXT, value_ped REAL NOT NULL, is_hof BOOLEAN DEFAULT 0, screenshot_path TEXT, FOREIGN KEY (hunting_session_id) REFERENCES hunting_sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_hunting_globals_session ON hunting_globals(hunting_session_id); CREATE INDEX IF NOT EXISTS idx_hunting_globals_value ON hunting_globals(value_ped); -- ============================================================================ -- LOOT EVENTS (Core data capture) -- ============================================================================ CREATE TABLE IF NOT EXISTS loot_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime event_type TEXT NOT NULL CHECK (event_type IN ('global', 'hof', 'regular', 'skill')), -- Loot data item_name TEXT, quantity INTEGER DEFAULT 1, value_ped REAL DEFAULT 0.0, is_shrapnel BOOLEAN DEFAULT 0, is_universal_ammo BOOLEAN DEFAULT 0, -- Context creature_name TEXT, -- For hunter module zone_name TEXT, -- Raw log line for debugging/audit raw_log_line TEXT, -- Screenshot reference (if triggered) screenshot_path TEXT, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_loot_session ON loot_events(session_id); CREATE INDEX IF NOT EXISTS idx_loot_timestamp ON loot_events(timestamp); CREATE INDEX IF NOT EXISTS idx_loot_type ON loot_events(event_type); CREATE INDEX IF NOT EXISTS idx_loot_value ON loot_events(value_ped); -- ============================================================================ -- COMBAT EVENTS (Detailed combat tracking) -- ============================================================================ CREATE TABLE IF NOT EXISTS combat_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime event_type TEXT NOT NULL CHECK (event_type IN ('damage_dealt', 'damage_taken', 'heal', 'evade', 'kill', 'critical_hit')), damage_amount REAL, heal_amount REAL, creature_name TEXT, weapon_name TEXT, raw_log_line TEXT, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_combat_session ON combat_events(session_id); CREATE INDEX IF NOT EXISTS idx_combat_type ON combat_events(event_type); -- ============================================================================ -- SKILL GAINS (Character progression tracking) -- ============================================================================ CREATE TABLE IF NOT EXISTS skill_gains ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime skill_name TEXT NOT NULL, gained_amount REAL DEFAULT 0.0, new_total REAL, raw_log_line TEXT, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_skill_session ON skill_gains(session_id); CREATE INDEX IF NOT EXISTS idx_skill_name ON skill_gains(skill_name); -- ============================================================================ -- DECAY TRACKING (Weapon/tool durability) -- ============================================================================ CREATE TABLE IF NOT EXISTS decay_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime item_name TEXT NOT NULL, decay_amount_ped REAL DEFAULT 0.0, decay_amount_pec REAL DEFAULT 0.0, shots_fired INTEGER DEFAULT 0, raw_log_line TEXT, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_decay_session ON decay_events(session_id); -- ============================================================================ -- SCREENSHOTS (Auto-capture on high-value events) -- ============================================================================ CREATE TABLE IF NOT EXISTS screenshots ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id INTEGER NOT NULL, timestamp TEXT, -- ISO format datetime file_path TEXT NOT NULL, trigger_event TEXT, -- What triggered the screenshot trigger_value_ped REAL, FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE ); CREATE INDEX IF NOT EXISTS idx_screenshots_session ON screenshots(session_id); -- ============================================================================ -- APPLICATION STATE (Singleton table for app settings) -- ============================================================================ CREATE TABLE IF NOT EXISTS app_state ( key TEXT PRIMARY KEY, value TEXT, updated_at TEXT -- ISO format datetime ); -- ============================================================================ -- DATABASE VERSION TRACKING -- ============================================================================ CREATE TABLE IF NOT EXISTS schema_version ( version INTEGER PRIMARY KEY, applied_at TEXT, -- ISO format datetime description TEXT ); -- Insert/update version INSERT OR REPLACE INTO schema_version (version, description) VALUES (2, 'Added comprehensive hunting session tracking with loot/cost breakdown'); -- ============================================================================ -- VIEWS FOR COMMON QUERIES (Performance optimization) -- ============================================================================ -- Active project summary CREATE VIEW IF NOT EXISTS v_project_summary AS SELECT p.id, p.name, p.type, p.status, p.created_at, COUNT(DISTINCT s.id) as session_count, SUM(s.total_spent_ped) as total_spent, SUM(s.total_return_ped) as total_return, SUM(s.net_profit_ped) as net_profit, SUM(CASE WHEN l.event_type = 'global' THEN 1 ELSE 0 END) as global_count, SUM(CASE WHEN l.event_type = 'hof' THEN 1 ELSE 0 END) as hof_count FROM projects p LEFT JOIN sessions s ON p.id = s.project_id LEFT JOIN loot_events l ON s.id = l.session_id GROUP BY p.id; -- Session performance metrics CREATE VIEW IF NOT EXISTS v_session_metrics AS SELECT s.id, s.project_id, p.name as project_name, s.started_at, s.ended_at, s.duration_seconds, s.total_spent_ped, s.total_return_ped, s.net_profit_ped, CASE WHEN s.total_spent_ped > 0 THEN ROUND((s.net_profit_ped / s.total_spent_ped) * 100, 2) ELSE 0 END as roi_percent, COUNT(l.id) as loot_events, SUM(CASE WHEN l.event_type IN ('global', 'hof') THEN 1 ELSE 0 END) as notable_events FROM sessions s JOIN projects p ON s.project_id = p.id LEFT JOIN loot_events l ON s.id = l.session_id GROUP BY s.id; -- Hunting session detailed view CREATE VIEW IF NOT EXISTS v_hunting_session_summary AS SELECT hs.id, hs.session_id, s.project_id, p.name as project_name, hs.started_at, hs.ended_at, hs.total_loot_ped, hs.total_other_loot_ped, hs.total_cost_ped, hs.damage_dealt, hs.kills, hs.globals_count, hs.hofs_count, hs.weapon_name, hs.weapon_dpp, CASE WHEN hs.total_cost_ped > 0 THEN ROUND((hs.total_other_loot_ped / hs.total_cost_ped) * 100, 2) ELSE 0 END as return_percent, CASE WHEN hs.kills > 0 THEN ROUND(hs.total_cost_ped / hs.kills, 4) ELSE 0 END as cost_per_kill, CASE WHEN hs.total_cost_ped > 0 THEN ROUND(hs.damage_dealt / hs.total_cost_ped, 2) ELSE 0 END as dpp FROM hunting_sessions hs JOIN sessions s ON hs.session_id = s.id JOIN projects p ON s.project_id = p.id; -- Weapon performance analysis CREATE VIEW IF NOT EXISTS v_weapon_performance AS SELECT weapon_name, COUNT(*) as sessions_count, AVG(total_other_loot_ped) as avg_loot, AVG(total_cost_ped) as avg_cost, AVG(CASE WHEN total_cost_ped > 0 THEN (total_other_loot_ped / total_cost_ped) * 100 ELSE 0 END) as avg_return_percent, AVG(dpp) as avg_dpp, SUM(kills) as total_kills, SUM(globals_count) as total_globals, SUM(hofs_count) as total_hofs FROM hunting_sessions WHERE weapon_name IS NOT NULL AND weapon_name != '' GROUP BY weapon_name;