"""Warstwa BAZODANOWA — usługa HTTP. Jedyne zadanie: przyjąć znormalizowane zapytanie z warstwy logicznej, wyszukać dane (w Excelu z cache lub w SQL) i zwrócić je w górę. Nie zna warstwy logicznej ani prezentacji. """ # build-marker: 2026-07-25 wymuszenie nowego obrazu po incydencie z tagiem :latest from __future__ import annotations from contextlib import asynccontextmanager from fastapi import FastAPI from app import canary, link_crypto, security from app.config import settings from app.models import HealthInfo, SearchQuery, SearchResult from app.providers.factory import build_provider provider = build_provider(settings) @asynccontextmanager async def lifespan(app: FastAPI): provider.warmup() # zbuduj/odśwież indeks i cache przy starcie yield app = FastAPI(title="astrololo · warstwa bazodanowa", lifespan=lifespan) security.install(app, "danych") # token międzywarstwowy (LOG-32) # Szyfrowanie łącza od logiki. PO `security.install`, żeby także odmowa # tokenowa wracała zaszyfrowana — inaczej klient nie umiałby jej odczytać. link_crypto.install(app, link_crypto.ENV_LOGIC_DATA, "danych") @app.post("/search", response_model=SearchResult) def search(query: SearchQuery) -> SearchResult: result = provider.search(query) # Rekordy-pułapki (DAN-26) odsiewamy TU, na wyjściu z warstwy danych — dzięki # temu nie dotrą ani wyżej, ani do promptu LLM (LOG-30), niezależnie od dostawcy. visible, report = canary.screen(result.rows, query.value) if report["active"]: result.rows = visible result.total = len(visible) return result @app.get("/health", response_model=HealthInfo) def health() -> HealthInfo: return provider.health()