feat: add backend FastAPI structure and Supabase schema

This commit is contained in:
Alan Alonso
2026-05-23 00:41:13 -06:00
parent 17cdde7dbb
commit e6eb466c14
38 changed files with 1760 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
from datetime import datetime, timedelta
from fastapi import APIRouter, HTTPException, Depends, status
from pydantic import BaseModel, EmailStr
import jwt
from passlib.context import CryptContext
from app.core.config import settings
from app.db.database import get_connection
router = APIRouter()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
class UserRegister(BaseModel):
email: EmailStr
phone: str | None = None
password: str
class UserLogin(BaseModel):
email: EmailStr
password: str
class TokenResponse(BaseModel):
access_token: str
token_type: str = "bearer"
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
def create_token(user_id: int) -> str:
expire = datetime.utcnow() + timedelta(minutes=settings.access_token_expire_minutes)
payload = {"sub": str(user_id), "exp": expire}
return jwt.encode(payload, settings.secret_key, algorithm=settings.algorithm)
@router.post("/register", response_model=TokenResponse)
async def register(user: UserRegister):
conn = get_connection()
existing = conn.execute(
"SELECT id FROM users WHERE email = ?", (user.email,)
).fetchone()
if existing:
raise HTTPException(status_code=400, detail="Email already registered")
password_hash = hash_password(user.password)
cursor = conn.execute(
"INSERT INTO users (email, phone, password_hash) VALUES (?, ?, ?) RETURNING id",
(user.email, user.phone, password_hash)
)
user_id = cursor.fetchone()[0]
# Create default preferences
conn.execute(
"INSERT INTO notification_preferences (user_id) VALUES (?)",
(user_id,)
)
conn.commit()
conn.close()
token = create_token(user_id)
return TokenResponse(access_token=token)
@router.post("/login", response_model=TokenResponse)
async def login(user: UserLogin):
conn = get_connection()
db_user = conn.execute(
"SELECT id, password_hash FROM users WHERE email = ?",
(user.email,)
).fetchone()
conn.close()
if not db_user or not verify_password(user.password, db_user[1]):
raise HTTPException(status_code=401, detail="Invalid credentials")
token = create_token(db_user[0])
return TokenResponse(access_token=token)