
- Complete FastAPI application with JWT authentication
- SQLite database with SQLAlchemy ORM and Alembic migrations
- User registration/login with secure password hashing
- Multi-cryptocurrency wallet system with balance tracking
- Advertisement system for buy/sell listings with fund locking
- Order management with automatic payment integration
- Payment provider API integration with mock fallback
- Automatic crypto release after payment confirmation
- Health monitoring endpoint and CORS configuration
- Comprehensive API documentation with OpenAPI/Swagger
- Database models for users, wallets, ads, orders, and payments
- Complete CRUD operations for all entities
- Security features including fund locking and order expiration
- Detailed README with setup and usage instructions
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
162 lines
8.0 KiB
Python
162 lines
8.0 KiB
Python
"""Initial migration
|
|
|
|
Revision ID: 001
|
|
Revises:
|
|
Create Date: 2024-01-01 00:00:00.000000
|
|
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = '001'
|
|
down_revision = None
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
# Create users table
|
|
op.create_table(
|
|
'users',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('email', sa.String(), nullable=False),
|
|
sa.Column('username', sa.String(), nullable=False),
|
|
sa.Column('hashed_password', sa.String(), nullable=False),
|
|
sa.Column('is_active', sa.Boolean(), nullable=True),
|
|
sa.Column('is_verified', sa.Boolean(), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
|
|
op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=True)
|
|
op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False)
|
|
|
|
# Create cryptocurrencies table
|
|
op.create_table(
|
|
'cryptocurrencies',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('symbol', sa.String(), nullable=False),
|
|
sa.Column('name', sa.String(), nullable=False),
|
|
sa.Column('is_active', sa.Boolean(), nullable=True),
|
|
sa.Column('min_trade_amount', sa.Float(), nullable=True),
|
|
sa.Column('max_trade_amount', sa.Float(), nullable=True),
|
|
sa.Column('precision', sa.Integer(), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index(op.f('ix_cryptocurrencies_symbol'), 'cryptocurrencies', ['symbol'], unique=True)
|
|
op.create_index(op.f('ix_cryptocurrencies_id'), 'cryptocurrencies', ['id'], unique=False)
|
|
|
|
# Create wallets table
|
|
op.create_table(
|
|
'wallets',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
|
sa.Column('cryptocurrency_id', sa.Integer(), nullable=False),
|
|
sa.Column('available_balance', sa.Float(), nullable=True),
|
|
sa.Column('locked_balance', sa.Float(), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.ForeignKeyConstraint(['cryptocurrency_id'], ['cryptocurrencies.id'], ),
|
|
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index('ix_user_crypto', 'wallets', ['user_id', 'cryptocurrency_id'], unique=True)
|
|
op.create_index(op.f('ix_wallets_id'), 'wallets', ['id'], unique=False)
|
|
|
|
# Create advertisements table
|
|
op.create_table(
|
|
'advertisements',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('user_id', sa.Integer(), nullable=False),
|
|
sa.Column('cryptocurrency_id', sa.Integer(), nullable=False),
|
|
sa.Column('ad_type', sa.Enum('buy', 'sell', name='adtype'), nullable=False),
|
|
sa.Column('price', sa.Float(), nullable=False),
|
|
sa.Column('min_order_amount', sa.Float(), nullable=False),
|
|
sa.Column('max_order_amount', sa.Float(), nullable=False),
|
|
sa.Column('available_amount', sa.Float(), nullable=False),
|
|
sa.Column('payment_methods', sa.String(), nullable=False),
|
|
sa.Column('terms_conditions', sa.Text(), nullable=True),
|
|
sa.Column('status', sa.Enum('active', 'inactive', 'completed', 'cancelled', name='adstatus'), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.ForeignKeyConstraint(['cryptocurrency_id'], ['cryptocurrencies.id'], ),
|
|
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index(op.f('ix_advertisements_id'), 'advertisements', ['id'], unique=False)
|
|
|
|
# Create orders table
|
|
op.create_table(
|
|
'orders',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('advertisement_id', sa.Integer(), nullable=False),
|
|
sa.Column('buyer_id', sa.Integer(), nullable=False),
|
|
sa.Column('seller_id', sa.Integer(), nullable=False),
|
|
sa.Column('cryptocurrency_id', sa.Integer(), nullable=False),
|
|
sa.Column('crypto_amount', sa.Float(), nullable=False),
|
|
sa.Column('fiat_amount', sa.Float(), nullable=False),
|
|
sa.Column('price', sa.Float(), nullable=False),
|
|
sa.Column('status', sa.Enum('pending', 'payment_pending', 'payment_confirmed', 'completed', 'cancelled', 'disputed', name='orderstatus'), nullable=True),
|
|
sa.Column('payment_account_number', sa.String(), nullable=True),
|
|
sa.Column('payment_reference', sa.String(), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('expires_at', sa.DateTime(), nullable=True),
|
|
sa.Column('notes', sa.Text(), nullable=True),
|
|
sa.ForeignKeyConstraint(['advertisement_id'], ['advertisements.id'], ),
|
|
sa.ForeignKeyConstraint(['buyer_id'], ['users.id'], ),
|
|
sa.ForeignKeyConstraint(['cryptocurrency_id'], ['cryptocurrencies.id'], ),
|
|
sa.ForeignKeyConstraint(['seller_id'], ['users.id'], ),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index(op.f('ix_orders_id'), 'orders', ['id'], unique=False)
|
|
|
|
# Create payments table
|
|
op.create_table(
|
|
'payments',
|
|
sa.Column('id', sa.Integer(), nullable=False),
|
|
sa.Column('order_id', sa.Integer(), nullable=False),
|
|
sa.Column('account_number', sa.String(), nullable=False),
|
|
sa.Column('account_name', sa.String(), nullable=False),
|
|
sa.Column('bank_name', sa.String(), nullable=False),
|
|
sa.Column('amount', sa.Float(), nullable=False),
|
|
sa.Column('reference', sa.String(), nullable=False),
|
|
sa.Column('status', sa.Enum('pending', 'confirmed', 'failed', 'cancelled', name='paymentstatus'), nullable=True),
|
|
sa.Column('provider_transaction_id', sa.String(), nullable=True),
|
|
sa.Column('confirmed_at', sa.DateTime(), nullable=True),
|
|
sa.Column('created_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
|
sa.ForeignKeyConstraint(['order_id'], ['orders.id'], ),
|
|
sa.PrimaryKeyConstraint('id')
|
|
)
|
|
op.create_index(op.f('ix_payments_reference'), 'payments', ['reference'], unique=True)
|
|
op.create_index(op.f('ix_payments_id'), 'payments', ['id'], unique=False)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_index(op.f('ix_payments_id'), table_name='payments')
|
|
op.drop_index(op.f('ix_payments_reference'), table_name='payments')
|
|
op.drop_table('payments')
|
|
|
|
op.drop_index(op.f('ix_orders_id'), table_name='orders')
|
|
op.drop_table('orders')
|
|
|
|
op.drop_index(op.f('ix_advertisements_id'), table_name='advertisements')
|
|
op.drop_table('advertisements')
|
|
|
|
op.drop_index(op.f('ix_wallets_id'), table_name='wallets')
|
|
op.drop_index('ix_user_crypto', table_name='wallets')
|
|
op.drop_table('wallets')
|
|
|
|
op.drop_index(op.f('ix_cryptocurrencies_id'), table_name='cryptocurrencies')
|
|
op.drop_index(op.f('ix_cryptocurrencies_symbol'), table_name='cryptocurrencies')
|
|
op.drop_table('cryptocurrencies')
|
|
|
|
op.drop_index(op.f('ix_users_id'), table_name='users')
|
|
op.drop_index(op.f('ix_users_username'), table_name='users')
|
|
op.drop_index(op.f('ix_users_email'), table_name='users')
|
|
op.drop_table('users') |