"""demo: drop the shared demo account (the owner's decision, 2026-10-04) The demo account — one shared user that whitelisted emails entered from the login page, reset on a schedule — goes with its code. Prod held the demo user and 10 whitelist rows. The upgrade deletes the demo user first (its playlists, states and subscriptions cascade; audit and quota rows keep their history with the actor nulled, as for any deleted account), then the traces that only the demo code could render: its audit rows (whitelist edits, manual resets, and every row about the reset job — its runs and its interval changes), the reset job's interval override and its completion notices. Nothing is migrated anywhere; the nightly backup holds the rows. The downgrade restores the schema as it stood (0014), empty: the demo user is created lazily on its first sign-in, so an empty `demo_whitelist` is the whole of its state. """ import sqlalchemy as sa from alembic import op revision: str = "0098_drop_demo_account" down_revision: str | None = "0097_drop_messages" branch_labels: str | None = None depends_on: str | None = None def upgrade() -> None: op.execute("DELETE FROM users WHERE is_demo") op.execute( "DELETE FROM audit_log WHERE action IN ('demo_add', 'demo_remove', 'demo_reset')" " OR (target_type = 'job' AND target_id = 'demo_reset')" ) op.execute("DELETE FROM scheduler_settings WHERE job_id = 'demo_reset'") op.execute("DELETE FROM notifications WHERE data->>'job_id' = 'demo_reset'") op.drop_index("ix_demo_whitelist_email", table_name="demo_whitelist") op.drop_table("demo_whitelist") op.drop_index("ix_users_is_demo", table_name="users") op.drop_column("users", "is_demo") def downgrade() -> None: op.add_column( "users", sa.Column("is_demo", sa.Boolean(), nullable=False, server_default=sa.false()), ) op.create_index("ix_users_is_demo", "users", ["is_demo"]) op.create_table( "demo_whitelist", sa.Column("id", sa.Integer(), primary_key=True), sa.Column("email", sa.String(length=320), nullable=False), sa.Column("note", sa.Text(), nullable=True), sa.Column("added_by", sa.String(length=320), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False ), ) op.create_index("ix_demo_whitelist_email", "demo_whitelist", ["email"], unique=True)