refactor: astroklient → astroklient-demo
Nazwa `astroklient` zostaje zarezerwowana dla przyszłej wersji produkcyjnej programu; obecna, demonstracyjna nazywa się od teraz `astroklient-demo`. Zmiana obejmuje katalog usługi, nazwę pliku testów, obraz w rejestrze (astrololo-astroklient-demo), job w CI, pętlę budowania obrazów, tytuł i nagłówek strony, nazwy loggerów, realm logowania, pole `layer` w /health oraz wymagania PRE-28/29 w xlsx. DWIE PUŁAPKI PODMIANY, obie sprawdzone po fakcie: Zdublowany przyrostek. `astroklient-demo` zawiera `astroklient`, więc powtórna podmiana dałaby `astroklient-demo-demo`. Sprawdziłem najpierw, że nigdzie nie ma jeszcze nowej nazwy, i dopiero wtedy podmieniłem raz. Polska odmiana. Ślepa podmiana zamieniła „astroklienta" na „astroklient-demoa” w czterech miejscach; poprawione na „astroklienta-demo". Tytuł FastAPI wyszedłby jako „astroklient-demo · demo", a nazwa jobu jako „Testy astroklienta-demo (wersja demo)" — oba skrócone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,12 +9,12 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Login
|
- name: Login
|
||||||
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.czernobog.pl -u gitea --password-stdin
|
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.czernobog.pl -u gitea --password-stdin
|
||||||
# astroklient dołącza do tej samej pętli: dzieli warstwę logiczną i łącze,
|
# astroklient-demo dołącza do tej samej pętli: dzieli warstwę logiczną i łącze,
|
||||||
# więc jego obraz ma powstawać z tego samego commita co reszta produktu.
|
# więc jego obraz ma powstawać z tego samego commita co reszta produktu.
|
||||||
- name: Build & push (data, logic, presentation, astroklient)
|
- name: Build & push (data, logic, presentation, astroklient-demo)
|
||||||
run: |
|
run: |
|
||||||
TAG=${GITHUB_SHA::8}
|
TAG=${GITHUB_SHA::8}
|
||||||
for SVC in data logic presentation astroklient; do
|
for SVC in data logic presentation astroklient-demo; do
|
||||||
docker build -t gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG ./services/$SVC
|
docker build -t gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG ./services/$SVC
|
||||||
docker push gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG
|
docker push gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ jobs:
|
|||||||
PYTHONPATH: .
|
PYTHONPATH: .
|
||||||
run: pytest tests -q -rs
|
run: pytest tests -q -rs
|
||||||
|
|
||||||
astroklient-tests:
|
astroklient-demo-tests:
|
||||||
name: Testy astroklienta (wersja demo)
|
name: Testy astroklienta-demo
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -100,14 +100,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
cache: pip
|
cache: pip
|
||||||
cache-dependency-path: services/astroklient/requirements-dev.txt
|
cache-dependency-path: services/astroklient-demo/requirements-dev.txt
|
||||||
- name: Instalacja zależności
|
- name: Instalacja zależności
|
||||||
run: pip install -r services/astroklient/requirements-dev.txt
|
run: pip install -r services/astroklient-demo/requirements-dev.txt
|
||||||
# Demo rozmawia z warstwą danych PRODUKCJI, więc jego powierzchnia musi być
|
# Demo rozmawia z warstwą danych PRODUKCJI, więc jego powierzchnia musi być
|
||||||
# pilnowana tak samo jak reszty: testy sprawdzają m.in., że nie przybyła
|
# pilnowana tak samo jak reszty: testy sprawdzają m.in., że nie przybyła
|
||||||
# żadna trasa poza dwiema funkcjami.
|
# żadna trasa poza dwiema funkcjami.
|
||||||
- name: Testy (pytest)
|
- name: Testy (pytest)
|
||||||
working-directory: services/astroklient
|
working-directory: services/astroklient-demo
|
||||||
env:
|
env:
|
||||||
PYTHONPATH: .
|
PYTHONPATH: .
|
||||||
run: pytest tests -q -rs
|
run: pytest tests -q -rs
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# astroklient — wersja demonstracyjna (PRE-28)
|
# astroklient-demo — wersja demonstracyjna (PRE-28)
|
||||||
|
|
||||||
Osobna warstwa prezentacji o **dwóch funkcjach**:
|
Osobna warstwa prezentacji o **dwóch funkcjach**:
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ okazji kodu reszty programu.
|
|||||||
## Izolacja: własne dane, pula na konto
|
## Izolacja: własne dane, pula na konto
|
||||||
|
|
||||||
```
|
```
|
||||||
astroklient → logic-demo → data-demo → udział astrololo-demo (pusty na starcie)
|
astroklient-demo → logic-demo → data-demo → udział astrololo-demo (pusty na starcie)
|
||||||
└── klientA/ ← pula konta
|
└── klientA/ ← pula konta
|
||||||
└── klientB/ ← pula konta
|
└── klientB/ ← pula konta
|
||||||
```
|
```
|
||||||
@@ -42,7 +42,7 @@ w nazwie katalogu: `../..` czy ukośnik wyprowadziłyby zapytanie poza udział.
|
|||||||
|
|
||||||
**Pula klienta to jeden katalog**, więc przejście na pełną wersję nie oznacza
|
**Pula klienta to jeden katalog**, więc przejście na pełną wersję nie oznacza
|
||||||
utraty wgrań — procedura importu jest w runbooku wdrożenia (repo `deploy`,
|
utraty wgrań — procedura importu jest w runbooku wdrożenia (repo `deploy`,
|
||||||
`astrololo/README-astroklient.md`).
|
`astrololo/README-astroklient-demo.md`).
|
||||||
|
|
||||||
## Konfiguracja
|
## Konfiguracja
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ cd services/presentation && python scripts/make_user.py demo
|
|||||||
## Uruchomienie lokalne
|
## Uruchomienie lokalne
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd services/astroklient
|
cd services/astroklient-demo
|
||||||
pip install -r requirements-dev.txt
|
pip install -r requirements-dev.txt
|
||||||
DEMO_PASSWORD=tajne LOGIC_URL=http://localhost:8001 \
|
DEMO_PASSWORD=tajne LOGIC_URL=http://localhost:8001 \
|
||||||
uvicorn app.main:app --port 8005
|
uvicorn app.main:app --port 8005
|
||||||
@@ -75,7 +75,7 @@ DEMO_PASSWORD=tajne LOGIC_URL=http://localhost:8001 \
|
|||||||
Testy:
|
Testy:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd services/astroklient && PYTHONPATH=. pytest tests -q
|
cd services/astroklient-demo && PYTHONPATH=. pytest tests -q
|
||||||
```
|
```
|
||||||
|
|
||||||
## Co pilnują testy
|
## Co pilnują testy
|
||||||
+1
-1
@@ -45,7 +45,7 @@ class LogicClient:
|
|||||||
def report(self, when_utc_iso: str, lat: float, lon: float) -> dict[str, Any]:
|
def report(self, when_utc_iso: str, lat: float, lon: float) -> dict[str, Any]:
|
||||||
"""Interpretacja urodzeniowa: sygnifikatory z obliczeń szukane w bazach.
|
"""Interpretacja urodzeniowa: sygnifikatory z obliczeń szukane w bazach.
|
||||||
|
|
||||||
Jedyne pytanie, jakie astroklient zadaje o treść — bez grupowania,
|
Jedyne pytanie, jakie astroklient-demo zadaje o treść — bez grupowania,
|
||||||
bez promptów, bez modelu językowego."""
|
bez promptów, bez modelu językowego."""
|
||||||
payload = {"when_utc": when_utc_iso, "lat": lat, "lon": lon,
|
payload = {"when_utc": when_utc_iso, "lat": lat, "lon": lon,
|
||||||
"limit": settings.report_limit, "group": False,
|
"limit": settings.report_limit, "group": False,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Konfiguracja astroklienta — wersji demonstracyjnej (PRE-28).
|
"""Konfiguracja astroklienta-demo — wersji demonstracyjnej (PRE-28).
|
||||||
|
|
||||||
Zna WYŁĄCZNIE adres warstwy logicznej, tak samo jak pełna prezentacja. Nie wie
|
Zna WYŁĄCZNIE adres warstwy logicznej, tak samo jak pełna prezentacja. Nie wie
|
||||||
nic o bazach, Excelu ani SQL-u.
|
nic o bazach, Excelu ani SQL-u.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""astroklient — wersja DEMONSTRACYJNA (PRE-28).
|
"""astroklient-demo — wersja DEMONSTRACYJNA (PRE-28).
|
||||||
|
|
||||||
DWIE FUNKCJE I ANI JEDNEJ WIĘCEJ:
|
DWIE FUNKCJE I ANI JEDNEJ WIĘCEJ:
|
||||||
1. dodanie pliku bazy (wgranie + włączenie do użytku),
|
1. dodanie pliku bazy (wgranie + włączenie do użytku),
|
||||||
@@ -10,7 +10,7 @@ Tutaj pozostałych funkcji NIE MA W OBRAZIE: nie ma tras, nie ma szablonów, nie
|
|||||||
nawet metod w kliencie warstwy logicznej. Demo można komuś oddać, nie oddając
|
nawet metod w kliencie warstwy logicznej. Demo można komuś oddać, nie oddając
|
||||||
przy okazji kodu reszty programu.
|
przy okazji kodu reszty programu.
|
||||||
|
|
||||||
UWAGA, ŚWIADOMA DECYZJA WŁAŚCICIELA: astroklient pracuje na TEJ SAMEJ warstwie
|
UWAGA, ŚWIADOMA DECYZJA WŁAŚCICIELA: astroklient-demo pracuje na TEJ SAMEJ warstwie
|
||||||
danych co produkcja. Kto ma do niego dostęp, czyta oryginalne bazy interpretacyjne,
|
danych co produkcja. Kto ma do niego dostęp, czyta oryginalne bazy interpretacyjne,
|
||||||
a pliki przez niego wgrane trafiają do produkcyjnego zbioru. Dlatego konto jest
|
a pliki przez niego wgrane trafiają do produkcyjnego zbioru. Dlatego konto jest
|
||||||
osobne (DEMO_USER/DEMO_PASSWORD) — żeby dało się odciąć demo jedną zmienną, bez
|
osobne (DEMO_USER/DEMO_PASSWORD) — żeby dało się odciąć demo jedną zmienną, bez
|
||||||
@@ -32,7 +32,7 @@ from app.clients.logic_client import LogicClient
|
|||||||
|
|
||||||
# Automatyczna dokumentacja WYŁĄCZONA — tak samo jak w pełnej aplikacji. /docs
|
# Automatyczna dokumentacja WYŁĄCZONA — tak samo jak w pełnej aplikacji. /docs
|
||||||
# wypisałoby komplet tras, a demo ma nie zdradzać nawet własnej powierzchni.
|
# wypisałoby komplet tras, a demo ma nie zdradzać nawet własnej powierzchni.
|
||||||
app = FastAPI(title="astroklient · demo", docs_url=None, redoc_url=None, openapi_url=None)
|
app = FastAPI(title="astroklient-demo", docs_url=None, redoc_url=None, openapi_url=None)
|
||||||
security.install(app)
|
security.install(app)
|
||||||
|
|
||||||
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
||||||
@@ -48,7 +48,7 @@ def _logic(request: Request) -> LogicClient:
|
|||||||
return LogicClient(tenant=getattr(request.state, "user", "") or "")
|
return LogicClient(tenant=getattr(request.state, "user", "") or "")
|
||||||
|
|
||||||
# Stan pliku „w użyciu" — ta sama nazwa, co w warstwie danych (DAN-27). Wpisana
|
# Stan pliku „w użyciu" — ta sama nazwa, co w warstwie danych (DAN-27). Wpisana
|
||||||
# tutaj wprost, bo astroklient nie importuje tamtej warstwy; literówka objawiłaby
|
# tutaj wprost, bo astroklient-demo nie importuje tamtej warstwy; literówka objawiłaby
|
||||||
# się dopiero na żywo, więc pilnuje jej test.
|
# się dopiero na żywo, więc pilnuje jej test.
|
||||||
ACTIVE = "active"
|
ACTIVE = "active"
|
||||||
|
|
||||||
@@ -152,4 +152,4 @@ def _wroc(error: str = "", done: str = "") -> RedirectResponse:
|
|||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
def health() -> dict:
|
def health() -> dict:
|
||||||
return {"status": "ok", "layer": "astroklient"}
|
return {"status": "ok", "layer": "astroklient-demo"}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Logowanie do astroklienta (PRE-28).
|
"""Logowanie do astroklienta-demo (PRE-28).
|
||||||
|
|
||||||
OSOBNE KONTO, NIE WSPÓŁDZIELONE Z GŁÓWNĄ APLIKACJĄ. Demo pracuje na tej samej
|
OSOBNE KONTO, NIE WSPÓŁDZIELONE Z GŁÓWNĄ APLIKACJĄ. Demo pracuje na tej samej
|
||||||
warstwie danych co produkcja, więc kto ma do niego dostęp, czyta oryginalne bazy
|
warstwie danych co produkcja, więc kto ma do niego dostęp, czyta oryginalne bazy
|
||||||
@@ -26,8 +26,8 @@ from collections import deque
|
|||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse
|
from fastapi.responses import HTMLResponse, JSONResponse
|
||||||
|
|
||||||
log = logging.getLogger("astroklient.security")
|
log = logging.getLogger("astroklient-demo.security")
|
||||||
audit_log = logging.getLogger("astroklient.audit")
|
audit_log = logging.getLogger("astroklient-demo.audit")
|
||||||
|
|
||||||
_SCRYPT_N, _SCRYPT_R, _SCRYPT_P, _SCRYPT_LEN = 2**14, 8, 1, 32
|
_SCRYPT_N, _SCRYPT_R, _SCRYPT_P, _SCRYPT_LEN = 2**14, 8, 1, 32
|
||||||
_HASH_PREFIX = "scrypt$"
|
_HASH_PREFIX = "scrypt$"
|
||||||
@@ -163,7 +163,7 @@ def install(app) -> None:
|
|||||||
_setup_audit_logging()
|
_setup_audit_logging()
|
||||||
if not auth_enabled():
|
if not auth_enabled():
|
||||||
log.warning(
|
log.warning(
|
||||||
"UWAGA: brak kont (DEMO_USERS / DEMO_PASSWORD) — astroklient stoi OTWARTY. "
|
"UWAGA: brak kont (DEMO_USERS / DEMO_PASSWORD) — astroklient-demo stoi OTWARTY. "
|
||||||
"Bez logowania nie ma też PULI: wszyscy pracowaliby na jednym, wspólnym "
|
"Bez logowania nie ma też PULI: wszyscy pracowaliby na jednym, wspólnym "
|
||||||
"zbiorze baz, widząc nawzajem swoje wgrania."
|
"zbiorze baz, widząc nawzajem swoje wgrania."
|
||||||
)
|
)
|
||||||
@@ -184,7 +184,7 @@ def install(app) -> None:
|
|||||||
if not user:
|
if not user:
|
||||||
return HTMLResponse(
|
return HTMLResponse(
|
||||||
"<h1>401 — wymagane logowanie</h1>", status_code=401,
|
"<h1>401 — wymagane logowanie</h1>", status_code=401,
|
||||||
headers={"WWW-Authenticate": 'Basic realm="astroklient"'})
|
headers={"WWW-Authenticate": 'Basic realm="astroklient-demo"'})
|
||||||
request.state.user = user
|
request.state.user = user
|
||||||
|
|
||||||
response = await call_next(request)
|
response = await call_next(request)
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
/* astroklient — arkusz CELOWO minimalny. Nie kopiujemy stylów pełnej aplikacji:
|
/* astroklient-demo — arkusz CELOWO minimalny. Nie kopiujemy stylów pełnej aplikacji:
|
||||||
demo ma dwa formularze i tabelę wyników, a każda przeniesiona klasa niosłaby
|
demo ma dwa formularze i tabelę wyników, a każda przeniesiona klasa niosłaby
|
||||||
nazwy funkcji, których tu nie ma. */
|
nazwy funkcji, których tu nie ma. */
|
||||||
:root {
|
:root {
|
||||||
+2
-2
@@ -3,13 +3,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>astroklient · {% block title %}{% endblock %}</title>
|
<title>astroklient-demo · {% block title %}{% endblock %}</title>
|
||||||
<link rel="stylesheet" href="/static/styles.css">
|
<link rel="stylesheet" href="/static/styles.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<h1>astroklient</h1>
|
<h1>astroklient-demo</h1>
|
||||||
{# CELOWO BEZ NAWIGACJI. Dwie funkcje mieszczą się na jednym ekranie,
|
{# CELOWO BEZ NAWIGACJI. Dwie funkcje mieszczą się na jednym ekranie,
|
||||||
a pasek zakładek z jedną pozycją tylko sugerowałby, że są inne. #}
|
a pasek zakładek z jedną pozycją tylko sugerowałby, że są inne. #}
|
||||||
</header>
|
</header>
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
"""astroklient — wersja demonstracyjna (PRE-28).
|
"""astroklient-demo — wersja demonstracyjna (PRE-28).
|
||||||
|
|
||||||
DWIE WŁASNOŚCI, KTÓRYCH PILNUJE TEN PLIK
|
DWIE WŁASNOŚCI, KTÓRYCH PILNUJE TEN PLIK
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ def test_without_credentials_nothing_is_served(env, monkeypatch):
|
|||||||
|
|
||||||
|
|
||||||
def test_demo_account_is_separate_from_the_main_application(env, monkeypatch):
|
def test_demo_account_is_separate_from_the_main_application(env, monkeypatch):
|
||||||
"""Konto astroklienta MUSI być własne: demo pracuje na tej samej warstwie
|
"""Konto astroklienta-demo MUSI być własne: demo pracuje na tej samej warstwie
|
||||||
danych co produkcja, więc odcięcie go nie może wymagać zmiany haseł
|
danych co produkcja, więc odcięcie go nie może wymagać zmiany haseł
|
||||||
w głównej aplikacji."""
|
w głównej aplikacji."""
|
||||||
monkeypatch.setenv("APP_USER", "astrololo")
|
monkeypatch.setenv("APP_USER", "astrololo")
|
||||||
Reference in New Issue
Block a user