"""FastAPI application entrypoint.""" from contextlib import asynccontextmanager from typing import Callable from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.health import router as health_router from app.api.auth_routes import router as auth_router from app.api.portfolios import router as portfolio_router from app.api.strategy_sets import router as strategy_sets_router from app.api.users import router as users_router from app.core.config import Settings, get_settings from app.core.errors import register_exception_handlers from app.core.security import hash_password from app.repositories.factory import get_portfolio_repository_from_settings from app.repositories.portfolio_repository import PortfolioRepository def _bootstrap_initial_user( settings: Settings, repository_factory: Callable[[Settings], PortfolioRepository], ) -> None: if not settings.db_enabled or settings.bootstrap_user_username is None or settings.bootstrap_user_password is None: return repository = repository_factory(settings) try: if repository.list_users(): return repository.create_user( settings.bootstrap_user_username, email=settings.bootstrap_user_email, password_hash=hash_password(settings.bootstrap_user_password), permission="admin", ) finally: if callable(getattr(type(repository), "close", None)): repository.close() def create_app( *, settings_factory: Callable[[], Settings] = get_settings, repository_factory: Callable[[Settings], PortfolioRepository] = get_portfolio_repository_from_settings, ) -> FastAPI: settings = settings_factory() @asynccontextmanager async def lifespan(_: FastAPI): _bootstrap_initial_user(settings, repository_factory) yield app = FastAPI( title=settings.app_name, version=settings.app_version, docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=settings.allowed_origins, allow_credentials=True, allow_methods=["GET", "POST", "PATCH", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type"], ) app.include_router(health_router) app.include_router(auth_router) app.include_router(portfolio_router) app.include_router(strategy_sets_router) app.include_router(users_router) register_exception_handlers(app) return app app = create_app()