Lade…
Lade…
| Bezeichnung | Kategorie | Intervall | Startdatum | Dauer | Betrag | Mtl. äquiv. |
|---|
| ASSETKLASSE | CAGR % P.A. | AKTUELL (€) | WERT IN 10 J. | ZUWACHS |
|---|
Verfügbare Verbindungen
CSV-Import
Pflichtfelder: Bezeichnung · Betrag · Kategorie · Intervall
Contabo VPS · 158.220.102.129
Detaillierte Echtzeit-Auswertung via Netdata Cloud.
Netdata öffnen ↗API-Datenvolumen · gemessen seit Aktivierung
WireGuard · 158.220.102.129
| Name | IP-Adresse | Status | Daten RX / TX | Aktionen |
|---|---|---|---|---|
| Lädt… | ||||
Prüft alle Datenquellen der Plattform — Backend, Broker, Krypto, Wirtschaftsdaten und Nachrichten.
Klicke auf Farbe oder Name zum Bearbeiten. Änderungen sofort aktiv.
Scannt alle Portfolio-Positionen auf fehlende Felder (Typ, Branche, Land, Währung) und schlägt passende Werte vor — vor der Übernahme manuell anpassbar.
Dieser Bereich gibt direkten Lese- und Schreibzugriff auf alle PostgreSQL-Tabellen. Bitte das Datenbank-Passwort eingeben.
Interaktiver Schema-Explorer mit ER-Diagramm und Datenzugriff. Datenbank-Passwort eingeben.
Jedes Backup ist ein vollständiger Dump der PostgreSQL-Datenbank, gespeichert auf dem VPS. Automatisch täglich um 07:00 Uhr; abgelaufene Backups werden automatisch entfernt.
/api/inbox mit Header Authorization: Bearer <INBOX_TOKEN> und JSON-Body {"text":"Idee: …"}.Auto-Klassifikation: Beginnt der Text mit „idee" → Idee, mit „todo/erinnere/merken" → Todo, sonst Notiz.
Kein Binance API Key konfiguriert. Nur Read-Rechte verwenden!
Lade…
Das Dashboard begann als reine Browser-Anwendung: Alle Finanzdaten lagen im localStorage des jeweiligen Geräts. Das funktioniert für ein einzelnes Gerät — scheitert aber, sobald PC und Handy parallel genutzt werden, denn jedes Gerät hätte seinen eigenen, abweichenden Datenstand.
Ziel des Umbaus: eine einzige, zentrale Datenquelle, die von allen Geräten gleichzeitig gelesen und beschrieben werden kann — als Grundlage für die geplante Android-App und Widgets.
Jedes Gerät öffnet dieselbe Oberfläche über den Webserver nginx. nginx liefert die HTML-Seite aus und reicht alle /api/-Aufrufe an das Flask-Backend weiter. Das Backend ist der einzige Baustein, der mit der PostgreSQL-Datenbank spricht — dort liegen sämtliche Finanzdaten zentral.
Eine Änderung auf einem Gerät landet sofort in der Datenbank. Über eine dauerhaft offene Live-Verbindung (SSE) werden alle anderen Geräte benachrichtigt und ziehen die Änderung automatisch nach.
- Hardware-Setup & Server-Architektur — Geräte, VPS, Repository und Sicherheitsinfrastruktur.
- Datenhaltung — die PostgreSQL-Datenbank und ihre Fachtabellen.
- Backend & REST-API — das Flask-Backend als Vermittler zur Datenbank.
- Synchronisation — wie Änderungen sicher zwischen Geräten abgeglichen werden.
- Betrieb & Deployment — VPS, nginx, systemd und die automatische Auslieferung.
- Sicherheit — Zugangsschichten und der Schutz sensibler Schlüssel.
- Datenbankverwaltung — der integrierte Direktzugriff auf alle Tabellen.
- Backups & Notfall — Sicherung und Wiederherstellung der Datenbank.
Gerät 1 — Windows 11 PC
Primärgerät für Entwicklung und Nutzung. Hier läuft Claude Code als KI-gestützte Entwicklungsumgebung sowie eine SSH-Verbindung direkt auf den VPS für serverseitige Wartung und Konfiguration. Das Dashboard wird im Browser aufgerufen — identisch zur Nutzung auf jedem anderen Gerät.
Gerät 2 — Android Smartphone
Mobiles Nutzungsgerät. Das Dashboard läuft vollständig im Browser — keine native App erforderlich. Die responsive Oberfläche passt sich dem Bildschirm an. Über das integrierte VPN (WireGuard) besteht bei Bedarf gesicherter Zugang auch außerhalb des Heimnetzes.
Der gesamte Betrieb läuft auf einem Virtual Private Server (VPS) bei Contabo. Der VPS ist unter personal-finance-v2.duckdns.org erreichbar und stellt alle serverseitigen Dienste bereit:
- nginx — Webserver, TLS-Terminierung, Reverse Proxy für die API.
- Flask / gunicorn — Backend-Anwendung auf
127.0.0.1:7700. - PostgreSQL — Datenbank für alle Finanzdaten.
- WireGuard — VPN-Server für gesicherten Remote-Zugang.
Der gesamte Quellcode liegt in einem privaten GitHub-Repository. Von dort aus wird der VPS per GitHub Actions automatisch bei jedem Push auf main aktualisiert — per SSH ohne manuelle Eingriffe. Details zur Deploy-Pipeline finden sich in Kapitel 06.
Auf dem VPS läuft ein WireGuard VPN-Server. Die Verwaltung der VPN-Peers (Geräte-Konfigurationen, IP-Zuteilungen, QR-Codes) erfolgt direkt über die VPN-Verwaltungsseite im Dashboard — die Konfigurationsdateien und Pre-Shared Keys werden sicher in Bitwarden abgelegt.
Über IP-Allowlisting lässt sich der Zugang zum Dashboard auf bestimmte IPs oder VPN-Adressen beschränken, sodass der VPS von außen nur für autorisierte Verbindungen erreichbar ist.
- ENV-Ablage — alle Secrets (DB-Passwort, API-Schlüssel, Token, Passwort-Hashes) liegen ausschließlich in
/opt/finance/.envauf dem VPS. Die Datei ist nicht versioniert und verlässt den Server nie. - Kein Secret im Code — das GitHub-Repository enthält keine sensiblen Daten. GitHub Actions nutzt verschlüsselte Repository-Secrets für den SSH-Deploy-Key.
- Zugriffsbeschränkungen — nginx Basic-Auth als erste Hürde, Dashboard-Login mit gehashtem Passwort (
SHA-256), separates DB-Admin-Passwort. Details in Kapitel 07. - SSH-Härtung — Root-Login per Passwort deaktiviert, Zugang nur per SSH-Key. Der Deploy-Key für GitHub Actions ist auf Minimal-Rechte beschränkt.
- VPN als Zugangskontrolle — sensible Verwaltungsfunktionen sind optional nur über die VPN-IP erreichbar, wodurch öffentliche Zugriffe strukturell ausgeschlossen werden können.
Früher lagen alle Daten als ein großer Block im Browser jedes Geräts. Heute liegen sie in einer PostgreSQL-Datenbank — einem ausgewachsenen Datenbanksystem, das auf dem Server läuft.
Statt eines formlosen Blobs hat jeder Datenbereich eine eigene Tabelle mit festen Spalten und Datentypen. Das erzwingt saubere, widerspruchsfreie Daten und macht gezielte Abfragen möglich.
Auf dem Server läuft PostgreSQL 16 mit der Datenbank finance und dem Benutzer finance. Die Zugangsdaten stehen als DATABASE_URL in der geschützten Konfigurationsdatei .env — nie im Code.
Die Daten verteilen sich auf elf Fachtabellen:
| Tabelle | Inhalt |
|---|---|
transactions | Einnahmen & Ausgaben |
categories | Kategorien für Ein- und Ausgaben |
loans | Darlehen & Kredite |
portfolio_stocks | Wertpapiere — Aktien & ETFs |
portfolio_metals | Edelmetalle — Gold & Silber |
portfolio_wallets | Krypto-Wallets — BTC & ETH |
binance_balances | Binance-Guthaben |
f24_cash | Freedom24-Cash-Bestände |
price_cache | zwischengespeicherte Kurse |
savings_goals | Sparziele |
settings | alle übrigen Einstellungen als Schlüssel/Wert-Paare |
schema.sql legt alle Tabellen und Indizes an. migrate.py hat einmalig die Altdaten aus dem localStorage-Backup importiert. db_pg.py kapselt die Datenbankverbindung über die Bibliothek psycopg2.
Bewusste Ausnahmen: Kurs-Caches für Edelmetall- und Crypto-Preise bleiben rein lokal pro Gerät — sie sind flüchtig und werden per API neu geholt. Die Sprach-Inbox nutzt weiterhin eine separate, kleine SQLite-Datei inbox.db.
Die Geräte sprechen nie direkt mit der Datenbank. Dazwischen sitzt das Flask-Backend: Es nimmt alle Anfragen entgegen, prüft Berechtigung und Inhalt und übersetzt sie in Datenbank-Befehle.
Dieser Zwischenschritt ist die Stelle, an der Sicherheit, Validierung und einheitliche Logik durchgesetzt werden — ein Browser kann die Datenbank so nicht direkt manipulieren.
Die Datei server.py definiert über 40 REST-Endpunkte. Jeder Datenbereich hat einen Endpunkt zum Lesen (GET) und zum Schreiben (POST / PUT / DELETE). Der Anwendungsserver gunicorn betreibt diese App als dauerhaft laufenden Dienst.
| Endpunkt | Funktion |
|---|---|
/api/transactions | Einnahmen & Ausgaben — lesen, anlegen, ändern, löschen |
/api/categories | Kategorien verwalten |
/api/portfolio/* | Wertpapiere, Edelmetalle, Wallets, Cash |
/api/loans | Darlehen verwalten |
/api/settings | alle übrigen Einstellungen |
/api/events | Live-Verbindung für Echtzeit-Updates (SSE) |
/api/dbadmin/* | Direktzugriff auf die Tabellen (Kapitel 08) |
/api/login | Anmeldung — gibt das Zugriffs-Token zurück |
db_pg.py stellt die Datenbankverbindung bereit. Bulk-Endpunkte wie /api/portfolio/bulk und /api/loans/bulk ersetzen eine ganze Tabelle atomar in einer einzigen Transaktion — entweder gelingt alles oder nichts.
Jeder schreibende Endpunkt ruft am Ende _notify_sse() auf. Damit erfahren alle verbundenen Geräte sofort, dass sich etwas geändert hat — die Brücke zur Synchronisation im nächsten Kapitel.
Weg A — Replace-all
Bei jeder Änderung wird der komplette Bereich (z. B. alle Kategorien) zum Server gespiegelt. Einfach und robust. Genutzt für Einstellungen, Kategorien, Kredite und Portfolio.
Weg B — Granular / Delta
Nur die tatsächlich geänderten Datensätze werden einzeln gesendet. Der aktuelle Stand wird gegen einen Schnappschuss (_txSnapshot) verglichen. Genutzt für Transaktionen — viele Einträge, kleine Änderungen.
- Dirty-Flag — blockiert das Überschreiben durch einen Server-Pull, solange eine lokale Änderung noch nicht gesendet wurde.
- Synchroner Re-Check — direkt vor dem Schreiben in den lokalen Speicher wird der Serverstand noch einmal geprüft.
- Init-Push — pro Bereich gibt es ein einmaliges erstes Hochladen (
_*_rest_init-Flags). - Leer-Schutz — ein leerer, nie synchronisierter Stand wird nie hochgeladen. So kann ein frisch geöffneter Browser die zentrale Datenbank nicht leeren.
Über den Endpunkt /api/events hält jedes Gerät eine dauerhaft offene Verbindung (Server-Sent Events). Schreibt ein Gerät etwas, ruft das Backend _notify_sse() — und alle anderen Geräte ziehen die Änderung sofort nach, ohne dass die Seite neu geladen werden muss.
Code-Änderungen sollen ohne manuelle Schritte auf dem Server live gehen. Ein git push auf den Hauptzweig genügt — der Rest läuft automatisch.
Das Dashboard läuft auf einem VPS (eigener virtueller Server) unter personal-finance-v2.duckdns.org. Drei Bausteine arbeiten zusammen:
- nginx — der Webserver. Liefert
Finance-dashboard.htmldirekt als Datei aus und reicht alle/api/-Aufrufe an das Backend weiter. - finance.service — ein systemd-Dienst. Hält das Backend (gunicorn auf
127.0.0.1:7700) dauerhaft am Laufen und startet es bei Boot oder Absturz automatisch neu. - GitHub Actions — die Automatik, die jeden Push auf den Server überträgt.
Bei jedem Push auf main verbindet sich GitHub Actions per SSH mit dem VPS und führt aus: Code holen (git reset --hard origin/main), Python-Abhängigkeiten installieren (pip install -r requirements.txt) und den Dienst neu laden (systemctl reload finance.service).
Arbeitsverzeichnis ist /opt/finance, die Konfiguration steht in /opt/finance/.env. HTML-Änderungen wirken sofort, weil nginx die Datei direkt ausliefert; Backend-Änderungen werden durch den Dienst-Neustart aktiv — beides erledigt die Pipeline automatisch.
Zwei Dinge müssen geschützt sein: der Zugang zu den Finanzdaten und die geheimen API-Schlüssel für externe Dienste. Beides wird durch mehrere voneinander unabhängige Schichten abgesichert.
- nginx Basic-Auth — die erste Hürde schon beim Aufruf der Seite, bevor überhaupt etwas geladen wird.
- Dashboard-Login — Benutzername und Passwort. Das Passwort liegt nur als SHA-256-Hash in der
.env. Ein erfolgreicher Login gibt ein Token zurück, das schreibende API-Aufrufe autorisiert. - dbadmin-Passwort — die Datenbankverwaltung (Kapitel 08) ist zusätzlich mit einem eigenen Passwort (
DB_ADMIN_PASSWORD) gesperrt.
Schlüssel für externe Dienste — etwa die Binance-API — liegen ausschließlich in /opt/finance/.env auf dem Server. Das Frontend bekommt sie nie zu sehen: Es ruft nur /api/binance/… auf, und der Server hängt die Schlüssel selbst an die Anfrage an externe Dienste.
So kann selbst ein kompromittierter Browser keine Schlüssel verraten.
hmac.compare_digest — ein zeitkonstanter Vergleich, der keine Rückschlüsse über die Antwortdauer zulässt (Schutz gegen Timing-Angriffe). Tokens und Schlüssel stehen niemals im Code, sondern immer in der nicht versionierten .env.Manchmal muss man Daten direkt korrigieren oder einsehen — ohne den Umweg über die normale Oberfläche und ohne ein externes Datenbank-Werkzeug. Genau dafür gibt es im System-Menü den Bereich Datenbankverwaltung.
Nach Eingabe des Datenbank-Passworts werden alle elf Tabellen aufgelistet. Jede lässt sich als Tabelle anzeigen; einzelne Zeilen können angelegt, bearbeitet und gelöscht werden.
Jede Schreibaktion löst — wie überall im System — _notify_sse() aus. So sehen offene Dashboards eine Korrektur sofort.
Die Backend-Endpunkte /api/dbadmin/* bedienen den Bereich: auth prüft das Passwort, tables listet die Tabellen, table/<name> liest und schreibt Zeilen. Tabellennamen werden serverseitig gegen eine feste Liste erlaubter Namen geprüft — das schließt SQL-Injection aus.
Das Werkzeug pg_dump schreibt den kompletten Inhalt der Datenbank in eine einzelne .sql-Datei. Diese eine Datei genügt, um die gesamte Datenbank exakt wiederherzustellen.
Ein Backup wird nicht direkt über die Live-Datenbank eingespielt. Stattdessen:
- Das Backup in eine temporäre Datenbank (z. B.
finance_restore) laden. - Dort die benötigten Tabellen prüfen.
- Gezielt per
pg_dump --data-onlynur die betroffenen Tabellen in die Live-Datenbank übertragen.
So bleibt die Live-Datenbank bei einem Teilverlust unangetastet — es wird nur das Fehlende ersetzt.
Ein automatisches tägliches Backup per pg_dump ist geplant. Aktuell erfolgt die Sicherung noch manuell.