Stage 0: Repository und Architekturgrundlage

- Pyproject.toml mit FastAPI, Pydantic v2, SQLAlchemy, httpx, asyncio,
  BeautifulSoup4, selectolax, trafilatura, uvicorn, pytest-asyncio
- Multi-stage Dockerfile (Python 3.12-slim, Non-Root-User nsct)
- docker-compose.yml (nsct-api + postgres + optional searxng)
- .env.example mit allen Config-Parametern
- Config-System: AppSettings mit LLMConfig, VisionConfig, AudioConfig,
  DatabaseConfig — komplett aus Environment, keine Hardcodes
- Strukturiertes Logging mit research_id/llm_request_id Tracking
- Pydantic v2 Schemas: SearchQuery, Source, Claim, EvidenceRelation,
  CitationEdge, ResearchReport
- SQLAlchemy 2.0 Declarative Models + async Engine Factory
- SSRF-Schutz: URL-Validation, IP-Blocklist (RFC1918, Cloud Metadata,
  file://, ftp://)
- Provider-Interfaces: LLMProvider, VisionProvider, AudioProvider,
  SearchProvider, ContentFetcher als ABCs
- Health-Endpoints: /health, /ready (LLM-Connect-Test), /providers
- FastAPI App mit CORS, lifespan (LLM Pre-Flight)
- CLI-Stub mit Entry-Points: nsct, nsct-core, nsct-api
- 6 Test-Cases: /health, /ready, /providers + No-Secrets-Test
- Vollständige Dokumentation: README, ARCHITECTURE, SECURITY,
  METHODOLOGY, API, DEPLOYMENT
- .gitignore (Python, Docker, IDE, .env)
This commit is contained in:
NSCT Agent
2026-08-23 11:33:45 +00:00
commit e9410be941
28 changed files with 4192 additions and 0 deletions

81
src/nsct/api/main.py Normal file
View File

@@ -0,0 +1,81 @@
"""FastAPI application — entry point for the API server."""
from __future__ import annotations
import logging
from contextlib import asynccontextmanager
import httpx
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from nsct.config import AppSettings
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------
# Lifespan
# ---------------------------------------------------------------------------
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan — startup and shutdown hooks."""
config: AppSettings = app.state.config
logger.info("NSCT API starting up — version %s", app.state.version)
# Pre-flight: validate LLM connectivity
llm_base = config.llm.base_url if config and config.llm and config.llm.base_url else ""
if llm_base:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
resp = await client.get(f"{llm_base}/models")
if resp.status_code == 200:
logger.info("LLM provider reachable — model endpoint returned 200")
else:
logger.warning("LLM provider returned %s", resp.status_code)
except Exception as exc:
logger.warning("LLM connectivity check failed: %s", exc)
yield
# ---------------------------------------------------------------------------
# App factory
# ---------------------------------------------------------------------------
def create_app() -> FastAPI:
"""Create the FastAPI application with all routes and middleware."""
config = AppSettings.from_env()
app = FastAPI(
title="NSCT API",
description="Neutral Search Crawler Tool — API server",
version="0.1.0",
docs_url="/docs" if config.debug else None,
redoc_url="/redoc" if config.debug else None,
lifespan=lifespan,
)
app.state.config = config
app.state.version = "0.1.0"
# CORS — allow local development
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "http://localhost:5173", "http://127.0.0.1:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Mount health router
from nsct.api.health import router as health_router
app.include_router(health_router, tags=["system"])
return app
app = create_app()