-- FORGE AI Database Schema -- PostgreSQL 16 -- Enable UUID extension CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Users & Authentication CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), azure_oid VARCHAR(255) UNIQUE, email VARCHAR(255) UNIQUE NOT NULL, hashed_password VARCHAR(255), display_name VARCHAR(255), avatar_url TEXT, role VARCHAR(50) DEFAULT 'user', department VARCHAR(255), is_active BOOLEAN DEFAULT true, last_login_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Create test user with password "password123" (bcrypt hash) INSERT INTO users (id, email, hashed_password, display_name, role, is_active) VALUES ( 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'test@forge.ai', '$2b$12$bg3.YrCZnAoL7L/qKzh3lusjFr5J8FZYZswb8j.wVNu4bqPYRtoIG', 'Test User', 'admin', true ); -- API Keys (centralized) CREATE TABLE api_keys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), provider VARCHAR(100) NOT NULL, key_name VARCHAR(255) NOT NULL, encrypted_key TEXT NOT NULL, is_active BOOLEAN DEFAULT true, rate_limit_per_minute INTEGER, monthly_budget DECIMAL(10,2), current_month_usage DECIMAL(10,2) DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Projects CREATE TABLE projects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, name VARCHAR(255) NOT NULL, description TEXT, is_archived BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Create default project for test user INSERT INTO projects (id, user_id, name, description) VALUES ( 'b0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'Default Project', 'Default project for testing' ); -- Assets (images, videos, documents, audio) CREATE TABLE assets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, project_id UUID REFERENCES projects(id) ON DELETE SET NULL, original_filename VARCHAR(500), stored_filename VARCHAR(500) NOT NULL, file_path TEXT NOT NULL, file_type VARCHAR(50) NOT NULL, mime_type VARCHAR(100), file_size_bytes BIGINT, width INTEGER, height INTEGER, duration_seconds DECIMAL(10,2), metadata JSONB DEFAULT '{}', source_module VARCHAR(100), source_job_id UUID, parent_asset_id UUID REFERENCES assets(id), is_temporary BOOLEAN DEFAULT false, expires_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_assets_user ON assets(user_id); CREATE INDEX idx_assets_project ON assets(project_id); CREATE INDEX idx_assets_type ON assets(file_type); CREATE INDEX idx_assets_module ON assets(source_module); -- Jobs (queue management) CREATE TABLE jobs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, project_id UUID REFERENCES projects(id) ON DELETE SET NULL, module VARCHAR(100) NOT NULL, action VARCHAR(100) NOT NULL, priority INTEGER DEFAULT 5, input_data JSONB NOT NULL, output_data JSONB, input_asset_ids UUID[], output_asset_ids UUID[], status VARCHAR(50) DEFAULT 'pending', progress INTEGER DEFAULT 0, error_message TEXT, retry_count INTEGER DEFAULT 0, max_retries INTEGER DEFAULT 3, queued_at TIMESTAMPTZ, started_at TIMESTAMPTZ, completed_at TIMESTAMPTZ, estimated_duration_seconds INTEGER, api_provider VARCHAR(100), api_model VARCHAR(100), api_request_id VARCHAR(255), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_jobs_user ON jobs(user_id); CREATE INDEX idx_jobs_status ON jobs(status); CREATE INDEX idx_jobs_module ON jobs(module); CREATE INDEX idx_jobs_created ON jobs(created_at DESC); -- Usage Tracking CREATE TABLE usage_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, job_id UUID REFERENCES jobs(id) ON DELETE SET NULL, module VARCHAR(100) NOT NULL, action VARCHAR(100) NOT NULL, api_provider VARCHAR(100), api_model VARCHAR(100), tokens_input INTEGER, tokens_output INTEGER, api_credits_used DECIMAL(10,4), estimated_cost_usd DECIMAL(10,4), processing_time_ms INTEGER, request_metadata JSONB, response_metadata JSONB, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_usage_user ON usage_logs(user_id); CREATE INDEX idx_usage_module ON usage_logs(module); CREATE INDEX idx_usage_provider ON usage_logs(api_provider); CREATE INDEX idx_usage_created ON usage_logs(created_at DESC); -- Audit Log CREATE TABLE audit_logs ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, action VARCHAR(100) NOT NULL, entity_type VARCHAR(100), entity_id UUID, old_values JSONB, new_values JSONB, ip_address INET, user_agent TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_audit_user ON audit_logs(user_id); CREATE INDEX idx_audit_action ON audit_logs(action); CREATE INDEX idx_audit_created ON audit_logs(created_at DESC); -- Work History CREATE TABLE work_history ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE SET NULL, session_id UUID, asset_id UUID REFERENCES assets(id) ON DELETE CASCADE, from_module VARCHAR(100), to_module VARCHAR(100), action_type VARCHAR(100), notes TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Saved Prompts CREATE TABLE saved_prompts ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, module VARCHAR(100) NOT NULL, name VARCHAR(255) NOT NULL, prompt_text TEXT NOT NULL, parameters JSONB, is_shared BOOLEAN DEFAULT false, use_count INTEGER DEFAULT 0, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- User Module Settings CREATE TABLE user_module_settings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID REFERENCES users(id) ON DELETE CASCADE, module VARCHAR(100) NOT NULL, settings JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(user_id, module) ); -- Views for Reporting CREATE VIEW v_user_usage_summary AS SELECT u.id as user_id, u.email, u.display_name, COUNT(DISTINCT j.id) as total_jobs, COUNT(DISTINCT CASE WHEN j.status = 'completed' THEN j.id END) as completed_jobs, COALESCE(SUM(ul.estimated_cost_usd), 0) as total_cost FROM users u LEFT JOIN jobs j ON u.id = j.user_id LEFT JOIN usage_logs ul ON u.id = ul.user_id GROUP BY u.id, u.email, u.display_name; CREATE VIEW v_daily_usage AS SELECT DATE(created_at) as date, module, api_provider, COUNT(*) as request_count, COALESCE(SUM(estimated_cost_usd), 0) as total_cost, COALESCE(AVG(processing_time_ms), 0) as avg_processing_time FROM usage_logs GROUP BY DATE(created_at), module, api_provider; -- Grant permissions GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO forge_user; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO forge_user;