gitea 5a7f7e1b13
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Failing after 4m55s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 17s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m37s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Failing after 4m53s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 19s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
fix(konta): awaria magazynu tłumaczy się zamiast dawać gołe 500
Ekran „Konta" wywalał się na produkcji błędem 500 bez słowa wyjaśnienia.
Odtworzone lokalnie: `_read()` łapał wyłącznie brak pliku i zły JSON, więc każdy
inny błąd systemu plików — a na udziale NFS to głównie prawa — leciał na wierzch
jako nieobsłużony wyjątek.

To jest szczególnie zły sposób na awarię AKURAT TUTAJ: ekran kont jest jedynym
miejscem, z którego administrator może taki problem naprawić, a gołe 500 nie mówi
mu ani co, ani gdzie.

Teraz każdy błąd magazynu ma twarz: osobny wyjątek AccountsUnavailable niosący
ŚCIEŻKĘ i powód z systemu operacyjnego, plus podpowiedź najczęstszej przyczyny
(prawa katalogu na udziale albo wolumen zamontowany tylko do odczytu). Strona
renderuje się normalnie z tym komunikatem u góry.

Objęte są wszystkie cztery drogi zapisu, a nie tylko odczyt. W szczególności
mkstemp: przy katalogu tylko do odczytu wywala się ONO pierwsze, jeszcze zanim
dojdzie do zapisu i podmiany — więc obudowanie samego os.replace nic by nie dało
(złapane testem, nie przeglądem kodu).

USZKODZONY PLIK NIE JEST NADPISYWANY. Wcześniej niepoprawny JSON dawał pusty
zbiór kont, co przy pierwszym zapisie skasowałoby WSZYSTKIE konta bez śladu.
Teraz to odmowa z komunikatem — plik zostaje nietknięty, a test tego pilnuje.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 19:37:21 +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%