Automated Action d63fc9b68d Implement complete Enviodeck Authentication API with FastAPI
- Phone number authentication with OTP verification
- Email/password authentication with secure bcrypt hashing
- Third-party OAuth login support for Google and Apple
- JWT token-based authentication system
- Rate limiting for OTP requests (5/minute)
- SQLite database with SQLAlchemy ORM
- Comprehensive user model with multiple auth providers
- Alembic database migrations setup
- API documentation with Swagger/OpenAPI
- Health check and system endpoints
- Environment configuration with security best practices
- Code quality with Ruff linting and formatting

Features:
- POST /auth/request-otp - Request OTP for phone authentication
- POST /auth/verify-otp - Verify OTP and get access token
- POST /auth/signup-email - Email signup with password
- POST /auth/login-email - Email login authentication
- POST /auth/login-google - Google OAuth integration
- POST /auth/login-apple - Apple OAuth integration
- GET /user/me - Get current authenticated user info
- GET / - API information and documentation links
- GET /health - Application health check
2025-06-21 08:59:35 +00:00

61 lines
1.8 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("phone_number", sa.String(), nullable=True),
sa.Column("email", sa.String(), nullable=True),
sa.Column("name", sa.String(), nullable=True),
sa.Column("password_hash", sa.String(), nullable=True),
sa.Column(
"auth_provider",
sa.Enum("PHONE", "GOOGLE", "APPLE", "EMAIL", name="authprovider"),
nullable=False,
),
sa.Column("is_active", sa.Boolean(), nullable=True),
sa.Column("is_verified", sa.Boolean(), nullable=True),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("(CURRENT_TIMESTAMP)"),
nullable=True,
),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
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_id"), "users", ["id"], unique=False)
op.create_index(
op.f("ix_users_phone_number"), "users", ["phone_number"], unique=True
)
def downgrade() -> None:
op.drop_index(op.f("ix_users_phone_number"), table_name="users")
op.drop_index(op.f("ix_users_id"), table_name="users")
op.drop_index(op.f("ix_users_email"), table_name="users")
op.drop_table("users")