-- Analytics Database Initialization (TimescaleDB) -- Enable extensions CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; CREATE EXTENSION IF NOT EXISTS pg_stat_statements; CREATE SCHEMA IF NOT EXISTS analytics; -- Content views (hypertable) CREATE TABLE IF NOT EXISTS analytics.content_views ( time TIMESTAMPTZ NOT NULL, content_id UUID NOT NULL, content_type VARCHAR(50) NOT NULL, user_id UUID, session_id VARCHAR(255), referrer TEXT, user_agent TEXT, country VARCHAR(2), device_type VARCHAR(20) ); SELECT create_hypertable('analytics.content_views', 'time', if_not_exists => TRUE); -- Engagement metrics (hypertable) CREATE TABLE IF NOT EXISTS analytics.engagement_metrics ( time TIMESTAMPTZ NOT NULL, content_id UUID NOT NULL, metric_type VARCHAR(50) NOT NULL, value DECIMAL(12, 4) NOT NULL, metadata JSONB DEFAULT '{}' ); SELECT create_hypertable('analytics.engagement_metrics', 'time', if_not_exists => TRUE); -- Revenue metrics (hypertable) CREATE TABLE IF NOT EXISTS analytics.revenue_metrics ( time TIMESTAMPTZ NOT NULL, creator_id UUID NOT NULL, transaction_type VARCHAR(50) NOT NULL, gross_amount DECIMAL(12, 2) NOT NULL, net_amount DECIMAL(12, 2) NOT NULL, platform_fee DECIMAL(12, 2) NOT NULL, currency VARCHAR(3) DEFAULT 'USD' ); SELECT create_hypertable('analytics.revenue_metrics', 'time', if_not_exists => TRUE); -- Dashboard snapshots CREATE TABLE IF NOT EXISTS analytics.dashboard_snapshots ( id SERIAL PRIMARY KEY, snapshot_type VARCHAR(50) NOT NULL, period VARCHAR(20) NOT NULL, data JSONB NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Continuous aggregates for common queries CREATE MATERIALIZED VIEW IF NOT EXISTS analytics.hourly_views WITH (timescaledb.continuous) AS SELECT time_bucket('1 hour', time) AS bucket, content_type, COUNT(*) as view_count, COUNT(DISTINCT user_id) as unique_users FROM analytics.content_views GROUP BY bucket, content_type WITH NO DATA; -- Enable compression then add compression policies (compress data older than 7 days) ALTER TABLE analytics.content_views SET (timescaledb.compress, timescaledb.compress_orderby = 'time DESC'); SELECT add_compression_policy('analytics.content_views', INTERVAL '7 days', if_not_exists => TRUE); ALTER TABLE analytics.engagement_metrics SET (timescaledb.compress, timescaledb.compress_orderby = 'time DESC'); SELECT add_compression_policy('analytics.engagement_metrics', INTERVAL '7 days', if_not_exists => TRUE); ALTER TABLE analytics.revenue_metrics SET (timescaledb.compress, timescaledb.compress_orderby = 'time DESC'); SELECT add_compression_policy('analytics.revenue_metrics', INTERVAL '7 days', if_not_exists => TRUE); -- Indexes CREATE INDEX IF NOT EXISTS idx_views_content ON analytics.content_views(content_id, time DESC); CREATE INDEX IF NOT EXISTS idx_engagement_content ON analytics.engagement_metrics(content_id, time DESC); CREATE INDEX IF NOT EXISTS idx_revenue_creator ON analytics.revenue_metrics(creator_id, time DESC); -- Permissions GRANT ALL PRIVILEGES ON SCHEMA analytics TO lilith; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA analytics TO lilith; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA analytics TO lilith; DO $$ BEGIN RAISE NOTICE 'Analytics database initialized with TimescaleDB'; END $$;