-- V1__Initial_Schema.sql -- Create quantengine schema and core tables CREATE SCHEMA IF NOT EXISTS quantengine; -- KIS API Token Cache CREATE TABLE IF NOT EXISTS quantengine.kis_tokens ( account TEXT PRIMARY KEY, access_token TEXT NOT NULL, expires_at TEXT NOT NULL, updated_at TEXT NOT NULL ); -- User Account Management CREATE TABLE IF NOT EXISTS quantengine.workspace_account ( ordinal INT NOT NULL, username TEXT PRIMARY KEY, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'Admin', is_active TEXT NOT NULL DEFAULT 'true', created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_workspace_account_active ON quantengine.workspace_account(is_active, username); -- Session Management CREATE TABLE IF NOT EXISTS quantengine.workspace_session ( session_token_hash TEXT PRIMARY KEY, username TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'Admin', created_at TEXT NOT NULL, expires_at TEXT NOT NULL, revoked_at TEXT ); CREATE INDEX IF NOT EXISTS idx_workspace_session_username ON quantengine.workspace_session(username, expires_at DESC); -- Collection Runs CREATE TABLE IF NOT EXISTS quantengine.collection_runs ( run_id TEXT PRIMARY KEY, collector_name TEXT NOT NULL, started_at TEXT NOT NULL, finished_at TEXT, status TEXT NOT NULL, input_source TEXT, output_json_path TEXT, output_db_path TEXT, notes TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Collection Snapshots CREATE TABLE IF NOT EXISTS quantengine.collection_snapshots ( run_id TEXT NOT NULL, dataset_name TEXT NOT NULL, ticker TEXT NOT NULL, name TEXT, sector TEXT, as_of_date TEXT, source_priority TEXT, source_status TEXT, payload_json TEXT NOT NULL, provenance_json TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (run_id, dataset_name, ticker) ); CREATE INDEX IF NOT EXISTS idx_collection_snapshots_ticker_time ON quantengine.collection_snapshots(ticker, created_at DESC); -- Collection Source Errors CREATE TABLE IF NOT EXISTS quantengine.collection_source_errors ( run_id TEXT NOT NULL, ticker TEXT, source_name TEXT NOT NULL, error_kind TEXT NOT NULL, error_message TEXT NOT NULL, payload_json TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_collection_source_errors_run ON quantengine.collection_source_errors(run_id, source_name); -- Settings CREATE TABLE IF NOT EXISTS quantengine.settings ( ordinal INT NOT NULL, key TEXT PRIMARY KEY, value_json TEXT NOT NULL, note TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL ); -- Account Snapshots CREATE TABLE IF NOT EXISTS quantengine.account_snapshot ( ordinal INT NOT NULL, row_json TEXT NOT NULL, captured_at TEXT NOT NULL DEFAULT '', account TEXT NOT NULL DEFAULT '', account_type TEXT NOT NULL DEFAULT '', ticker TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', parse_status TEXT NOT NULL DEFAULT '', user_confirmed TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_account_snapshot_captured_at ON quantengine.account_snapshot(captured_at); CREATE INDEX IF NOT EXISTS idx_account_snapshot_ticker ON quantengine.account_snapshot(ticker); -- Workspace Metadata CREATE TABLE IF NOT EXISTS quantengine.workspace_meta ( key TEXT PRIMARY KEY, value_json TEXT NOT NULL ); -- Workspace Change Log CREATE TABLE IF NOT EXISTS quantengine.workspace_change_log ( id SERIAL PRIMARY KEY, domain TEXT NOT NULL, action TEXT NOT NULL, target_ref TEXT NOT NULL DEFAULT '', actor TEXT NOT NULL DEFAULT 'system', note TEXT NOT NULL DEFAULT '', before_json TEXT NOT NULL DEFAULT 'null', after_json TEXT NOT NULL DEFAULT 'null', created_at TEXT NOT NULL ); -- Workspace Approval CREATE TABLE IF NOT EXISTS quantengine.workspace_approval_v2 ( domain TEXT NOT NULL, target_ref TEXT NOT NULL DEFAULT '*', status TEXT NOT NULL, approved_by TEXT NOT NULL DEFAULT '', approved_at TEXT NOT NULL DEFAULT '', note TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL, PRIMARY KEY (domain, target_ref) ); -- Workspace Lock CREATE TABLE IF NOT EXISTS quantengine.workspace_lock ( domain TEXT NOT NULL, target_ref TEXT NOT NULL DEFAULT '', locked_by TEXT NOT NULL DEFAULT '', reason TEXT NOT NULL DEFAULT '', locked_at TEXT NOT NULL, PRIMARY KEY (domain, target_ref) );