"""Add feedback_events table and vibe_embedding to playlists Revision ID: 004 Revises: 003 Create Date: 2026-02-23 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op from pgvector.sqlalchemy import Vector revision: str = "004" down_revision: Union[str, None] = "003" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # Add vibe_embedding to playlists (nullable — only set for vibe playlists) op.add_column("playlists", sa.Column("vibe_embedding", Vector(512), nullable=True)) # Create feedback_events table op.create_table( "feedback_events", sa.Column("id", sa.BigInteger, primary_key=True), sa.Column("playlist_id", sa.BigInteger, sa.ForeignKey("playlists.id"), nullable=False), sa.Column("track_id", sa.BigInteger, sa.ForeignKey("tracks.id"), nullable=False), sa.Column("vibe_embedding", Vector(512), nullable=False), sa.Column("vibe_text", sa.Text, nullable=True), sa.Column("signal", sa.Text, nullable=False), sa.Column("signal_weight", sa.REAL, nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # B-tree index on track_id (primary query pattern: fetch events by track) op.create_index("ix_feedback_events_track_id", "feedback_events", ["track_id"]) def downgrade() -> None: op.drop_index("ix_feedback_events_track_id", table_name="feedback_events") op.drop_table("feedback_events") op.drop_column("playlists", "vibe_embedding")