| """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") | |
| 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 | |
| async def root(): | |
| """Root endpoint.""" | |
| return { | |
| "status": "ok", | |
| "service": "DataEyond Agentic Service", | |
| "version": "0.1.0" | |
| } | |
| 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 | |
| ) | |