2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00
2026-04-21 21:17:36 +02:00

Saldo

Saldo ist eine moderne Flask-PWA für Mehrbenutzer-Haushaltsplanung. Die App fokussiert sich auf Monatsplanung, Überweisungsverteilungen, variable Einkommen, Restbetragsvorschläge und externe Kostenbeteiligung, statt klassische Buchhaltung nachzubauen.

Aktueller Projektstand: 0.1.0

Features

  • automatische Monatsanlage beim ersten Öffnen eines neuen Kalendermonats
  • Kopieren des Vormonats inklusive Einkommen, Planwerten, Verteilungen und Beteiligungslogik
  • variable Einkommenszeilen pro Monat
  • verpflichtende Anzeigenamen für Nutzer, sichtbar in Avataren, Splits und Budgetdetails
  • Vorschlags-Engine für Sparen, Urlaub, Freizeit und Persönliche Auszahlung
  • externe Kostenbeteiligte ohne App-Login
  • PWA mit Manifest und Service Worker
  • Web Push mit VAPID-Keys
  • Rollenmodell mit admin und editor
  • keine offene Registrierung
  • Healthcheck unter /health

Stack

  • Python 3
  • Flask
  • SQLAlchemy
  • Flask-Login
  • Flask-Migrate / Alembic
  • Jinja Templates
  • leichtes Vanilla JS
  • Chart.js
  • SQLite als Default
  • Gunicorn

Projektstruktur

app/
  admin/            Admin-Views für Benutzer und Beteiligte
  auth/             Login/Logout
  main/             Übersicht, Auswertungen, Healthcheck
  months/           Monatsliste, Locking, manuelles Anlegen
  planning/         Monatliche Bearbeitung von Einkommen, Kosten, Verteilungen
  services/         Domänenlogik für Monate, Vorschläge, Vergleiche, Shares, Push
  static/           CSS, JS, Icons, Manifest, Service Worker
  templates/        Jinja-Templates
  models.py         SQLAlchemy-Modelle
  seed.py           Seed-Daten
migrations/         Alembic-Migrationen
tests/              Pytest-Suite

Lokal starten

python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
export FLASK_APP=wsgi:app
python -m flask db upgrade
python -m flask seed
python -m flask run --debug

Die App läuft lokal standardmäßig mit SQLite im instance- bzw. konfigurierten Datenverzeichnis. Beim ersten Aufruf öffnet sich automatisch die Setup-Seite zur Anlage des ersten Admins.

Wichtig für lokale Tests:

  • die lokale Datenbank liegt standardmäßig in instance/saldo.db
  • Uploads und andere Laufzeitdaten liegen ebenfalls im Datenverzeichnis
  • diese Dateien werden über .gitignore bewusst nicht versioniert
  • dadurch kannst du lokal testen, später Änderungen pullen und danach einfach wieder python -m flask db upgrade ausführen

Wichtige Umgebungsvariablen

Siehe .env.example.

  • SECRET_KEY
  • DATABASE_URL
  • SALDO_DATA_DIR
  • SALDO_ADMIN_USERNAME
  • SALDO_ADMIN_PASSWORD
  • SALDO_ADMIN_EMAIL
  • VAPID_PUBLIC_KEY
  • VAPID_PRIVATE_KEY
  • VAPID_SUBJECT
  • SALDO_ALLOCATION_TARGET_RULES
  • SALDO_STRONG_INCOME_CHANGE_THRESHOLD

CLI-Kommandos

python -m flask create-admin --username admin2 --display-name "Admin 2" --email admin2@example.com --password secret
python -m flask bootstrap-admin
python -m flask seed
python -m flask run-reminders

seed legt nur die Grundstruktur an. bootstrap-admin bleibt als optionaler CLI-Weg verfügbar. run-reminders kann auf Cloudron als Scheduled Task oder per Cron ausgeführt werden.

Cloudron-Hinweise

Vorbereitete Paketdateien:

  • CloudronManifest.json
  • Dockerfile
  • start.sh
  • DESCRIPTION.md
  • CHANGELOG
  • POSTINSTALL.md

