diff --git a/db/migrations/0031_phase2_observability_and_pooling.sql b/db/migrations/0031_phase2_observability_and_pooling.sql index add042c1..11568f84 100644 --- a/db/migrations/0031_phase2_observability_and_pooling.sql +++ b/db/migrations/0031_phase2_observability_and_pooling.sql @@ -20,9 +20,9 @@ CREATE TABLE IF NOT EXISTS opendata.opendart_cache ( UNIQUE(ticker, quarter) ); -CREATE INDEX idx_opendart_cache_ticker ON opendata.opendart_cache(ticker); -CREATE INDEX idx_opendart_cache_expires_at ON opendata.opendart_cache(expires_at); -CREATE INDEX idx_opendart_cache_published_at ON opendata.opendart_cache(published_at); +CREATE INDEX IF NOT EXISTS idx_opendart_cache_ticker ON opendata.opendart_cache(ticker); +CREATE INDEX IF NOT EXISTS idx_opendart_cache_expires_at ON opendata.opendart_cache(expires_at); +CREATE INDEX IF NOT EXISTS idx_opendart_cache_published_at ON opendata.opendart_cache(published_at); -- OpenDart batch execution log CREATE TABLE IF NOT EXISTS opendata.opendart_batch_log ( @@ -38,8 +38,8 @@ CREATE TABLE IF NOT EXISTS opendata.opendart_batch_log ( UNIQUE(batch_date) ); -CREATE INDEX idx_opendart_batch_log_batch_date ON opendata.opendart_batch_log(batch_date); -CREATE INDEX idx_opendart_batch_log_status ON opendata.opendart_batch_log(status); +CREATE INDEX IF NOT EXISTS idx_opendart_batch_log_batch_date ON opendata.opendart_batch_log(batch_date); +CREATE INDEX IF NOT EXISTS idx_opendart_batch_log_status ON opendata.opendart_batch_log(status); -- ============================================================================ -- KIS SCHEMA: Korea Investment & Securities Connection Pool @@ -62,9 +62,9 @@ CREATE TABLE IF NOT EXISTS kis.connection_pool_state ( UNIQUE(connection_id) ); -CREATE INDEX idx_kis_connection_pool_state ON kis.connection_pool_state(state); -CREATE INDEX idx_kis_connection_pool_expires_at ON kis.connection_pool_state(expires_at); -CREATE INDEX idx_kis_connection_pool_priority ON kis.connection_pool_state(priority); +CREATE INDEX IF NOT EXISTS idx_kis_connection_pool_state ON kis.connection_pool_state(state); +CREATE INDEX IF NOT EXISTS idx_kis_connection_pool_expires_at ON kis.connection_pool_state(expires_at); +CREATE INDEX IF NOT EXISTS idx_kis_connection_pool_priority ON kis.connection_pool_state(priority); -- KIS token refresh log CREATE TABLE IF NOT EXISTS kis.token_refresh_log ( @@ -78,9 +78,9 @@ CREATE TABLE IF NOT EXISTS kis.token_refresh_log ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_kis_token_refresh_connection_id ON kis.token_refresh_log(connection_id); -CREATE INDEX idx_kis_token_refresh_status ON kis.token_refresh_log(status); -CREATE INDEX idx_kis_token_refresh_executed_at ON kis.token_refresh_log(executed_at); +CREATE INDEX IF NOT EXISTS idx_kis_token_refresh_connection_id ON kis.token_refresh_log(connection_id); +CREATE INDEX IF NOT EXISTS idx_kis_token_refresh_status ON kis.token_refresh_log(status); +CREATE INDEX IF NOT EXISTS idx_kis_token_refresh_executed_at ON kis.token_refresh_log(executed_at); -- ============================================================================ -- INFRASTRUCTURE SCHEMA: Rate Limiting & Circuit Breaker @@ -102,7 +102,7 @@ CREATE TABLE IF NOT EXISTS infrastructure.rate_limit_quota ( UNIQUE(api_name) ); -CREATE INDEX idx_rate_limit_quota_api_name ON infrastructure.rate_limit_quota(api_name); +CREATE INDEX IF NOT EXISTS idx_rate_limit_quota_api_name ON infrastructure.rate_limit_quota(api_name); -- Rate limit events (for audit trail) CREATE TABLE IF NOT EXISTS infrastructure.rate_limit_events ( @@ -117,8 +117,8 @@ CREATE TABLE IF NOT EXISTS infrastructure.rate_limit_events ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_rate_limit_events_api_name ON infrastructure.rate_limit_events(api_name); -CREATE INDEX idx_rate_limit_events_occurred_at ON infrastructure.rate_limit_events(occurred_at); +CREATE INDEX IF NOT EXISTS idx_rate_limit_events_api_name ON infrastructure.rate_limit_events(api_name); +CREATE INDEX IF NOT EXISTS idx_rate_limit_events_occurred_at ON infrastructure.rate_limit_events(occurred_at); -- Circuit breaker state CREATE TABLE IF NOT EXISTS infrastructure.circuit_breaker_state ( @@ -135,7 +135,7 @@ CREATE TABLE IF NOT EXISTS infrastructure.circuit_breaker_state ( UNIQUE(api_name) ); -CREATE INDEX idx_circuit_breaker_state_api_name ON infrastructure.circuit_breaker_state(api_name); +CREATE INDEX IF NOT EXISTS idx_circuit_breaker_state_api_name ON infrastructure.circuit_breaker_state(api_name); -- Circuit breaker events (for audit trail) CREATE TABLE IF NOT EXISTS infrastructure.circuit_breaker_events ( @@ -148,8 +148,8 @@ CREATE TABLE IF NOT EXISTS infrastructure.circuit_breaker_events ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_circuit_breaker_events_api_name ON infrastructure.circuit_breaker_events(api_name); -CREATE INDEX idx_circuit_breaker_events_occurred_at ON infrastructure.circuit_breaker_events(occurred_at); +CREATE INDEX IF NOT EXISTS idx_circuit_breaker_events_api_name ON infrastructure.circuit_breaker_events(api_name); +CREATE INDEX IF NOT EXISTS idx_circuit_breaker_events_occurred_at ON infrastructure.circuit_breaker_events(occurred_at); -- ============================================================================ -- OBSERVABILITY SCHEMA: Metrics & Monitoring @@ -170,8 +170,8 @@ CREATE TABLE IF NOT EXISTS observability.batch_sla_metrics ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_batch_sla_job_name ON observability.batch_sla_metrics(job_name); -CREATE INDEX idx_batch_sla_completed_at ON observability.batch_sla_metrics(completed_at); +CREATE INDEX IF NOT EXISTS idx_batch_sla_job_name ON observability.batch_sla_metrics(job_name); +CREATE INDEX IF NOT EXISTS idx_batch_sla_completed_at ON observability.batch_sla_metrics(completed_at); -- Data quality quarantine (rows marked for manual review) CREATE TABLE IF NOT EXISTS observability.data_quality_quarantine ( @@ -185,8 +185,8 @@ CREATE TABLE IF NOT EXISTS observability.data_quality_quarantine ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_data_quality_module ON observability.data_quality_quarantine(module_name); -CREATE INDEX idx_data_quality_quarantined_at ON observability.data_quality_quarantine(quarantined_at); +CREATE INDEX IF NOT EXISTS idx_data_quality_module ON observability.data_quality_quarantine(module_name); +CREATE INDEX IF NOT EXISTS idx_data_quality_quarantined_at ON observability.data_quality_quarantine(quarantined_at); -- ============================================================================ -- APPEND-ONLY AUDIT TRAIL (for all Phase 2-3 operations) @@ -203,9 +203,9 @@ CREATE TABLE IF NOT EXISTS infrastructure.operation_audit_trail ( published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -CREATE INDEX idx_operation_audit_type ON infrastructure.operation_audit_trail(operation_type); -CREATE INDEX idx_operation_audit_correlation_id ON infrastructure.operation_audit_trail(correlation_id); -CREATE INDEX idx_operation_audit_occurred_at ON infrastructure.operation_audit_trail(occurred_at); +CREATE INDEX IF NOT EXISTS idx_operation_audit_type ON infrastructure.operation_audit_trail(operation_type); +CREATE INDEX IF NOT EXISTS idx_operation_audit_correlation_id ON infrastructure.operation_audit_trail(correlation_id); +CREATE INDEX IF NOT EXISTS idx_operation_audit_occurred_at ON infrastructure.operation_audit_trail(occurred_at); -- Permissions: schemas owned by executing role; no explicit role-based GRANT in dev/test -- In production, add explicit role-based GRANT via separate admin script after schema creation