Add the Healthcare platform backend (phases 13.0–13.7) with Alembic migration revision fix, production deploy script, validation reports, shared UI exports, and loyalty list page client directives so Next.js build succeeds. Co-authored-by: Cursor <cursoragent@cursor.com>
140 lines
2.4 KiB
Python
140 lines
2.4 KiB
Python
from contextlib import asynccontextmanager
|
|
|
|
|
|
|
|
from fastapi import FastAPI, Request
|
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from fastapi.responses import JSONResponse
|
|
|
|
|
|
|
|
from app import __version__
|
|
|
|
from app.api.v1 import api_router
|
|
|
|
from app.api.v1 import health
|
|
|
|
from app.core.config import settings
|
|
|
|
from app.core.logging import configure_logging, get_logger
|
|
|
|
from app.middlewares.tenant import TenantHeaderMiddleware
|
|
|
|
from shared.exceptions import AppError
|
|
|
|
from shared.responses import ErrorDetail, ErrorResponse
|
|
|
|
|
|
|
|
configure_logging(settings.log_level)
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
@asynccontextmanager
|
|
|
|
async def lifespan(app: FastAPI):
|
|
|
|
logger.info("service_starting", extra={"service": settings.service_name})
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
|
|
app = FastAPI(
|
|
|
|
title="Healthcare Platform",
|
|
|
|
version=__version__,
|
|
|
|
description="Torbat Healthcare — Healthcare Platform (Phase 13.7 Delivery Integration)",
|
|
|
|
lifespan=lifespan,
|
|
|
|
)
|
|
|
|
app.add_middleware(
|
|
|
|
CORSMiddleware,
|
|
|
|
allow_origins=settings.cors_origin_list,
|
|
|
|
allow_origin_regex=r"https?://([a-z0-9-]+\.)*torbatyar\.ir",
|
|
|
|
allow_credentials=False,
|
|
|
|
allow_methods=["*"],
|
|
|
|
allow_headers=["*"],
|
|
|
|
)
|
|
|
|
app.add_middleware(TenantHeaderMiddleware)
|
|
|
|
|
|
|
|
@app.exception_handler(AppError)
|
|
|
|
async def app_error_handler(request: Request, exc: AppError) -> JSONResponse:
|
|
|
|
return JSONResponse(
|
|
|
|
status_code=exc.status_code,
|
|
|
|
content=ErrorResponse(
|
|
|
|
error=ErrorDetail(
|
|
|
|
code=exc.error_code, message=exc.message, details=exc.details
|
|
|
|
)
|
|
|
|
).model_dump(),
|
|
|
|
)
|
|
|
|
|
|
|
|
@app.exception_handler(Exception)
|
|
|
|
async def unhandled_handler(request: Request, exc: Exception) -> JSONResponse:
|
|
|
|
logger.error("unhandled_exception", extra={"error": str(exc)}, exc_info=exc)
|
|
|
|
return JSONResponse(
|
|
|
|
status_code=500,
|
|
|
|
content=ErrorResponse(
|
|
|
|
error=ErrorDetail(code="internal_error", message="خطای داخلی سرور")
|
|
|
|
).model_dump(),
|
|
|
|
)
|
|
|
|
|
|
|
|
app.include_router(health.router)
|
|
|
|
app.include_router(api_router, prefix=settings.api_v1_prefix)
|
|
|
|
return app
|
|
|
|
|
|
|
|
|
|
|
|
app = create_app()
|
|
|
|
|