feat(astroklient): własna warstwa danych i pule per konto (PRE-29)

Zmiana wobec pierwszej wersji: demo NIE pracuje już na produkcyjnej warstwie
danych. Ma własną logikę i własne dane, na osobnym udziale astrololo-demo,
pustym na starcie. Oryginalne bazy są dla demo nieosiągalne — nie przez
uprawnienia, tylko dlatego, że nie ma do nich drogi.

DLACZEGO OSOBNA JEST TEŻ WARSTWA LOGICZNA. Zna ona JEDEN adres warstwy danych,
więc astroklient korzystający z produkcyjnej logiki i tak trafiłby na produkcyjne
bazy. Izolacja musi sięgnąć obu warstw naraz, inaczej nie ma jej wcale. Jedyną
różnicą logic-demo wobec produkcyjnej jest DATA_URL — i to jest cała izolacja,
więc wpisanie tam „logic" cofnęłoby ją jednym słowem. Stąd komentarz przy tej
linii i sąsiedztwo obu plików.

PULE PER KONTO. Każde konto demo dostaje własny podkatalog na tym udziale,
niewidoczny dla pozostałych — w liście plików i w wynikach wyszukiwania. Konta
są listą `login:sekret` w sekrecie, bo jedno wspólne oznaczałoby wspólną pulę,
czyli klientów oglądających nawzajem swoje wgrania.

Ten sam OBRAZ co produkcja dla data i logic — różni je wyłącznie konfiguracja.
Osobny obraz to drugi kod do utrzymania i pewność, że kiedyś się rozjadą.

Logika demo nie dostaje kluczy do modeli językowych: astroklient nie umie o nie
prosić, więc nie ma powodu, żeby leżały w tym podzie.

