Refactoring code for modular approach

This commit is contained in:
2025-09-09 21:27:58 +02:00
parent 9a5d70e825
commit 71153a1ff5
55 changed files with 3928 additions and 1352 deletions

0
app/core/__init__.py Normal file
View File

26
app/core/config.py Normal file
View File

@@ -0,0 +1,26 @@
from pydantic_settings import BaseSettings
from typing import List
import os
class Settings(BaseSettings):
PROJECT_NAME: str = "Ecommerce Backend API with Marketplace Support"
DESCRIPTION: str = "Advanced product management system with JWT authentication"
VERSION: str = "2.2.0"
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql://user:password@localhost/ecommerce")
SECRET_KEY: str = os.getenv("SECRET_KEY", "your-secret-key-change-in-production")
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
ALLOWED_HOSTS: List[str] = ["*"] # Configure for production
# Rate limiting
RATE_LIMIT_REQUESTS: int = 100
RATE_LIMIT_WINDOW: int = 3600
class Config:
env_file = ".env"
extra = "ignore"
settings = Settings()

21
app/core/database.py Normal file
View File

@@ -0,0 +1,21 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from .config import settings
engine = create_engine(settings.DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Database dependency with connection pooling
def get_db():
db = SessionLocal()
try:
yield db
except Exception as e:
db.rollback()
raise
finally:
db.close()

48
app/core/lifespan.py Normal file
View File

@@ -0,0 +1,48 @@
from contextlib import asynccontextmanager
from fastapi import FastAPI
from sqlalchemy import text
from .logging import setup_logging
from .database import engine
from models.database_models import Base
import logging
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan events"""
# Startup
logger = setup_logging() # Configure logging first
logger.info("Starting up ecommerce API")
# Create tables
Base.metadata.create_all(bind=engine)
# Create indexes
create_indexes()
yield
# Shutdown
logger.info("Shutting down ecommerce API")
def create_indexes():
"""Create database indexes"""
with engine.connect() as conn:
try:
# User indexes
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_user_email ON users(email)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_user_username ON users(username)"))
# Product indexes
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_product_gtin ON products(gtin)"))
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_product_marketplace ON products(marketplace)"))
# Stock indexes
conn.execute(text("CREATE INDEX IF NOT EXISTS idx_stock_gtin_location ON stock(gtin, location)"))
conn.commit()
logger.info("Database indexes created successfully")
except Exception as e:
logger.warning(f"Index creation warning: {e}")

42
app/core/logging.py Normal file
View File

@@ -0,0 +1,42 @@
# app/core/logging.py
import logging
import sys
from pathlib import Path
from app.core.config import settings
def setup_logging():
"""Configure application logging with file and console handlers"""
# Create logs directory if it doesn't exist
log_file = Path(settings.LOG_FILE)
log_file.parent.mkdir(parents=True, exist_ok=True)
# Configure root logger
logger = logging.getLogger()
logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper()))
# Remove existing handlers
for handler in logger.handlers[:]:
logger.removeHandler(handler)
# Create formatters
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Console handler
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# File handler
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
# Configure specific loggers
logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING)
return logging.getLogger(__name__)