Files
astrololo/services/data
gitea 78af6d4755
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 7s
feat(dane): mechanizm rekordów-pułapek (canary) — wykrywanie wycieku baz (DAN-26)
Zabezpieczenie DETEKCYJNE (nie prewencyjne): kilka unikalnych, wiarygodnie
wyglądających rekordów-pułapek w bazach. Nie zmieniają interpretacji (odsiewamy
je z wyników), ale jeśli pojawią się w cudzej kopii — są dowodem pochodzenia, a
przy wariancie na kopię — wskazują ŹRÓDŁO wycieku.

`canary.py`: pułapkę rozpoznajemy po MARKERZE (unikalny ciąg z ENV, nieobecny w
realnych danych). `screen(rows, query_value)`:
- ODSIEWA rekordy z markerem z wyników — i to na WYJŚCIU z warstwy danych
  (`/search`), więc nie dotrą wyżej ani do promptu LLM (LOG-30), niezależnie od
  dostawcy (Excel/SQL);
- TRIPWIRE: gdy zapytanie celuje wprost w marker (enumeracja bazy, nie liczenie
  horoskopu) → log warning.
Bez `CANARY_MARKERS` — przezroczyste, zero kosztu dla normalnego ruchu.

Rejestr wariant→kopia (traitor tracing) i wstrzyknięcie do REALNYCH baz to krok
właściciela (poza kodem — nie ruszamy kupionych plików automatycznie);
instrukcja: docs/canary-registry.md. Mechanizm zbudowany i przetestowany na
syntetycznych pułapkach.

Testy: +7 (przezroczystość bez markerów, odsiewanie, tripwire, marker w dowolnym
polu, endpoint odsiewa przed zwrotem). Pierwsze testy w usłudze `data`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 21:15:53 +02:00
..

Warstwa bazodanowa (data)

Niezależna usługa. Jedyne zadanie: wyszukać dane i podać je w górę. Nie zna warstwy logicznej ani prezentacji — komunikacja wyłącznie przez HTTP/JSON (models.py).

API

  • POST /searchSearchQuerySearchResult
  • GET /healthHealthInfo

Architektura wewnętrzna

providers/        wymienna implementacja (wzorzec Repository)
  base.py         interfejs DataProvider  ← kontrakt
  excel_provider  dziś: Excel + 4 poziomy cache
  sql_provider    jutro: SQL (ten sam interfejs)
  factory.py      DATA_PROVIDER=excel|sql
excel/            wykrywanie nagłówka + mapowanie układu kolumn (jedyne miejsce znające .xlsx)
cache/            fingerprint, schema(L1), frame/parquet(L2), query(L3), index(L4)
ingest/           build_index.py (warmup), to_sql.py (migracja ETL)

Cache — dlaczego szybko

Poziom Co cache'uje Zysk
L1 schema.db wykryty nagłówek + układ kolumn per plik brak ponownego skanu heurystyką
L2 Parquet znormalizowany arkusz 10100× szybciej niż parsowanie .xlsx
L3 QueryCache wynik zapytania (TTL/LRU) powtarzalne zapytania natychmiast
L4 index.db odwrócony indeks wartość→plik otwieramy tylko trafione pliki, nie setki

Unieważnianie: klucz = odcisk pliku (mtime+rozmiar, opcjonalnie sha256). Zmiana pliku → inny odcisk → automatyczny przebudowa.

Uruchomienie lokalne

pip install -r requirements.txt
python scripts/make_sample_data.py     # przykładowe .xlsx
python -m app.ingest.build_index       # (opcjonalnie) prebuild indeksu
uvicorn app.main:app --port 8002

Migracja do SQL (gdy nadejdzie czas)

python -m app.ingest.to_sql            # Excel -> tabela 'records' + indeksy
export DATA_PROVIDER=sql               # przełącz warstwę — reszta systemu bez zmian