Cloudron-Release-Stand:

  • App-Version: 0.1.0
  • Healthcheck: /health
  • interner Port: 8000
  • persistente Daten: /app/data
  • Build-Hygiene: .dockerignore schließt lokale DBs, instance/, Test-Caches und Editor-Dateien aus

Empfohlene Env-Konfiguration für eine Cloudron-Subdomain wie https://saldo.example.com:

SECRET_KEY=<random>
DATABASE_URL=sqlite:////app/data/saldo.db
SALDO_DATA_DIR=/app/data
SALDO_ADMIN_USERNAME=admin
SALDO_ADMIN_PASSWORD=<random>
SALDO_ADMIN_EMAIL=admin@example.invalid
VAPID_PUBLIC_KEY=<public>
VAPID_PRIVATE_KEY=<private>
VAPID_SUBJECT=mailto:admin@example.invalid

Startkommando:

gunicorn -c gunicorn.conf.py wsgi:app

Im Container übernimmt start.sh vor dem Start automatisch:

python -m flask db upgrade
python -m flask seed

Wenn du mit der Cloudron CLI paketierst oder hochlädst:

  • die lokale SQLite-Datei aus instance/ wird nicht mitgeschickt
  • lokale .env-Dateien werden nicht mitgeschickt
  • Test-/Cache-Dateien und Editor-Metadaten bleiben ebenfalls draußen
  • produktive Daten sollen weiterhin ausschließlich in /app/data liegen

Cloudron-Kompatibilität in diesem Projekt:

  • persistente Daten im konfigurierbaren Datenverzeichnis
  • Logging über stdout/stderr
  • Healthcheck-Route /health
  • keine Benutzer-Selbstregistrierung
  • Erststart-Setup im Browser für den ersten Admin
  • optionaler Admin-Bootstrap per CLI
  • Reminder-Check als separater wiederverwendbarer CLI-Task
  • neutrale Basisdaten werden auf Fresh-Install automatisch angelegt

Hinweis für spätere Update-Verteilung:

  • Laut Cloudron-Publishing-Workflow wird nach dem ersten Build die Datei CloudronVersions.json mit cloudron versions add erzeugt und anschließend öffentlich bereitgestellt.
  • Damit erscheinen neue Versionen später automatisch als Community-App-Updates.

Basisdaten

Das Seed-Script legt an:

  • Standardkonten, Kategorien und Einträge
  • Gemeinschaftskonten-Grundstruktur

Nicht angelegt werden:

  • Beispielzugänge
  • Beispielpersonen
  • Demo-Monatswerte

Tests

python -m pytest -q

Aktueller Stand:

  • 31 Tests grün

Hinweise zur Kernlogik

MonthService.ensure_month():

  • legt den aktuellen Kalendermonat automatisch an
  • übernimmt beim Anlegen den letzten vorhandenen Monat
  • fällt beim ersten Start auf einen Seed-Standardmonat zurück

AllocationSuggestionService.recompute():

  • berechnet den verteilbaren Restbetrag
  • respektiert gesperrte Zielkonten
  • verteilt den übrigen Betrag gewichtet
  • gleicht Rundungsreste in der letzten Vorschlagszeile aus

PWA und Push

Git und Releases

Repo-Vorbereitung in diesem Stand:

  • .gitignore verhindert, dass lokale SQLite-Datenbank, Uploads und Laufzeitdaten eingecheckt werden
  • .dockerignore hält lokale Test- und Laufzeitdateien auch aus Cloudron-Builds heraus
  • VERSION und CHANGELOG dokumentieren den aktuellen Release-Stand
  • LICENSE erlaubt private Nutzung

Empfohlene Release-Schritte:

git init -b main
git remote add origin https://git.hnz.io/hnzio/saldo.git
git add .
git commit -m "chore: prepare saldo 0.1.0 for git and cloudron"
git push -u origin main
S
Description
No description provided
Readme 290 KiB
Languages
Python 65.3%
HTML 21.5%
CSS 8.2%
JavaScript 4.7%
Mako 0.1%
Other 0.1%