from fastapi import FastAPI, Request from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles from contextlib import asynccontextmanager from src.utils.logging_config import setup_logging from alembic.config import Config from alembic import command import os import logging @asynccontextmanager async def lifespan(app: FastAPI): # Startup setup_logging() logger = logging.getLogger(__name__) logger.info("--- Application Starting Up ---") logger.debug("--- TEST DEBUG LOG AT STARTUP ---") alembic_cfg = Config("alembic.ini") database_url = os.getenv("DATABASE_URL") if database_url and not os.getenv("TESTING"): alembic_cfg.set_main_option("sqlalchemy.url", database_url) try: # command.upgrade(alembic_cfg, "head") logger.info("Database migrations skipped (manual override).") except Exception as e: logger.error(f"Error running database migrations: {e}") else: logger.warning("DATABASE_URL not set, skipping migrations.") # Start Scheduler if not os.getenv("TESTING"): try: from src.services.scheduler import scheduler scheduler.start() logger.info("Scheduler started.") except Exception as e: logger.error(f"Failed to start scheduler: {e}") else: logger.info("TESTING mode detected: Scheduler disabled.") yield logger.info("--- Application Shutting Down ---") if not os.getenv("TESTING"): try: from src.services.scheduler import scheduler scheduler.stop() except: pass app = FastAPI(lifespan=lifespan) # Add middleware for request logging @app.middleware("http") async def log_requests(request: Request, call_next): logger = logging.getLogger("src.middleware") logger.info(f"Incoming Request: {request.method} {request.url.path}") try: response = await call_next(request) logger.info(f"Request Completed: {response.status_code}") return response except Exception as e: logger.error(f"Request Failed: {e}") raise from pathlib import Path # Resolve absolute path to static directory BASE_DIR = Path(__file__).resolve().parent STATIC_DIR = BASE_DIR.parent / "static" if not STATIC_DIR.exists(): # Fallback or create? # For now, just logging warning or ensuring it works in dev logging.warning(f"Static directory not found at {STATIC_DIR}") # Create it to prevent crash? STATIC_DIR.mkdir(parents=True, exist_ok=True) app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") templates = Jinja2Templates(directory="templates") from src.api import status, sync, auth, logs, metrics, activities, scheduling, config_routes app.include_router(status.router, prefix="/api") app.include_router(sync.router, prefix="/api") app.include_router(auth.router, prefix="/api") app.include_router(config_routes.router, prefix="/api") app.include_router(logs.router, prefix="/api") app.include_router(metrics.router, prefix="/api") app.include_router(activities.router, prefix="/api") app.include_router(activities.router, prefix="/api") app.include_router(scheduling.router, prefix="/api") from src.api import segments app.include_router(segments.router, prefix="/api") from src.api import bike_setups app.include_router(bike_setups.router) from src.api import discovery app.include_router(discovery.router, prefix="/api/discovery") from src.api import analysis app.include_router(analysis.router, prefix="/api") from src.routers import web app.include_router(web.router) # Trigger reload