diff --git a/app/core/lifespan.py b/app/core/lifespan.py index 0962e666..ddff61bc 100644 --- a/app/core/lifespan.py +++ b/app/core/lifespan.py @@ -1,10 +1,11 @@ # app/core/lifespan.py -"""Summary description .... +"""Application lifespan management - Clean Migration Approach. This module provides classes and functions for: -- .... -- .... -- .... +- Application startup and shutdown events +- Logging setup +- Default user creation +- NO database table creation (handled by Alembic) """ import logging @@ -14,7 +15,7 @@ from fastapi import FastAPI from sqlalchemy import text from middleware.auth import AuthManager -from models.database.base import Base +# Remove this import if not needed: from models.database.base import Base from .database import SessionLocal, engine from .logging import setup_logging @@ -25,62 +26,106 @@ auth_manager = AuthManager() @asynccontextmanager async def lifespan(app: FastAPI): - """Application lifespan events.""" - # Startup - app_logger = setup_logging() # Configure logging first + """Application lifespan events - Clean migration approach.""" + + # === STARTUP === + app_logger = setup_logging() app_logger.info("Starting up ecommerce API") - # Create tables - Base.metadata.create_all(bind=engine) + # === REMOVED: Database table creation === + # Base.metadata.create_all(bind=engine) # ❌ Removed - handled by Alembic + # create_indexes() # ❌ Removed - handled by Alembic - # Create indexes - create_indexes() + # === KEPT: Application-level initialization === - # Create default admin user + # Create default admin user (after migrations have run) db = SessionLocal() try: auth_manager.create_default_admin_user(db) + logger.info("Default admin user initialization completed") except Exception as e: logger.error(f"Failed to create default admin user: {e}") + # In development, this might fail if tables don't exist yet + # That's OK - migrations should be run separately finally: db.close() + # Add any other application-level initialization here + # Examples: + # - Load configuration + # - Initialize caches + # - Set up external service connections + # - Load initial data (AFTER migrations) + + logger.info("✅ Application startup completed") + yield - # Shutdown + # === SHUTDOWN === app_logger.info("Shutting down ecommerce API") + # Add cleanup tasks here if needed -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)") - ) +# === REMOVED FUNCTION === +# def create_indexes(): +# """Create database indexes.""" +# # This is now handled by Alembic migrations +# pass - # 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)" - ) - ) +# === NEW HELPER FUNCTION === +def check_database_ready(): + """Check if database is ready (migrations have been run).""" + try: + with engine.connect() as conn: + # Try to query a table that should exist + result = conn.execute(text("SELECT name FROM sqlite_master WHERE type='table' LIMIT 1")) + tables = result.fetchall() + return len(tables) > 0 + except Exception: + return False - conn.commit() - logger.info("Database indexes created successfully") - except Exception as e: - logger.warning(f"Index creation warning: {e}") + +def get_migration_status(): + """Get current Alembic migration status.""" + try: + from alembic import command + from alembic.config import Config + + alembic_cfg = Config("alembic.ini") + + # This would need more implementation to actually check status + # For now, just return a placeholder + return "Migration status check not implemented" + except Exception as e: + logger.warning(f"Could not check migration status: {e}") + return "Unknown" + + +# === STARTUP VERIFICATION (Optional) === +def verify_startup_requirements(): + """Verify that all startup requirements are met.""" + + issues = [] + + # Check if database exists and has tables + if not check_database_ready(): + issues.append("Database not ready - run 'make migrate-up' first") + + # Add other checks as needed + # - Configuration validation + # - External service connectivity + # - Required environment variables + + if issues: + logger.error("❌ Startup verification failed:") + for issue in issues: + logger.error(f" - {issue}") + return False + + logger.info("✅ Startup verification passed") + return True + +# You can call this in your main.py if desired: +# if not verify_startup_requirements(): +# raise RuntimeError("Application startup requirements not met") diff --git a/requirements-dev.txt b/requirements-dev.txt index 4117a9e4..1adc13da 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,11 @@ - +# Database migrations +alembic>=1.13.0 # Linting and formatting tools +# Development tools black>=23.0.0 isort>=5.12.0 flake8>=6.0.0 -mypy>=1.0.0 +mypy>=1.5.0 # Optional: More advanced linting flake8-docstrings>=1.7.0 diff --git a/requirements.txt b/requirements.txt index 3f5141c0..83d9a59d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +# Database migrations +alembic>=1.13.0 starlette==0.27.0 # requirements.txt # Core FastAPI and web framework