-- ============================================================================== -- OnEver Drive — PostgreSQL Production Schema -- ============================================================================== CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, hashed_password VARCHAR(255) NOT NULL, full_name VARCHAR(255), role VARCHAR(50) DEFAULT 'ADMIN' NOT NULL, is_active BOOLEAN DEFAULT TRUE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE TABLE IF NOT EXISTS clients ( id SERIAL PRIMARY KEY, client_code VARCHAR(50) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, hostname VARCHAR(255), os_info VARCHAR(255), ip_address VARCHAR(100), agent_version VARCHAR(50) DEFAULT '1.0.0' NOT NULL, status VARCHAR(50) DEFAULT 'OFFLINE' NOT NULL, storage_used_bytes BIGINT DEFAULT 0 NOT NULL, storage_quota_bytes BIGINT DEFAULT 107374182400 NOT NULL, last_seen_at TIMESTAMP WITH TIME ZONE, last_backup_at TIMESTAMP WITH TIME ZONE, is_active BOOLEAN DEFAULT TRUE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE TABLE IF NOT EXISTS client_credentials ( id SERIAL PRIMARY KEY, client_id INTEGER REFERENCES clients(id) ON DELETE CASCADE NOT NULL, device_id VARCHAR(100) UNIQUE NOT NULL, token_hash VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) DEFAULT 'Primary Windows Agent' NOT NULL, is_revoked BOOLEAN DEFAULT FALSE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, last_used_at TIMESTAMP WITH TIME ZONE ); CREATE TABLE IF NOT EXISTS registration_codes ( id SERIAL PRIMARY KEY, code VARCHAR(50) UNIQUE NOT NULL, is_used BOOLEAN DEFAULT FALSE NOT NULL, client_name_hint VARCHAR(255), expires_at TIMESTAMP WITH TIME ZONE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE TABLE IF NOT EXISTS backup_jobs ( id SERIAL PRIMARY KEY, job_code VARCHAR(50) UNIQUE NOT NULL, client_id INTEGER REFERENCES clients(id) ON DELETE CASCADE NOT NULL, name VARCHAR(255) NOT NULL, source_path VARCHAR(1024) NOT NULL, file_patterns VARCHAR(255) DEFAULT '*.bak,*.mdf' NOT NULL, schedule_cron VARCHAR(100) DEFAULT '0 2 * * *' NOT NULL, keep_daily INTEGER DEFAULT 7 NOT NULL, keep_weekly INTEGER DEFAULT 4 NOT NULL, keep_monthly INTEGER DEFAULT 12 NOT NULL, min_stable_time_seconds INTEGER DEFAULT 60 NOT NULL, status VARCHAR(50) DEFAULT 'IDLE' NOT NULL, last_run_at TIMESTAMP WITH TIME ZONE, next_run_at TIMESTAMP WITH TIME ZONE, is_active BOOLEAN DEFAULT TRUE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE TABLE IF NOT EXISTS backup_sessions ( id SERIAL PRIMARY KEY, session_code VARCHAR(100) UNIQUE NOT NULL, client_id INTEGER REFERENCES clients(id) ON DELETE CASCADE NOT NULL, job_id INTEGER REFERENCES backup_jobs(id) ON DELETE CASCADE, filename VARCHAR(512) NOT NULL, file_size BIGINT NOT NULL, chunk_size INTEGER DEFAULT 4194304 NOT NULL, total_chunks INTEGER NOT NULL, received_chunks_count INTEGER DEFAULT 0 NOT NULL, sha256_full VARCHAR(64) NOT NULL, status VARCHAR(50) DEFAULT 'PENDING' NOT NULL, error_message TEXT, started_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, completed_at TIMESTAMP WITH TIME ZONE ); CREATE TABLE IF NOT EXISTS backup_chunks ( id SERIAL PRIMARY KEY, session_id INTEGER REFERENCES backup_sessions(id) ON DELETE CASCADE NOT NULL, chunk_index INTEGER NOT NULL, chunk_size INTEGER NOT NULL, sha256 VARCHAR(64) NOT NULL, is_received BOOLEAN DEFAULT FALSE NOT NULL, received_at TIMESTAMP WITH TIME ZONE, UNIQUE(session_id, chunk_index) ); CREATE TABLE IF NOT EXISTS backup_files ( id SERIAL PRIMARY KEY, client_id INTEGER REFERENCES clients(id) ON DELETE CASCADE NOT NULL, job_id INTEGER REFERENCES backup_jobs(id) ON DELETE CASCADE, session_id INTEGER REFERENCES backup_sessions(id) ON DELETE SET NULL, filename VARCHAR(512) NOT NULL, relative_path VARCHAR(1024) NOT NULL, file_size BIGINT NOT NULL, sha256 VARCHAR(64) NOT NULL, retention_tag VARCHAR(50) DEFAULT 'DAILY' NOT NULL, is_active BOOLEAN DEFAULT TRUE NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL ); CREATE TABLE IF NOT EXISTS event_logs ( id SERIAL PRIMARY KEY, timestamp TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL, event_type VARCHAR(100) NOT NULL, severity VARCHAR(50) DEFAULT 'INFO' NOT NULL, client_id INTEGER, job_id INTEGER, user_email VARCHAR(255), ip_address VARCHAR(100), message TEXT NOT NULL, details_json TEXT ); CREATE INDEX IF NOT EXISTS idx_sessions_client_status ON backup_sessions(client_id, status); CREATE INDEX IF NOT EXISTS idx_event_logs_timestamp ON event_logs(timestamp);