101 lines
3.7 KiB
TypeScript
101 lines
3.7 KiB
TypeScript
|
|
/**
|
||
|
|
* Migration: Add anomalies and predictions tables
|
||
|
|
* Version: 011
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { Pool } from 'pg'
|
||
|
|
|
||
|
|
export async function up(db: Pool): Promise<void> {
|
||
|
|
// Anomalies table for detected anomalies
|
||
|
|
await db.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS anomalies (
|
||
|
|
id VARCHAR(255) PRIMARY KEY,
|
||
|
|
resource_id UUID NOT NULL REFERENCES resource_inventory(id) ON DELETE CASCADE,
|
||
|
|
metric_type VARCHAR(100) NOT NULL,
|
||
|
|
severity VARCHAR(50) NOT NULL CHECK (severity IN ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL')),
|
||
|
|
anomaly_type VARCHAR(50) NOT NULL CHECK (anomaly_type IN ('SPIKE', 'DROP', 'PATTERN', 'THRESHOLD')),
|
||
|
|
value NUMERIC NOT NULL,
|
||
|
|
expected_value NUMERIC,
|
||
|
|
deviation NUMERIC NOT NULL,
|
||
|
|
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
|
|
description TEXT NOT NULL,
|
||
|
|
recommendation TEXT,
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
|
|
)
|
||
|
|
`)
|
||
|
|
|
||
|
|
// Indexes for anomalies
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_anomalies_resource_id ON anomalies(resource_id)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_anomalies_metric_type ON anomalies(metric_type)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_anomalies_severity ON anomalies(severity)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_anomalies_timestamp ON anomalies(timestamp)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_anomalies_resource_metric ON anomalies(resource_id, metric_type)
|
||
|
|
`)
|
||
|
|
|
||
|
|
// Trigger for anomalies updated_at
|
||
|
|
await db.query(`
|
||
|
|
CREATE TRIGGER update_anomalies_updated_at BEFORE UPDATE ON anomalies
|
||
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()
|
||
|
|
`)
|
||
|
|
|
||
|
|
// Predictions table for predictive analytics
|
||
|
|
await db.query(`
|
||
|
|
CREATE TABLE IF NOT EXISTS predictions (
|
||
|
|
id VARCHAR(255) PRIMARY KEY,
|
||
|
|
resource_id UUID NOT NULL REFERENCES resource_inventory(id) ON DELETE CASCADE,
|
||
|
|
metric_type VARCHAR(100) NOT NULL,
|
||
|
|
prediction_type VARCHAR(50) NOT NULL CHECK (prediction_type IN ('USAGE', 'COST', 'CAPACITY', 'FAILURE')),
|
||
|
|
current_value NUMERIC NOT NULL,
|
||
|
|
predicted_value NUMERIC NOT NULL,
|
||
|
|
confidence INTEGER NOT NULL CHECK (confidence >= 0 AND confidence <= 100),
|
||
|
|
timeframe VARCHAR(10) NOT NULL CHECK (timeframe IN ('1H', '6H', '24H', '7D', '30D')),
|
||
|
|
timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
|
||
|
|
trend VARCHAR(50) NOT NULL CHECK (trend IN ('INCREASING', 'DECREASING', 'STABLE')),
|
||
|
|
recommendation TEXT,
|
||
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||
|
|
)
|
||
|
|
`)
|
||
|
|
|
||
|
|
// Indexes for predictions
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_predictions_resource_id ON predictions(resource_id)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_predictions_metric_type ON predictions(metric_type)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_predictions_prediction_type ON predictions(prediction_type)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_predictions_timestamp ON predictions(timestamp)
|
||
|
|
`)
|
||
|
|
await db.query(`
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_predictions_resource_metric ON predictions(resource_id, metric_type)
|
||
|
|
`)
|
||
|
|
|
||
|
|
// Trigger for predictions updated_at
|
||
|
|
await db.query(`
|
||
|
|
CREATE TRIGGER update_predictions_updated_at BEFORE UPDATE ON predictions
|
||
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column()
|
||
|
|
`)
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function down(db: Pool): Promise<void> {
|
||
|
|
await db.query(`DROP TRIGGER IF EXISTS update_predictions_updated_at ON predictions`)
|
||
|
|
await db.query(`DROP TABLE IF EXISTS predictions`)
|
||
|
|
await db.query(`DROP TRIGGER IF EXISTS update_anomalies_updated_at ON anomalies`)
|
||
|
|
await db.query(`DROP TABLE IF EXISTS anomalies`)
|
||
|
|
}
|
||
|
|
|