2d7775f9b3
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m17s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Testy astroklienta (wersja demo) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 6s
Testy / Kontrola składni wszystkich warstw (push) Successful in 4s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m21s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m25s
Testy / Testy astroklienta (wersja demo) (pull_request) Successful in 9m26s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 5s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 4s
Demo ma być rozdawane szeroko i różnym osobom, więc pierwsza wersja — jedno konto na produkcyjnej warstwie danych — nie nadawała się do użycia: każdy dostawałby dostęp do oryginalnych baz, a wgrania jednego klienta widzieliby wszyscy. IZOLACJA OD PRODUKCJI. Warstwa danych i logiczna demo są osobne (manifesty w repo deploy). Osobna musi być TEŻ LOGICZNA, bo zna ona jeden adres warstwy danych — demo korzystające z produkcyjnej logiki i tak trafiłoby na produkcyjne bazy. PULE PER KONTO w warstwie danych. Zapytanie i lista plików niosą nazwę puli; puste = cały udział, czyli produkcja działa dokładnie jak dotąd i o pulach nic nie wie. Nazwa puli przechodzi przez sito dopuszczające wyłącznie znaki bezpieczne w nazwie katalogu — „../..” albo ukośnik wyprowadziłyby zapytanie wprost do cudzych baz, więc sito ZAMIENIA podejrzane znaki zamiast ufać, że nikt ich nie poda. PULA MUSI BYĆ W KLUCZU CACHE ZAPYTAŃ. Bez tego wynik policzony dla jednego konta trafiłby z cache do drugiego — cicha wymiana treści baz między klientami, niewidoczna w logach i nie do wykrycia z zewnątrz. Osobny test tego pilnuje. PULA WYNIKA Z LOGINU, nigdy z żądania. Klient warstwy logicznej jest budowany per żądanie i związany z pulą zalogowanej osoby; gdyby nazwa przychodziła z formularza, wystarczyłoby podstawić cudzy login. Test wysyła `tenant`, `user` i `login` w polach formularza i sprawdza, że nie mają na nią wpływu. Pulę wstrzykujemy w INSTANCJĘ klienta, nie w sygnatury metod. Argumentem trzeba by ją przeprowadzić przez protokół DataSource i build_report — kod, który o kontach nie ma prawa nic wiedzieć — a każde nowe wywołanie byłoby okazją, żeby o nią zapomnieć i sięgnąć nie tam. Konta demo to lista `login:sekret` (DEMO_USERS), bo jedno wspólne konto oznaczałoby wspólną pulę. Format i skrypt haseł te same, co w głównej aplikacji. Pula klienta to JEDEN KATALOG, więc przejście na pełną wersję nie oznacza utraty wgrań — procedurę importu opisuje runbook w repo deploy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 /search→SearchQuery→SearchResultGET /health→HealthInfo
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 | 10–100× 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