# astrololo Aplikacja w **modelu trójwarstwowym**, w pełni modułowa: trzy niezależne usługi, każda komunikuje się wyłącznie z sąsiadem (nigdy „przez głowę”). ``` ┌──────────────────────┐ formularz (w dół) ┌──────────────────────┐ zapytanie (w dół) ┌──────────────────────┐ │ PREZENTACJA (:8000) │ ───────────────────▶ │ LOGICZNA (:8001) │ ───────────────────▶ │ BAZODANOWA (:8002) │ │ strona WWW + form │ ◀─────────────────── │ reguły biznesowe │ ◀─────────────────── │ wyszukiwanie danych │ └──────────────────────┘ wyniki (w górę) └──────────────────────┘ dane (w górę) └──────────────────────┘ HTML/UI pośrednik + logika Excel(+cache) ▸ SQL ``` Każda warstwa to osobny katalog, osobny `requirements.txt`, osobny `Dockerfile` i osobne README. Komunikacja przez HTTP/JSON. Warstwa zna **tylko adres warstwy bezpośrednio pod nią** — nic o jej wnętrzu. | Warstwa | Katalog | Zna w dół | Zadanie | |--------|---------|-----------|---------| | Prezentacji | [`services/presentation`](services/presentation) | `LOGIC_URL` | serwuje stronę, przekazuje formularz, renderuje wyniki | | Logiczna | [`services/logic`](services/logic) | `DATA_URL` | reguły biznesowe, tłumaczenie zapytań, opracowanie wyników | | Bazodanowa | [`services/data`](services/data) | pliki Excela / SQL | **tylko** wyszukiwanie danych i podanie ich w górę | ## Szybki start (Docker) ```bash make sample # przykładowe pliki .xlsx do warstwy bazodanowej make up # zbuduj i uruchom 3 warstwy # otwórz http://localhost:8000 ``` ## Szybki start (lokalnie, 3 terminale) ```bash cd services/data && pip install -r requirements.txt && python scripts/make_sample_data.py make dev-data # terminal 1 -> :8002 make dev-logic # terminal 2 -> :8001 make dev-presentation # terminal 3 -> :8000 ``` ## Modułowość — dowód - Wymień prezentację (np. na SPA/React) → reszta bez zmian, kontrakt `/api/query` stały. - Wymień bazę (Excel → SQL) → prezentacja i logika bez zmian (patrz niżej). - Każdą warstwę da się uruchomić, testować i wdrażać osobno. ## Wydajność warstwy Excela — cache 4-poziomowy Dziś dane to setki dużych `.xlsx`, przeszukiwanych po **wykrytym nagłówku** i **układzie kolumn**. To kosztowne, więc warstwa bazodanowa ma cache (szczegóły: [`services/data/README.md`](services/data/README.md)): 1. **Schemat (L1, SQLite)** — wykryty nagłówek + mapowanie kolumn zapisane raz na wersję pliku. 2. **Dane (L2, Parquet)** — znormalizowany arkusz; kolejne odczyty 10–100× szybsze niż `.xlsx`. 3. **Zapytania (L3, in-memory TTL/LRU)** — powtarzalne wyszukiwania natychmiast (łatwo podmienić na Redis). 4. **Odwrócony indeks (L4, SQLite)** — `wartość → plik`; otwieramy tylko trafione pliki zamiast skanu setek. Unieważnianie automatyczne: klucz cache = **odcisk pliku** (`mtime+rozmiar`, opcjonalnie `sha256`). Zmiana pliku → przebudowa tylko jego wpisów. ## Droga na przyszłość — migracja do SQL Warstwa bazodanowa ukrywa źródło za interfejsem `DataProvider` (wzorzec Repository). Migracja: ```bash make migrate # ETL: tym samym loaderem Excel -> tabela 'records' + indeksy export DATA_PROVIDER=sql # przełącz całą warstwę ``` `SqlDataProvider` realizuje ten sam kontrakt `/search`, więc **warstwa logiczna i prezentacji nie zmieniają ani jednej linii**. Odwrócony indeks z L4 (SQLite) jest już pomostem — rozbudowa o wszystkie kolumny = docelowa baza.