feat(render): raport PDF przez LaTeX jako osobna usluga (PRE-24)
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 34s
Testy / Kontrola składni wszystkich warstw (push) Successful in 22s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m57s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 34s
Testy / Kontrola składni wszystkich warstw (push) Successful in 22s
Ostatnia z osmiu wskazowek partnerow. Nowa usluga services/render sklada raport:
generuje plik posredni .tex i kompiluje go XeLaTeX-em do PDF.
OSOBNY komponent, nie czesc prezentacji — ta sama zasada co przy izolacji
swissepha (LOG-27). TeX Live wazy setki megabajtow; w obrazie produktu
spowalnialby kazdy build, a tak aktualizuje sie niezaleznie i jego awaria nie
kladzie aplikacji, tylko przycisk „Pobierz PDF".
SZYFROWANIE, o ktore prosiles: lacze prezentacja↔render idzie tak samo jak
pozostale, ale z WLASNYM, TRZECIM kluczem (LINK_KEY_PRESENTATION_RENDER). Osobny,
bo tym laczem plynie CALY raport — dane urodzeniowe i opisy z baz — wiec przejecie
go nie moze otwierac lacza do logiki ani do danych. Fail-closed: bez klucza pod
nie wstaje. Test kopii link_crypto obejmuje teraz cztery uslugi.
Uklad PDF wg prosby: imie i nazwisko -> wprowadzone dane -> RYSUNEK kosmogramu
-> interpretacja natalna -> predykcje okresowe. Test pilnuje kolejnosci.
Dwie rzeczy, ktore wyszly dopiero przy skladaniu tego kawalka:
1. KOSMOGRAM NIE NADAWAL SIE DO PDF. Uzywa zmiennych CSS (var(--line)) i klasy
.glyph, ktorej font podaje styles.css — a samodzielny konwerter SVG→PDF nie zna
naszego arkusza. Wyszlyby czarne kreski BEZ SYMBOLI. Stad wariant „print":
konkretne kolory na bialym tle i font glifow wpisany wprost w rysunek. Przy
okazji zalatwia to etap 4 planu kola (wariant do druku).
2. UCIECZKA ZNAKOW LATEXA byla zepsuta — i zlapal to moj wlasny test. Zamiana
„\” na \textbackslash{} szla w tej samej petli co nawiasy, wiec kolejne
podmiany ucieklyby nawiasy dopiero co wstawione: wychodzilo
\textbackslash\{\}. Poprawka: ukosnik chowany pod znacznik zastepczy i
rozwijany na koncu. To nie kosmetyka — niezauwazony „%” komentuje RESZTE LINII,
wiec zdanie od modelu urywaloby sie w polowie, a PDF powstawalby normalnie,
tylko krotszy. Test na wrogim tekscie sprawdza tez, ze \end{document} ani
\input{} nie wyrwa sie z dokumentu.
Usluga nie zapisuje nic poza katalogiem tymczasowym, ktory sprzata po sobie;
w manifescie readOnlyRootFilesystem + emptyDir na /tmp. /health raportuje
obecnosc xelatex i rsvg-convert, zeby zepsuty obraz bylo widac od razu.
Zweryfikowane na zywo (TestClient uslugi render): zadanie bez szyfrowania
z POPRAWNYM tokenem -> 400; obcy klucz -> 400 i tajny opis nie wraca; wlasciwy
klucz -> zadanie dochodzi do aplikacji, tresci baz NIE MA na kablu, odpowiedz
zaszyfrowana. Manifesty przechodza kubectl apply --dry-run=server na zywym
klastrze.
CZEGO NIE SPRAWDZILEM: samej kompilacji PDF. W tym srodowisku nie ma ani TeX
Live, ani dzialajacego runtime'u kontenerow (docker CLI jest, daemon nie) —
probowalem zbudowac obraz i sie nie dalo. Sprawdzone jest wszystko dookola:
generowanie .tex, ucieczka znakow, szyfrowanie, kontrakt API, samowystarczalnosc
SVG. Pierwsze uruchomienie na klastrze trzeba obejrzec — dlatego PRE-24 zostaje
jako „W trakcie", nie „Zrobione".
Instrukcja wdrozenia: docs/wdrozenie-render-pdf.md (klucz, obraz, merge,
weryfikacja, znane ograniczenia).
Testy: 15 nowych (render) + 14 (lacze i wariant druku w prezentacji).
Calosc: prezentacja 131, logika 265/1 skip, render 15.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,139 @@
|
||||
# Wdrożenie usługi `render` — raport PDF (PRE-24)
|
||||
|
||||
Instrukcja krok po kroku dla nowego komponentu. Dotyczy dwóch repozytoriów:
|
||||
|
||||
| Repo | Co wnosi |
|
||||
|---|---|
|
||||
| `gitea/astrololo` | usługa `services/render`, klient w prezentacji, przycisk „Pobierz PDF", wariant kosmogramu do druku |
|
||||
| `gitea/deploy` | `astrololo/render.yaml`, adres i klucz łącza w `presentation.yaml` |
|
||||
|
||||
---
|
||||
|
||||
## Dlaczego osobna usługa
|
||||
|
||||
TeX Live waży setki megabajtów. W obrazie prezentacji spowalniałby każdy build
|
||||
i deploy, a przy każdej poprawce w CSS trzeba by go ciągnąć od nowa. Osobno:
|
||||
obraz produktu zostaje mały, TeX aktualizuje się niezależnie, a **awaria renderu
|
||||
nie kładzie aplikacji** — przestaje działać wyłącznie przycisk „Pobierz PDF".
|
||||
|
||||
To ta sama zasada, co przy izolacji silnika swisseph (LOG-27).
|
||||
|
||||
---
|
||||
|
||||
## Krok 1 — klucz łącza (PRZED wdrożeniem)
|
||||
|
||||
Usługa dostaje **cały raport**: dane urodzeniowe i opisy z baz. Łącze jest
|
||||
szyfrowane AES-256-GCM, własnym, **trzecim** kluczem — przejęcie go nie może
|
||||
otwierać łącza do logiki ani do danych.
|
||||
|
||||
Sekret `astrololo-link` już istnieje (PRE-16); dokładamy do niego trzeci klucz,
|
||||
**zachowując dwa dotychczasowe**:
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo create secret generic astrololo-link \
|
||||
--from-literal=LINK_KEY_PRESENTATION_LOGIC="$(kubectl -n astrololo get secret astrololo-link \
|
||||
-o jsonpath='{.data.LINK_KEY_PRESENTATION_LOGIC}' | base64 -d)" \
|
||||
--from-literal=LINK_KEY_LOGIC_DATA="$(kubectl -n astrololo get secret astrololo-link \
|
||||
-o jsonpath='{.data.LINK_KEY_LOGIC_DATA}' | base64 -d)" \
|
||||
--from-literal=LINK_KEY_PRESENTATION_RENDER="$(openssl rand -hex 32)" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
Sprawdzenie — mają być **trzy** klucze:
|
||||
```bash
|
||||
kubectl -n astrololo get secret astrololo-link -o jsonpath='{.data}' | tr ',' '\n'
|
||||
```
|
||||
|
||||
> **Uwaga:** `LINK_ENCRYPTION_REQUIRED=true` działa fail-closed. Bez klucza pod
|
||||
> `render` **nie wstanie** — i tak ma być. Usługa, która wstała i po cichu nie
|
||||
> szyfruje, jest gorsza niż CrashLoop, bo awarii nie widać.
|
||||
|
||||
---
|
||||
|
||||
## Krok 2 — obraz usługi
|
||||
|
||||
Obraz budowany jest osobnym workflow (jak silnik swisseph — nie wchodzi do
|
||||
głównego pipeline'u produktu). Pierwszy build trwa dłużej, bo ciągnie TeX Live.
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo get deploy render -o jsonpath='{.spec.template.spec.containers[0].image}'; echo
|
||||
```
|
||||
|
||||
Pakiety w obrazie dobrane **wąsko** (nie `texlive-full`, który ma kilka GB):
|
||||
|
||||
| Pakiet | Po co |
|
||||
|---|---|
|
||||
| `texlive-xetex` | silnik **XeLaTeX** — konieczny, bo raport ma polskie znaki i glify astrologiczne; `pdflatex` ich nie złoży |
|
||||
| `texlive-latex-recommended` | `geometry`, `graphicx` |
|
||||
| `fonts-dejavu-core` | jeden font na polskie znaki **i** symbole (♄ ♓ ☉) |
|
||||
| `librsvg2-bin` | `rsvg-convert` — SVG kosmogramu → PDF (LaTeX nie wstawia SVG wprost) |
|
||||
|
||||
Dockerfile sprawdza obecność obu narzędzi **przy budowie**, więc zepsuty obraz
|
||||
nie dojedzie na produkcję niezauważony.
|
||||
|
||||
---
|
||||
|
||||
## Krok 3 — merge manifestów
|
||||
|
||||
```bash
|
||||
tea pr merge --login gitea --repo gitea/deploy <numer>
|
||||
kubectl -n astrololo rollout status deploy/render deploy/presentation
|
||||
```
|
||||
|
||||
Wjeżdża naraz: `Deployment` + `Service` renderu (ClusterIP — **bez** Ingressu
|
||||
i NodePortu, nie ma powodu sięgać do niej z zewnątrz) oraz `RENDER_URL`
|
||||
i trzeci klucz w prezentacji.
|
||||
|
||||
---
|
||||
|
||||
## Krok 4 — sprawdzenie
|
||||
|
||||
### Narzędzia są na miejscu
|
||||
`/health` raportuje obecność `xelatex` i `rsvg-convert`, żeby zepsuty obraz
|
||||
było widać od razu, a nie dopiero przy pierwszym raporcie:
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo exec deploy/presentation -- \
|
||||
python -c "import httpx; print(httpx.get('http://render:8004/health').text)"
|
||||
```
|
||||
Oczekiwane: `{"status":"ok","layer":"render","tools":{"xelatex":true,"rsvg-convert":true}}`.
|
||||
Gdy `status` to `degraded` — obraz zbudował się bez któregoś narzędzia.
|
||||
|
||||
### Łącze faktycznie szyfruje
|
||||
Najmocniejszy test to próba obejścia. Z wnętrza klastra, **z poprawnym tokenem,
|
||||
ale bez szyfrowania**:
|
||||
|
||||
```bash
|
||||
kubectl -n astrololo exec deploy/presentation -- python -c "
|
||||
import httpx, os
|
||||
r = httpx.post('http://render:8004/pdf', json={'person':'test'},
|
||||
headers={'X-Astrololo-Token': os.environ['INTERNAL_TOKEN']})
|
||||
print(r.status_code, r.text[:80])
|
||||
"
|
||||
```
|
||||
Oczekiwane: **400** i `Łącze międzywarstwowe wymaga szyfrowania.` Sam token już
|
||||
nie wystarcza — o to chodziło.
|
||||
|
||||
### Raport od końca do końca
|
||||
W przeglądarce: **Skompiluj** → wypełnij dane → *Złóż podsumowanie* → *Pobierz PDF*.
|
||||
PDF ma zacząć się od imienia i nazwiska, potem wprowadzone dane, **rysunek
|
||||
kosmogramu**, a po nim interpretacja natalna i predykcje okresowe.
|
||||
|
||||
---
|
||||
|
||||
## Czego ta wersja nie załatwia
|
||||
|
||||
- **Kompilacja PDF nie została sprawdzona end-to-end** w środowisku, w którym
|
||||
powstawała — nie było tam ani TeX Live, ani runtime'u kontenerów. Sprawdzone
|
||||
jest wszystko dookoła: generowanie źródła `.tex` (w tym ucieczka znaków
|
||||
specjalnych), szyfrowanie łącza, kontrakt API i samowystarczalność SVG.
|
||||
**Pierwsze uruchomienie na klastrze trzeba obejrzeć.**
|
||||
- **Dzielenie wyrazów** jest angielskie — nie wciągamy `polyglossia`, żeby nie
|
||||
puchł obraz. Tekst składa się poprawnie, tylko przenoszenie bywa nieoptymalne.
|
||||
- **Brak kolejki**. Długi raport blokuje jedno połączenie na czas kompilacji
|
||||
(timeout klienta: 180 s). Przy większym ruchu warto dołożyć zadania w tle.
|
||||
- **Glify w tekście od modelu**. Kosmogram idzie jako obraz (rysuje go
|
||||
`rsvg-convert` z DejaVu), ale gdyby model wplótł symbole w prozę, złoży je
|
||||
XeLaTeX — też z DejaVu. Jeśli któregoś zabraknie, LaTeX zgłasza
|
||||
„Missing character" w logu i **nie drukuje znaku**; warto zerknąć w log
|
||||
pierwszego raportu.
|
||||
Reference in New Issue
Block a user