"""Main application entry point.""" from contextlib import asynccontextmanager from fastapi import FastAPI from src.middlewares.logging import configure_logging, get_logger from src.middlewares.cors import add_cors_middleware # F-2 service-secret gate UNWIRED 2026-07-27 (lead decision, DEV_PLAN #37). The only # caller of this service is the browser SPA, which we don't own and can't change to # send the header, so the gate could never be armed without a 401 outage. Restore by # re-adding these imports + the `_guard` dependency on each router mount below. # from fastapi import Depends # from src.middlewares.service_auth import is_enforced, require_service_secret from src.middlewares.rate_limit import limiter, _rate_limit_exceeded_handler from slowapi.errors import RateLimitExceeded # --- pr/5 Phase 1: unwire non-AI routers (Go owns these now). --- # Routers below are commented out, NOT deleted. The router files stay alive; # they're just not mounted, so they also disappear from Swagger. # from src.api.v1.document import router as document_router # unwired: Go handles documents # from src.api.v1.room import router as room_router # unwired: replaced by analysis_id # from src.api.v1.users import router as users_router # unwired: login moved off Python # from src.api.v1.db_client import router as db_client_router # unwired: Go registers DB client # from src.api.v1.data_catalog import router as data_catalog_router # unwired: Go handles the catalog # NOTE: src.api.v1.analysis was DELETED (Go owns analysis + its data_sources binding). # from src.api.v1.chat import router as chat_router # unwired: replaced by /api/v2/chat/stream # NOTE: src.api.v1.chat module still imported by v2 chat + /tools/help — keep the file. from src.api.v1.report import router as report_router from src.api.v1.tools import router as tools_router from src.api.v1.help import router as help_router # pr/5 Phase 2: dedicated /tools/help from src.api.v1.traceability import router as traceability_router # KM-691 from src.api.v1.charts import router as charts_router # W2: GET /api/v1/charts (SPINE_V2_PLAN §4.5) from src.api.v2.chat import router as chat_v2_router # pr/5 Phase 2: v2 chat pilot (analysis_id) from src.db.postgres.init_db import init_db from src.config.settings import settings import uvicorn # Configure logging configure_logging() logger = get_logger("main") @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Starting application...") if not settings.skip_init_db: await init_db() logger.info("Database initialized") else: logger.info("Skipping database initialization (SKIP_INIT_DB=true)") # F-2 service-secret gate UNWIRED 2026-07-27 (DEV_PLAN #37): the live surface is # unauthenticated by design — Python cannot authenticate a browser-only caller it # doesn't front. The real fix is a verified per-user identity forwarded by Go # (DEV_PLAN #43). Do not expose this service beyond the demo. logger.warning( "No caller authentication on the live surface (F-2 unwired — see DEV_PLAN #37)" ) yield # Create FastAPI app app = FastAPI( title="DataEyond Agentic Service", description="Multi-agent AI backend with RAG capabilities", version="0.1.0", lifespan=lifespan, ) # Add middleware add_cors_middleware(app) app.state.limiter = limiter app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # Include routers # --- pr/5 Phase 1: AI-only surface. Non-AI routers unwired (Go owns them). --- # app.include_router(users_router) # unwired: login moved off Python # app.include_router(document_router) # unwired: Go handles documents # app.include_router(room_router) # unwired: replaced by analysis_id # app.include_router(db_client_router) # unwired: Go registers DB client # app.include_router(data_catalog_router) # unwired: Go handles the catalog # app.include_router(chat_router) # unwired: v2 chat replaces it (drops v1 cache ops routes) # F-2 service-secret gate UNWIRED 2026-07-27 (lead decision, DEV_PLAN #37). It shipped # 2026-07-23 as a router-level dependency, inert until `dataeyond__service__secret` was # set. But the sole caller is the browser SPA (verified in E2E-Frontend `agenticApi.ts`), # which we don't own and can't change to send `X-Dataeyond-Service-Secret` — so the gate # could never be armed without a 401 outage. A wired-but-unarmable gate is a footgun, so # the dependency is removed here. `src/middlewares/service_auth.py` stays in-tree (parked, # not deleted). To restore: re-add the imports above and # _guard = [Depends(require_service_secret)] # then pass `dependencies=_guard` to each mount below. Real auth = DEV_PLAN #43. app.include_router(report_router) app.include_router(tools_router) app.include_router(help_router) app.include_router(traceability_router) # KM-691: GET /api/v1/traceability app.include_router(charts_router) # W2: GET /api/v1/charts (§4.5) app.include_router(chat_v2_router) # pr/5 Phase 2: POST /api/v2/chat/stream @app.get("/") async def root(): """Root endpoint.""" return { "status": "ok", "service": "DataEyond Agentic Service", "version": "0.1.0" } @app.get("/health") async def health_check(): """Health check endpoint.""" return {"status": "healthy"} if __name__ == "__main__": uvicorn.run( "main:app", host="0.0.0.0", port=7860, reload=True )