feat: Phase 2 – Budget-Engine + Direktzugriff (http://IP:Port)

Budget:
- Modelle + Migration 0003: budget_template_lines, planned_income_lines,
  budget_periods, budget_period_lines.
- services/budget: Perioden-Grenzen (einstellbarer Starttag, Label nach Endmonat),
  Standard-Vorlage vs. Monats-Override (Snapshot-on-Customize), Soll/Ist inkl.
  budgetierter Sparen-Transfers, geplante Einnahmen (Soll/Ist).
- routers/budgets: Vorlage, geplante Einnahmen (CRUD), Monats-Soll/Ist,
  Monats-Override, Zurücksetzen. pytest: Perioden, Soll/Ist, Override/Reset, Einnahmen.
- Frontend: Budget-Seite (Monat + Standard-Budget), Fortschrittsbalken grün/rot,
  Monats-Navigation, editierbare Soll-Beträge; Sparen-Option im Transfer-Formular.

Deployment-Fix (Nutzer-Anforderung: http://IP:Port muss funktionieren):
- Dienst bindet an APP_BIND_HOST=0.0.0.0 (direkt im LAN erreichbar).
- APP_COOKIE_SECURE=false als Standard (sonst kein Login über reines HTTP);
  für reinen HTTPS-Betrieb umstellbar. Doku + install.sh entsprechend angepasst.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido
2026-08-19 19:16:27 +02:00
co-authored by Claude Opus 4.8
parent d692c04cc1
commit 8ed4bf5254
21 changed files with 1352 additions and 22 deletions
+13 -8
View File
@@ -95,6 +95,8 @@ if [[ -f "$ENV_FILE" ]]; then
else
echo "APP_GIT_SHA=$GIT_SHA" >> "$ENV_FILE"
fi
# Direktzugriff (http://IP:Port) für ältere Konfigurationen nachrüsten.
grep -q '^APP_BIND_HOST=' "$ENV_FILE" || echo "APP_BIND_HOST=0.0.0.0" >> "$ENV_FILE"
ADMIN_USER="$(grep -E '^APP_ADMIN_USERNAME=' "$ENV_FILE" | cut -d= -f2-)"
GENERATED_PASS=""
else
@@ -110,9 +112,10 @@ else
info "Erzeuge Konfiguration: $ENV_FILE"
cat > "$ENV_FILE" <<EOF
APP_DATA_DIR=$DATA_DIR
APP_BIND_HOST=0.0.0.0
APP_PORT=$local_port
APP_SESSION_SECRET=$(rand 48)
APP_COOKIE_SECURE=true
APP_COOKIE_SECURE=false
APP_ADMIN_USERNAME=$admin_user
APP_ADMIN_PASSWORD=$admin_pass
APP_DEFAULT_BASE_CURRENCY=EUR
@@ -139,7 +142,7 @@ User=$SERVICE_USER
Group=$SERVICE_USER
WorkingDirectory=$REPO_DIR/backend
EnvironmentFile=$ENV_FILE
ExecStart=$REPO_DIR/backend/.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port \${APP_PORT}
ExecStart=$REPO_DIR/backend/.venv/bin/uvicorn app.main:app --host \${APP_BIND_HOST} --port \${APP_PORT}
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
@@ -167,24 +170,26 @@ for _ in $(seq 1 30); do
sleep 2
done
LAN_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
echo
if [[ "$ok" -eq 1 ]]; then
info "Fertig – Certain Finance läuft. 🎉"
else
warn "Backend antwortet noch nicht. Logs: journalctl -u $APP_SLUG -e"
fi
echo " Interner Dienst: http://127.0.0.1:$PORT (nur lokal)"
echo " Web-UI (direkt): http://${LAN_IP:-<LXC-IP>}:$PORT"
echo " Admin-Login: ${ADMIN_USER:-admin}"
if [[ -n "${GENERATED_PASS:-}" ]]; then
echo " Admin-Passwort: ${GENERATED_PASS}"
warn "Bitte dieses Passwort notieren – es wird nicht erneut angezeigt."
fi
echo
echo " Nginx Proxy Manager: neuen Proxy-Host anlegen ->"
echo " Forward Hostname/IP: <IP-dieses-LXC>"
echo " Forward Port: $PORT"
echo " SSL: Let's Encrypt aktivieren; 'Block Common Exploits' ok."
echo " (Websockets nicht nötig. Für spätere Uploads client_max_body_size >= 20M.)"
echo " Optional über HTTPS (Nginx Proxy Manager): neuen Proxy-Host ->"
echo " Forward Hostname/IP: ${LAN_IP:-<LXC-IP>}"
echo " Forward Port: $PORT (Scheme: http)"
echo " SSL: Let's Encrypt aktivieren. Dann in $ENV_FILE APP_COOKIE_SECURE=true"
echo " setzen und 'systemctl restart $APP_SLUG'. (Uploads: client_max_body_size >= 20M.)"
echo
echo " Logs: journalctl -u $APP_SLUG -f"
echo " Neustart: systemctl restart $APP_SLUG"