# 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 ```text 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 ```bash 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](/home/hnzio/Projekte/saldo/.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 ```bash 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`: ```bash SECRET_KEY= DATABASE_URL=sqlite:////app/data/saldo.db SALDO_DATA_DIR=/app/data SALDO_ADMIN_USERNAME=admin SALDO_ADMIN_PASSWORD= SALDO_ADMIN_EMAIL=admin@example.invalid VAPID_PUBLIC_KEY= VAPID_PRIVATE_KEY= VAPID_SUBJECT=mailto:admin@example.invalid ``` Startkommando: ```bash gunicorn -c gunicorn.conf.py wsgi:app ``` Im Container übernimmt `start.sh` vor dem Start automatisch: ```bash 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 ```bash 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 - Manifest: [app/static/manifest.json](/home/hnzio/Projekte/saldo/app/static/manifest.json) - Service Worker: [app/static/service-worker.js](/home/hnzio/Projekte/saldo/app/static/service-worker.js) - Push-Subscription-Route: [app/planning/routes.py](/home/hnzio/Projekte/saldo/app/planning/routes.py:113) - Reminder-Logik: [app/services/notification_service.py](/home/hnzio/Projekte/saldo/app/services/notification_service.py) ## 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: ```bash 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 ```