From d080a20ee13cf0892d60211b3f7e28d76d01365c Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 18 Dec 2025 17:09:05 -0600 Subject: [PATCH] Add migration to seed default dropdown options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Populates the dropdown_options table with default channels, sub-channels, and proof types that were previously hardcoded: - Social (Meta, X, LinkedIn, TikTok, YouTube) - Display (Programmatic, Direct Buy, Rich Media) - Email (Marketing, Transactional) - Print (Magazine, Newspaper, Direct Mail) - OOH (Billboard, Transit, Street Furniture) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../versions/002_seed_dropdown_options.py | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 backend/alembic/versions/002_seed_dropdown_options.py diff --git a/backend/alembic/versions/002_seed_dropdown_options.py b/backend/alembic/versions/002_seed_dropdown_options.py new file mode 100644 index 0000000..5532cb0 --- /dev/null +++ b/backend/alembic/versions/002_seed_dropdown_options.py @@ -0,0 +1,94 @@ +"""Seed default dropdown options + +Revision ID: 002_seed_dropdown +Revises: 001_initial +Create Date: 2024-12-18 + +""" +from typing import Sequence, Union +from uuid import uuid4 + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = '002_seed_dropdown' +down_revision: Union[str, None] = '001_initial' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Seed default channel/sub-channel/proof-type options.""" + + # Default dropdown hierarchy (from original hardcoded values) + dropdown_data = { + "Social": { + "Meta": ["In-feed 1x1", "In-feed 4x5", "In-feed 9x16", "Stories"], + "X (Twitter)": ["In-feed 1x1", "In-feed 16x9"], + "LinkedIn": ["In-feed 1x1", "In-feed 1.91x1"], + "TikTok": ["In-feed 9x16"], + "YouTube": ["Pre-roll", "Bumper", "Display"], + }, + "Display": { + "Programmatic": ["300x250", "300x600", "728x90", "160x600", "320x50"], + "Direct Buy": ["300x250", "300x600", "728x90", "970x250"], + "Rich Media": ["Expandable", "Interstitial", "Floating"], + }, + "Email": { + "Marketing": ["Newsletter", "Promotional", "Product Update"], + "Transactional": ["Confirmation", "Receipt", "Notification"], + }, + "Print": { + "Magazine": ["Full Page", "Half Page", "Quarter Page"], + "Newspaper": ["Full Page", "Half Page", "Quarter Page"], + "Direct Mail": ["Letter", "Postcard", "Brochure"], + }, + "OOH": { + "Billboard": ["Standard", "Digital", "Spectacular"], + "Transit": ["Bus Shelter", "Rail", "Airport"], + "Street Furniture": ["Kiosk", "Bench", "Phone Box"], + }, + } + + # Get connection for raw SQL inserts + conn = op.get_bind() + + for channel_name, sub_channels in dropdown_data.items(): + # Insert channel + channel_id = str(uuid4()) + conn.execute( + sa.text(""" + INSERT INTO dropdown_options (id, option_type, parent_id, value, display_order) + VALUES (:id, 'channel', NULL, :value, 0) + """), + {"id": channel_id, "value": channel_name} + ) + + for sub_channel_name, proof_types in sub_channels.items(): + # Insert sub-channel + sub_channel_id = str(uuid4()) + conn.execute( + sa.text(""" + INSERT INTO dropdown_options (id, option_type, parent_id, value, display_order) + VALUES (:id, 'sub_channel', :parent_id, :value, 0) + """), + {"id": sub_channel_id, "parent_id": channel_id, "value": sub_channel_name} + ) + + for proof_type_name in proof_types: + # Insert proof type + proof_type_id = str(uuid4()) + conn.execute( + sa.text(""" + INSERT INTO dropdown_options (id, option_type, parent_id, value, display_order) + VALUES (:id, 'proof_type', :parent_id, :value, 0) + """), + {"id": proof_type_id, "parent_id": sub_channel_id, "value": proof_type_name} + ) + + +def downgrade() -> None: + """Remove all seeded dropdown options.""" + op.execute("DELETE FROM dropdown_options WHERE option_type IN ('channel', 'sub_channel', 'proof_type')")