Commit Graph

11 Commits

Author SHA1 Message Date
gitea a833965909 feat(bezpieczeństwo): konta z uprawnieniami do zakładek i funkcji (PRE-27)
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m58s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 3m37s
Testy / Kontrola składni wszystkich warstw (push) Successful in 9s
build / build (push) Successful in 18s
Ekran „Konta" dla administratora: zakładanie, kasowanie i nadawanie uprawnień.
Zestaw funkcji zależy od konta, a konto ograniczone widzi program KOMPLETNY —
tylko mniejszy.

PODZIAŁ NA GRUPY. Ekrany to zakładki (7), bo zakładka jest naturalną jednostką —
to ją widać w nawigacji. Rozszerzenia to POZIOMY ZŁOŻONOŚCI wewnątrz ekranów:
porównanie systemów domów, wykresy dodatkowe, obliczenia zaawansowane, generowanie
tekstu przez model (kosztuje pieniądze) i eksport plików. Konto bez porównania
domów dostaje horoskop w Whole Sign i nie wie, że systemów jest trzynaście.

NIC NIE ZDRADZA, ŻE JEST WIĘCEJ:
- brak pozycji w menu zamiast pozycji wyszarzonej,
- 404 zamiast 403 — odmowa z powodem sama mówi, że coś tam jest,
- rysunki bez uprawnienia w OGÓLE NIE POWSTAJĄ, więc nie ma ich nawet w źródle,
- automatyczna dokumentacja API wyłączona. /docs, /redoc i /openapi.json wypisują
  komplet tras, czyli spis wszystkich funkcji programu — ochrona zakładek nic by
  nie dała, gdyby obok leżał ich katalog. Znalezione TESTEM przechodzącym po
  trasach aplikacji, nie przeglądem kodu.

KONTO ADMINISTRACYJNE zostaje w APP_USER/APP_PASSWORD, jak było. Nie leży w pliku
kont, więc nie da się go skasować ani ograniczyć z ekranu. Konto założone w pliku
o tym samym loginie NIE przesłoni administracyjnego — kolejność sprawdzania jest
odwrotna, inaczej dałoby się odebrać uprawnienia jedynemu, kto może je nadawać.
Uprawnienia administracyjnego nie da się też nadać z formularza: odsiewamy je
w normalise(), a nie w handlerze, więc żadne spreparowane żądanie tam nie sięgnie.

GRANICA JEST W HANDLERZE, NIE W SZABLONIE. Ukrycie pola chroni przed przypadkiem,
nie przed kimś, kto zna nazwy pól — _limit_options() ścina opcje po stronie
serwera i test wysyła spreparowane żądanie, żeby to potwierdzić.

MAPA TRASA→UPRAWNIENIE JEST JEDNA (features.ROUTES). Rozproszenie jej po
dekoratorach kończy się trasą, o której ochronie ktoś zapomniał — a taka dziura
jest niewidoczna, dopóki ktoś jej nie znajdzie. Trasa bez wpisu wymaga
administratora: przeoczenie ma ZAMYKAĆ, nie otwierać. Test idzie po trasach
APLIKACJI, nie po wpisach mapy — inaczej potwierdzałby tylko sam siebie.

Konta w pliku JSON na własnym podkatalogu NFS (nie tam, gdzie bazy — zamontowanie
całego udziału obeszłoby bokiem DAN-25). Hasła wyłącznie jako hash scrypt, tym
samym mechanizmem co APP_USERS. Zapis atomowy, bo przerwanie zapisu na NFS
obcięłoby plik, czyli skasowało wszystkie konta naraz.

Przy okazji przepisane trzy testy, które greppowały nawigację i main.py: menu
powstaje teraz z katalogu funkcji, więc szukanie sztywnych linków w base.html
niczego już nie sprawdzało.

