diff --git a/veza-backend-api/migrations/946_advanced_analytics_v0111.sql b/veza-backend-api/migrations/946_advanced_analytics_v0111.sql new file mode 100644 index 000000000..7797c3304 --- /dev/null +++ b/veza-backend-api/migrations/946_advanced_analytics_v0111.sql @@ -0,0 +1,66 @@ +-- Migration 946: Advanced Analytics v0.11.1 (F396-F399) +-- Adds tables for listening heatmaps, period comparisons, marketplace analytics, and metric alerts + +-- F396: Track listening heatmap — stores aggregated segment listen counts +CREATE TABLE IF NOT EXISTS track_segment_stats ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + track_id UUID NOT NULL REFERENCES tracks(id) ON DELETE CASCADE, + segment_index INT NOT NULL, -- 0-based segment index + segment_start_ms BIGINT NOT NULL, -- segment start in milliseconds + segment_end_ms BIGINT NOT NULL, -- segment end in milliseconds + listen_count BIGINT NOT NULL DEFAULT 0, + drop_off_count BIGINT NOT NULL DEFAULT 0, -- how many stopped here + replay_count BIGINT NOT NULL DEFAULT 0, -- how many seeked back here + date DATE NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + CONSTRAINT uq_segment_stats_track_segment_date UNIQUE(track_id, segment_index, date) +); + +CREATE INDEX IF NOT EXISTS idx_segment_stats_track_id ON track_segment_stats(track_id); +CREATE INDEX IF NOT EXISTS idx_segment_stats_date ON track_segment_stats(date); +CREATE INDEX IF NOT EXISTS idx_segment_stats_track_date ON track_segment_stats(track_id, date); + +-- F398: Marketplace analytics — product view tracking for conversion rates +CREATE TABLE IF NOT EXISTS product_views ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + source VARCHAR(50) NOT NULL DEFAULT 'direct', -- 'search', 'feed', 'profile', 'direct' + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_product_views_product_id ON product_views(product_id); +CREATE INDEX IF NOT EXISTS idx_product_views_created_at ON product_views(created_at); + +-- F399: Metric alerts — opt-in milestone notifications for creators +CREATE TABLE IF NOT EXISTS metric_alerts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + metric_type VARCHAR(50) NOT NULL, -- 'plays', 'followers', 'sales', 'listeners' + threshold BIGINT NOT NULL, -- e.g., 100, 500, 1000 + is_triggered BOOLEAN NOT NULL DEFAULT FALSE, + triggered_at TIMESTAMP WITH TIME ZONE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + CONSTRAINT uq_metric_alert_user_type_threshold UNIQUE(user_id, metric_type, threshold) +); + +CREATE INDEX IF NOT EXISTS idx_metric_alerts_user_id ON metric_alerts(user_id); +CREATE INDEX IF NOT EXISTS idx_metric_alerts_not_triggered ON metric_alerts(user_id) WHERE is_triggered = FALSE; + +-- F399: Metric alert preferences — which alert types are enabled +CREATE TABLE IF NOT EXISTS metric_alert_preferences ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + metric_type VARCHAR(50) NOT NULL, -- 'plays', 'followers', 'sales', 'listeners' + enabled BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + CONSTRAINT uq_alert_pref_user_type UNIQUE(user_id, metric_type) +); + +CREATE INDEX IF NOT EXISTS idx_alert_prefs_user_id ON metric_alert_preferences(user_id); + +-- Add segment_positions to playback_analytics for heatmap data collection +ALTER TABLE playback_analytics ADD COLUMN IF NOT EXISTS segment_positions JSONB DEFAULT '[]'; diff --git a/veza-backend-api/migrations/946_advanced_analytics_v0111_down.sql b/veza-backend-api/migrations/946_advanced_analytics_v0111_down.sql new file mode 100644 index 000000000..e1782d845 --- /dev/null +++ b/veza-backend-api/migrations/946_advanced_analytics_v0111_down.sql @@ -0,0 +1,8 @@ +-- Rollback Migration 946: Advanced Analytics v0.11.1 (F396-F399) + +ALTER TABLE playback_analytics DROP COLUMN IF EXISTS segment_positions; + +DROP TABLE IF EXISTS metric_alert_preferences; +DROP TABLE IF EXISTS metric_alerts; +DROP TABLE IF EXISTS product_views; +DROP TABLE IF EXISTS track_segment_stats;