Szkielet aplikacji trójwarstwowej (prezentacja / logika / dane)

Trzy niezależne usługi FastAPI komunikujące się przez HTTP/JSON, każda
zna tylko adres warstwy bezpośrednio pod nią:

- presentation (:8000) — strona WWW + formularz
- logic (:8001) — reguły biznesowe, pośrednik
- data (:8002) — wyszukiwanie danych za interfejsem DataProvider

Warstwa danych: czytanie setek plików .xlsx z wykrywaniem nagłówka i
mapowaniem układu kolumn na schemat kanoniczny, z 4-poziomowym cache
(schemat L1, Parquet L2, wyniki zapytań L3, odwrócony indeks L4) i
unieważnianiem po odcisku pliku. Gotowa ścieżka migracji do SQL
(ingest/to_sql.py + SqlDataProvider, przełączane przez DATA_PROVIDER).

Zawiera docker-compose, Makefile, generator danych przykładowych.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 17:35:09 +02:00
parent a43d1ff955
commit 16d35c16dc
52 changed files with 1491 additions and 1 deletions
+30
View File
@@ -0,0 +1,30 @@
"""Klient HTTP do warstwy bazodanowej.
Jedyny punkt styku w dół. Gdyby warstwa bazodanowa zmieniła implementację
(Excel→SQL), tutaj nie zmienia się NIC — kontrakt /search jest stały.
"""
from __future__ import annotations
from typing import Any
import httpx
from app.config import settings
class DataClient:
def __init__(self, base_url: str | None = None) -> None:
self.base_url = (base_url or settings.data_url).rstrip("/")
def search(self, key: str, value: str, exact: bool, limit: int) -> dict[str, Any]:
payload = {"key": key, "value": value, "exact": exact, "limit": limit}
with httpx.Client(timeout=settings.http_timeout) as client:
r = client.post(f"{self.base_url}/search", json=payload)
r.raise_for_status()
return r.json()
def health(self) -> dict[str, Any]:
with httpx.Client(timeout=settings.http_timeout) as client:
r = client.get(f"{self.base_url}/health")
r.raise_for_status()
return r.json()