import os from fastapi import APIRouter, FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from slowapi import _rate_limit_exceeded_handler from slowapi.errors import RateLimitExceeded from api.lifespan import app_lifespan from api.middlewares import UserConfigEnvUpdateMiddleware from api.middlewares.auth_middleware import AuthMiddleware from api.middlewares.rate_limit_middleware import limiter from utils.safe_error_handler import safe_exception_handler from api.middlewares.request_size_middleware import RequestSizeLimitMiddleware from api.middlewares.security_headers_middleware import SecurityHeadersMiddleware from api.v1.ppt.router import API_V1_PPT_ROUTER from api.v1.webhook.router import API_V1_WEBHOOK_ROUTER from api.v1.mock.router import API_V1_MOCK_ROUTER from api.v1.auth.router import AUTH_ROUTER from api.v1.admin.users_router import USERS_ROUTER from api.v1.admin.teams_router import TEAMS_ROUTER from api.v1.admin.clients_router import CLIENTS_ROUTER from api.v1.admin.audit_router import AUDIT_ROUTER from api.v1.admin.brand_config_router import BRAND_CONFIG_ROUTER from api.v1.admin.master_decks_router import MASTER_DECKS_ROUTER from api.v1.admin.analytics_router import ANALYTICS_ROUTER from api.v1.admin.storage_router import STORAGE_ROUTER from api.v1.admin.settings_router import SETTINGS_ROUTER from api.v1.ppt.endpoints.jobs import JOBS_ROUTER from api.v1.ppt.endpoints.review import REVIEW_ROUTER from api.v1.ppt.endpoints.export import EXPORT_ROUTER from api.middlewares.audit_middleware import AuditMiddleware app = FastAPI(lifespan=app_lifespan) # Configure rate limiting app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # Configure safe error handling (prevent info disclosure) app.add_exception_handler(Exception, safe_exception_handler) # Admin router aggregator ADMIN_ROUTER = APIRouter(prefix="/api/v1/admin") ADMIN_ROUTER.include_router(USERS_ROUTER) ADMIN_ROUTER.include_router(TEAMS_ROUTER) ADMIN_ROUTER.include_router(CLIENTS_ROUTER) ADMIN_ROUTER.include_router(AUDIT_ROUTER) ADMIN_ROUTER.include_router(BRAND_CONFIG_ROUTER) ADMIN_ROUTER.include_router(MASTER_DECKS_ROUTER) ADMIN_ROUTER.include_router(ANALYTICS_ROUTER) ADMIN_ROUTER.include_router(STORAGE_ROUTER) ADMIN_ROUTER.include_router(SETTINGS_ROUTER) # Routers app.include_router(AUTH_ROUTER) app.include_router(ADMIN_ROUTER) app.include_router(API_V1_PPT_ROUTER) app.include_router(JOBS_ROUTER) app.include_router(REVIEW_ROUTER) app.include_router(EXPORT_ROUTER) app.include_router(API_V1_WEBHOOK_ROUTER) app.include_router(API_V1_MOCK_ROUTER) # Serve static assets (placeholder images, etc.) _static_dir = os.path.join(os.path.dirname(__file__), "..", "static") if os.path.isdir(_static_dir): app.mount("/static", StaticFiles(directory=_static_dir), name="static") # Serve data directory (images, exports, uploads) for local dev # In Docker, nginx serves these directly; this is a fallback for dev mode _data_dir = os.environ.get("APP_DATA_DIRECTORY", os.path.join(os.path.dirname(__file__), "..", "data")) os.makedirs(_data_dir, exist_ok=True) app.mount("/app_data", StaticFiles(directory=_data_dir), name="app_data") # Middlewares (executed in reverse order: last added = first executed) # 1. CORS must run first (handles preflight OPTIONS) origins = os.getenv("ALLOWED_ORIGINS", "http://localhost:3000").split(",") app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type", "Accept"], ) # 2. Security headers (add protective HTTP headers) app.add_middleware(SecurityHeadersMiddleware) # 3. Request size limit (reject large requests early) max_request_size = int(os.getenv("MAX_REQUEST_SIZE", str(100 * 1024 * 1024))) # 100MB app.add_middleware(RequestSizeLimitMiddleware, max_size=max_request_size) # 4. Auth middleware (validates JWT, attaches user to request.state) app.add_middleware(AuthMiddleware) # 5. Audit middleware (fire-and-forget logging for mutations) app.add_middleware(AuditMiddleware) # 6. User config middleware app.add_middleware(UserConfigEnvUpdateMiddleware)