diff --git a/docs/superpowers/plans/2026-07-20-ausbaustufe-10.md b/docs/superpowers/plans/2026-07-20-ausbaustufe-10.md index a4a3ac1..3990114 100644 --- a/docs/superpowers/plans/2026-07-20-ausbaustufe-10.md +++ b/docs/superpowers/plans/2026-07-20-ausbaustufe-10.md @@ -61,7 +61,7 @@ systemd `--user`), Grafana OSS 12.1.0, Bash-Deployskript. `FB_SESSION_COOKIE_SECURE`, Default `False`). Bool-Parsing via Modul-Helfer `_env_bool(value: str) -> bool` (truthy: `1/true/yes/on`, case-insensitiv). -- [ ] **Step 1: Failing Tests schreiben** — an `finance/tests/test_config.py` +- [x] **Step 1: Failing Tests schreiben** — an `finance/tests/test_config.py` anhängen (oben `import pytest` ergänzen, falls nicht vorhanden): ```python @@ -105,12 +105,12 @@ def test_session_cookie_secure_parsing(monkeypatch, val, expected): get_settings.cache_clear() ``` -- [ ] **Step 2: Tests laufen lassen, Fehlschlag prüfen** +- [x] **Step 2: Tests laufen lassen, Fehlschlag prüfen** Run: `cd finance && .venv/bin/python -m pytest tests/test_config.py -q` Expected: FAIL (`AttributeError: ... 'grafana_public_url'` / `session_cookie_secure`). -- [ ] **Step 3: Implementieren** — `finance/app/config.py`. Bool-Helfer vor +- [x] **Step 3: Implementieren** — `finance/app/config.py`. Bool-Helfer vor `get_settings` einfügen, zwei Felder ins `@dataclass Settings` und zwei Zeilen in den `Settings(...)`-Konstruktor: @@ -142,17 +142,17 @@ In `get_settings()` in den `return Settings(...)`-Aufruf (nach session_cookie_secure=_env_bool(e("FB_SESSION_COOKIE_SECURE", "")), ``` -- [ ] **Step 4: Tests grün** +- [x] **Step 4: Tests grün** Run: `cd finance && .venv/bin/python -m pytest tests/test_config.py -q` Expected: PASS. -- [ ] **Step 5: Volle Suite** +- [x] **Step 5: Volle Suite** Run: `cd finance && .venv/bin/python -m pytest -q` Expected: PASS (> 199). -- [ ] **Step 6: Fable-Gate + Commit** +- [x] **Step 6: Fable-Gate + Commit** ```bash git add finance/app/config.py finance/tests/test_config.py @@ -173,7 +173,7 @@ git commit -m "feat: FB_GRAFANA_PUBLIC_URL + FB_SESSION_COOKIE_SECURE in Setting `secure`) auf: jetzt per Env konfigurierbar, Default unverändert (kein `secure` im Lokalbetrieb). -- [ ] **Step 1: Failing Tests** — an `finance/tests/test_auth.py` anhängen. +- [x] **Step 1: Failing Tests** — an `finance/tests/test_auth.py` anhängen. Sicherstellen, dass oben importiert ist: `from app.config import get_settings`. Die Tests nutzen die vorhandene `client`-Fixture (setzt Passwort-Hash) und schalten das Flag zur Laufzeit um (Login liest `get_settings()` je Request): @@ -197,12 +197,12 @@ def test_login_cookie_not_secure_by_default(client, monkeypatch): assert "secure" not in r.headers["set-cookie"].lower() ``` -- [ ] **Step 2: Fehlschlag prüfen** +- [x] **Step 2: Fehlschlag prüfen** Run: `cd finance && .venv/bin/python -m pytest tests/test_auth.py::test_login_cookie_secure_when_enabled -q` Expected: FAIL (`assert "secure" in ...`, Cookie hat noch kein secure-Flag). -- [ ] **Step 3: Implementieren** — in `finance/app/main.py` den +- [x] **Step 3: Implementieren** — in `finance/app/main.py` den `set_cookie`-Aufruf im Login um `secure=` ergänzen: ```python @@ -219,17 +219,17 @@ def login(username: str = Form(...), password: str = Form(...)): return resp ``` -- [ ] **Step 4: Tests grün** +- [x] **Step 4: Tests grün** Run: `cd finance && .venv/bin/python -m pytest tests/test_auth.py -q` Expected: PASS. -- [ ] **Step 5: Volle Suite** +- [x] **Step 5: Volle Suite** Run: `cd finance && .venv/bin/python -m pytest -q` Expected: PASS. -- [ ] **Step 6: Fable-Gate + Commit** +- [x] **Step 6: Fable-Gate + Commit** ```bash git add finance/app/main.py finance/tests/test_auth.py @@ -254,7 +254,7 @@ git commit -m "feat: Session-Cookie secure-Flag per FB_SESSION_COOKIE_SECURE" `http://:8097`. Templates hängen bei Bedarf `/d/finanzen/...` an — mit sub-path-URL ergibt das `.../grafana/d/finanzen/...`. -- [ ] **Step 1: Failing Tests** — an `finance/tests/test_gui.py` anhängen. Oben +- [x] **Step 1: Failing Tests** — an `finance/tests/test_gui.py` anhängen. Oben `from app.config import get_settings` ergänzen, falls nicht vorhanden: ```python @@ -287,12 +287,12 @@ def test_grafana_links_fallback_to_host_port_when_unset(client, monkeypatch): get_settings.cache_clear() ``` -- [ ] **Step 2: Fehlschlag prüfen** +- [x] **Step 2: Fehlschlag prüfen** Run: `cd finance && .venv/bin/python -m pytest tests/test_gui.py::test_grafana_links_use_public_url_when_set -q` Expected: FAIL (Templates nutzen noch `:8097`, `:8097` ist im Text). -- [ ] **Step 3a: Jinja-Global implementieren** — `finance/app/routers/gui.py`. +- [x] **Step 3a: Jinja-Global implementieren** — `finance/app/routers/gui.py`. Import ergänzen (bei den `from app...`-Imports): ```python @@ -319,7 +319,7 @@ def grafana_public_base(request: Request) -> str: templates.env.globals["grafana_public_base"] = grafana_public_base ``` -- [ ] **Step 3b: Templates umstellen.** +- [x] **Step 3b: Templates umstellen.** `finance/app/templates/base.html` Zeile 20: @@ -342,22 +342,22 @@ templates.env.globals["grafana_public_base"] = grafana_public_base Kurven in Grafana ansehen. ``` -- [ ] **Step 4: Tests grün** +- [x] **Step 4: Tests grün** Run: `cd finance && .venv/bin/python -m pytest tests/test_gui.py -q` Expected: PASS. -- [ ] **Step 5: Kontrollgriff — keine hartkodierten `:8097` mehr in Templates** +- [x] **Step 5: Kontrollgriff — keine hartkodierten `:8097` mehr in Templates** Run: `grep -rn ":8097" finance/app/templates` Expected: keine Treffer. -- [ ] **Step 6: Volle Suite** +- [x] **Step 6: Volle Suite** Run: `cd finance && .venv/bin/python -m pytest -q` Expected: PASS. -- [ ] **Step 7: Fable-Gate + Commit** +- [x] **Step 7: Fable-Gate + Commit** ```bash git add finance/app/routers/gui.py finance/app/templates/base.html \ @@ -381,7 +381,7 @@ git commit -m "feat: Grafana-Links aus FB_GRAFANA_PUBLIC_URL (Sub-Pfad-tauglich) nur an `127.0.0.1` gebunden ist und ausschließlich der lokale Traefik ihn erreicht (dokumentiert in docs/reverse-proxy.md, Task 6). -- [ ] **Step 1: Failing Test** — `finance/tests/test_entrypoint.py` anlegen: +- [x] **Step 1: Failing Test** — `finance/tests/test_entrypoint.py` anlegen: ```python from pathlib import Path @@ -395,12 +395,12 @@ def test_entrypoint_enables_proxy_headers(): assert "--forwarded-allow-ips" in text ``` -- [ ] **Step 2: Fehlschlag prüfen** +- [x] **Step 2: Fehlschlag prüfen** Run: `cd finance && .venv/bin/python -m pytest tests/test_entrypoint.py -q` Expected: FAIL (Flags fehlen noch). -- [ ] **Step 3: Implementieren** — `finance/entrypoint.sh` vollständig: +- [x] **Step 3: Implementieren** — `finance/entrypoint.sh` vollständig: ```sh #!/bin/sh @@ -416,17 +416,17 @@ exec uvicorn app.main:app --host 0.0.0.0 --port 8000 \ --proxy-headers --forwarded-allow-ips='*' ``` -- [ ] **Step 4: Test grün + Shell-Syntaxcheck** +- [x] **Step 4: Test grün + Shell-Syntaxcheck** Run: `cd finance && .venv/bin/python -m pytest tests/test_entrypoint.py -q && sh -n entrypoint.sh && echo OK` Expected: PASS + `OK`. -- [ ] **Step 5: Volle Suite** +- [x] **Step 5: Volle Suite** Run: `cd finance && .venv/bin/python -m pytest -q` Expected: PASS. -- [ ] **Step 6: Fable-Gate + Commit** +- [x] **Step 6: Fable-Gate + Commit** ```bash git add finance/entrypoint.sh finance/tests/test_entrypoint.py @@ -451,7 +451,7 @@ git commit -m "feat: uvicorn Proxy-Headers fuer Reverse-Proxy-Betrieb" `bash -n`, isolierten Test der Sub-Pfad-Extraktion und den Live-Redeploy in Task 7. -- [ ] **Step 1: Sub-Pfad-Berechnung einfügen** — in `create_pod_finance.sh` +- [x] **Step 1: Sub-Pfad-Berechnung einfügen** — in `create_pod_finance.sh` VOR dem **API**-`podman run` (`podman run -d --name "$API_CTR_NAME" ...`) diesen Block einfügen. WICHTIG: nicht erst vor dem Grafana-Container — der API-Container läuft im Skript zuerst und verwendet bereits `${GF_SUBPATH}` @@ -481,7 +481,7 @@ if [ -n "${FB_GRAFANA_PUBLIC_URL:-}" ]; then fi ``` -- [ ] **Step 2: Grafana-Container um die Sub-Pfad-Args ergänzen** — im +- [x] **Step 2: Grafana-Container um die Sub-Pfad-Args ergänzen** — im `podman run -d --name "$GRAFANA_CTR_NAME" ...`-Aufruf eine Zeile einfügen (z.B. direkt nach `-e GF_SECURITY_COOKIE_SAMESITE=lax \`): @@ -492,7 +492,7 @@ fi (Bei leerem Array expandiert das unter bash zu nichts — Lokalbetrieb unverändert.) -- [ ] **Step 3: API-Container um die drei Env-Durchreichungen ergänzen** — im +- [x] **Step 3: API-Container um die drei Env-Durchreichungen ergänzen** — im `podman run -d --name "$API_CTR_NAME" ...`-Aufruf nach der Zeile `-e FB_UPLOADS_DIR=/data/uploads \` einfügen: @@ -506,7 +506,7 @@ unverändert.) zum bisherigen Config-Default; im Sub-Pfad-Modus `http://localhost:3000/grafana`, damit die GUI-Passwortänderung die Grafana-Admin-API unter dem Präfix trifft.) -- [ ] **Step 4: Grafana-Health-Check-URL sub-path-bewusst machen** — die Zeile +- [x] **Step 4: Grafana-Health-Check-URL sub-path-bewusst machen** — die Zeile ```bash CHECK_URL_GRAFANA="http://$HOST_LOCAL_IP:$GRAFANA_HOST_PORT/api/health" @@ -518,7 +518,7 @@ ersetzen durch: CHECK_URL_GRAFANA="http://$HOST_LOCAL_IP:$GRAFANA_HOST_PORT${GF_SUBPATH}/api/health" ``` -- [ ] **Step 5: Statische Verifikation** +- [x] **Step 5: Statische Verifikation** Run: `bash -n create_pod_finance.sh && echo SYNTAX-OK` Expected: `SYNTAX-OK`. @@ -538,7 +538,7 @@ http://host.tld/g/ -> [/g] -> [] ``` -- [ ] **Step 6: Fable-Gate (adversariale Skript-Review) + Commit** +- [x] **Step 6: Fable-Gate (adversariale Skript-Review) + Commit** Fable prüft insbesondere: Lokalbetrieb (leere Variable) ist echter No-Op (leeres Array, leerer Präfix, `FB_GRAFANA_URL=http://localhost:3000`); @@ -562,7 +562,7 @@ git commit -m "feat: create_pod_finance.sh Grafana-Sub-Pfad + interne URLs sub-p - Produces: Betriebsdoku für den Proxy-Umzug. Beispiel-Snippets sind Vorlagen — die eigentliche Proxy-Konfiguration macht der Nutzer. -- [ ] **Step 1: `docs/reverse-proxy.md` anlegen** mit folgendem Inhalt: +- [x] **Step 1: `docs/reverse-proxy.md` anlegen** mit folgendem Inhalt: ````markdown # Reverse-Proxy-Betrieb (Ausbaustufe 10) @@ -658,7 +658,7 @@ Forwarded-Proto https` ist wichtig, damit uvicorn (mit `--proxy-headers`) das entfernen (oder leeren) und `./create_pod_finance.sh` erneut ausführen. ```` -- [ ] **Step 2: Verweis in `docs/ARCHITEKTUR.md`** — im Deployment-Abschnitt +- [x] **Step 2: Verweis in `docs/ARCHITEKTUR.md`** — im Deployment-Abschnitt (Abschnitt 3) einen Hinweis auf die neue Doku ergänzen, z.B.: ```markdown @@ -668,10 +668,10 @@ entfernen (oder leeren) und `./create_pod_finance.sh` erneut ausführen. > Direktbetrieb unverändert. ``` -- [ ] **Step 3: `CLAUDE.md`** — im Abschnitt zur `.env` die zwei neuen +- [x] **Step 3: `CLAUDE.md`** — im Abschnitt zur `.env` die zwei neuen Variablen kurz erwähnen (ein Satz), inkl. Verweis auf `docs/reverse-proxy.md`. -- [ ] **Step 4: Fable-Gate (Faktencheck gegen Skript/Config/Templates) + Commit** +- [x] **Step 4: Fable-Gate (Faktencheck gegen Skript/Config/Templates) + Commit** Fable prüft: Snippets stimmen mit dem tatsächlichen Verhalten aus Task 1–5 überein (Ports 8096/8097, kein Prefix-Stripping, `serve_from_sub_path`, @@ -696,26 +696,26 @@ git commit -m "docs: Reverse-Proxy-Snippets (Traefik/Apache) + .env-Schalter" - Live-Verifikation, dass der **Lokalbetrieb** (leere Proxy-Variablen) mit v0.10.0 unverändert funktioniert. -- [ ] **Step 1: Version hochzählen** +- [x] **Step 1: Version hochzählen** `finance/VERSION`: ``` 0.10.0 ``` -- [ ] **Step 2: Volle Suite** +- [x] **Step 2: Volle Suite** Run: `cd finance && .venv/bin/python -m pytest -q` Expected: PASS (> 199). -- [ ] **Step 3: Redeploy (Lokalbetrieb, `.env` OHNE Proxy-Variablen)** +- [x] **Step 3: Redeploy (Lokalbetrieb, `.env` OHNE Proxy-Variablen)** Run: `./create_pod_finance.sh` Expected: Läuft durch bis „API is reachable ... (200)" und „Grafana is reachable ... (200)"; Service enabled+active. Der Health-Check spricht ohne Präfix `:8097/api/health` (weil `FB_GRAFANA_PUBLIC_URL` leer). -- [ ] **Step 4: Live-Check Lokalbetrieb unverändert** +- [x] **Step 4: Live-Check Lokalbetrieb unverändert** ```bash # Login → 303 + Cookie (Cookie OHNE Secure, da FB_SESSION_COOKIE_SECURE leer) @@ -737,12 +737,12 @@ Expected: Login `303` + `set-cookie: fb_session=...` **ohne** `Secure`; `/api/version` → `{"version":"0.10.0"}`; Grafana-Link enthält `:8097/d/finanzen` und **kein** `/grafana`; alle Seiten `200`; `grafana:200`. -- [ ] **Step 5: Plan-Haken + Ledger** — alle Task-Checkboxen dieses Plans +- [x] **Step 5: Plan-Haken + Ledger** — alle Task-Checkboxen dieses Plans setzen; in `.superpowers/sdd/progress.md` einen A10-Abschluss-Eintrag ergänzen (Commit-Range, Fable-Befunde je Task, Live-Check-Ergebnis; **keine** echten Kontodaten/Domain-Secrets). -- [ ] **Step 6: Fable-Release-Gate + Commit** +- [x] **Step 6: Fable-Release-Gate + Commit** Fable verifiziert: Suite grün, Version live `0.10.0`, Lokalbetrieb im Live-Check unverändert (Cookie ohne Secure, Grafana-Fallback `:8097`), diff --git a/finance/VERSION b/finance/VERSION index 1f50484..8d93765 100644 --- a/finance/VERSION +++ b/finance/VERSION @@ -1 +1 @@ -0.9.0 +0.10.0