"""FastAPI application entrypoint: routers, static files, security headers, startup.""" import logging from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import JSONResponse, FileResponse from fastapi.staticfiles import StaticFiles from starlette.middleware.base import BaseHTTPMiddleware from app.api.routers import (accounts, attachments, auth, campaigns, dashboard, recipients, settings_router, subjects, suppression, templates, phones, test_send, logs, unsubscribe as unsub_router) from app.core.config import settings logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s") @asynccontextmanager async def lifespan(app: FastAPI): yield from app.db.session import close_engines await close_engines() app = FastAPI(title=settings.APP_NAME, lifespan=lifespan, docs_url="/api/docs", openapi_url="/api/openapi.json") class SecurityHeadersMiddleware(BaseHTTPMiddleware): async def dispatch(self, request, call_next): response = await call_next(request) response.headers.setdefault("X-Content-Type-Options", "nosniff") response.headers.setdefault("X-Frame-Options", "DENY") response.headers.setdefault("Referrer-Policy", "no-referrer") response.headers.setdefault("Content-Security-Policy", "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline';" " script-src 'self'; frame-src 'self' data: blob:;" " object-src 'self' data: blob:; frame-ancestors 'none'") if settings.ENVIRONMENT == "production": response.headers.setdefault("Strict-Transport-Security", "max-age=63072000; includeSubDomains") return response app.add_middleware(SecurityHeadersMiddleware) app.include_router(auth.router) app.include_router(accounts.router) app.include_router(recipients.router) app.include_router(subjects.router) === routers dir === __init__.py __pycache__ accounts.py attachments.py auth.py campaigns.py dashboard.py logs.py phones.py recipients.py settings_router.py subjects.py suppression.py templates.py test_send.py unsubscribe.py === check for license/admin already === /workspace/bulkmailer/app/core/encryption.py /workspace/bulkmailer/app/core/config.py /workspace/bulkmailer/app/models/__init__.py /workspace/bulkmailer/app/api/routers/settings_router.py /workspace/bulkmailer/app/api/routers/auth.py