gitea 6466ab89a9
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m12s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 19s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 12m25s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m33s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 16s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
feat(dane): interfejs zarządzania plikami baz — trzy poziomy dostępu (DAN-27)
Ekran „Pliki" z trzema poziomami, wpiętymi w kontrolę dostępu z PRE-27:

  „files"        widzi listę i KLIKANIEM decyduje, z których baz program korzysta,
  „files_input"  dokłada wgrywanie i ARCHIWIZACJĘ,
  administrator  kasowanie, przywracanie z archiwum i REGUŁY WALIDACJI.

STAN JEST TERAZ TRWAŁY. DAN-15 trzymał go w zmiennej DISABLED_BASES, bo warstwa
danych nie miała gdzie zapisywać — udział był montowany read-only. Skoro stan ma
być klikany, musi przetrwać restart, więc udział jest zapisywalny, a stan leży
w pliku obok baz (zapis atomowy: plik opisuje CAŁY zbiór, więc obcięcie w połowie
skasowałoby wiedzę o wszystkich naraz). DISABLED_BASES zostaje jako awaryjne
wyłączenie z konfiguracji i odsiewa DODATKOWO — nie odwrotnie, bo inaczej ktoś
z dostępem do ekranu włączyłby bazę wyłączoną świadomie na poziomie wdrożenia.

ARCHIWIZACJA NIE KASUJE. Plik zostaje na dysku, zamrożony, ze znacznikiem czasu;
znika wyłącznie z użytku. To najdalej idąca operacja osoby wgrywającej dane —
kasować może tylko administrator. Test sprawdza, że plik po archiwizacji nadal
istnieje, bo to jest cała istota tej operacji.

WALIDACJA JEST BRAMKĄ DO UŻYTKU, NIE FILTREM NA WEJŚCIU. Plik wgrany zostaje
NIEZALEŻNIE od wyniku — nie tracimy niczego, co ktoś wgrał. Zmienia się tylko to,
czy da się go włączyć. Sprawdzenie biegnie też w chwili włączania, nie tylko przy
wgrywaniu: reguły mogą się zmienić po fakcie.

O WALIDACJI WIE TYLKO ADMINISTRATOR. Pliki wstrzymane są odsiewane W WARSTWIE
DANYCH przy for_admin=False, a nie ukrywane w szablonie — gdyby dochodziły do
przeglądarki, wystarczyłby podgląd źródła, żeby poznać reguły. Odmowa włączenia
wraca do konta bez uprawnień BEZ POWODU, bo powód zdradza regułę. Sekcja reguł
nie trafia nawet do źródła strony. Test parametryzowany po obu niższych poziomach
szuka w odpowiedzi śladów mechanizmu i wymaga, żeby żadnego nie było.

Każdy plik ma policzony sha256 — tożsamość niezależna od nazwy. Wykorzystuje ją
już odrzucanie duplikatów, a w kroku drugim posłuży do pilnowania zgodności
lustra w SQL.

Przy okazji naprawiony błąd, który dopiero co bym wprowadził: Path("") to
Path("."), czyli wartość PRAWDZIWA, więc `Path(os.getenv(...)) or domyślna`
zawsze wybierało pustą zmienną i zapisywało stan do katalogu bieżącego.

Wymaga zapisywalnego udziału — osobny PR w repo deploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 14:39:42 +02:00
2026-07-28 22:28:47 +02:00
2026-07-20 19:52:21 +02:00

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 LOGIC_URL serwuje stronę, przekazuje formularz, renderuje wyniki
Logiczna services/logic DATA_URL reguły biznesowe, tłumaczenie zapytań, opracowanie wyników
Bazodanowa services/data pliki Excela / SQL tylko wyszukiwanie danych i podanie ich w górę

Szybki start (Docker)

make sample      # przykładowe pliki .xlsx do warstwy bazodanowej
make up          # zbuduj i uruchom 3 warstwy
# otwórz http://localhost:8000

Szybki start (lokalnie, bez Dockera — zalecane)

python -m venv .env && source .env/bin/activate   # venv (jednorazowo)
make install                                       # zależności WSZYSTKICH warstw
make sample                                        # opcjonalnie: dane przykładowe

Potem w 3 osobnych terminalach (w każdym source .env/bin/activate):

make dev-data            # terminal 1  -> :8002
make dev-logic           # terminal 2  -> :8001
make dev-presentation    # terminal 3  -> :8000   ->  http://localhost:8000

make install instaluje zależności wszystkich trzech warstw do aktywnego venv. Testy silnika: make test. Wyczyszczenie cache: make clean-cache.

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):

  1. Schemat (L1, SQLite) — wykryty nagłówek + mapowanie kolumn zapisane raz na wersję pliku.
  2. Dane (L2, Parquet) — znormalizowany arkusz; kolejne odczyty 10100× 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:

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.

updater test Mon 20 Jul 2026 19:52:08 CEST

S
Description
No description provided
Readme 3.8 MiB
Languages
Python 86.4%
HTML 6.2%
JavaScript 3.8%
CSS 2.9%
Dockerfile 0.4%
Other 0.3%