TorbatYar/backend/services/identity-access/app/main.py
Mortezakoohjani 800b0ba2c5 Deploy TorbatYar for torbatyar.ir with nginx multi-tenant routing.
Wire production domain, CORS for tenant subdomains, celery volume mounts, and nginx reverse proxy configs for apex, API, identity, auth, and wildcard tenants.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-21 21:43:33 +03:30

88 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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, health
from app.core.config import settings
from app.core.logging import configure_logging, get_logger
from shared.exceptions import AppError
from shared.responses import ErrorDetail, ErrorResponse
configure_logging()
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="Identity & Access Service",
version=__version__,
description="سرویس احراز هویت و دسترسی (فاز ۲) — SSO با Keycloak",
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=["*"],
)
def _cors_headers(request: Request) -> dict[str, str]:
"""هدرهای CORS برای پاسخ‌های خطا.
هندلر خطای عمومی (۵۰۰) بیرون از CORSMiddleware اجرا می‌شود، بنابراین
هدر CORS را دستی اضافه می‌کنیم تا خطاهای سرور در مرورگر به‌اشتباه
«خطای CORS» نمایش داده نشوند و پیام واقعی به کاربر برسد.
"""
import re
origin = request.headers.get("origin")
if not origin:
return {}
if origin in settings.cors_origin_list or re.fullmatch(
r"https?://([a-z0-9-]+\.)*torbatyar\.ir", origin
):
return {
"Access-Control-Allow-Origin": origin,
"Vary": "Origin",
}
return {}
@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(),
headers=_cors_headers(request),
)
@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(),
headers=_cors_headers(request),
)
app.include_router(health.router)
app.include_router(api_router, prefix=settings.api_v1_prefix)
return app
app = create_app()