3ce3911f55
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m50s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m50s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 30s
Testy / Kontrola składni wszystkich warstw (push) Successful in 21s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m47s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m52s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 35s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 17s
Warstwy rozmawialy ze soba jawnym tekstem wewnatrz klastra. Token miedzywarstwowy (LOG-32) mowil KTO pyta, ale nie ukrywal CZEGO dotyczy odpowiedz — a plyna nia surowe wiersze oryginalnych baz interpretacyjnych, czyli rdzen produktu. Kto podsluchal ruch wewnatrz sieci (drugi pod, mirror portu na switchu, zrzut z wezla), mial je w calosci. Nowy modul link_crypto (kopia w kazdej z trzech uslug — nie maja wspolnej biblioteki; test pilnuje, ze kopie sa identyczne): - AES-256-GCM na ciele kazdego zadania i odpowiedzi. GCM daje poufnosc I uwierzytelnienie naraz, wiec nie ma wariantu „zaszyfrowane, ale podatne na modyfikacje". - DWA niezalezne klucze, po jednym na pare rozmowcow (prezentacja-logika, logika-dane). Przejecie klucza prezentacji nie otwiera warstwy danych, gdzie leza cale bazy. Z kazdego klucza lacza HKDF wyprowadza osobne podklucze na kierunek, wiec zadanie i odpowiedz nigdy nie szyfruja sie tym samym kluczem. - Do materialu uwierzytelnianego (AAD) wchodza kierunek, sciezka, znacznik czasu i numer ramki — wiec ramki nie da sie przekleic na inny endpoint, odtworzyc po czasie (okno MAX_SKEW) ani przestawic w strumieniu. - Strona serwerowa to czyste ASGI: podmienia cialo zanim zobaczy je FastAPI i przepuszcza odpowiedz strumieniowa kawalek po kawalku (okno postepu dziala dalej). Fail-closed: przy ustawionym kluczu jawne zadanie dostaje odmowe. Najgrozniejszy blad wyszedl dopiero z PODSLUCHU prawdziwego gniazda, nie z testow: klient BEZ klucza wysylal pytanie jawnym tekstem, ZANIM serwer zdazyl odmowic. Odpowiedz byla chroniona, zapytanie juz nie — a to wlasnie ono niesie sygnifikatory. Stad LINK_ENCRYPTION_REQUIRED: klient nie wysyla niczego, a usluga nie wstaje, jesli klucza brak. Ta sama zasada co przy sekrecie logowania — wolimy pod w CrashLoop niz usluge, ktora wstala i po cichu nie chroni niczego. Klient prezentacji przepuszczony przez jeden punkt `_post()`: dopoki kazda metoda skladala zadanie sama, dolozenie nowej znaczylo, ze latwo zapomniec o tokenie albo kluczu (401 wyszedl juz raz dopiero na produkcji). Test strukturalny rozszerzony: kazde wyjscie w dol musi miec i token, i klucz lacza, a surowe httpx wolno tylko na sciezkach wyjetych spod szyfrowania (/health). Weryfikacja: - 23 testy link_crypto, w tym dowod, ze tajny opis NIE wystepuje w bajtach lecacych po sieci, oraz odrzucenie: obcego klucza, przestawionego bitu, przekleconej sciezki, przestawionej ramki, przeterminowanej koperty, urwanego strumienia i absurdalnej dlugosci ramki. - E2E na prawdziwym uvicornie z proxy zrzucajacym gniazdo do pliku: przy wlaczonym wymaganiu tresci baz NIE MA na kablu (grep = 0) w obie strony; bez klucza / ze zlym kluczem — odmowa; klucz jednej pary nie otwiera drugiej. - Calosc: logika 200 passed/1 skipped, prezentacja 25 passed. docs/wdrozenie-pre16.md: instrukcja krok po kroku (klucze -> cert-manager -> DNS -> merge aplikacji -> merge manifestow -> zaufanie CA -> weryfikacja), z uzasadnieniem kolejnosci i tabela diagnostyki. Co-Authored-By: Claude Opus 4.8 <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