from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.v1.router import api_router from app.core.config import settings from app.core.exceptions import register_exception_handlers from app.crud.user import ensure_admin_exists from app.db.base import Base from app.db.session import SessionLocal, engine @asynccontextmanager async def lifespan(_: FastAPI): # Ensure models are imported so metadata is populated from app.models import user as user_model # noqa: F401 if settings.ENV == "development": async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async with SessionLocal() as session: await ensure_admin_exists(session) yield def create_app() -> FastAPI: app = FastAPI( title="CTMS 后端 API", description="临床试验项目管理系统后端接口文档", version="0.1.0", debug=settings.ENV == "development", lifespan=lifespan, openapi_tags=[ {"name": "auth", "description": "认证与登录"}, {"name": "users", "description": "用户管理"}, {"name": "studies", "description": "项目管理"}, {"name": "sites", "description": "中心管理"}, {"name": "study-members", "description": "项目成员"}, {"name": "comments", "description": "通用评论"}, {"name": "attachments", "description": "通用附件"}, {"name": "audit-logs", "description": "审计日志"}, {"name": "milestones", "description": "里程碑"}, {"name": "tasks", "description": "任务"}, {"name": "dashboard", "description": "项目总览与统计"}, {"name": "subjects", "description": "受试者"}, {"name": "visits", "description": "访视"}, {"name": "aes", "description": "不良事件"}, {"name": "issues", "description": "风险 / 问题"}, {"name": "data-queries", "description": "数据问题单"}, {"name": "verifications", "description": "SDV/SDR 核查进度"}, {"name": "imp-products", "description": "药品产品"}, {"name": "imp-batches", "description": "药品批次"}, {"name": "imp-inventory", "description": "药品库存"}, {"name": "imp-transactions", "description": "药品台账流水"}, {"name": "finance", "description": "费用管理"}, {"name": "faq-categories", "description": "FAQ 分类"}, {"name": "faqs", "description": "FAQ 条目"}, {"name": "health", "description": "健康检查"}, {"name": "faq", "description": "常量字典"}, ], ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) register_exception_handlers(app) @app.get( "/health", tags=["health"], summary="健康检查", description="返回服务存活状态。", ) async def health() -> dict[str, str]: return {"status": "ok"} app.include_router(api_router, prefix="/api/v1") return app app = create_app()