-- Database Schema for Intelligent Planet Plan -- PostgreSQL 15+ with TimescaleDB -- Generated at: 2024-01-20 -- ============================================ -- EXTENSIONS -- ============================================ CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "timescaledb"; -- ============================================ -- ENUMS -- ============================================ CREATE TYPE user_role AS ENUM ('super_admin', 'admin', 'operator', 'viewer'); CREATE TYPE datasource_priority AS ENUM ('P0', 'P1', 'P2'); CREATE TYPE task_status AS ENUM ('pending', 'running', 'success', 'failed', 'cancelled'); CREATE TYPE alert_severity AS ENUM ('critical', 'warning', 'info'); CREATE TYPE alert_status AS ENUM ('active', 'acknowledged', 'resolved'); CREATE TYPE data_module AS ENUM ('L1', 'L2', 'L3', 'L4'); -- ============================================ -- USERS & AUTHENTICATION -- ============================================ CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role user_role NOT NULL DEFAULT 'viewer', is_active BOOLEAN NOT NULL DEFAULT TRUE, last_login_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE INDEX idx_users_username ON users(username); CREATE INDEX idx_users_role ON users(role); CREATE INDEX idx_users_is_active ON users(is_active); CREATE TABLE refresh_tokens ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, token VARCHAR(500) NOT NULL UNIQUE, expires_at TIMESTAMP WITH TIME ZONE NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), revoked_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX idx_refresh_tokens_user ON refresh_tokens(user_id); CREATE INDEX idx_refresh_tokens_token ON refresh_tokens(token); CREATE INDEX idx_refresh_tokens_expires ON refresh_tokens(expires_at); -- ============================================ -- DATA SOURCES -- ============================================ CREATE TABLE data_sources ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, module data_module NOT NULL, priority datasource_priority NOT NULL DEFAULT 'P1', frequency_minutes INTEGER NOT NULL DEFAULT 60, collector_class VARCHAR(100) NOT NULL, config JSONB NOT NULL DEFAULT '{}', is_active BOOLEAN NOT NULL DEFAULT TRUE, last_run_at TIMESTAMP WITH TIME ZONE, last_status task_status, next_run_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE INDEX idx_datasources_module ON data_sources(module); CREATE INDEX idx_datasources_priority ON data_sources(priority); CREATE INDEX idx_datasources_is_active ON data_sources(is_active); CREATE INDEX idx_datasources_next_run ON data_sources(next_run_at); -- ============================================ -- COLLECTION TASKS -- ============================================ CREATE TABLE collection_tasks ( id BIGSERIAL PRIMARY KEY, datasource_id INTEGER NOT NULL REFERENCES data_sources(id) ON DELETE CASCADE, status task_status NOT NULL DEFAULT 'pending', started_at TIMESTAMP WITH TIME ZONE, completed_at TIMESTAMP WITH TIME ZONE, records_processed INTEGER DEFAULT 0, error_message TEXT, traceback TEXT, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE INDEX idx_tasks_datasource ON collection_tasks(datasource_id); CREATE INDEX idx_tasks_status ON collection_tasks(status); CREATE INDEX idx_tasks_created_at ON collection_tasks(created_at DESC); -- Hypertable for time-series queries SELECT create_hypertable('collection_tasks', 'created_at'); -- ============================================ -- GPU CLUSTERS (L1 - Hypertables) -- ============================================ CREATE TABLE gpu_clusters ( time TIMESTAMP WITH TIME ZONE NOT NULL, cluster_id VARCHAR(100) NOT NULL, name VARCHAR(200) NOT NULL, country VARCHAR(100), city VARCHAR(100), latitude DOUBLE PRECISION, longitude DOUBLE PRECISION, organization VARCHAR(200), gpu_count INTEGER, gpu_type VARCHAR(100), total_flops DOUBLE PRECISION, rank INTEGER, source VARCHAR(50) NOT NULL ); SELECT create_hypertable('gpu_clusters', 'time'); CREATE INDEX idx_gpu_clusters_cluster_id ON gpu_clusters(cluster_id); CREATE INDEX idx_gpu_clusters_country ON gpu_clusters(country); CREATE INDEX idx_gpu_clusters_source ON gpu_clusters(source); CREATE INDEX idx_gpu_clusters_time ON gpu_clusters(time DESC); -- Latest snapshot view CREATE VIEW gpu_clusters_latest AS SELECT DISTINCT ON (cluster_id) * FROM gpu_clusters ORDER BY cluster_id, time DESC; -- ============================================ -- MODEL ECOSYSTEM (L1) -- ============================================ CREATE TABLE model_ecosystem ( time TIMESTAMP WITH TIME ZONE NOT NULL, model_id VARCHAR(200) NOT NULL, model_name VARCHAR(200) NOT NULL, publisher VARCHAR(200), downloads INTEGER, likes INTEGER, stars INTEGER, license VARCHAR(100), size_bytes BIGINT, source VARCHAR(50) NOT NULL ); SELECT create_hypertable('model_ecosystem', 'time'); CREATE INDEX idx_models_model_id ON model_ecosystem(model_id); CREATE INDEX idx_models_source ON model_ecosystem(source); CREATE INDEX idx_models_time ON model_ecosystem(time DESC); -- ============================================ -- SUPERCOMPUTERS (L1) -- ============================================ CREATE TABLE supercomputers ( time TIMESTAMP WITH TIME ZONE NOT NULL, rank INTEGER NOT NULL, name VARCHAR(200) NOT NULL, country VARCHAR(100), city VARCHAR(100), latitude DOUBLE PRECISION, longitude DOUBLE PRECISION, organization VARCHAR(200), rmax_tflops DOUBLE PRECISION, rpeak_tflops DOUBLE PRECISION, power_mw DOUBLE PRECISION, cpu_cores INTEGER, accelerator_cores INTEGER, memory_tb DOUBLE PRECISION, interconnect VARCHAR(100), os VARCHAR(100), source VARCHAR(50) NOT NULL ); SELECT create_hypertable('supercomputers', 'time'); CREATE INDEX idx_supercomputers_rank ON supercomputers(rank); CREATE INDEX idx_supercomputers_country ON supercomputers(country); CREATE INDEX idx_supercomputers_time ON supercomputers(time DESC); -- ============================================ -- SUBCABLE CABLES (L2) -- ============================================ CREATE TABLE submarine_cables ( id SERIAL PRIMARY KEY, cable_id VARCHAR(100) NOT NULL UNIQUE, name VARCHAR(200) NOT NULL, length_km INTEGER, owners JSONB DEFAULT '[]', capacity_tbps DOUBLE PRECISION, status VARCHAR(50) DEFAULT 'active', source VARCHAR(50) NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE TABLE cable_landing_points ( id SERIAL PRIMARY KEY, cable_id VARCHAR(100) NOT NULL REFERENCES submarine_cables(cable_id) ON DELETE CASCADE, sequence_number INTEGER NOT NULL, country VARCHAR(100) NOT NULL, city VARCHAR(100), latitude DOUBLE PRECISION NOT NULL, longitude DOUBLE PRECISION NOT NULL, landing_type VARCHAR(50), UNIQUE(cable_id, sequence_number) ); CREATE INDEX idx_cables_name ON submarine_cables(name); CREATE INDEX idx_cables_status ON submarine_cables(status); CREATE INDEX idx_landing_cable ON cable_landing_points(cable_id); -- ============================================ -- IXP NODES (L2) -- ============================================ CREATE TABLE ixp_nodes ( id SERIAL PRIMARY KEY, ixp_id VARCHAR(100) NOT NULL UNIQUE, name VARCHAR(200) NOT NULL, country VARCHAR(100), city VARCHAR(100), latitude DOUBLE PRECISION, longitude DOUBLE PRECISION, member_count INTEGER, traffic_tbps DOUBLE PRECISION, source VARCHAR(50) NOT NULL, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE INDEX idx_ixp_country ON ixp_nodes(country); CREATE INDEX idx_ixp_source ON ixp_nodes(source); -- ============================================ -- CLOUD INFRASTRUCTURE (L1) -- ============================================ CREATE TABLE cloud_infrastructure ( time TIMESTAMP WITH TIME ZONE NOT NULL, provider VARCHAR(100) NOT NULL, region VARCHAR(100) NOT NULL, availability_zone VARCHAR(100), data_center_count INTEGER, total_capacity_mw DOUBLE PRECISION, source VARCHAR(50) NOT NULL ); SELECT create_hypertable('cloud_infrastructure', 'time'); CREATE INDEX idx_cloud_provider ON cloud_infrastructure(provider); CREATE INDEX idx_cloud_region ON cloud_infrastructure(region); CREATE INDEX idx_cloud_time ON cloud_infrastructure(time DESC); -- ============================================ -- ALERTS -- ============================================ CREATE TABLE alert_rules ( id SERIAL PRIMARY KEY, name VARCHAR(200) NOT NULL, description TEXT, datasource_id INTEGER REFERENCES data_sources(id) ON DELETE SET NULL, condition JSONB NOT NULL, severity alert_severity NOT NULL, notification_channels JSONB DEFAULT '[]', is_active BOOLEAN NOT NULL DEFAULT TRUE, cooldown_minutes INTEGER DEFAULT 30, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); CREATE INDEX idx_alert_rules_active ON alert_rules(is_active); CREATE INDEX idx_alert_rules_severity ON alert_rules(severity); CREATE TABLE alerts ( id BIGSERIAL PRIMARY KEY, rule_id INTEGER NOT NULL REFERENCES alert_rules(id), datasource_id INTEGER REFERENCES data_sources(id) ON DELETE SET NULL, severity alert_severity NOT NULL, status alert_status NOT NULL DEFAULT 'active', message TEXT NOT NULL, detail JSONB DEFAULT '{}', acknowledged_by INTEGER REFERENCES users(id), acknowledged_at TIMESTAMP WITH TIME ZONE, resolved_by INTEGER REFERENCES users(id), resolved_at TIMESTAMP WITH TIME ZONE, resolution_note TEXT, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); SELECT create_hypertable('alerts', 'created_at'); CREATE INDEX idx_alerts_status ON alerts(status); CREATE INDEX idx_alerts_severity ON alerts(severity); CREATE INDEX idx_alerts_datasource ON alerts(datasource_id); CREATE INDEX idx_alerts_created ON alerts(created_at DESC); -- ============================================ -- AUDIT LOGS -- ============================================ CREATE TABLE audit_logs ( id BIGSERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, action VARCHAR(100) NOT NULL, resource VARCHAR(100) NOT NULL, resource_id VARCHAR(100), detail JSONB DEFAULT '{}', ip_address INET, user_agent TEXT, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); SELECT create_hypertable('audit_logs', 'created_at'); CREATE INDEX idx_audit_user ON audit_logs(user_id); CREATE INDEX idx_audit_action ON audit_logs(action); CREATE INDEX idx_audit_resource ON audit_logs(resource); CREATE INDEX idx_audit_created ON audit_logs(created_at DESC); -- ============================================ -- SYSTEM CONFIGURATION -- ============================================ CREATE TABLE system_config ( id SERIAL PRIMARY KEY, key VARCHAR(100) NOT NULL UNIQUE, value JSONB NOT NULL, description TEXT, is_sensitive BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); -- Default configurations INSERT INTO system_config (key, value, description) VALUES ('data_retention_days', '30', 'Number of days to retain time-series data'), ('refresh_interval', '300', 'Default WebSocket refresh interval in seconds'), ('timezone', 'Asia/Shanghai', 'System timezone'), ('max_concurrent_tasks', '5', 'Maximum concurrent collection tasks'), ('api_rate_limit', '100', 'API requests per minute per user'), ('jwt_access_token_expire', '900', 'JWT access token expiration in seconds'), ('jwt_refresh_token_expire', '604800', 'JWT refresh token expiration in seconds'); -- ============================================ -- FUNCTIONS & TRIGGERS -- ============================================ -- Updated_at trigger function CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; -- Apply updated_at trigger to all tables with updated_at column CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_datasources_updated_at BEFORE UPDATE ON data_sources FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_alert_rules_updated_at BEFORE UPDATE ON alert_rules FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_system_config_updated_at BEFORE UPDATE ON system_config FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================ -- VIEWS -- ============================================ -- Data source overview CREATE VIEW datasource_overview AS SELECT ds.id, ds.name, ds.module, ds.priority, ds.frequency_minutes, ds.is_active, ds.last_run_at, ds.last_status, COUNT(ct.id) FILTER (WHERE ct.status = 'success') as total_success, COUNT(ct.id) FILTER (WHERE ct.status = 'failed') as total_failed, MAX(ct.created_at) as last_task_at FROM data_sources ds LEFT JOIN collection_tasks ct ON ct.datasource_id = ds.id GROUP BY ds.id; -- System health view CREATE VIEW system_health AS SELECT NOW() as check_time, (SELECT COUNT(*) FROM data_sources WHERE is_active = true) as active_datasources, (SELECT COUNT(*) FROM collection_tasks WHERE status = 'running') as running_tasks, (SELECT COUNT(*) FROM alerts WHERE status = 'active') as active_alerts, (SELECT COUNT(*) FROM users WHERE is_active = true) as active_users; -- ============================================ -- DATA RETENTION POLICY -- ============================================ -- Example: Add retention policy for hypertables -- SELECT add_retention_policy('gpu_clusters', INTERVAL '30 days'); -- SELECT add_retention_policy('collection_tasks', INTERVAL '90 days'); -- SELECT add_retention_policy('audit_logs', INTERVAL '180 days'); -- ============================================ -- ROW LEVEL SECURITY (RLS) -- ============================================ -- Enable RLS for sensitive tables ALTER TABLE users ENABLE ROW LEVEL SECURITY; ALTER TABLE audit_logs ENABLE ROW LEVEL SECURITY; -- RLS policies CREATE POLICY "Admins can view all users" ON users FOR SELECT USING (current_setting('app.current_role', true) IN ('super_admin', 'admin')); CREATE POLICY "Users can view own data" ON users FOR SELECT USING (auth.uid() = id); -- ============================================ -- COMMENTS -- ============================================ COMMENT ON TABLE gpu_clusters IS 'L1: Global AI GPU cluster distribution data'; COMMENT ON TABLE submarine_cables IS 'L2: Submarine cable infrastructure and landing points'; COMMENT ON TABLE ixp_nodes IS 'L2: Internet Exchange Point nodes and connectivity'; COMMENT ON TABLE model_ecosystem IS 'L1: AI model download statistics and ecosystem data'; COMMENT ON TABLE cloud_infrastructure IS 'L1: Cloud data center capacity and distribution';