"""Initial database schema Revision ID: 001_initial Revises: Create Date: 2024-12-31 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa # revision identifiers, used by Alembic. revision: str = '001_initial' down_revision: Union[str, None] = None branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # Create users table op.create_table( 'users', sa.Column('id', sa.String(36), primary_key=True), sa.Column('email', sa.String(255), unique=True, nullable=False), sa.Column('name', sa.String(255), nullable=False), sa.Column('password_hash', sa.String(255), nullable=False), sa.Column('email_verified', sa.Boolean(), default=False), sa.Column('is_active', sa.Boolean(), default=True), sa.Column('avatar_url', sa.String(500), nullable=True), sa.Column('plan', sa.String(20), default='free'), sa.Column('subscription_status', sa.String(20), default='active'), sa.Column('stripe_customer_id', sa.String(255), nullable=True), sa.Column('stripe_subscription_id', sa.String(255), nullable=True), sa.Column('docs_translated_this_month', sa.Integer(), default=0), sa.Column('pages_translated_this_month', sa.Integer(), default=0), sa.Column('api_calls_this_month', sa.Integer(), default=0), sa.Column('extra_credits', sa.Integer(), default=0), sa.Column('usage_reset_date', sa.DateTime()), sa.Column('created_at', sa.DateTime()), sa.Column('updated_at', sa.DateTime()), sa.Column('last_login_at', sa.DateTime(), nullable=True), ) op.create_index('ix_users_email', 'users', ['email']) op.create_index('ix_users_email_active', 'users', ['email', 'is_active']) op.create_index('ix_users_stripe_customer', 'users', ['stripe_customer_id']) # Create translations table op.create_table( 'translations', sa.Column('id', sa.String(36), primary_key=True), sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False), sa.Column('original_filename', sa.String(255), nullable=False), sa.Column('file_type', sa.String(10), nullable=False), sa.Column('file_size_bytes', sa.BigInteger(), default=0), sa.Column('page_count', sa.Integer(), default=0), sa.Column('source_language', sa.String(10), default='auto'), sa.Column('target_language', sa.String(10), nullable=False), sa.Column('provider', sa.String(50), nullable=False), sa.Column('status', sa.String(20), default='pending'), sa.Column('error_message', sa.Text(), nullable=True), sa.Column('processing_time_ms', sa.Integer(), nullable=True), sa.Column('characters_translated', sa.Integer(), default=0), sa.Column('estimated_cost_usd', sa.Float(), default=0.0), sa.Column('created_at', sa.DateTime()), sa.Column('completed_at', sa.DateTime(), nullable=True), ) op.create_index('ix_translations_user_date', 'translations', ['user_id', 'created_at']) op.create_index('ix_translations_status', 'translations', ['status']) # Create api_keys table op.create_table( 'api_keys', sa.Column('id', sa.String(36), primary_key=True), sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False), sa.Column('name', sa.String(100), nullable=False), sa.Column('key_hash', sa.String(255), nullable=False), sa.Column('key_prefix', sa.String(10), nullable=False), sa.Column('is_active', sa.Boolean(), default=True), sa.Column('scopes', sa.JSON(), default=list), sa.Column('last_used_at', sa.DateTime(), nullable=True), sa.Column('usage_count', sa.Integer(), default=0), sa.Column('created_at', sa.DateTime()), sa.Column('expires_at', sa.DateTime(), nullable=True), ) op.create_index('ix_api_keys_prefix', 'api_keys', ['key_prefix']) op.create_index('ix_api_keys_hash', 'api_keys', ['key_hash']) # Create usage_logs table op.create_table( 'usage_logs', sa.Column('id', sa.String(36), primary_key=True), sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False), sa.Column('date', sa.DateTime(), nullable=False), sa.Column('documents_count', sa.Integer(), default=0), sa.Column('pages_count', sa.Integer(), default=0), sa.Column('characters_count', sa.BigInteger(), default=0), sa.Column('api_calls_count', sa.Integer(), default=0), sa.Column('provider_breakdown', sa.JSON(), default=dict), ) op.create_index('ix_usage_logs_user_date', 'usage_logs', ['user_id', 'date'], unique=True) # Create payment_history table op.create_table( 'payment_history', sa.Column('id', sa.String(36), primary_key=True), sa.Column('user_id', sa.String(36), sa.ForeignKey('users.id', ondelete='CASCADE'), nullable=False), sa.Column('stripe_payment_intent_id', sa.String(255), nullable=True), sa.Column('stripe_invoice_id', sa.String(255), nullable=True), sa.Column('amount_cents', sa.Integer(), nullable=False), sa.Column('currency', sa.String(3), default='usd'), sa.Column('payment_type', sa.String(50), nullable=False), sa.Column('status', sa.String(20), nullable=False), sa.Column('description', sa.String(255), nullable=True), sa.Column('created_at', sa.DateTime()), ) op.create_index('ix_payment_history_user', 'payment_history', ['user_id', 'created_at']) def downgrade() -> None: op.drop_table('payment_history') op.drop_table('usage_logs') op.drop_table('api_keys') op.drop_table('translations') op.drop_table('users')