import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.rate_limit import RateLimiter from app.routes import router from app.security import OriginValidator, RequestSizeLimiter logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Waitlist service starting (env=%s)", settings.ENVIRONMENT) yield logger.info("Waitlist service shutting down") app = FastAPI( title="adiuvAI Waitlist", version="1.0.0", docs_url="/docs" if settings.ENVIRONMENT != "production" else None, redoc_url=None, openapi_url="/openapi.json" if settings.ENVIRONMENT != "production" else None, lifespan=lifespan, ) # ── Middleware stack (outermost runs first) ────────────────────────── # 1. CORS — locked to allowed origins app.add_middleware( CORSMiddleware, allow_origins=settings.origins_list, allow_methods=["POST", "OPTIONS"], allow_headers=["Content-Type"], allow_credentials=False, max_age=86400, ) # 2. Rate limiter (per-IP, Cloudflare-aware) app.add_middleware(RateLimiter) # 3. Origin / Referer validation (production only) app.add_middleware(OriginValidator) # 4. Request body size limit (4 KB) app.add_middleware(RequestSizeLimiter) # ── Routes ─────────────────────────────────────────────────────────── app.include_router(router, prefix="/api/v1") @app.get("/health") async def health(): return {"status": "ok"}