# 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 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.