Wymaga wolumenu na konta — osobny PR w repo deploy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 12:18:14 +00:00
gitea baf4e0e38a fix(kosmogram): własne dymki zamiast natywnych — działają też po powiększeniu
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m51s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 19s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 25s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m38s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m28s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 17s
Testy / Kontrola składni wszystkich warstw (push) Successful in 9s
Rysunek niesie <title> przy każdym obiekcie i każdej linii aspektu i to
wystarczało, dopóki koło było statyczne. Po dodaniu powiększania na pełne okno
dymki przestały się pokazywać.

CO SPRAWDZIŁEM W PRZEGLĄDARCE (1280×900, komplet danych): elementy z <title>
SĄ osiągalne kursorem — 19 z 20 trafień w hit-teście — więc nic ich nie zasłania
i problem nie leży w geometrii ani w pointer-events. Której dokładnie reguły
przeglądarka używa do stłumienia natywnego dymka, nie ustaliłem.

Nie ma to jednak znaczenia, bo natywny dymek jest tu i tak kiepskim narzędziem:
pojawia się po sekundzie zwłoki, nie da się go stylować, nie działa na dotyku
i nie ma go czym wywołać z klawiatury. Własny dymek usuwa zależność od zachowania
przeglądarki i przy okazji jest czytelniejszy.

Tekst bierzemy z <title> JUŻ OBECNEGO w rysunku, a nie z drugiej kopii opisów
w JS — inaczej rozjechałyby się przy pierwszej zmianie treści. Na czas najechania
<title> jest odpinany i wieszany z powrotem po zejściu kursora: dzięki temu nigdy
nie widać dwóch dymków naraz, a czytniki ekranu zachowują nazwę dostępną.

Warstwa 1150 CELOWO pomiędzy: nad nakładką powiększonego koła (1100), bo tam
właśnie zgłoszono problem, i pod oknem postępu (1200), które ma zostać na wierzchu
podczas pisania horoskopu. Test pilnuje tej kolejności liczbowo.

Ścieżka PDF nietknięta — składa się po stronie serwera, <title> zostają w rysunku.