Runbook opisuje IMPORT PULI KLIENTA do pełnej aplikacji — sedno całego układu,
bo klient przechodzący na pełną wersję nie może stracić wgrań. Jego pula to jeden
katalog: sprawdzenie kolizji nazw, kopiowanie z -n (nigdy nadpisania bazy
produkcyjnej), bez pliku stanu (produkcja ma własny), a na końcu świadome
włączenie w zakładce Pliki. Nie włączają się same, bo przeniesienie jest
czynnością techniczną, a decyzja o użyciu należy do właściciela.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 18:59:20 +02:00
parent 82c73f6aa5
commit e52284c88f
5 changed files with 280 additions and 56 deletions
+135 -44
View File
@@ -1,86 +1,177 @@
# astroklient — wdrożenie wersji demo (PRE-28)
# astroklient — wdrożenie wersji demo (PRE-28/29)
Osobna usługa o dwóch funkcjach: **dodanie pliku bazy** i **zapytanie o
interpretację urodzeniową**. Opis samej aplikacji: `services/astroklient/README.md`
interpretację urodzeniową**. Opis aplikacji: `services/astroklient/README.md`
w repo aplikacji.
---
## ⚠️ Przeczytaj, zanim komuś dasz adres
## Jak to jest odizolowane
Demo pracuje na **produkcyjnej warstwie danych**. To była świadoma decyzja, ale
niesie dwie konsekwencje, o których trzeba pamiętać za każdym razem:
```
astroklient → logic-demo → data-demo → /mnt/Tank1/astrololo-demo
└── klientA/ ← pula konta
└── klientB/ ← pula konta
```
* **kto ma dostęp do demo, czyta Twoje oryginalne bazy interpretacyjne** — czyli
rdzeń produktu, którego pilnują LOG-32, DAN-25 i PRE-27,
* **pliki wgrane przez demo trafiają do produkcyjnego zbioru** i od razu biorą
udział w wyszukiwaniu, także w pełnej aplikacji.
**Oryginalne bazy są dla demo nieosiągalne.** Nie chodzi o uprawnienia: demo ma
własną warstwę danych, pracującą na osobnym udziale, pustym na starcie.
Jeśli demo ma trafić do kogoś spoza kręgu zaufania, właściwą odpowiedzią jest
osobna warstwa danych z pustym udziałem — **nie jest to dziś zrobione**.
Dlaczego osobna jest też **warstwa logiczna**: zna ona jeden adres warstwy danych,
więc astroklient korzystający z produkcyjnej logiki i tak trafiłby na produkcyjne
bazy. Izolacja musi sięgnąć obu warstw naraz, inaczej nie ma jej wcale.
**Każde konto ma własną pulę** — swój podkatalog na tym udziale. Konta nie widzą
swoich plików nawzajem ani w liście, ani w wynikach wyszukiwania. Pula bierze się
z **loginu zalogowanej osoby**, nigdy z pola formularza.
---
## Krok 1 — sekret z hasłem demo
## Krok 1 — udział `astrololo-demo` na TrueNAS
Osobny sekret, nie `astrololo-auth`. Dzięki temu demo odcina się **jedną komendą**,
bez ruszania kont głównej aplikacji i bez zmiany hasła komukolwiek.
Ta sama procedura co przy `astrololo-state`, więc jeśli tamten działa, ten też
zadziała. Po SSH na NAS:
```bash
read -rs -p "Hasło do demo (DEMO_PASSWORD): " DEMO; echo
sudo zfs create Tank1/astrololo-demo # albo: sudo mkdir -p /mnt/Tank1/astrololo-demo
```
```bash
midclt call sharing.nfs.query '[["path","=","/mnt/Tank1/astrololo-demo"]]' \
| python3 -m json.tool
```
**Pusta lista `[]`** — twórz:
```bash
midclt call sharing.nfs.create '{
"path": "/mnt/Tank1/astrololo-demo",
"comment": "astrololo — pule kont wersji demo (PRE-29)",
"hosts": ["192.168.1.73", "192.168.1.80", "192.168.1.81"],
"enabled": true,
"ro": false,
"mapall_user": "root",
"mapall_group": "root"
}'
```
**Coś zwróciło** — weź `id` i użyj `sharing.nfs.update <ID>` z tą samą treścią.
```bash
midclt call service.restart nfs
sudo exportfs -v | grep astrololo-demo
```
Musi tam być `rw`. Sprawdź jeszcze zapis z węzła — to jest ten test, którego
zabrakło przy poprzednim udziale:
```bash
ssh <węzeł> 'sudo mkdir -p /mnt/t && sudo mount -t nfs 192.168.1.34:/mnt/Tank1/astrololo-demo /mnt/t \
&& sudo touch /mnt/t/proba && echo ZAPIS-OK || echo ZAPIS-NIE; sudo rm -f /mnt/t/proba; sudo umount /mnt/t'
```
---
## Krok 2 — konta demo
Każde konto to osobna pula, więc **rozdajesz konta, nie jedno hasło**.
Hasła najlepiej jako hash — wtedy nie leżą nigdzie jawnie (skrypt jest w repo
aplikacji, `services/presentation/scripts/make_user.py`):
```bash
python scripts/make_user.py klientA # wypisze: scrypt$…
python scripts/make_user.py klientB
```
```bash
kubectl -n astrololo create secret generic astrololo-demo \
--from-literal=DEMO_USERS='klientA:scrypt$…,klientB:scrypt$…'
```
### Dodanie konta później
```bash
STARE=$(kubectl -n astrololo get secret astrololo-demo -o jsonpath='{.data.DEMO_USERS}' | base64 -d)
kubectl -n astrololo create secret generic astrololo-demo \
--from-literal=DEMO_PASSWORD="$DEMO"
--from-literal=DEMO_USERS="${STARE},klientC:scrypt\$…" \
--dry-run=client -o yaml | kubectl apply -f -
unset DEMO
kubectl -n astrololo rollout restart deploy/astroklient
```
Login to `demo` (zmienny przez `DEMO_USER` w `astroklient.yaml`).
### Odebranie dostępu
Hasło może być też hashem `scrypt$…` — wtedy nie leży nigdzie jawnie:
```bash
cd services/presentation && python scripts/make_user.py demo # w repo aplikacji
```
Usuń wpis z `DEMO_USERS` tą samą drogą. **Pula zostaje na udziale** — pliki
klienta nie znikają, tylko przestaje być komu je pokazywać.
---
## Krok 2 — wdrożenie
## Krok 3 — wdrożenie
```bash
kubectl apply -k astrololo
kubectl -n astrololo rollout status deploy/astroklient
kubectl -n astrololo rollout status deploy/data-demo deploy/logic-demo deploy/astroklient
```
Image-updater ma astroklienta na liście, więc kolejne obrazy podbiją się same.
---
## Krok 3 — wejście z zewnątrz
Usługa jest `ClusterIP`; z zewnątrz wchodzi się **wyłącznie przez Ingress po
https**, tak samo jak do prezentacji. Dopisz regułę do `ingress.yaml` — osobny
host albo ścieżka, zależnie od tego, jak chcesz demo udostępniać.
Na czas sprawdzenia wystarczy tunel:
Sprawdzenie na czas jednej sesji, bez wystawiania na świat:
```bash
kubectl -n astrololo port-forward deploy/astroklient 8005:8005
```
i `http://localhost:8005` — login `demo`, hasło z kroku 1.
Wejście z zewnątrz wymaga reguły w `ingress.yaml` — osobny host albo ścieżka.
**Celowo nie zakładam tego za Ciebie**: to decyzja, pod jakim adresem świat
zobaczy demo.
---
## Odcięcie demo
## Import puli klienta do pełnej aplikacji
Sedno całego układu: klient, który przechodzi na pełną wersję, **nie traci
dotychczasowych wgrań**. Jego pula to jeden katalog.
**1. Zobacz, co tam jest** (na NAS):
```bash
kubectl -n astrololo delete secret astrololo-demo
kubectl -n astrololo rollout restart deploy/astroklient
LOGIN=klientA
sudo ls -la /mnt/Tank1/astrololo-demo/$LOGIN/
```
> Uwaga: **pod bez sekretu nie wstanie** i to jest zachowanie zamierzone.
> Alternatywnie `kubectl -n astrololo scale deploy/astroklient --replicas=0`,
> jeśli chcesz tylko wyłączyć, zachowując konfigurację.
**2. Sprawdź kolizje nazw** z bazami produkcyjnymi:
Konta głównej aplikacji pozostają nietknięte w obu przypadkach.
```bash
comm -12 \
<(cd /mnt/Tank1/astrololo-demo/$LOGIN && ls *.xlsx 2>/dev/null | sort) \
<(cd /mnt/Tank1/astrololo && ls *.xlsx 2>/dev/null | sort)
```
Pusto = brak kolizji. Cokolwiek się wypisze, przenieś ręcznie pod inną nazwą —
**nie nadpisuj bazy produkcyjnej**.
**3. Skopiuj** (`-n` = nie nadpisuj niczego, co już jest):
```bash
sudo cp -n /mnt/Tank1/astrololo-demo/$LOGIN/*.xlsx /mnt/Tank1/astrololo/
```
> Kopiujemy **tylko pliki `.xlsx`**. Plik `.files-state.json` zostaje — opisuje
> stan wewnątrz puli demo i w produkcji nie ma sensu; produkcja ma własny.
**4. Włącz je w pełnej aplikacji**: zakładka **Pliki**, nowe bazy pojawią się jako
„gotowa, odstawiona". Klikasz przełącznik przy tych, które mają wejść do użytku.
To, że nie włączają się same, jest zamierzone: przeniesienie plików jest czynnością
techniczną, a decyzja, które bazy biorą udział w interpretacji, należy do Ciebie.
---
## Odcięcie całego demo
```bash
kubectl -n astrololo scale deploy/astroklient --replicas=0
```
Pule i dane zostają. Skasowanie sekretu `astrololo-demo` zatrzyma pod (nie wstanie
bez niego) i to też jest zachowanie zamierzone.