"""JIRA AI Fixer - Enterprise Issue Analysis Platform.""" from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse, RedirectResponse from starlette.middleware.base import BaseHTTPMiddleware import os from app.core.config import settings from app.core.database import init_db from app.api import api_router class HTTPSRedirectMiddleware(BaseHTTPMiddleware): """Force HTTPS in redirects when behind reverse proxy.""" async def dispatch(self, request: Request, call_next): response = await call_next(request) # Fix Location header to use HTTPS if behind proxy if response.status_code in (301, 302, 303, 307, 308): location = response.headers.get("location", "") if location.startswith("http://"): response.headers["location"] = location.replace("http://", "https://", 1) return response @asynccontextmanager async def lifespan(app: FastAPI): # Startup await init_db() yield # Shutdown app = FastAPI( title=settings.APP_NAME, version=settings.APP_VERSION, description="Enterprise AI-powered issue analysis and automated fix generation", docs_url="/api/docs", redoc_url="/api/redoc", openapi_url="/api/openapi.json", lifespan=lifespan, redirect_slashes=False # Disable automatic slash redirects ) # Add HTTPS redirect middleware app.add_middleware(HTTPSRedirectMiddleware) # CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # API routes app.include_router(api_router, prefix="/api") # Health check @app.get("/api/health") async def health(): return { "status": "healthy", "service": "jira-ai-fixer", "version": settings.APP_VERSION } # Serve static frontend (will be mounted if exists) FRONTEND_DIR = "/app/frontend" ASSETS_DIR = f"{FRONTEND_DIR}/assets" if os.path.exists(FRONTEND_DIR) and os.path.exists(ASSETS_DIR): app.mount("/assets", StaticFiles(directory=ASSETS_DIR), name="assets") @app.get("/") async def serve_frontend(): return FileResponse(f"{FRONTEND_DIR}/index.html") @app.get("/{path:path}") async def serve_spa(path: str): if path.startswith("api/"): return None # Let API routes handle file_path = f"{FRONTEND_DIR}/{path}" if os.path.exists(file_path) and os.path.isfile(file_path): return FileResponse(file_path) return FileResponse(f"{FRONTEND_DIR}/index.html") # Fallback: serve basic info page when no frontend @app.get("/") async def root(): return { "service": settings.APP_NAME, "version": settings.APP_VERSION, "docs": "/api/docs", "health": "/api/health" }