Zweryfikowane w obu stanach koła: dymek pokazuje „Sun · 12°30'00'' · dom 1" nad
glifem i „Sun trygon Moon · orb 3.64°" nad linią aspektu, po powiększeniu też
(kursor-lupa mu nie przeszkadza), a po zejściu kursora wszystkie 20 <title>
wraca na miejsce.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 16:31:07 +02:00
gitea 4c1e7f8808 feat: przegląd baz na udziale + globalne włączanie/wyłączanie (DAN-15/PRE-09)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m30s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 12s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 40s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m3s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m35s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 14s
Testy / Kontrola składni wszystkich warstw (push) Successful in 10s
Wymaganie przedefiniowane pod model serwerowy (#47): nie wybiera się folderu —
pliki leżą na stałym NFS. Potrzeba za to WIDZIEĆ, jakie bazy są dostępne i móc
zdecydować, które biorą udział w interpretacji.

Warstwa danych: `bases.py` (lista plików + metaopis: nazwa, ścieżka, rozmiar,
data, stan) i endpoint `/bases`. Wyłączone bazy są ODSIEWANE z kandydatów przy
wyszukiwaniu, więc naprawdę nie biorą udziału w interpretacji — nie tylko znikają
z listy. Lista wyłączonych wchodzi do klucza cache zapytań: bez tego zmiana
ustawień oddawałaby wynik sprzed zmiany, czyli treść bazy uznanej za wyłączoną.
`list_bases()` doszło do interfejsu dostawcy jako OPCJONALNE (SQL nie operuje na
plikach → pusto, zamiast wywrotki).

Przelot logika → prezentacja i ekran „Ustawienia" z tabelą baz. Przez łącze idą
SAME METADANE — podgląd listy nie jest kolejną drogą do wyniesienia treści.

Stan przełączników jest DEKLARATYWNY (`DISABLED_BASES`), nie klikalny — i to jest
świadome: udział z bazami montujemy read-only, a katalog cache to `emptyDir`, więc
zapisany przełącznik ginąłby przy restarcie poda i po cichu włączał z powrotem
wyłączoną bazę. Ekran mówi wprost, jak wyłączyć bazę i dlaczego nie klikaniem.
Tryb klikalny wymagałby dołożenia trwałego wolumenu.

Weryfikacja na żywym łańcuchu: `/bases` przechodzi przez SZYFROWANE łącze
(logic→data), pokazuje 3 bazy z metaopisem i stanem; wyszukiwanie daje 3 → 2 → 0
wierszy w miarę wyłączania baz. Testy: dane +6, prezentacja +6. Dane 13,
logika 277, prezentacja 249.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 22:09:27 +02:00
gitea 7b435d4263 feat: synastria — aspekty między dwoma horoskopami (PRE-04)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m32s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m28s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 9s
build / build (push) Successful in 25s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m18s
Testy / Kontrola składni wszystkich warstw (push) Successful in 31s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 13m6s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Failing after 13m25s
Pierwsza technika relacyjna z pełnym UI (Returns były już w kalendarzu od LOG-12).
Dwie osoby → aspekty MIĘDZY ich horoskopami (planeta osoby A do planety osoby B).

Silnik: `find_cross_aspects(a, b, orb, luminary_bonus, minor)` — każdy obiekt A ×
każdy obiekt B. `obj1` = osoba A, `obj2` = osoba B. Statyczne (dwa natale, brak
wspólnego czasu) → bez applying/separating. Par sztywnych (NN/SN) NIE wycinamy —
między dwiema osobami to realny aspekt, nie artefakt definicji. Wspólny matcher
`_first_aspect` (z find_aspects), więc orb/bonus/aspekty poboczne działają tak samo.

Endpoint `POST /chart/synastry` (dwie osoby + zodiak + ustawienia aspektów) →
pozycje obu + siatka aspektów z glifami. Prezentacja: zakładka „Synastria",
formularz dwóch osób (pętla po a_/b_), tabela aspektów A · aspekt · B · orb.

Weryfikacja na żywym API: 13+13 obiektów, 63 aspekty synastryczne z poprawnymi
glifami i bonusem świateł (A.Sun ☌ B.Venus przy orbie 8.67 = 8+2). Testy: logika
+4 (cross-aspekty, kolejność A/B, brak filtra par sztywnych, brak applying),
prezentacja +7 (trasa, formularz dwóch osób, klient, tabela). Logika 277,
prezentacja 228.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 20:55:49 +02:00
gitea a0d1135db1 feat(prezentacja): cache-busting plików statycznych (PRE-26)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m29s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m36s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 11s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 8s
build / build (push) Successful in 50s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m51s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m29s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 11s
Testy / Kontrola składni wszystkich warstw (push) Successful in 8s
Po deployu przeglądarka trzymała stare styles.css / *.js — ten sam URL, więc
serwowała z cache mimo nowej wersji. Doklejamy do URL-a krótki HASH TREŚCI pliku:
zmienił się plik → zmienił się URL → przeglądarka pobiera nowy; bez zmian URL
zostaje ten sam i cache dalej działa (bustujemy tylko to, co się zmieniło).

- `static_url(name)` + globalny helper Jinja `static()`: `/static/x?v=<md5[:8]>`.
  Hash liczony raz na proces (lru_cache) — nowy pod po deployu = świeży hash;
  brak pliku → `?v=0`, nie wywala strony.
- Wszystkie odwołania w szablonach (styles.css, nasze *.js, vendor Leaflet) idą
  teraz przez helper zamiast surowego `/static/...`.

Testy: +5 (hash w URL, zależny od treści, brak-pliku-bezpieczny, żaden szablon nie
serwuje surowej ścieżki, base używa helpera). Test kolejności skryptów zaktualizowany
pod nowy format. Prezentacja 214.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 11:22:38 +02:00
gitea 6c9029c496 feat(prezentacja): zakladka „Skompiluj" — zbiorczy raport (PRE-23)
build / build (push) Successful in 52s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m16s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 32s
Testy / Kontrola składni wszystkich warstw (push) Failing after 8s
Czwarta wskazowka partnerow. Nowa zakladka sklada w jedno trzy kawalki liczone
w roznych miejscach: policzony horoskop, interpretacje natalna z AI i wszystkie
zapamietane predykcje okresowe.

Uklad sekcji dokladnie wg prosby: imie i nazwisko -> wprowadzone dane ->
RYSUNEK kosmogramu -> interpretacja natalna -> predykcje okresowe. Test pilnuje
tej kolejnosci, bo to jedyna rzecz, ktora latwo przestawic przy refaktorze,
a partnerzy podali ja wprost.

Skad material:
- HOROSKOP liczymy TU NA NOWO z danych formularza, zamiast go zapamietywac.
  To czysta funkcja wejscia — tanio powtorzyc, a odpada trzymanie w przegladarce
  duzego wyniku, ktory moglby sie rozjechac z aktualnym formularzem.
- INTERPRETACJA NATALNA — nowy natal.js, odpowiednik predictions.js. Natalna jest
  JEDNA (dotyczy momentu urodzenia, nie okresu), wiec ponowne wygenerowanie
  podmienia slot zamiast dokladac wpis.
- PREDYKCJE — z magazynu z PRE-22.

compile.js czyta magazyny przez ICH API (window.astrololoNatal /
astrololoPredictions), a nie siegajac wprost do localStorage — format danych ma
jednego wlasciciela: modul, ktory je zapisuje. Test tego pilnuje.

Zakladka MOWI, CZEGO BRAKUJE: panel gotowosci z trzema pozycjami i podpowiedzia,
na ktorej zakladce uzupelnic. Bez tego uzytkownik zlozylby niekompletny raport
i dowiedzialby sie o tym dopiero po otwarciu PDF-a.

Tresc od modelu jest ESKEJPOWANA przed wstawieniem do DOM — to tekst z zewnatrz,
wiec bez tego mielibysmy wektor wstrzykniecia.

Weryfikacja na zywej aplikacji: dwie predykcje zapisane w Kalendarzu, natalna
w Interpretacjach, obie odczytane na Skompiluj (panel: brak horoskopu na zolto,
dwa pozostale na zielono). Po zlozeniu wszystkie trzy zielone, a raport zaczyna
sie od „Jan Kowalski" i danych wejsciowych. Kolejnosc sekcji sprawdzona na
wyrenderowanym HTML: naglowek 2931 < dane 3033 < kosmogram 3158 < natalna 26544
< predykcje 26575.

Testy: 16 nowych. Poprawione tez trzy wlasne testy, ktore lapaly nazwy plikow
w KOMENTARZACH zamiast w tagach skryptow. Calosc: prezentacja 117 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 18:09:56 +02:00
gitea 76fbdefeaa feat(prezentacja): kliknięcie powiększa kosmogram na pełne okno (PRE-25)
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m52s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 46s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 19s
build / build (push) Successful in 1m10s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m59s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m50s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 42s
Testy / Kontrola składni wszystkich warstw (push) Successful in 19s
Ósma wskazówka partnerów, jako małe QoL przed PRE-22. Koło rysujemy w kolumnie
tekstu, więc na mniejszym ekranie glify i stopnie robią się nieczytelne.
Kliknięcie rozciąga wykres na całe okno, ponowne wraca do strony. SVG skaluje
się bez utraty jakości, więc nie potrzeba drugiej wersji rysunku ani biblioteki.

Wyjście z powiększenia na trzy sposoby: klik w wykres, klik w tło, Esc.
Dostępne też z klawiatury (Enter/Spacja, focus-visible), bo inaczej obejrzenie
szczegółów wymagałoby myszy.

Dwie decyzje warte odnotowania:

1. WARSTWA. z-index 1100 CELOWO pomiędzy: ponad kontrolkami Leafleta (1000),
   ale PONIŻEJ okna postępu (1200). Gdy trwa pisanie horoskopu, log operacji ma
   zostać na wierzchu. Test pilnuje tej nierówności, bo to jedyna liczba tutaj,
   którą łatwo zmienić bez zastanowienia i zepsuć coś niewidocznego na oko.

2. ROZMIAR. Koło jest kwadratowe, więc ograniczamy je KRÓTSZYM bokiem okna
   (min(96vw, 92vh)) — inaczej na szerokim ekranie wystawałoby w pionie.

Skrypt podpięty globalnie w base.html i osłonięty sprawdzeniem, czy koło w ogóle
jest na stronie — zadziała też na przyszłej zakładce „Skompiluj" bez zmian.
Przy powiększeniu blokujemy przewijanie strony pod spodem.

Weryfikacja na żywej aplikacji, pomiarami w DOM: po kliknięciu .wheel-fig ma
position:fixed, display:flex, z-index:1100; SVG rośnie z 460×460 do 662×653
przy oknie 1280×720, visibility visible; body dostaje overflow:hidden. Ponowne
kliknięcie wraca do 460×460 i zdejmuje klasę. Zrzutu ekranu stanu powiększonego
NIE mam — panel przeglądarki zaciął się w trakcie (puste klatki, viewport
raportowany jako 0×0), więc opieram się na pomiarach i testach.

Testy: 10 nowych. Całość: prezentacja 87 passed, logika 265 / 1 skip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:22:48 +02:00
gitea f34016a4a5 feat(prezentacja): wspolne dane formularza miedzy zakladkami + imie i nazwisko (PRE-21)
build / build (push) Successful in 58s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m53s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 38s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
Trzecia wskazowka partnerow. Kazda zakladke (Horoskop / Interpretacje /
Kalendarz) wypelnialo sie od nowa — te same imie, data, godzina, strefa
i miejsce. Teraz raz wpisane dane wedruja za uzytkownikiem, a zmiana w jednej
zakladce przenosi sie na pozostale.

Nowy formsync.js trzyma stan w localStorage. Dlaczego nie sesja na serwerze:
serwer zostaje BEZSTANOWY — zadnego magazynu sesji, zadnych danych urodzeniowych
trzymanych po stronie uslugi (spojne z postawa z LOG-32/PRE-16). Przy okazji
dane synchronizuja sie tez miedzy osobnymi kartami przegladarki, bo zdarzenie
`storage` daje to za darmo.

Dolozone pole „imie i nazwisko" (wszystkie trzy zakladki) — potrzebne do
naglowka raportu PDF (PRE-24). Handlery przyjmuja je i oddaja, wiec nie znika
po przeliczeniu.

Dwie rzeczy, ktore trzeba bylo domknac, zeby to dzialalo naprawde:

1. KOLEJNOSC SKRYPTOW. formsync.js ladowany w <head> z `defer` — skrypty defer
   wykonuja sie w kolejnosci dokumentu, wiec ten zdazy odtworzyc wspolrzedne,
   ZANIM geo.js zbuduje mape. Mapa startuje od razu we wlasciwym miejscu,
   zamiast przeskakiwac po chwili.

2. geo.js ustawia pola z KODU (`.value = ...`), co samo z siebie NIE wywoluje
   zdarzen — bez tego synchronizacja przegapilaby kazdy wybor z mapy, z
   wyszukiwarki i z „Tu i teraz". Dolozony setVal(), ktory jawnie zglasza
   `change`.

Zakladka bez danego pola (np. Sygnifikatory) nie kasuje wartosci zapamietanej
gdzie indziej; uszkodzony wpis w localStorage nie blokuje formularza.

Q-14 rozstrzygniete: lancuch LaTeX->PDF stanie jako OSOBNA USLUGA render —
spojne z izolacja swisseph (LOG-27), obraz produktu zostaje maly.

Weryfikacja na zywym stacku (data+logika+prezentacja) w przegladarce: dane
wpisane w Horoskopie pojawily sie w Interpretacjach; zmiana godziny w
Interpretacjach dotarla do Kalendarza; pola nieobecne na zakladce (zodiak,
system domow) przetrwaly; po POST imie zostalo, a horoskop policzyl sie
normalnie. Testy: 22 nowe strukturalne. Calosc: prezentacja 67 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 15:12:49 +00:00
gitea c4a181b810 Spięcie osi czasu z bazą interpretacji i widokiem (LOG-14, 1B->2B)
Realizuje przepływ 1B->2B z notes2: predykcyjne sygnifikatory (z datami)
dopasowane do interpretacji z bazy.

Logika:
- timeline.py: zdarzenia niosą strukturę (directed/aspect/target dla dyrekcji,
  lord/sign dla profekcji) do budowy tokenów.
- significators.interpret_events + _event_tokens: z każdego zdarzenia buduje
  tokeny bazy (dyrekcja: [planeta][aspekt][cel]; profekcja: [władca][znak]) i
  dopina interpretacje reużywając _facet_samples (AND tokenów, dedup, rozwinięcie).
- /chart/timeline: flaga interpret=true.

Prezentacja:
- nowa strona /timeline "Kalendarz": formularz (urodzenie + zakres dat) -> oś
  czasu z technikami, datami i interpretacjami; nawigacja + wspólne now.js.

Walidacja E2E na realnym main_base.xlsx (2025-2026):
- dyr. Saturn kwadratura MC -> 50 interpret. ("...5th house" -> "abortion/miscarriage")
- Władca Roku Saturn (wiek 42) -> 63; strona renderuje badge dat/technik.
71 testów przechodzi (nowy test_timeline_interpret).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 12:31:50 +02:00
gitea eef67d37b5 Wyszukiwarka: wynik obliczeń szukany w bazie interpretacji
Pierwsza wersja mostu horoskop -> sygnifikatory -> baza (zalążek LOG-16/18/19).

- logic/significators.py: z pozycji generuje tokeny w składni bazy (planeta
  [Su, znak [Tau...), pyta warstwę danych o rekordy z tokenem planety i zawęża
  do tych, które wspominają też jej znak ("planeta w swoim znaku"); odsiewa szum.
- logic /chart/report: nowy endpoint (pozycje -> raport dopasowań z interpretacjami).
- logic DataClient.search: parametr fields (lżejszy payload).
- data: naprawa str.contains regex=True -> regex=False (sygnifikatory zawierają
  [ + itd., metaznaki regex); podniesiony górny limit zapytania (le=50000).
- prezentacja: strona /interpret (formularz -> wyszukane interpretacje per obiekt)
  + nawigacja.

Zweryfikowano end-to-end na realnym pliku (Encyclopaedia of Medical Astrology,
53969 wierszy): dla horoskopu 30.04.1984 znaleziono m.in. Sun w Taurus 46,
Mars w Scorpio 57, Saturn w Scorpio 61 dopasowań; przykłady: "[Su in [Tau" ->
"the bump of amativeness prominent". 15 testów przechodzi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 14:57:26 +02:00
gitea 3195d9b003 Warstwa prezentacji: widok horoskopu do ręcznego testowania
Strona główna "/" = formularz podstawowych danych momentu (data, godzina,
strefa, opcjonalnie lokalizacja) → tabela policzonych pozycji w formie
human-readable (znak, pozycja w znaku, absolutna, kierunek, prędkość).
Woła logic /chart/positions; przelicza czas lokalny + offset na UTC.
Przycisk "Tu i teraz" uzupełnia bieżącą datę/godzinę i strefę przeglądarki.
Retrogradacja wyróżniona w tabeli.

Wyszukiwarkę sygnifikatorów przeniesiono pod "/significants" -> /significators,
dodano nawigację (base.html). Czytelny komunikat, gdy logika nie ma jeszcze
endpointu silnika.

Zweryfikowano end-to-end: formularz → przeliczenie UTC → render tabeli
(przez stub kontraktu /chart/positions).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 20:08:43 +02:00