feat: Initial v0.9 release with API Key authentication
## v0.9.20260325_144654 ### Features - API Key Authentication System - Job Worker System - V2 Backup Versioning ### Bug Fixes - get_processor_results_by_job column mapping Co-authored-by: OpenCode
This commit is contained in:
94
migrations/001_api_key_management.sql
Normal file
94
migrations/001_api_key_management.sql
Normal file
@@ -0,0 +1,94 @@
|
||||
-- API Key Management Migration
|
||||
-- Version: 001
|
||||
-- Date: 2026-03-21
|
||||
-- Description: Add API key management tables for secure API access
|
||||
|
||||
-- API Keys Table
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key_id VARCHAR(48) UNIQUE NOT NULL,
|
||||
key_hash VARCHAR(64) NOT NULL,
|
||||
key_prefix VARCHAR(8) NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
key_type VARCHAR(20) NOT NULL DEFAULT 'user',
|
||||
user_id BIGINT,
|
||||
service_name VARCHAR(64),
|
||||
permissions JSONB DEFAULT '["read", "write"]',
|
||||
expires_at TIMESTAMP,
|
||||
last_used_at TIMESTAMP,
|
||||
last_used_ip VARCHAR(45),
|
||||
usage_count BIGINT DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'active',
|
||||
rotation_required BOOLEAN DEFAULT FALSE,
|
||||
rotation_reason TEXT,
|
||||
grace_period_end TIMESTAMP,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Indexes for api_keys
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_key_id ON api_keys(key_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_type ON api_keys(key_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_status ON api_keys(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_user_id ON api_keys(user_id);
|
||||
|
||||
-- API Key Audit Log Table
|
||||
CREATE TABLE IF NOT EXISTS api_key_audit_log (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key_id VARCHAR(32) NOT NULL,
|
||||
action VARCHAR(50) NOT NULL,
|
||||
actor VARCHAR(128),
|
||||
ip_address VARCHAR(45),
|
||||
user_agent TEXT,
|
||||
request_path TEXT,
|
||||
response_code INT,
|
||||
anomaly_type VARCHAR(30),
|
||||
details JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Indexes for audit log
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_key_id ON api_key_audit_log(key_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_action ON api_key_audit_log(action);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_created_at ON api_key_audit_log(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_ip ON api_key_audit_log(ip_address);
|
||||
|
||||
-- API Key Anomalies Table
|
||||
CREATE TABLE IF NOT EXISTS api_key_anomalies (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key_id VARCHAR(32) NOT NULL,
|
||||
anomaly_type VARCHAR(30) NOT NULL,
|
||||
severity VARCHAR(10) NOT NULL,
|
||||
ip_address VARCHAR(45),
|
||||
request_count INT,
|
||||
error_count INT,
|
||||
error_rate DOUBLE PRECISION,
|
||||
unique_ips INT,
|
||||
details JSONB,
|
||||
resolved BOOLEAN DEFAULT FALSE,
|
||||
resolved_at TIMESTAMP,
|
||||
resolved_by VARCHAR(128),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Indexes for anomalies
|
||||
CREATE INDEX IF NOT EXISTS idx_anomalies_key_id ON api_key_anomalies(key_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_anomalies_resolved ON api_key_anomalies(resolved);
|
||||
CREATE INDEX IF NOT EXISTS idx_anomalies_severity ON api_key_anomalies(severity);
|
||||
CREATE INDEX IF NOT EXISTS idx_anomalies_created_at ON api_key_anomalies(created_at);
|
||||
|
||||
-- API Key Types Reference
|
||||
-- System (msys_): Internal system use, 365 days TTL, 72h grace
|
||||
-- User (muser_): User authentication, 90 days TTL, 24h grace
|
||||
-- Service (msvc_): Service-to-service, 180 days TTL, 48h grace
|
||||
-- Integration (mint_): Third-party integrations, 30 days TTL, 24h grace
|
||||
-- Emergency (memg_): Emergency access, 1 day TTL, 0h grace (immediate)
|
||||
|
||||
-- Anomaly Types Reference
|
||||
-- high_request_rate: Requests exceed threshold per minute
|
||||
-- high_error_rate: Error rate exceeds threshold
|
||||
-- multiple_ips: Unusual number of unique IPs
|
||||
-- unusual_time: Activity at unusual hours
|
||||
-- brute_force: Potential brute force attack
|
||||
-- data_exfiltration: Unusual data access patterns
|
||||
140
migrations/003_job_worker.sql
Normal file
140
migrations/003_job_worker.sql
Normal file
@@ -0,0 +1,140 @@
|
||||
-- ================================================================
|
||||
-- Migration 003: Job Worker System
|
||||
-- Version: 003
|
||||
-- Date: 2026-03-24
|
||||
-- Description: Add job worker system tables and columns for
|
||||
-- automatic video processing after registration
|
||||
-- ================================================================
|
||||
|
||||
-- 3.1.1: Update videos table - add status, user_id, job_id columns
|
||||
ALTER TABLE videos ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'pending';
|
||||
ALTER TABLE videos ADD COLUMN IF NOT EXISTS user_id BIGINT;
|
||||
ALTER TABLE videos ADD COLUMN IF NOT EXISTS job_id INTEGER;
|
||||
|
||||
COMMENT ON COLUMN videos.status IS 'Video processing status: pending, processing, completed, failed';
|
||||
COMMENT ON COLUMN videos.user_id IS 'WordPress user ID (for user association tracking)';
|
||||
COMMENT ON COLUMN videos.job_id IS 'Associated monitor_jobs ID';
|
||||
|
||||
-- 3.1.2: Add foreign key for job_id after ensuring monitor_jobs table exists
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_name = 'monitor_jobs'
|
||||
) THEN
|
||||
ALTER TABLE videos ADD CONSTRAINT fk_videos_job_id
|
||||
FOREIGN KEY (job_id) REFERENCES monitor_jobs(id) ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3.1.3: Update monitor_jobs table - add video_id, user_id, processors columns
|
||||
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS video_id BIGINT;
|
||||
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS user_id BIGINT;
|
||||
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS processors VARCHAR(20)[];
|
||||
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS completed_processors VARCHAR(20)[];
|
||||
ALTER TABLE monitor_jobs ADD COLUMN IF NOT EXISTS failed_processors VARCHAR(20)[];
|
||||
|
||||
COMMENT ON COLUMN monitor_jobs.video_id IS 'Foreign key to videos.id';
|
||||
COMMENT ON COLUMN monitor_jobs.user_id IS 'WordPress user ID';
|
||||
COMMENT ON COLUMN monitor_jobs.processors IS 'Processors to run: asr, cut, yolo, ocr, face, pose, asrx';
|
||||
COMMENT ON COLUMN monitor_jobs.completed_processors IS 'Successfully completed processors';
|
||||
COMMENT ON COLUMN monitor_jobs.failed_processors IS 'Failed processors';
|
||||
|
||||
-- 3.1.4: Add foreign key for video_id in monitor_jobs
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'monitor_jobs' AND column_name = 'video_id'
|
||||
) THEN
|
||||
ALTER TABLE monitor_jobs ADD CONSTRAINT fk_monitor_jobs_video_id
|
||||
FOREIGN KEY (video_id) REFERENCES videos(id) ON DELETE CASCADE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3.1.5: Create processor_results table
|
||||
CREATE TABLE IF NOT EXISTS processor_results (
|
||||
id SERIAL PRIMARY KEY,
|
||||
job_id INTEGER REFERENCES monitor_jobs(id) ON DELETE CASCADE,
|
||||
video_id BIGINT REFERENCES videos(id) ON DELETE CASCADE,
|
||||
processor VARCHAR(20) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
output_path TEXT,
|
||||
started_at TIMESTAMP,
|
||||
completed_at TIMESTAMP,
|
||||
error_message TEXT,
|
||||
progress_total INT DEFAULT 0,
|
||||
progress_current INT DEFAULT 0,
|
||||
last_checkpoint JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT unique_job_processor UNIQUE(job_id, processor)
|
||||
);
|
||||
|
||||
-- 3.1.6: Create indexes for processor_results
|
||||
CREATE INDEX IF NOT EXISTS idx_processor_results_job ON processor_results(job_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_processor_results_video ON processor_results(video_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_processor_results_status ON processor_results(status);
|
||||
|
||||
COMMENT ON TABLE processor_results IS 'Tracks individual processor execution status';
|
||||
COMMENT ON COLUMN processor_results.status IS 'pending, running, completed, failed, skipped';
|
||||
|
||||
-- 3.1.7: Add function to update updated_at timestamp
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- 3.1.8: Create triggers for updated_at
|
||||
DROP TRIGGER IF EXISTS update_videos_updated_at ON videos;
|
||||
CREATE TRIGGER update_videos_updated_at
|
||||
BEFORE UPDATE ON videos
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_monitor_jobs_updated_at ON monitor_jobs;
|
||||
CREATE TRIGGER update_monitor_jobs_updated_at
|
||||
BEFORE UPDATE ON monitor_jobs
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
DROP TRIGGER IF EXISTS update_processor_results_updated_at ON processor_results;
|
||||
CREATE TRIGGER update_processor_results_updated_at
|
||||
BEFORE UPDATE ON processor_results
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- 3.1.9: Add check constraint for videos.status
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'videos' AND column_name = 'status'
|
||||
) THEN
|
||||
ALTER TABLE videos ADD CONSTRAINT chk_videos_status
|
||||
CHECK (status IN ('pending', 'processing', 'completed', 'failed'));
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 3.1.10: Add check constraint for monitor_jobs.status (update existing if needed)
|
||||
ALTER TABLE monitor_jobs DROP CONSTRAINT IF EXISTS chk_monitor_jobs_status;
|
||||
ALTER TABLE monitor_jobs ADD CONSTRAINT chk_monitor_jobs_status
|
||||
CHECK (status IN ('pending', 'running', 'completed', 'failed', 'cancelled'));
|
||||
|
||||
-- 3.1.11: Add check constraint for processor_results.status
|
||||
ALTER TABLE processor_results DROP CONSTRAINT IF EXISTS chk_processor_results_status;
|
||||
ALTER TABLE processor_results ADD CONSTRAINT chk_processor_results_status
|
||||
CHECK (status IN ('pending', 'running', 'completed', 'failed', 'skipped'));
|
||||
|
||||
-- 3.1.12: Create index on videos.status for efficient queries
|
||||
CREATE INDEX IF NOT EXISTS idx_videos_status ON videos(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_videos_job_id ON videos(job_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_videos_user_id ON videos(user_id);
|
||||
|
||||
-- 3.1.13: Create index on monitor_jobs.video_id
|
||||
CREATE INDEX IF NOT EXISTS idx_monitor_jobs_video_id ON monitor_jobs(video_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_monitor_jobs_status_created ON monitor_jobs(status, created_at);
|
||||
Reference in New Issue
Block a user