CREATE TABLE technician_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, token_hash BLOB NOT NULL UNIQUE, csrf_token TEXT NOT NULL, gitea_login TEXT NOT NULL, display_name TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME NOT NULL, last_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_technician_sessions_expires ON technician_sessions(expires_at); CREATE TABLE packages ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT NOT NULL UNIQUE, display_name TEXT NOT NULL, package_name TEXT NOT NULL, package_version TEXT NOT NULL, file_name TEXT NOT NULL, sha256 TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE authorizations ( id INTEGER PRIMARY KEY AUTOINCREMENT, code_hash BLOB NOT NULL UNIQUE, code_hint TEXT NOT NULL, created_by TEXT NOT NULL, customer_label TEXT NOT NULL DEFAULT '', host_limit INTEGER NOT NULL CHECK (host_limit > 0), created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME NOT NULL, revoked_at DATETIME ); CREATE INDEX idx_authorizations_expires ON authorizations(expires_at); CREATE INDEX idx_authorizations_created_by ON authorizations(created_by, created_at); CREATE TABLE authorization_packages ( authorization_id INTEGER NOT NULL, package_id INTEGER NOT NULL, package_slug TEXT NOT NULL, display_name TEXT NOT NULL, package_name TEXT NOT NULL, package_version TEXT NOT NULL, file_name TEXT NOT NULL, sha256 TEXT NOT NULL, PRIMARY KEY (authorization_id, package_id), FOREIGN KEY (authorization_id) REFERENCES authorizations(id) ON DELETE CASCADE, FOREIGN KEY (package_id) REFERENCES packages(id) ON DELETE RESTRICT ); CREATE TABLE authorization_hosts ( id INTEGER PRIMARY KEY AUTOINCREMENT, authorization_id INTEGER NOT NULL, host_fingerprint BLOB NOT NULL, hostname TEXT NOT NULL, first_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, last_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE (authorization_id, host_fingerprint), FOREIGN KEY (authorization_id) REFERENCES authorizations(id) ON DELETE CASCADE ); CREATE TABLE download_sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, token_hash BLOB NOT NULL UNIQUE, authorization_id INTEGER NOT NULL, authorization_host_id INTEGER NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME NOT NULL, revoked_at DATETIME, FOREIGN KEY (authorization_id) REFERENCES authorizations(id) ON DELETE CASCADE, FOREIGN KEY (authorization_host_id) REFERENCES authorization_hosts(id) ON DELETE CASCADE ); CREATE INDEX idx_download_sessions_expires ON download_sessions(expires_at); CREATE TABLE audit_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_type TEXT NOT NULL, actor TEXT NOT NULL DEFAULT '', authorization_id INTEGER, hostname TEXT NOT NULL DEFAULT '', package_slug TEXT NOT NULL DEFAULT '', source_ip TEXT NOT NULL DEFAULT '', details TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_audit_created ON audit_events(created_at); CREATE INDEX idx_audit_authorization ON audit_events(authorization_id, created_at); CREATE INDEX idx_audit_exchange_limit ON audit_events(event_type, source_ip, created_at); CREATE TABLE installer_actions ( slug TEXT NOT NULL PRIMARY KEY, display_name TEXT NOT NULL, sort_order INTEGER NOT NULL DEFAULT 0, enabled INTEGER NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE authorization_actions ( authorization_id INTEGER NOT NULL, action_slug TEXT NOT NULL, PRIMARY KEY (authorization_id, action_slug), FOREIGN KEY (authorization_id) REFERENCES authorizations(id) ON DELETE CASCADE, FOREIGN KEY (action_slug) REFERENCES installer_actions(slug) ON DELETE RESTRICT ); INSERT INTO installer_actions (slug, display_name, sort_order, enabled) VALUES ('install-rmm', 'Install ConnectWise RMM agent', 10, 1), ('install-acronis', 'Install Acronis agent', 20, 1), ('install-screenconnect', 'Install ScreenConnect agent', 30, 1);