from contextlib import asynccontextmanager import logging from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from sqlalchemy import text from sqlalchemy.exc import OperationalError from app.config import settings from app.database import Base, engine from app.mongo import close_mongo, connect_mongo from app.routers import auth, collab, documents, health, templates, tenant from app.services.collaboration_service import ensure_collaboration_indexes from app.services.document_service import ensure_indexes from app.services.template_service import ensure_template_indexes from app.services.history_service import ensure_history_indexes logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(_: FastAPI): try: Base.metadata.create_all(bind=engine) logger.info("Database connected and tables ready") except OperationalError: logger.warning("Database unavailable — check DATABASE_URL in .env") try: await connect_mongo() from app.mongo import get_mongo_db await ensure_indexes(get_mongo_db()) await ensure_collaboration_indexes(get_mongo_db()) await ensure_template_indexes(get_mongo_db()) await ensure_history_indexes(get_mongo_db()) logger.info("MongoDB connected and indexes ready") except Exception: logger.warning("MongoDB unavailable — will connect when available") yield await close_mongo() app = FastAPI(title=settings.app_name, debug=settings.debug, lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origin_list, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(health.router, prefix="/api/v1") app.include_router(auth.router, prefix="/api/v1") app.include_router(documents.router, prefix="/api/v1") app.include_router(templates.router, prefix="/api/v1") app.include_router(collab.router, prefix="/api/v1") app.include_router(tenant.router, prefix="/api/v1") @app.get("/") def root() -> dict[str, str]: return {"message": "Silos API", "docs": "/docs"}