"""enhance invite codes with plan assignment and email Revision ID: 030 Revises: 029 Create Date: 2026-02-12 Adds email, assigned_plan, trial_duration_days, and email_sent_at columns to invite_codes table for plan-aware invite code creation. """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = '030' down_revision: Union[str, None] = '029' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.add_column('invite_codes', sa.Column('email', sa.String(255), nullable=True)) op.add_column('invite_codes', sa.Column('assigned_plan', sa.String(50), nullable=False, server_default='free')) op.add_column('invite_codes', sa.Column('trial_duration_days', sa.Integer(), nullable=True)) op.add_column('invite_codes', sa.Column('email_sent_at', sa.DateTime(timezone=True), nullable=True)) op.create_index('ix_invite_codes_email', 'invite_codes', ['email']) # Plan must be free/pro/team op.create_check_constraint( 'ck_invite_codes_assigned_plan', 'invite_codes', "assigned_plan IN ('free', 'pro', 'team')" ) # Trial duration 1-90 days or NULL op.create_check_constraint( 'ck_invite_codes_trial_duration', 'invite_codes', "trial_duration_days IS NULL OR (trial_duration_days >= 1 AND trial_duration_days <= 90)" ) # Free plan cannot have trial duration op.create_check_constraint( 'ck_invite_codes_free_no_trial', 'invite_codes', "assigned_plan != 'free' OR trial_duration_days IS NULL" ) def downgrade() -> None: op.drop_constraint('ck_invite_codes_free_no_trial', 'invite_codes', type_='check') op.drop_constraint('ck_invite_codes_trial_duration', 'invite_codes', type_='check') op.drop_constraint('ck_invite_codes_assigned_plan', 'invite_codes', type_='check') op.drop_index('ix_invite_codes_email', table_name='invite_codes') op.drop_column('invite_codes', 'email_sent_at') op.drop_column('invite_codes', 'trial_duration_days') op.drop_column('invite_codes', 'assigned_plan') op.drop_column('invite_codes', 'email')